ChatGPT解决这个技术问题 Extra ChatGPT

受污染的画布不得出口

我想将画布保存到 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";
}

它给了我错误:

未捕获的安全错误:无法在“HTMLCanvasElement”上执行“toDataURL”:可能无法导出受污染的画布。

我应该怎么办?

在什么浏览器中? stackoverflow.com/a/21362569/476716 声称这是一个错误。
在 chrome 和 Firefox 上

n
naXa stands with Ukraine

出于安全原因,您的本地驱动器被声明为“其他域”并且会污染画布。

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

在测试时尝试以下解决方法:

将所有与页面相关的文件(.html、.jpg、.js、.css 等)放在桌面上(而不是放在子文件夹中)。

将您的图片发布到支持跨域共享的网站(如 dropbox.com 或 GitHub)。确保将图像放在 Dropbox 的公用文件夹中,并在下载图像时设置交叉源标志(var img=new Image(); img.crossOrigin="anonymous" ...)

在您的开发计算机上安装一个网络服务器(IIS 和 PHP 网络服务器都有免费版本,可以在本地计算机上很好地工作)。


谢谢,设置 img.crossOrigin 属性帮助了我!
@markE - 我从 localStorage 加载图像数据,而不是从文件或任何 url 加载,然后对其进行一些操作,例如添加文本。然后尝试使用 toDataURL() 将其还原到 localStorage。但它显示“无法在 'HTMLCanvasElement' 上执行 'toDataURL':可能无法导出受污染的画布”。在这种情况下,我没有使用任何外部文件或 url 来解决跨域问题。那为什么会导致这个错误呢?
@Saijth - 您可能想要验证用于图像的路径。我也遇到了这个问题,因为我正在测试通过其 IP (127.0.xx/) 直接访问我的本地虚拟服务器,但一些图像是通过域 (localhost/) 链接的。一旦我使用了本地主机,它就解决了。因此,请确保您没有遇到类似的事情。
(1)从xampp webserver查看,localhost/file而不是c:/localdisk/file;那么chrome就不会抱怨安全错误。 (2) 或者启动chrome时使用这个标志:--allow-file-access-from-files
只是添加另一个可能的问题:如果您尝试导出包含带有 ForeignObject 的 svg 的画布,某些浏览器会将其标记为已污染。
R
Roko C. Buljan

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

<img crossorigin="anonymous" />

但是在 html5 canvas 的情况下怎么办,而不是 img 元素
在画布元素的情况下,问题的根源总是与您在其上绘制的一些图像(或图像)有关。因此,您只需要在加载图像之前跟踪图像并按照指示设置其 crossOrigin 属性。
适用于 html2canvas(element.nativeElement, {useCORS: true}) .then(canvas => { const dataUrl = canvas.toDataURL('image/png'); })
值得注意的是,一旦加载图像,设置 image.crossOrigin = 'Anonymous' 将无济于事。但是,如果重新加载是一个选项,您可以选择以下内容:document.querySelectorAll('img').forEach(image => { image.crossOrigin = 'Anonymous'; image.src += ' '; })。另请参阅 this article on MDN 以供参考。
这对我来说并不是全部小写,但 crossOrigin 有效。
s
sknight

如果有人对我的回答有意见,您可能处于这种情况:

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

答对了!

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

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

https://i.stack.imgur.com/qsgp8.png


极好的。适用于所有来源,例如 TileImage 等。
太棒了!正是我在寻找自己的东西,很容易修复我正在做的 OpenLayers 演示。
我正在使用矢量切片图层并将此属性添加到源后,但它也不起作用!
我用的是ol6。但它不起作用,添加此行后没有变化
@JayCummins,我添加了 OL6 代码。它也许对你有帮助。
L
Lawrence Cherone

如果您使用 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 导出它


这对我不起作用。仍然收到 Tainted canvases may not be exported. 错误消息。
这个对我有用。谢谢。 @SamSverko 确保在 img.src 之前设置属性。
不工作。说被 CORS 政策阻止
被 CORS 策略阻止:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。 “img”的 FetchEvent。
F
Frederick

在我的例子中,我正在使用 canvas.drawImage(video, 0, 0) 之类的视频在画布标签上绘图。为了解决受污染的画布错误,我必须做两件事:

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

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

将视频标签设置为 crossorigin="anonymous"


A
Ahmad Zahabi

我使用 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();
    });

这里唯一适合我的解决方案!
P
Prasanna Aarthi

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


您能否更准确地回答您的答案,因为我并不真正了解所有这些概念。如何从我的服务器获取该图像?
您从哪里获取该图像,是从您的服务器还是其他服务器?
它是这样的: loadImage("example.jpg", 0, 0, 500, 300);我可以将随机图像 url 或图像放在我电脑的同一个文件夹中,它仍然是一样的
是的,但我只是在油漆上创建了图像,它仍然是一样的
我给了文件 Access-Control-Allow-Origin:* ,但它仍然显示错误
Z
Zsolt Meszaros

从 MDN 查看 CORS enabled image。基本上,您必须有一个服务器托管具有适当的 Access-Control-Allow-Origin 标头的图像。

SetEnvIf Origin ":" IS_CORS Header set Access-Control- Allow-Origin "*" env=IS_CORS

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

var img = new Image, canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"), src = "http://example.com/image"; // 在此处插入图片 url 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; // 确保缓存图像的加载事件也会触发 if ( img.complete || img.complete === undefined ) { img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; img.src = src; }


虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
感谢您的通知。我只是从 MDN 链接添加内容:)
J
Jatin Mandanka

这个可以在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();
});

我收到一个错误“画布未定义”,我不知道如何解决它
@LaurențiuCozma 在我的代码中,画布是一个变量。例如 canvas = document.getElementById('my-canvas');
L
Ludolfyn

就像@markE 的答案一样。您可以通过本地服务器为您的网站提供服务。在本地服务器上不会出现此错误。

如果您的计算机上安装了 PHP(一些较旧的 MacOS 版本已预装):

打开您的终端/cmd 导航到您的网站文件所在的文件夹 在此文件夹中,运行命令 php -S localhost:3000 打开浏览器并在 URL 栏中转到 localhost:3000。您的网站应该在那里运行。

或者

如果您的计算机上安装了 Node.js:

打开您的终端/cmd 导航到您的网站文件所在的文件夹 在此文件夹中,运行命令 npm init -y 运行 npm install live-server -g 或 sudo npm install live-server -g 在 Mac 上运行 live-服务器,它应该会在您的网站打开的情况下自动在浏览器中打开一个新选项卡。

注意:请记住在文件夹的根目录中有一个 index.html 文件,否则您可能会遇到一些问题。


Mac OS 没有预装 php。我有 macos,它与 PHP 无关。如果你有 php,你或其他人安装了它。
这不是真的@LukasLiesis。一个简单的 Google 搜索将显示它是:google.com/…。我曾经使用过的所有 Mac 都预装了它。如果您默认安装了 Big Sur(而不是作为更新),您可能需要激活它(尽管我没有这样做):google.com/…
在终端中,您可以运行 php --version 来查看您安装的版本。
去获取新的 mac,运行文章中引用的 apache 守护程序脚本,你会看到 PHP 不是 mac 的一部分。除非你运行一些旧版本的操作系统,这绝不是一个好主意,至少在 mac 上是这样。关于 Apache 的 php 模块的行甚至不在 httpd.conf 中,但似乎它在旧操作系统上就存在。有一行注释:#PHP was deprecated in macOS 11 and removed from macOS 12 您链接的两篇文章都是错误的。 php --version 表示 command not found,而 php 不是 mac 的一部分 :)
事实上,我有一个月前购买的全新 macbook,它仍然预装并激活了 PHP。 PHP 立即工作。我唯一能注意到的是我选择了英特尔芯片而不是 M1 芯片(为了与我正在使用的某些软件兼容)。没有人说它是mac的一部分。我说它是预装的,它确实如此 :) 虽然当你在终端中检查 PHP 的版本时,它确实会打印一条警告信息——我引用:“macOS 的未来版本将不包括 PHP。”这是一个屏幕截图:imgur.com/a/ZZL1SwN
J
Jeet

我还通过在我的代码中添加 useCORS : true, 解决了这个错误,例如 -

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

A
Anil Singh

在我的情况下,我是从我的桌面测试它,即使在将图像本地保存到子文件夹之后也会出现 CORS 错误。

解决方案:

在我的情况下,将文件夹移动到本地服务器 WAMP。从本地服务器完美运行。

注意:仅当您在本地保存图像时才有效。


Y
Yaser AZ

对于即使在应用服务器跨域设置后仍遇到 S3 相同问题的任何人,这可能是浏览器缓存问题。所以你需要确保禁用缓存并再次测试,你可以从浏览器开发工具->网络选项卡->单击禁用现金选项->再试一次:

https://i.stack.imgur.com/PhZPl.png


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅