将HTML5 Canvas保存为PNG文件

62

我想将一个HTML5画布转换成一张图片。目前为止,我得到的代码如下:

var tmp_canvas = document.getElementById('canvas');
var dataURL = tmp_canvas.toDataURL("image/png");
$('#thumbnail_list').append($('<img/>', { src : dataURL }).addClass('image'));

但问题在于我得到了这段代码:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsCAYAAADtt+XCAAAgAElEQVR4nNS6Z1xVaZbvv/c+CVOZc6mYEMlJMZRizgljGRARs6AgOSMGQATBSM5ZyTkoOQkSzJWrp3t6etLt6Z7pmf/c++L7f3EOiBZW2dM9dz73xfdzztl7n3Oe/Txrrd9a69mCTC4gkwvIZAKSTECUBARRQBA+jii+46f.......class="image">

我想要一个普通的图像路径,用户可以下载!

有什么帮助吗?


1
你得到的是画布转换成图像后的base64表示,我认为你需要将其转换为字节然后将这些字节保存到所需的图像文件中。 - yogi
你可以添加一个简单的提示,告诉用户右键单击生成的缩略图并点击“另存为”。 - boz
4个回答

94

提示:IE10+浏览器完全不支持以下方法。其他人已经完成了工作并实现了跨浏览器的解决方案。其中这个是其中之一。

首先,将生成的数据URL添加到<a>标签的href属性中。然而,在某些浏览器上,仅仅这样做是无法触发下载的。相反,它会在新页面中打开链接的图像。

对于base64图片的下载对话框:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...." class="image" />

根据上面的例子,将数据URL的MIME类型转换为这个:

<a href="data:application/octet-stream;base64,iVBORw0KGgoAAAANSUhEUg....">Download</a>

通过将数据的类型设置为application/octet-stream,浏览器会要求你把它保存到硬盘上。


指定文件名:

正如Adi在下面的评论中所说,使用此方法定义文件名没有标准方法。但是,在某些浏览器中可能有两种方法可行。

A) 由Google Chrome引入的download属性

<a download="image.png" href="...">

B) 在数据URL中定义HTTP头
headers=Content-Disposition: attachment; filename=image.png

<a href="data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=image.png;base64,iVBORw0KGgoAAAA">

这在 Opera 的一些较旧的版本中至少是有效的。这里有关于这个问题的讨论

查看主要浏览器的 Bug/Feature-Tracking 系统可以发现,定义文件名是社区的一个很大需求。也许我们将在不久的将来看到跨浏览器兼容的解决方案!;)


节省 RAM 和 CPU 资源:

如果您不想膨胀您访问者的浏览器 RAM,您还可以动态生成数据 URL:

<a id="dl" download="Canvas.png">Download Canvas</a>
function dlCanvas() {
    var dt = canvas.toDataURL('image/png');
    this.href = dt;
};
dl.addEventListener('click', dlCanvas, false);

这样,您的画布仍可以通过浏览器显示为图像文件。 如果您想增加打开下载对话框的概率,您应该扩展上面的函数,使其像上面所示进行替换:

function dlCanvas() {
    var dt = canvas.toDataURL('image/png');
    this.href = dt.replace(/^data:image\/[^;]/, 'data:application/octet-stream');
};
dl.addEventListener('click', dlCanvas, false);

最后,添加HTTP头以确保大多数浏览器向您提供有效的文件名! ;)

var canvas = document.getElementById("cnv");
var ctx = canvas.getContext("2d");

/* FILL CANVAS WITH IMAGE DATA */
function r(ctx, x, y, w, h, c) {
  ctx.beginPath();
  ctx.rect(x, y, w, h);
  ctx.strokeStyle = c;
  ctx.stroke();
}
r(ctx, 0, 0, 32, 32, "black");
r(ctx, 4, 4, 16, 16, "red");
r(ctx, 8, 8, 16, 16, "green");
r(ctx, 12, 12, 16, 16, "blue");

/* REGISTER DOWNLOAD HANDLER */
/* Only convert the canvas to Data URL when the user clicks. 
   This saves RAM and CPU ressources in case this feature is not required. */
function dlCanvas() {
  var dt = canvas.toDataURL('image/png');
  /* Change MIME type to trick the browser to downlaod the file instead of displaying it */
  dt = dt.replace(/^data:image\/[^;]*/, 'data:application/octet-stream');

  /* In addition to <a>'s "download" attribute, you can define HTTP-style headers */
  dt = dt.replace(/^data:application\/octet-stream/, 'data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=Canvas.png');

  this.href = dt;
};
document.getElementById("dl").addEventListener('click', dlCanvas, false);
<canvas id="cnv" width="32" height="32"></canvas>
<a id="dl" download="Canvas.png" href="#">Download Canvas</a>


4
很遗憾,您不能以这种方式指定文件名。 - Adi
不幸的是,它在Safari版本7.0.3(9537.75.14)Mac OS X上无法工作。 - Miguel Mota
嗨@Moogs,很遗憾我没有机会在Mac上测试,但我一直很好奇;) 你能提供更多细节吗,比如:画布是否呈现三个彩色框?您是否在错误控制台上获得输出?您是否获得下载对话框?无论如何,Safari _7.0.3正好一岁了_。官方上来说,Safari <7.1没有完整的HTML5支持。 - Nippey
当你说链接消失时,你是指格式吗?这暗示着一个空字符串已被分配。所以要么.toDataURL返回了无效的内容,要么.replace破坏了字符串。嗯,我真的很喜欢深入研究这样的问题,但远程操作很困难 :) - Nippey
1
这对于Chrome和Firefox对我有效。但是在IE11上完全失败了(没有下载,也没有显示对话框)。 - beginner_
显示剩余7条评论

13
你可以使用reimg库将画布转换为图像对象,并为用户触发下载。
在将库插入页面后,只需使用以下代码: ReImg.fromCanvas(yourCanvasElement).downloadPng()

5
你有两个选项(几乎适用于所有浏览器):
1- 将数据POST到服务器
在服务器上,你需要一个脚本来处理数据,然后告诉浏览器提示用户下载。
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=something.png");
header("Content-Type: image/png");
echo base64_decode($_POST['imageData']);
exit;

2- 使用 Downloadify 提示用户进行下载

<div id="clickMe"></div>

Downloadify.create( 'clickMe', {
   data: base64String,
   dataType: 'base64',
   filename: 'something.png'
});

-1
你也可以考虑使用Concrete.js http://www.concretejs.com,它是一个轻量级的HTML5 Canvas框架,可以实现像下载这样的外围功能。你只需要这样做:
canvas.download({
  fileName: 'my-file.png'
});

然后你就完成了。


2
那个画布是什么?如何创建它?它是一个具体的对象吗?它是一个HTML元素吗?如何初始化它以拥有来自您库的下载功能?这是哪个版本的Concrete?是否有CDN可用? - Belun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接