uni-app合并两张图片必须走canvas绘制流程:先用getimageinfo获取合法图像源,再按物理像素计算坐标逐张drawimage,最后在ctx.draw(false, callback)回调中导出;需注意canvas-id写死、平台差异及尺寸限制。

uni-app 把两张图片合并成一张图,不是简单叠 DOM 层级,必须走 canvas 绘制流程。直接用 position + z-index 只能“视觉叠加”,无法导出为单张图;真要保存、分享、上传,就得用 ctx.drawImage() 逐张画进画布,再调用导出 API。
canvas.draw() 必须加回调,否则导出黑屏或空白
常见错误是调用 uni.canvasToTempFilePath() 前没等 canvas 真正渲染完——ctx.draw() 是异步的,不加回调就相当于“边画边截”。
-
ctx.draw(false, () => { uni.canvasToTempFilePath(...) })是最小可靠组合,第一个参数false表示不立即渲染,把控制权交给回调 - H5 端不能用
uni.canvasToTempFilePath,得改用canvas.toDataURL(),且网络图要提前设crossOrigin="anonymous" - App 端(尤其 iOS)对 canvas 尺寸敏感,单边建议 ≤ 1500px,超限会静默失败,不报错也不出图
drawImage 前必须先 getImageInfo,不能直接传 URL 或 tempFilePath
小程序和 App 平台下,ctx.drawImage() 不接受原始 URL 或 tempFilePath,必须通过 uni.getImageInfo() 获取合法图像源。
- 网络图:先
uni.downloadFile()→ 得到tempFilePath→ 再uni.getImageInfo({ src: tempFilePath })→ 成功回调里的res.path才能传给drawImage - 本地图(如
/static/xxx.png):可直接传路径给getImageInfo,但也要等回调,不能跳过 - H5 端可用
new Image(),但必须监听onload,且跨域资源需服务端配 CORS 或前端加img.crossOrigin = 'anonymous'
坐标和缩放必须手动算,别依赖 CSS 或 rpx
canvas API 只认物理像素,width="750rpx" 或 style="width: 750rpx" 对绘制无效,会导致模糊、错位、比例失真。
- 画布宽高必须设为像素值,比如
width="750"(不是750rpx),推荐用uni.upx2px(750)转换(H5/小程序有效) - 每张图的
x、y、width、height都要基于原始尺寸动态计算:先取getImageInfo的width/height,再按目标区域缩放,保持宽高比 - 留白、间距用固定 px(如
4),别用rpx,否则 Android/iOS/H5 渲染不一致 - 避免用
ctx.scale()整体缩放——会影响字体、线条粗细,且导出尺寸难控
canvas-id 和节点挂载容易失效,尤其在 v-if 或页面切换时
报错 canvas is empty 或 找不到 canvasId,90% 是 canvas 节点没正确挂载,不是图片没画上去。
-
canvas-id必须写死,如canvas-id="myCanvas",不能动态绑定(:canvas-id="id"在小程序端会失效) - 不要在
v-if里渲染 canvas,条件切换时上下文丢失;改用v-show或确保onReady后再创建 context -
uni.createCanvasContext('myCanvas')调用前,确保 canvas 已渲染,可加setTimeout(() => {}, 100)或放在onReady生命周期里 - App nvue 页面中,canvas 必须用
canvas-id,不能用原生<canvas></canvas>标签
实际拼合两张图(底图 + 二维码)时,最简可靠流程就是:等第一张图 getImageInfo 完 → 画到底部 → 等第二张图 getImageInfo 完 → 计算右下角坐标 → 画上去 → ctx.draw(false, callback) → 导出。中间任何一环跳过加载校验,都会在真机上悄无声息失败。











