ios canvas模糊主因是canvas.width/height未乘dpr,导致物理像素不足;须在onready取pixelratio,用node.width/height赋值,每次绘图前settransform(dpr,dpr),图片需下载转本地路径,小字宜加描边或换黑体。

canvas.width/height没乘dpr导致物理像素不足
iOS真机模糊最常见原因:只设置了style.width/style.height(CSS尺寸),却忘了改canvas.width和canvas.height属性。这两个属性决定实际绘图缓冲区的物理像素数,不乘dpr就等于用1x画布强行撑满2x或3x显示区域,浏览器只能插值拉伸——结果就是毛边、发虚、文字糊成一片。
实操要点:
-
uni.getSystemInfoSync().pixelRatio必须在onReady里取,不能用onLoad,否则可能拿不到准确值 - 通过
uni.createSelectorQuery()查节点,拿到node后直接赋值:node.width = 375 * dpr、node.height = 600 * dpr(375/600是你设计稿的逻辑宽高) - 千万别用
setAttribute('width', ...),某些iOS版本下会失效;必须用node.width = ...这种原生属性写法
ctx.scale(dpr, dpr)调用时机和重置问题
很多开发者写了ctx.scale(dpr, dpr),但只在初始化时调一次。一旦后续执行ctx.clearRect()或重新开始路径,坐标系会被重置,缩放失效——新画的内容又回到1x精度,立刻模糊。
正确做法是:
- 每次调用
ctx.beginPath()前,先执行ctx.scale(dpr, dpr) - 或者更稳妥:每次绘图前都重设变换矩阵,用
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)代替scale,避免累积误差 - 字号、线宽、坐标全部按逻辑尺寸写(比如
ctx.setFontSize(14)),不要手动乘dpr——缩放后它们自然对应物理像素
drawImage加载远程图在iOS上空白或降质
iOS WebView对跨域图片有严格限制,且会自动对https://图片做降采样。直接传URL给ctx.drawImage(),轻则模糊,重则白屏。
绕过方案必须走本地路径:
- 先用
uni.downloadFile()把图下到临时路径 - 再用
uni.getImageInfo({ src: tempFilePath })获取真实宽高(含orientation修正) - 最后用
ctx.drawImage(imageData.path, x, y, width, height)绘制——imageData.path才是iOS能稳定读取的本地路径 - 如果图源只有1x,再怎么缩放也救不回来;务必确保服务端提供@2x/@3x图或SVG
字体渲染在iOS Canvas中发虚
iOS Canvas对文字抗锯齿处理较弱,尤其小字号+非黑体时容易糊。这不是dpr问题,而是渲染策略差异。
缓解手段有限但有效:
- 避免用
ctx.fillText()直接写小于12px的字;能放大就放大,导出后再缩放 - 优先用系统默认黑体(如
"PingFang SC"、"Helvetica Neue"),别硬套自定义webfont - 给文字加1px描边:
ctx.setStrokeStyle('#000')+ctx.strokeText(),再fillText(),能显著提升边缘锐度 - 若必须高清小字,考虑用SVG转Canvas或预渲染成高清位图再贴图
真正卡住人的不是某一行代码,而是dpr缩放、图片加载、字体渲染这三件事必须同时做对——漏掉任意一环,iOS上就大概率糊。而且这些操作全得在onReady之后、绘制之前完成,顺序错了也不行。











