简体   繁体   English

受污染的画布不得出口

[英]Tainted canvases may not be exported

I want to save my canvas to a img .我想将我的画布保存到img I have this function:我有这个功能:

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

It gives me error:它给我错误:

Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.未捕获的 SecurityError:无法在“HTMLCanvasElement”上执行“toDataURL”:可能无法导出受污染的画布。

What should I do?我应该怎么办?

For security reasons, your local drive is declared to be "other-domain" and will taint the canvas.出于安全原因,您的本地驱动器被声明为“其他域”并且会污染画布。

(That's because your most sensitive info is likely on your local drive!). (那是因为您最敏感的信息可能在您的本地驱动器上!)。

While testing try these workarounds:在测试时尝试以下解决方法:

  • Put all page related files (.html, .jpg, .js, .css, etc) on your desktop (not in sub-folders).将所有与页面相关的文件(.html、.jpg、.js、.css 等)放在桌面上(而不是放在子文件夹中)。

  • Post your images to a site that supports cross-domain sharing (like dropbox.com or GitHub).将您的图片发布到支持跨域共享的网站(如 dropbox.com 或 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" ...)确保将图像放在 Dropbox 的公用文件夹中,并在下载图像时设置交叉原点标志( 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).在您的开发计算机上安装一个网络服务器(IIS 和 PHP 网络服务器都有免费版本,可以在本地计算机上很好地工作)。

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

<img crossorigin="anonymous" />

If someone views on my answer, you maybe in this condition:如果有人对我的回答有意见,您可能处于这种情况:

1. Trying to get a map screenshot in canvas using openlayers (version >= 3) 1.尝试使用openlayers(版本> = 3)在画布中获取地图截图
2. And viewed the example of exporting map 2.查看导出地图示例
3. Using ol.source.XYZ to render map layer 3.使用ol.source.XYZ渲染地图图层

Bingo!答对了!

Using ol.source.XYZ.crossOrigin = 'Anonymous' to solve your confuse.使用ol.source.XYZ.crossOrigin = 'Anonymous'来解决您的困惑。 Or like following code:或者像下面的代码:

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

In OpenLayers6, something is changed with ES6.在 OpenLayers6 中,ES6 改变了一些东西。 However, the code is similar.但是,代码是相似的。

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
      }
    })
  })

What's more, don't forget to set the access-control-allow-origin: * or access-control-allow-origin: [your whitelist origins] in the response header if the tiles are requested in your own server.更重要的是,如果在您自己的服务器中请求磁贴,请不要忘记在响应标头中设置access-control-allow-origin: *access-control-allow-origin: [your whitelist origins]
Like this:像这样: 在此处输入图像描述 More details , and this one更多细节,还有这个

If you're using ctx.drawImage() function, you can do the following:如果您使用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;
}

And in your callback you can now use ctx.drawImage and export it using toDataURL在您的回调中,您现在可以使用ctx.drawImage并使用toDataURL导出它

In my case I was drawing onto a canvas tag from a video with something like canvas.drawImage(video, 0, 0) .在我的情况下,我正在使用类似canvas.drawImage(video, 0, 0)的视频在画布标签上绘图。 To address the tainted canvas error I had to do two things:为了解决受污染的画布错误,我必须做两件事:

<video id="video_source" crossorigin="anonymous">
    <source src="http://crossdomain.example.com/myfile.mp4">
</video>
  • Ensure Access-Control-Allow-Origin header is set in the video source response (proper setup of crossdomain.example.com)确保在视频源响应中设置了Access-Control-Allow-Origin标头(正确设置 crossdomain.example.com)
  • Set the video tag to have crossorigin="anonymous"将视频标签设置为crossorigin="anonymous"

I resolved the problem using useCORS: true option我使用useCORS: true选项解决了这个问题

 html2canvas(document.getElementsByClassName("droppable-area")[0], { useCORS:true}).then(function (canvas){
        var imgBase64 = canvas.toDataURL();
        // console.log("imgBase64:", imgBase64);
        var imgURL = "data:image/" + imgBase64;
        var triggerDownload = $("<a>").attr("href", imgURL).attr("download", "layout_"+new Date().getTime()+".jpeg").appendTo("body");
        triggerDownload[0].click();
        triggerDownload.remove();
    });

似乎您正在使用来自未设置正确 Access-Control-Allow-Origin 标头的 URL 的图像,因此出现问题..您可以从服务器获取该图像并从服务器获取它以避免 CORS 问题..

Check out CORS enabled image from MDN.从 MDN 查看启用了 CORS 的图像 Basically you must have a server hosting images with the appropriate Access-Control-Allow-Origin header.基本上,您必须有一个服务器托管具有适当的 Access-Control-Allow-Origin 标头的图像。

 <IfModule mod_setenvif.c> <IfModule mod_headers.c> <FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$"> SetEnvIf Origin ":" IS_CORS Header set Access-Control-Allow-Origin "*" env=IS_CORS </FilesMatch> </IfModule> </IfModule>

You will be able to save those images to DOM Storage as if they were served from your domain otherwise you will run into security issue.您将能够将这些图像保存到 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; }

Just as a build on @markE's answer.就像@markE 的答案一样。 You can serve your website via a local server.您可以通过本地服务器为您的网站提供服务。 You won't have this error on a local server.在本地服务器上不会出现此错误。

If you have PHP installed on your computer (some older MacOS versions has it preinstalled):如果您的计算机上安装了 PHP(一些较旧的 MacOS 版本已预装):

  1. Open up your terminal/cmd打开你的终端/cmd
  2. Navigate into the folder where your website files are导航到您的网站文件所在的文件夹
  3. While in this folder, run the command php -S localhost:3000在此文件夹中,运行命令php -S localhost:3000
  4. Open up your browser and in the URL bar go to localhost:3000 .打开浏览器并在 URL 栏中转到localhost:3000 Your website should be running there.您的网站应该在那里运行。

or或者


If you have Node.js installed on your computer:如果您的计算机上安装了 Node.js:

  1. Open up your terminal/cmd打开你的终端/cmd
  2. Navigate into the folder where your website files are导航到您的网站文件所在的文件夹
  3. While in this folder, run the command npm init -y在此文件夹中,运行命令npm init -y
  4. Run npm install live-server -g or sudo npm install live-server -g on a mac在 Mac 上运行npm install live-server -gsudo npm install live-server -g
  5. Run live-server and it should automatically open up a new tab in the browser with your website open.运行live-server ,它应该会自动在浏览器中打开一个新选项卡,同时打开您的网站。

Note: remember to have an index.html file in the root of your folder or else you might have some issues.注意:请记住在文件夹的根目录中有一个 index.html 文件,否则您可能会遇到一些问题。

This one can work smoothly in laravel.这个可以在laravel中顺利运行。

First of all, you need to convert tainted canvas to blob.首先,您需要将受污染的画布转换为 blob。 after that, you can upload a blob to serve and save it as an image.之后,您可以上传 blob 以提供服务并将其另存为图像。 Return image URL in ajax call.在 ajax 调用中返回图像 URL。

Here is an ajax call to upload canvas blob.这是一个上传画布 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();
});

I also solved this error by adding useCORS : true, in my code like -我还通过添加useCORS : true,在我的代码中,比如 -

html2canvas($("#chart-section")[0], {
        useCORS : true,
        allowTaint : true,
        scale : 0.98,
        dpi : 500,
        width: 1400, height: 900
    }).then();

In my case I was testing it from my desktop, having CORS error even after saving image locally to sub-folder.在我的情况下,我是从我的桌面测试它,即使在将图像本地保存到子文件夹之后也会出现 CORS 错误。

Solution:解决方案:

Moved the folder to local server WAMP in my case.在我的情况下,将文件夹移动到本地服务器 WAMP。 Worked perfect from local server.从本地服务器完美运行。

Note: Works only when you have saved image locally.注意:仅当您在本地保存图像时才有效。

For anyone who still encountering the same issue from S3 even after applying the server cross-origin settings, it probably a browser caching issue.对于即使在应用服务器跨域设置后仍遇到 S3 相同问题的任何人,这可能是浏览器缓存问题。 So you need to make sure to disable the caching and test again, you can do that from the browser dev-tools -> network tab -> click on disable cash option -> try again:所以你需要确保禁用缓存并再次测试,你可以从浏览器开发工具->网络选项卡->单击禁用现金选项->再试一次:

chrome dev-tools 缓存选项

tl;dr tl;博士

This issue made me crazy and solved it by loading image with crossOrigin="anonymous" before rendering canvas .这个问题让我抓狂,并通过在渲染 canvas 之前使用 crossOrigin="anonymous" 加载图像来解决它。

Detailed and too-specific solution详细且过于具体的解决方案

For those who uses React + canvg + Amazon S3 and want to export svg as png via canvas, this could be useful.对于使用 React + canvg + Amazon S3 并希望通过 canvas 将 svg 导出为 png 的用户,这可能很有用。

First, create a React hook to detect preloading cross-origin images:首先,创建一个 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,
  }
}

Then, render svg lazily after loading images:然后,加载图像后延迟渲染 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>
  )
}

Finally, you can convert the canvas element into png:最后,您可以将 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 })

Finally, the S3 cors policy should be like this:最后,S3 cors 策略应该是这样的:

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

Please leave "MaxAgeSeconds" empty.请将"MaxAgeSeconds"留空。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Canvas.toDataURL() 受污染的画布可能无法导出 - Canvas.toDataURL() Tainted canvases may not be exported 带有 React 的 Tesseract.js:受污染的画布可能无法导出 - Tesseract.js with React: Tainted canvases may not be exported DOMException:无法在“HTMLCanvasElement”上执行“toDataURL”:可能无法导出受污染的画布 - DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported 离线版本的 HTML2canvas - 受污染的画布可能无法导出 - HTML2canvas in offline version - Tainted canvases may not be exported 未捕获的 DOMException:无法在“HTMLCanvasElement”上执行“toDataURL”:可能无法导出受污染的画布 - Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported 可能无法导出空白的PNG /污染的画布(不使用图像) - Blank PNG / Tainted canvases may not be exported (not using images) Chrome:受污染的画布可能无法导出; 仅限离线应用 - Chrome: Tainted canvases may not be exported; Offline-only app JavaScript:toDataUrl()抛出“安全错误:可能无法导出受污染的画布”。 - JavaScript: toDataUrl() throwing “Security Error: Tainted canvases may not be exported.” 受污染的“OffscreenCanvas”可能无法导出 - Tainted "OffscreenCanvas" may not be exported 无法在“HTMLCanvasElement”上执行“toBlob”:受污染的画布可能无法在 react-image-crop 中导出 - Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported in react-image-crop
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM