uni-app中canvas drawimage不生效的根本原因是未按平台规范提供合法图像源:小程序需用getimageinfo后的res.path,app仅支持本地文件路径,h5需处理跨域;必须动态计算坐标缩放、统一物理像素绘制、在draw回调中导出。

uni-app 里 Canvas 合成多张图片为什么 drawImage 不生效?
常见现象是调用 ctx.drawImage() 后 canvas 显示空白,或只显示最后一张图。根本原因是:uni-app 的 canvas 组件在非 H5 平台(如微信小程序、App)中,drawImage **不支持直接传入本地临时路径(如 tempFilePath)或 file:// 协议地址**,必须转为合法的图像源(CanvasImageSource)。
正确做法是:先用 uni.getImageInfo() 获取图片宽高和合法 path(小程序平台会自动转为 base64 或内部资源引用),再传给 drawImage;H5 平台可直接用 new Image() 加载,但需注意跨域。
- 微信小程序:必须走
uni.getImageInfo({ src })→ 成功回调里的res.path才能被drawImage正确识别 - App(nvue):仅支持本地文件路径(
/storage/emulated/0/...或_www/xxx.png),且需确保路径存在、有读取权限 - H5:图片需同域或服务端配置 CORS,否则
drawImage报错 “Tainted canvases may not be exported”
如何在不同平台统一处理多图拼接的坐标与缩放?
拼图本质是按网格或自定义布局把多张图绘制到目标 canvas 上,关键在计算每张图的 x、y、width、height。不能硬编码像素值,必须基于原始图尺寸和目标画布尺寸动态算。
推荐流程:先用 uni.getImageInfo() 拿到每张图的 width 和 height,再根据拼图模式(如 2×2、3×3、瀑布流)统一分辨率适配策略。例如固定输出画布为 750rpx 宽,高度按比例堆叠:
const canvasWidth = 750; const colCount = 2; const itemWidth = canvasWidth / colCount; // 每张图等比缩放到 itemWidth 宽,保持宽高比 const scale = itemWidth / imgInfo.width; const itemHeight = imgInfo.height * scale;
- 避免直接用 rpx 值传给
drawImage—— canvas API 只认物理像素,需用uni.upx2px(750)转换(H5 和小程序有效,App nvue 需用uni.getSystemInfoSync().screenWidth推算) - 多图间留白用固定 px 值(如 4px),别用 rpx,否则各平台渲染错位
- 旋转/镜像拼图需调用
ctx.save()+ctx.rotate(),但注意坐标系变化,建议先translate到中心再 rotate
合成后导出图片失败或模糊?检查这三处
canvas.toTempFilePath()(小程序)或 canvas.toDataURL()(H5/App)失败,90% 出在以下环节:
- 没等
ctx.draw(true, () => {...})回调执行完就调用导出方法 —— 必须在 draw 回调里触发导出,否则 canvas 还未渲染 - 目标 canvas 宽高设得太小(如 100×100),导致高清图被压缩失真;建议按设备像素比放大:用
uni.getSystemInfoSync().pixelRatio× 设计稿尺寸 - 微信小程序中,
toTempFilePath的quality参数仅对 jpg 生效,且最低 0.2;png 不支持 quality,若要保透明通道,必须用 png 格式
示例导出逻辑:
ctx.draw(true, () => {
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
quality: 0.8,
success: res => console.log('拼图完成:', res.tempFilePath),
fail: err => console.error('导出失败', err)
}, this);
});
为什么真机调试时图片位置偏移或错乱?
这是最隐蔽也最常被忽略的问题:uni-app 中 canvas 组件的 width/height 属性(wxml 中写的)和 JS 里 ctx 实际绘图区域的物理像素不一致,尤其在 iPhone X 及以上机型或安卓全面屏设备上。
根本原因:wxml 里写的 width="750rpx" 在高 DPR 屏幕下实际 canvas 缓冲区远大于 750 物理像素,但 ctx.drawImage() 默认按 CSS 尺寸绘制,导致图像被拉伸/压缩/偏移。
- 解决方案:用
uni.createCanvasContext('id', this)创建上下文后,立即通过uni.getSystemInfoSync().pixelRatio计算真实画布尺寸,并在drawImage时显式传入目标宽高(而非依赖 CSS 尺寸) - 更稳妥做法:wxml 中 canvas 设为固定 px 值(如
style="width:375px;height:600px;"),JS 里按此 px 值计算所有坐标,避免 rpx 转换误差 - nvue 页面中 canvas 是原生控件,
width/height必须用px单位,且不能写在 style 里,得用属性绑定::width="375"
拼图不是简单叠加,核心在于“控制每一像素的来源”。平台差异、DPR、坐标系、异步时机,四个点漏一个,图就拼歪了。











