canvastotempfilepath返回黑图或纯白图是因导出早于gpu光栅化完成;ios真机易全黑,android偶发局部有效;需用ctx.draw(false, callback)并在回调中调用canvastotempfilepath。

canvasToTempFilePath返回黑图或纯白图
不是图片内容没画,是导出时机早于GPU光栅化完成。微信小程序(尤其iOS)和uni-app App端的canvas渲染管线异步性极强,ctx.draw()回调只表示CPU指令下发完毕,不代表像素已写入缓冲区。
实操建议:
- 必须用
ctx.draw(false, callback),且callback里再调uni.canvasToTempFilePath;别用await ctx.draw()或setTimeout(100)硬等 - App端更敏感:iOS真机常见整张黑图,Android 10+偶发左上角局部有效,本质是异步光栅化未就绪
- Vue 3中
this不可直接传入回调,需显式绑定组件实例:uni.createCanvasContext('id', instance) - 若用了
type="2d",务必先用uni.createSelectorQuery()确认canvas节点已挂载且node非null
iOS Canvas高度超4096px直接空白
这不是bug,是WebKit内核对GPU缓冲区的硬限制。iPhone物理像素高度超过4096时,绘图命令被静默丢弃——不报错、不警告、只留白。
判断依据:开发者工具和安卓正常,iPhone上全白 → 立刻查逻辑高度 × dpr是否>4096。
解决路径:
- 动态缩放:例如设计稿高2000rpx、dpr=3,则物理高度6000px,需压缩逻辑高度至≤1365rpx(4096 ÷ 3 ≈ 1365)
- 分段绘制:拆成多个
<canvas></canvas>分别生成,后端拼接(适合服务端可控场景) - 绕过canvas:改用
painter插件(基于WXML节点快照),支持rpx计算且无高度限制,但不支持复杂滤镜或动态文字测量
文字模糊、边缘发虚的根本原因
根本不是canvas画质低,是没适配devicePixelRatio(dpr)。iPhone 14的dpr为3,若按375×667逻辑尺寸设canvas宽高,实际缓冲区只有375×667像素,被拉伸到1125×2001物理像素,必然糊。
用户要生成可打印的中文字帖/练习纸、导出多页 A4 PDF 报告,或把 SVG 设计稿零误差还原到 Canvas 时使用。本技能是「Canvas 内容工厂闭环」的总控,编排:网格渲染引擎(13 种教育网格+拼音标注) → 多页 PDF 导出(A4 合成) → SVG 精准复刻(坐标误差<0.001px)。触发词:生成字帖、练习纸、导出 PDF、SVG 转 Canvas、印刷级还原、A4 报告、米字格田字格。
正确三步法:
- 取真实dpr:
const dpr = uni.getSystemInfoSync().pixelRatio - 设canvas属性宽高(非
style):node.width = 375 * dpr、node.height = 667 * dpr - 绘图前缩放ctx:
ctx.scale(dpr, dpr),之后所有坐标/字号/线宽都按375×667写,不用乘dpr
漏掉任意一步,高清就是空谈。
App端返回空路径或tempFilePath为空字符串
现象是调用成功但tempFilePath为空,文件不存在,或加载后为1px占位图。这在iOS真机和Android高版本高频复现,且H5/小程序正常,容易误判为代码问题。
关键检查点:
-
canvas-id必须与uni.canvasToTempFilePath参数中的canvasId完全一致(区分大小写、不可含空格) - context必须在
onReady或mounted后获取,避免节点未挂载;可用uni.createSelectorQuery().select('#id').fields({ node: true, size: true }).exec()验证节点存在且尺寸非零 - nvue页面必须用
native-canvas,不能用web canvas API;web-view或原生组件(如map)无法被canvas捕获,需换平台原生能力
真正难缠的点不在代码逻辑,而在不同平台对“渲染完成”的定义差异——iOS要求GPU帧提交,Android依赖WebView光栅队列,而小程序又走另一套合成路径。靠猜时序不如靠draw回调加平台兜底延迟。










