iOS真机导出签名图旋转是因EXIF方向标记未处理,需用getImageInfo检测orientation并用canvasPutImageData重绘像素矫正,同时Canvas宽高须按pixelRatio设物理像素。

Canvas签名后图片旋转90度/180度怎么修正
uni-app里用 canvasToTempFilePath 导出签名图,经常发现横着签的字变成竖着的——不是Canvas画布歪了,是iOS真机(尤其是iPhone)对canvasToTempFilePath生成的图片自动加了EXIF方向标记,而uni-app默认不处理这个标记,导致显示时被旋转。
解决思路不是“把Canvas内容手动旋转”,而是导出前告诉Canvas:你按设备实际方向画,别依赖系统orientation。
- 在
uni.createCanvasContext创建时,**必须传id和this上下文**,且Canvas组件需设置disable-scroll="true",否则某些安卓机型会因滚动层干扰坐标 - 调用
canvasToTempFilePath前,**显式设置quality: 1+fileType: 'png'**,避免iOS对jpg做额外orientation补偿 - 关键一步:导出后用
uni.getImageInfo检查返回的orientation字段,如果是'right-top'或'left-bottom'等非'upright'值,说明图片被标记旋转了,得用uni.canvasPutImageData手动重绘一次(见下节)
用canvasPutImageData手动矫正旋转图片
不能靠CSS rotate或image标签的transform修——那是视觉欺骗,导出的文件还是歪的。真正要改的是像素数据本身。
步骤是:读取原图 → 获取ImageData → 根据orientation计算新宽高和坐标映射 → 把像素逐点拷贝到新ImageData → 写回Canvas → 再导出。
-
uni.getImageInfo返回的width/height是原始尺寸,但orientation决定了“哪边是上”。比如'right-top'表示图片本该顺时针转90度才 upright - 新建Canvas时,
width和height要按旋转后尺寸设:若原图100×200、orientation为'right-top',新Canvas应设为200×100 - 拷贝像素用双循环,例如顺时针90度:原图
(x, y)→ 新图(y, width - 1 - x);注意RGBA四通道要一起搬,别只搬R - 安卓部分机型(如华为EMUI)可能不支持
canvasPutImageData,得降级用drawImage配合save/rotate,但那样会模糊,优先走ImageData路径
签名Canvas在不同端的坐标偏移问题
同一个触摸点,在iOS、安卓、微信小程序、H5里拿到的touches[0].x值可能差几十像素——不是bug,是各端Canvas的devicePixelRatio和CSS像素比不一致导致的。
根本解法:不用事件对象里的x/y,改用getBoundingClientRect()算相对位置。
- 给Canvas加
ref="signCanvas",在touchstart里调用this.$refs.signCanvas.$el.getBoundingClientRect() - 用
event.touches[0].clientX - rect.left算Canvas内坐标,再除以uni.getSystemInfoSync().pixelRatio得到逻辑像素 - H5端必须监听
touchstart而非mousedown,否则PC调试时看似正常,真机就断触 - 微信小程序里Canvas层级可能被cover-view遮挡,签名区域要设
style="position: relative; z-index: 1;"
签名图导出后变模糊或发虚
不是压缩质量低,是Canvas的物理像素没对齐设备dpr。uni-app的Canvas默认按CSS像素渲染,但canvasToTempFilePath读的是物理像素缓冲区。
比如iPhone的pixelRatio=3,你设Canvas宽高300×150(CSS px),实际缓冲区是900×450,但没告诉Canvas“我要画900×450”,它就按300×150画,结果拉伸模糊。
- 创建Canvas DOM时,用
uni.getSystemInfoSync().pixelRatio乘以目标CSS宽高,再设canvas.width/canvas.height属性(注意:是DOM属性,不是style) - 同时用
style="width: 300px; height: 150px;"控制显示大小,让CSS像素和逻辑像素对齐 - 所有
lineWidth也要乘dpr,否则线条细得看不见;setLineWidth(2 * pixelRatio) - 安卓低端机内存紧张,Canvas宽高别超2000px,否则
canvasToTempFilePath直接失败,错误信息是"fail canvas is empty"
事情说清了就结束。最常漏的是getImageInfo后的orientation判断和Canvas物理像素初始化——这两步一跳过,真机上签名永远歪着。











