Canvas导出图像应按场景选择toDataURL或toBlob:toDataURL返回base64字符串,兼容好但体积大、有iOS长度限制和跨域问题;toBlob生成Blob对象,支持质量控制、内存需手动释放,且更适配上传与下载。

Canvas 导出图像数据,核心就两条路:toDataURL 和 toBlob。它们不是“选哪个更好”,而是“在什么场景下必须用哪个”。关键差异不在写法,而在数据形态、内存行为和实际限制。
toDataURL:快但有硬伤
它直接返回一个 base64 字符串,比如 data:image/png;base64,iVBORw0KGgo…。优点是简单、同步、兼容性好(IE9+ 就支持)。但问题也很实在:
- 字符串体积比原始二进制大 33%~74%,一张 2MB 图片导出后可能超 3.5MB;
- iOS Safari 对 URL 长度有限制,拼到
<a href="data:..."></a>里容易截断,导致下载空白或失败; - 跨域图片一旦 draw 进 canvas,toDataURL 就静默返回空字符串或抛错,无法绕过;
- 无法控制 JPEG 压缩质量,导出 PNG 又没法去透明背景。
toBlob:更接近真实文件的路径
它不生成字符串,而是产出一个 Blob 对象——本质就是浏览器里的“二进制文件块”。整个流程是异步的,靠回调接收结果:
- 调用
canvas.toBlob(callback, "image/jpeg", 0.8),第三个参数能精细控图质; - 回调里拿到 blob,用
URL.createObjectURL(blob)创建临时地址,再赋给 标签下载; - 下载完成后必须调
URL.revokeObjectURL(url),否则内存一直占着; - 如果要上传,可直接
new File([blob], "name.jpg", {type: "image/jpeg"})包一层,后端就能正常识别文件名和类型。
导出高清图,尺寸设置不能只靠 CSS
很多人把 canvas 写成 <canvas style="width:100%;height:400px"></canvas>,以为拉伸显示就等于高清输出。其实导出分辨率只认 canvas 元素自身的 width 和 height 属性(单位是逻辑像素):
- 要导出 1200×800 的图,就得提前设
canvas.width = 1200; canvas.height = 800;; - 再用 CSS 控制显示大小,比如
style="width:600px;height:400px",靠浏览器缩放预览,不影响导出清晰度; - 如果内容是手绘或动态绘制,记得按新尺寸重算坐标或用
ctx.scale(2, 2)调整笔触粗细。
兼容性与 fallback 必须考虑
toBlob 在 IE 完全不可用,旧版 Android WebView 也有回调不触发的问题。稳妥做法是:
- 先检测
canvas.toBlob是否存在; - 不存在就 fallback 到 toDataURL + atob 构造 Blob(需处理 base64 解码和类型映射);
- 对含透明像素的内容导 JPEG,务必先画白底:新建 canvas → fillRect(0,0,w,h) → drawImage 原 canvas,再 toBlob;
- 本地开发别用 file:// 协议测试,跨域和 canvas 污染问题在本地服务器(如 Live Server)下才可复现和调试。

















