将HTML画布下载为PNG

huangapple go评论66阅读模式
英文:

Download HTML canvas as PNG

问题

如何允许我的网站用户将HTML画布的内容以PNG文件的形式下载?

问题在于,我正在从不同的源绘制图像到这个画布上(用户可以插入图像的URL,然后将其绘制到画布上)。因此,我不能使用toDataURL()、toBlob()或类似的方法,因为它们会因为跨源原因而抛出一个DOMException: 操作不安全。

据我所知,这个限制的目的是防止网站将画布数据发送回服务器,这可能会泄露用户的私人数据,例如,如果只有他访问了被绘制的图像的URL。

但是允许用户将画布作为PNG下载本身并不构成安全风险,这让我认为一定有一种安全的方法来实现它。但是如何呢?

或者是否有一种从公共角度加载图像的方法,而不是从用户的角度,这也会消除安全风险(假设我对这个限制的理解是正确的)?

英文:

How can i allow the users of my website to download the content of an HTML canvas as a PNG file?

The problem is, that I am drawing images from different origins onto this canvas. (The user can insert the URL of an image, and that is drawn onto the canvas).
Therefore I cannot use toDataURL(), toBlob() or similar, because they will throw a

> DOMException: The operation is insecure.

for cross-origin reasons.
As far as I know, the goal of this restriction is to prevent the website from sending the canvas data back to the server, which could leak private data of the user, for example if only he had access to the URL of the image that was drawn.

But allowing the user to download the canvas as a png is not a security risk itself, which makes me think there must be a safe way to do it.
But how?

Or is there a way to load the image from a public point of view, instead of the users point of view, which would also get rid of the security risk (assuming my understanding for this restriction is right)?

答案1

得分: 2

你说得对,这个限制只是为了防止网站访问不应该访问的数据。这也是为什么那些允许保存画布为图像的浏览器仍然可以这样做,即使画布已经被污染。

所以(除了Safari),您的用户实际上可以在他们的计算机上下载受污染的画布,方法是右键单击画布,然后在上下文菜单中选择“另存为图像”:

const img = new Image();
img.src = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
img.decode().then(() => {
  const canvas = document.querySelector("canvas");
  canvas.width = img.width;
  canvas.height = img.height;
  const ctx = canvas.getContext("2d");
  ctx.filter = "invert(1)";
  ctx.drawImage(img, 0, 0);
  // just to be sure we tainted the canvas as expected
  try {
    canvas.toDataURL();
    console.error("o_0 画布没有被污染");
  } catch (err) {
    console.log("画布被污染。右键单击它并选择“另存为图像”");
  }
});
<canvas></canvas>

然而,您的网站无法以任何形式访问这些数据,也无法强制使用“另存为图像”功能。值得注意的是,Safari不允许将<canvas>保存为磁盘上的图像(无论<canvas>是否受到污染),因此对于您的Safari用户,他们将无法将生成的图像保存到磁盘上,除非手动截屏。

英文:

You are right, this limitation is only to prevent the website to access data it shouldn't have access to. And this is why browsers that do allow to save canvas as image still do even if the canvas has been tainted.

So (in all but Safari) your users can actually download the tainted canvas on their computer, by right-clicking the canvas, and then select "Save As Image" in the context menu:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const img = new Image();
img.src = &quot;https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png&quot;;
img.decode().then(() =&gt; {
  const canvas = document.querySelector(&quot;canvas&quot;);
  canvas.width = img.width;
  canvas.height = img.height;
  const ctx = canvas.getContext(&quot;2d&quot;);
  ctx.filter = &quot;invert(1)&quot;;
  ctx.drawImage(img, 0, 0);
  // just to be sure we tainted the canvas as expected
  try {
    canvas.toDataURL();
    console.error(&quot;o_0 canvas is not tainted&quot;);
  } catch (err) {
    console.log(&quot;Canvas is tainted. Right-click it and &#39;Save Image As...&#39;&quot;);
  }
});

<!-- language: lang-html -->

&lt;canvas&gt;&lt;/canvas&gt;

<!-- end snippet -->

However your website can't access this data in any form, and it can't either force this "Save As Image" feature.
Also worth noting that Safari doesn't allow saving &lt;canvas&gt; as images on disk (whether the &lt;canvas&gt; is tainted or not), so for your Safari users they will indeed be unable to save the resulting image on disk, short of taking a screenshot manually.

huangapple
  • 本文由 发表于 2023年4月7日 01:58:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/75952447.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定