uni-app中canvas旋转90度需绕中心点:先translate到中心,再rotate,最后drawimage用负坐标摆正;导出前须处理exif orientation元数据;canvas宽高须按物理像素设整数,跨平台需适配pixelratio;文字标注需save/restore或逆变换坐标。

uni-app里canvas旋转90度必须绕中心点,不能只调ctx.rotate()
直接ctx.rotate(Math.PI / 2)会让图片绕画布左上角旋转,大概率一半跑出画布、留黑边。真机上尤其明显——安卓可能裁掉右下角,iOS直接白图。正确做法是先平移到图片中心,再旋转,最后平移回去。
-
ctx.translate(imageWidth / 2, imageHeight / 2)把原点移到图片中心 -
ctx.rotate(Math.PI / 2)此时旋转轴就是中心点 -
ctx.drawImage(path, -imageWidth / 2, -imageHeight / 2, imageWidth, imageHeight)注意x/y用负半宽高,把图“摆正”在新坐标系里 - 每次绘制后必须调
ctx.draw(true, callback),否则canvasToTempFilePath取不到内容
导出后图片仍横着?大概率是EXIF orientation标记没处理
iOS和部分安卓相机会在原图里写orientation字段(比如'right-top'),uni-app默认不读也不修正,导致canvas画得再对,导出的文件还是被系统自动旋转。这不是canvas画歪了,是元数据在捣鬼。
- 用
uni.getImageInfo({ src: tempPath })拿到orientation值,非'upright'就要干预 - H5端可用
exif-js提前读取并加transform: rotate(90deg)仅作预览,但导出无效 - 真正要改像素数据:新建Canvas,宽高按orientation交换(如原100×200+
'right-top'→ 新Canvas设200×100),再用ctx.putImageData()逐像素搬移 - App端若
putImageData不支持,退而用drawImage配合save/rotate/restore,但会轻微模糊
不同平台canvas宽高设置差异极大,90度旋转时最容易踩坑
旋转90度后,逻辑宽高互换,但canvas的width和height属性必须是整数物理像素,且不能等于CSS显示尺寸——否则H5缩放、iOS retina屏都会让坐标算错2倍。
- 原始图800×600 → 顺时针转90°后,新canvas
width="600"height="800"(不是CSS样式里的600px) - 小程序里
<canvas width="600" height="800"></canvas>必须写死,不能用style="width: 600px"替代 - App端需结合
uni.getSystemInfoSync().pixelRatio,比如pixelRatio=2时,canvas宽高应设为逻辑尺寸×2,否则文字模糊、线条锯齿 - H5可直接用原生
HTMLCanvasElement,比uni.createCanvasContext更可控
文字标注跟着旋转后位置偏移?别信直觉坐标
旋转后整个坐标系变了,你在视觉上觉得“这里该写字”,但fillText(x, y)的y是基线位置,不是顶部,且没考虑旋转带来的坐标偏移。直接填数字几乎必错。
- 先设
ctx.textBaseline = 'top',让y控制文字顶部,行为更可预测 - 字体必须显式设
ctx.font = '16px sans-serif',不能靠默认值,不同平台默认字号不同 - 如果文字要固定在图片某区域(比如右下角水印),得把目标坐标做逆变换:用旋转角度反推原始图上的落点,再映射到当前canvas坐标
- 简单方案:旋转前先
ctx.save(),画完文字立刻ctx.restore(),避免后续操作受干扰











