小程序Canvas导出图片白边本质是绘图区域与物理像素尺寸不匹配,需严格设置canvas.width/height为CSS宽高×pixelRatio,drawImage参数及canvasToTempFilePath的destWidth/destHeight均须基于物理像素,导出前fillRect填充背景并确保ctx.draw回调中执行导出。

小程序端Canvas导出图片出现白边,本质是绘图区域与目标画布尺寸不匹配,而非样式或透明度问题。直接加background: transparent或改fileType无效。
canvas宽高必须严格等于目标绘制区域物理像素
白边最常见原因是 canvas 元素的 CSS 宽高(如 width: 375px; height: 500px)和底层渲染缓冲区(canvas.width/canvas.height)不一致。微信小程序会按 CSS 尺寸缩放渲染结果,若缓冲区过大或过小,就会在边缘留白或裁剪。
- 必须显式设置 canvas 的
width和height属性值(非 style),单位为物理像素 - 推荐用
uni.getSystemInfo拿pixelRatio,再计算:canvas.width = cssWidth * pixelRatio,canvas.height = cssHeight * pixelRatio - 不要依赖默认值或仅靠
:style绑定,否则 H5 和小程序行为不一致
drawImage 参数必须按实际缓冲区尺寸计算
调用 ctx.drawImage 时,第五、六、七、八个参数(dx, dy, dWidth, dHeight)必须基于 canvas 缓冲区尺寸,而不是 CSS 尺寸。否则图片会被拉伸、偏移或未填满,导致白边。
- 假设 canvas 缓冲区是
750 × 1000(375px × 500px@2x),则dWidth应设为750,不是375 - 若原图宽高比与目标区域不一致,需先算等比缩放值,再代入
drawImage,不能硬写固定值 - 务必用
uni.getImageInfo获取原始图尺寸,避免用 URL 直接传参导致跨域污染或尺寸误判
导出前必须 fillRect 清除默认透明背景(尤其 iOS)
iOS 微信小程序中,canvas 初始状态是透明,但 uni.canvasToTempFilePath 导出 PNG 时可能将透明区域渲染为白色——这不是 bug,是平台对 alpha 通道的处理策略。
- 在
drawImage前执行ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, canvas.width, canvas.height) - 如果需要透明背景,只能改用
type="2d"Canvas 并配合createImageBitmap,但兼容性差,不推荐 - 注意:此填充必须在
ctx.draw(false, callback)的callback外执行,否则会被覆盖
draw 调用后必须等待完成再导出
白边有时是假象——实际是导出时绘图尚未提交到缓冲区,拿到的是初始化空白帧。这在 iOS 端尤为明显,且无法靠 setTimeout 粗暴解决。
- 必须用
ctx.draw(false, () => { uni.canvasToTempFilePath(...) }),不能省略回调 - 不要在
draw外层套setTimeout,这会破坏时序保证;只有在极少数 case(如多图叠加)才考虑加 100ms 内延迟 - H5 端需额外检查
preserveDrawingBuffer: true是否生效,可通过canvas.getContext('2d', { alpha: true })显式声明
最容易被忽略的是:canvas 缓冲区尺寸、CSS 尺寸、drawImage 参数、canvasToTempFilePath 的 destWidth/destHeight 这四者必须全部基于同一套物理像素体系,缺一不可。任意一个环节用 rpx 或 CSS px 混入,白边就几乎必然出现。


















