我想保存我的画布到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”:受污染的画布可能无法导出。

我该怎么办?


当前回答

检查从MDN启用的CORS图像。 基本上,你必须有一个服务器托管图像与适当的Access-Control-Allow-Origin头。

< IfModule mod_setenvif c >。 < IfModule mod_headers c >。 < FilesMatch”\。(狗| gif | ico | jpe ? g | png | svgz ? | webp美元)" > “IS_CORS” 标题集access -控制 < / FilesMatch > < / IfModule > < / IfModule >

您将能够将这些图像保存到DOM存储,就像它们是从您的域提供的一样,否则您将遇到安全问题。

var img = new Image, canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"), src = "http://example.com/image"; // insert image url here img.crossOrigin = "Anonymous"; img.onload = function() { canvas.width = img.width; canvas.height = img.height; ctx.drawImage( img, 0, 0 ); localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") ); } img.src = src; // make sure the load event fires for cached images too if ( img.complete || img.complete === undefined ) { img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; img.src = src; }

其他回答

如果你正在使用ctx.drawImage()函数,你可以做以下事情:

var img = loadImage('../yourimage.png', callback);

function loadImage(src, callback) {
    var img = new Image();

    img.onload = callback;
    img.setAttribute('crossorigin', 'anonymous'); // works for me

    img.src = src;

    return img;
}

在你的回调中,你现在可以使用ctx。drawImage并使用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”保留为空。

在我的例子中,我从一个视频中用画布之类的东西画在一个画布标签上。为了解决受污染的画布错误,我必须做两件事:

<video id="video_source" crossorigin="anonymous">
    <source src="http://crossdomain.example.com/myfile.mp4">
</video>

确保在视频源响应中设置了Access-Control-Allow-Origin头(正确设置crossdomain.example.com) 设置视频标签为crossorigin="anonymous"

出于安全原因,您的本地驱动器被声明为“other-domain”,并将污染画布。

(这是因为你最敏感的信息可能在你的本地驱动器上!)

在测试时尝试以下变通方法:

Put all page related files (.html, .jpg, .js, .css, etc) on your desktop (not in sub-folders). Post your images to a site that supports cross-domain sharing (like dropbox.com or GitHub). Be sure you put your images in dropbox's public folder and also set the cross origin flag when downloading the image (var img=new Image(); img.crossOrigin="anonymous" ...) Install a webserver on your development computer (IIS and PHP web servers both have free editions that work nicely on a local computer).

在img标签中将crossorigin设置为Anonymous。

<img crossorigin="anonymous" />