Appearance
Canvas 图片处理、导出与坑点
问题
如何把图片画到 Canvas?Canvas 生成分享图、压缩图片、截图视频、导出图片会遇到哪些坑?
结论
图片、视频、SVG、另一个 Canvas 都可以作为 drawImage() 的来源。Canvas 导出图片常用 toBlob() 或 toDataURL(),业务优先 toBlob(),避免超大 base64 字符串占用内存。
跨域资源是最常见的导出坑:只要把未授权的跨源图片或视频画到 Canvas 上,这个 Canvas 就会被污染,随后调用 toDataURL()、toBlob()、getImageData() 会失败。解决方式是图片标签设置 crossOrigin="anonymous",并且资源服务器返回允许的 CORS 响应头。
常见坑点:
- 没等图片
load就绘制。 - Canvas 尺寸和 CSS 尺寸不一致导致模糊或变形。
- 跨域图片导致 tainted canvas。
- 字体未加载完成,分享图文字回退。
globalAlpha叠加不是简单相加。- 频繁全量重绘导致性能问题。
- 旧 IE 不支持原生 Canvas,现代项目通常不再为 IE9 以下兼容 Canvas。
Demo
安全绘制跨源图片:
js
async function loadImage(src) {
const image = new Image();
image.crossOrigin = 'anonymous';
image.src = src;
await image.decode();
return image;
}
const image = await loadImage('https://cdn.example.com/avatar.png');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
ctx.drawImage(image, 0, 0);
const blob = await new Promise((resolve) => {
canvas.toBlob(resolve, 'image/png');
});透明度叠加示例:两个半透明图形重叠区域的最终颜色由 alpha compositing 计算,不是 0.6 + 0.2。在默认 source-over 合成下,最终 alpha 是:
js
const outAlpha = sourceAlpha + destinationAlpha * (1 - sourceAlpha);面试回答:
Canvas 导出图片前要确保所有图片、字体、视频帧已经加载。跨域资源必须同时设置
crossOrigin和服务端 CORS,否则 Canvas 会被污染,无法导出。分享图建议用toBlob,避免toDataURL产生大 base64。高 DPR、字体加载、透明度合成和性能重绘都是常见坑点。