【发布时间】:2018-02-22 17:05:54
【问题描述】:
我在客户端 JavaScript 代码中生成像素数组并将其转换为 blob。然后我将 blob 的 URL 作为 image.src 传递,并在 image.onload 回调中撤销它。我没有保留对前面步骤生成的数据的任何引用,因此这些数据可能会被 GC 释放。
以这种方式生成的图像很多,而且效果很好。但有时用户可能希望通过单击图像附近的保存按钮来保存生成的图像。我不想再次生成图像,因为生成速度很慢,并且图像已经生成并且在屏幕上可见。所以我想从图像中取回我的像素。我尝试再次创建画布,在其上绘制图像,然后调用 toBlob,但浏览器将此图像视为跨源并抛出异常:“无法在 'HTMLCanvasElement' 上执行 'toBlob':可能无法导出受污染的画布”。我在 canvas.toDataUrl 和 canvasContext.getImageData 中遇到了类似的错误。
这个问题有解决办法吗?
我也尝试创建画布而不是图像,但是当我创建第二个画布时,第一个画布的内容会清除。
已添加 此错误仅发生在 Chrome 和其他 WebKit 浏览器中。 Firefox 和 MS Edge 工作正常。当我注释掉撤销 blob url 的代码行时,此错误消失了 - 我可以在画布上绘制图像并获取其像素数据而不会出现 CORS 问题。但是这样做是没有意义的,因为我已经有没有被删除的 blob。 但是我的页面可能会生成许多图像 - 它取决于其用户并且是无限的。图像的大小也是无限的——生成 4096x4096 的图像可能很有用。所以我想尽可能地减少我的页面的内存消耗。所有这些图像都应该是可下载的。大多数图像的生成使用先前生成的图像,因此要重新生成链中的最后一个图像,我必须重新生成所有图像。
所以我需要一个仅适用于 Chrome 浏览器的解决方法。
添加了 2 个 我试图在 JS Fiddle 中重现这个问题,但不能。但是在本地我的代码不起作用 - 我在本地开发了我的应用程序,但我没有尝试在服务器上运行它。在你的电脑上创建 test.html 文件并在浏览器中打开它(本地,没有服务器):
<html>
<body>
<pre id="log"></pre>
</body>
<script>
var log = document.getElementById("log");
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 256;
var ctx = canvas.getContext("2d");
canvas.toBlob(function(blob) {
var img = new Image();
var blobUrl = URL.createObjectURL(blob);
img.src = blobUrl;
img.onload = function()
{
URL.revokeObjectURL(blobUrl);
ctx.drawImage(img, 0, 0);
try { canvas.toBlob(function(blob) { log.textContent += 'success\n'; }); }
catch(e) {log.textContent += e.message + '\n';}
};
});
</script>
</html>
它将打印Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported.。
所以,我认为,我的解决方法是检测该页面是在 WebKit 浏览器和file:/// 协议的组合上运行的。而且我可以将撤销 blob URL 推迟到仅针对此组合的页面卸载。
【问题讨论】:
-
您在哪个浏览器上收到此错误?听起来像一个错误。是的,如果您撤销 blobURI,那么通过画布是您唯一的选择,因为浏览器会从内存中删除数据(有点像您在提供文件后确实从服务器中删除了文件)。但是您制作了多少张图片,有多少张可以下载?你不能只在页面卸载时撤销它们吗?按需复制每张图片很难吗?
-
因为你已经撤销了图片的URL,所以无法再访问数据了。我唯一能说的是,当您确定不再需要数据时,您应该只撤销图像 URL,因为这样您就可以将该 blob URL 设置为具有
download属性的锚点的href,而无需将其重绘到画布上。 -
@Kaiido 这不是错误。 Blob URI 在字符串中使用不同的协议,因此将被视为跨域图像。
-
@PatrickRoberts 不,blobURI 不应被视为跨域资源。它们来自浏览器的内存,甚至没有 HTTP 请求。
-
@Kaiido according to the definition in the W3C specification,“URL 的来源”和“Blob URL 的来源”的定义有冲突,所以存在一些浏览器目前可能没有的问题将其视为同域请求。但无论如何,由于 URL 已从 blob 存储中撤消,因此使用该 URL 无论如何都会产生网络错误。
标签: javascript image canvas blob