You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS端Canvas渲染Base64图片旋转问题求助

解决iOS端Canvas渲染Base64图片旋转的问题

这个问题我之前帮不少开发者排查过,本质是iOS和浏览器对图片方向信息的处理逻辑不一样导致的,我给你拆解清楚原因,再给你落地的解决方案:

为啥会出现旋转?

iOS相机(包括相册里的照片)会把拍摄时的方向信息存在图片的EXIF元数据里。浏览器的<img>标签会自动读取这个EXIF信息,悄悄帮你把图片调整到正确方向显示;但Canvas API本身完全不管这个元数据,你直接把图片画上去,它就会按照图片原始的像素方向渲染,自然就出现旋转错位了。Android设备的拍照逻辑在方向存储上和iOS不同,所以不会有这个问题。

具体解决步骤

核心思路就是:先读取图片的EXIF方向,再根据这个方向对Canvas做旋转、平移等变换,最后再绘制图片。

1. 读取图片的EXIF方向信息

要拿到这个方向值,最靠谱的方式是用轻量的EXIF处理库(比如exif-js,体积很小,不会给项目加负担)。如果你用的是Cordova/Angular项目,直接npm安装后引入就行。

这里给你写个封装好的异步函数,用来获取方向值:

// 假设你的Base64图片数据是dataUrl
async function getImageOrientation(dataUrl) {
  return new Promise((resolve) => {
    const img = new Image();
    img.src = dataUrl;
    img.onload = () => {
      // 用exif-js读取Orientation标签
      EXIF.getData(img, function() {
        const orientation = EXIF.getTag(this, 'Orientation');
        // 默认返回1(正常方向)
        resolve(orientation || 1);
      });
    };
  });
}

如果你不想引入第三方库,手动解析EXIF的话需要处理Base64的二进制数据,过程比较繁琐,不推荐,除非你对二进制操作很熟。

2. 根据方向调整Canvas绘制逻辑

拿到方向值后,我们需要对Canvas上下文做对应的变换,再绘制图片。下面是覆盖所有常见方向情况的完整代码:

async function drawImageToCanvasCorrectly(canvas, dataUrl) {
  const ctx = canvas.getContext('2d');
  const img = new Image();
  img.src = dataUrl;
  
  // 等图片加载完成再处理
  await new Promise(resolve => img.onload = resolve);
  
  const orientation = await getImageOrientation(dataUrl);
  
  // 先清空Canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // 根据不同方向做变换
  switch(orientation) {
    case 2: // 水平翻转
      ctx.translate(img.width, 0);
      ctx.scale(-1, 1);
      ctx.drawImage(img, 0, 0, img.width, img.height);
      break;
    case 3: // 旋转180度
      ctx.translate(img.width, img.height);
      ctx.rotate(Math.PI);
      ctx.drawImage(img, 0, 0, img.width, img.height);
      break;
    case 4: // 垂直翻转
      ctx.translate(0, img.height);
      ctx.scale(1, -1);
      ctx.drawImage(img, 0, 0, img.width, img.height);
      break;
    case 5: // 水平翻转后旋转90度
      ctx.rotate(0.5 * Math.PI);
      ctx.scale(1, -1);
      ctx.drawImage(img, 0, -img.width, img.width, img.height);
      break;
    case 6: // 旋转90度(iOS竖屏拍照最常见的情况)
      // 先调整Canvas尺寸,因为旋转后宽高互换了
      canvas.width = img.height;
      canvas.height = img.width;
      ctx.rotate(0.5 * Math.PI);
      ctx.translate(0, -img.height);
      ctx.drawImage(img, 0, 0, img.width, img.height);
      break;
    case 7: // 水平翻转后旋转270度
      ctx.rotate(0.5 * Math.PI);
      ctx.scale(-1, 1);
      ctx.drawImage(img, -img.height, 0, img.width, img.height);
      break;
    case 8: // 旋转270度
      canvas.width = img.height;
      canvas.height = img.width;
      ctx.rotate(-0.5 * Math.PI);
      ctx.translate(-img.width, 0);
      ctx.drawImage(img, 0, 0, img.width, img.height);
      break;
    default: // 正常方向,直接绘制
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.drawImage(img, 0, 0, img.width, img.height);
  }
}

3. 配合你的拍照代码优化

看你的代码用的是Cordova Camera插件,其实可以尝试添加correctOrientation: true参数,让插件自动调整图片方向:

const options: CameraOptions = { 
  quality: 50, 
  destinationType: this.camera.DestinationType.DATA_URL,
  correctOrientation: true, // 尝试让插件自动修正方向
  ...
};

不过实测下来,有些iOS版本或者插件版本可能不生效,所以还是建议配合上面的Canvas处理逻辑,双重保障,不管是拍照还是选相册图片都能处理。

小提醒

  • 一定要等图片加载完成后再读取EXIF和绘制,否则会获取不到正确的方向信息。
  • 这个逻辑对相册选择的图片同样适用,因为相册里的iOS照片也带EXIF方向信息。

内容的提问来源于stack exchange,提问作者Vikas Jindal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:47:04