Canvas合成多图海报需预设画布尺寸、等待所有图片onload完成、设置crossOrigin处理跨域、用drawImage精准定位缩放,并通过toDataURL导出后用a标签下载;移动端需适配保存逻辑。

用 canvas 合成多张不同尺寸的图片生成海报并下载,核心是控制绘制顺序、坐标定位、跨域处理和导出时机。不是简单堆叠,而是像素级合成——最终输出一张真正的图片文件。
预设画布尺寸,不能靠 CSS 缩放
画布宽高必须提前算好,比如海报总宽 750px、高 1334px,就直接设:
canvas.width = 750; canvas.height = 1334;
千万别用 CSS 改 canvas 大小(如 style="width:100%"),否则导出图片会模糊或拉伸。
所有图片加载完成再绘制,避免空白或错位
每张图必须等 img.onload 触发后才能画。多张图异步加载,顺序不确定,不能边加载边画。
推荐用 Promise 封装每张图:
- 为每张
Image实例绑定onload和onerror - 用
Promise.all([p1, p2, p3])等全部 resolve 后统一调用drawImage - 任一图片加载失败(如 404),
onerror中reject,整个流程中断,方便排查
处理跨域图片,否则导出报错
如果某张图来自 CDN 或其他域名(比如二维码、头像、背景图),不加处理会导致:
Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
解决方法很明确:
- 创建
Image后立刻设置:img.crossOrigin = 'anonymous' - 确保服务端支持 CORS(返回
Access-Control-Allow-Origin: *) - 注意:设了
crossOrigin后,即使是同域图,也要走 CORS 流程,所以本地 file:// 协议下可能失效,建议用本地服务器调试
按需定位与缩放,适配不同尺寸图片
drawImage 有三种常用写法,拼接海报时基本都用得上:
-
ctx.drawImage(img, x, y)—— 原图大小贴到 (x,y),适合尺寸已匹配的图(如底图) -
ctx.drawImage(img, x, y, width, height)—— 强制缩放到指定宽高,适合头像、logo、二维码等固定区域 -
ctx.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)—— 裁剪+缩放+定位,适合从大图中抠局部再贴入海报
例如:把一张 800×600 的用户照片,裁剪中间 400×400 区域,缩放到 200×200 贴在海报 (500, 300) 位置:
ctx.drawImage(img, 200, 100, 400, 400, 500, 300, 200, 200);
导出并触发下载(含移动端保存到相册)
合成完成后,调用 canvas.toDataURL('image/jpeg', 0.95)(推荐 JPEG,体积小;质量 0.95 平衡清晰与大小)。
下载逻辑可复用:
- 创建
a标签,href设为 data URL,download设文件名 - 移动端 Safari 不支持
download属性,需用URL.createObjectURL()+location.href或调用navigator.clipboard.write()配合提示“长按保存” - 微信内可唤起“保存图片到相册”能力(需使用
canvas.toBlob()+plus.gallery.save()等原生桥接,或引导用户长按 canvas 元素)



















