我想保存我的画布到img。我有这样一个函数:

function save() {
    document.getElementById("canvasimg").style.border = "2px solid";
    var dataURL = canvas.toDataURL();
    document.getElementById("canvasimg").src = dataURL;
    document.getElementById("canvasimg").style.display = "inline";
}

它给出了错误:

Uncaught SecurityError:未能在“HTMLCanvasElement”上执行“toDataURL”:受污染的画布可能无法导出。

我该怎么办?


当前回答

博士tl;

这个问题让我很抓狂,在渲染画布之前用crossOrigin="anonymous"加载图像解决了这个问题。

详细和过于具体的解决方案

对于那些使用React + canvg + Amazon S3并希望通过canvas将svg导出为png的人来说,这可能很有用。

首先,创建一个React钩子来检测预加载的跨原点图像:

// useLoadCrossOriginImage.tsx

import { useReducer, useMemo } from 'react'

export function useLoadCrossOriginImage(imageUrls: string[]) {
  const [count, increase] = useReducer((count) => count + 1, 0)

  const render = () =>
    imageUrls.map((url) => (
      <img
        src={url}
        crossOrigin="anonymous"
        onLoad={increase}
        className="hidden"
      />
    ))

  const loaded = useMemo(() => count === imageUrls.length, [count, imageUrls])

  return {
    render,
    loaded,
  }
}

然后,加载图像后,惰性渲染svg:

// ImagePreview.tsx

import { useLoadCrossOriginImage } from './useLoadCrossOriginImage'

// This is usually state from parent component
const imageUrls = [
  'https://s3-ap-northeast-1.amazonaws.com/bucket/xxxxxxx.png',
  'https://s3-ap-northeast-1.amazonaws.com/bucket/yyyyyyy.png',
]

export const ImagePreview = () => {
  const { loaded, render } = useLoadCrossOriginImage(imageUrls)

  return (
    <div className="border border-slate-300" onClick={onClick}>
      {render()}
      {loaded && (
        <svg xmlns="http://www.w3.org/2000/svg">
          {imageUrls.map((imageUrl) => (
            <image key={el.id} href={imageUrl} />
          ))}
        </svg>
      )}
      <canvas className="hidden" />
    </div>
  )
}

最后,你可以将canvas元素转换为png:

const canvas = document.querySelector('canvas')!
const ctx = canvas.getContext('2d')!
const svg = document.querySelector('svg')!
const v = Canvg.fromString(ctx, svg.outerHTML, { anonymousCrossOrigin: true })

最后,S3的cors策略应该是这样的:

{
  "CORSRules": [
    {
      "ID": "s3-cors-policy",
      "AllowedHeaders": ["*"],
      "AllowedMethods": ["GET", "HEAD"],
      "AllowedOrigins": ["*"],
      "ExposeHeaders": []
    }
  ]
}

请将“maxagesecseconds”保留为空。

其他回答

对于任何在应用服务器跨源设置后仍然在S3中遇到相同问题的人来说,这可能是浏览器缓存问题。 所以你需要确保禁用缓存并再次测试,你可以从浏览器的dev-tools ->网络选项卡->单击禁用现金选项->重试:

在我的情况下,我从我的桌面进行测试,即使在本地保存图像到子文件夹后,也有CORS错误。

解决方案:

移动文件夹到本地服务器WAMP在我的情况下。从本地服务器完美工作。

注意: 只有在本地保存图像时才有效。

如果有人对我的回答有看法,你可能会有这样的情况:

1. 尝试在画布中使用openlayers获取地图截图(版本>= 3) 2. 并查看了导出map的示例 3.使用ol.source.XYZ渲染地图层

宾果!

使用ol.source.XYZ.crossOrigin = '匿名'来解决你的困惑。 或者像下面的代码:

 var baseLayer = new ol.layer.Tile({
     name: 'basic',
     source: new ol.source.XYZ({
         url: options.baseMap.basic,
         crossOrigin: "Anonymous"
     })
 });

在OpenLayers6中,ES6做了一些改变。然而,代码是相似的。

import { XYZ } from 'ol/source'
import { Tile as TileLayer } from 'ol/layer'
const baseLayer = new TileLayer({
    name : 'basic',
    source: new XYZ({
      url: 'example.tile.com/x/y/z', // your tile url
      crossOrigin: 'Anonymous',
      // remove this function config if the tile's src is nothing to decorate. It's usually to debug the src
      tileLoadFunction: function(tile, src) {
        tile.getImage().src = src
      }
    })
  })

更重要的是,不要忘记在响应头中设置access-control-allow-origin: *或access-control-allow-origin:[你的白名单起源],如果瓷砖是在你自己的服务器上请求的。 是这样的: 更多细节,还有这个

这个可以在laravel中顺利工作。

首先,您需要将受污染的画布转换为blob。在此之后,您可以上传一个blob来服务并将其保存为图像。在ajax调用中返回图像URL。

这是一个上传画布blob的ajax调用。

$("#downloadCollage").click(function(){
  canvas.toBlob(function(blob){

    var formDataToUpload = new FormData();
    formDataToUpload.append("_token", "{{ csrf_token() }}");
    formDataToUpload.append("image",  blob);

    $.ajax({
        url:"{{ route('selfie_collage_upload') }}",
        data: formDataToUpload,
        type:"POST",
        contentType:false,
        processData:false,
        cache:false,
        dataType:"json",
        error:function(err){
            console.error(err);
        },
        success:function(data){
            window.location.href= data.url;
        },
        complete:function(){
        }
    });
  },'image/png');
  link.click();
});

似乎您正在使用的图像来自一个URL,没有设置正确的访问控制-允许起源头,因此出现了问题。您可以从您的服务器获取该映像,并从您的服务器获取它以避免CORS问题。