关于照片Exif Orientation信息的处理

在展示照片尤其是手机拍摄的照片时,可能会遇到这么一个奇怪的现象,明明看到的图片是横的,但在部分浏览器中打开可能是竖的,导致这个问题的原因就是照片中存储的exif信息在作祟,有的浏览器矫正了exif中存储的旋转角度,有的浏览器则没有,就会导致我们看到的图片不一致。

一、什么是exif

Exif(可交换图像文件格式)是一种协议,用于存储有关数码相机拍摄的图像的各种元信息。Exif与实际图像数据一起存储。Exif中的一些元信息包括相机制造商,快门速度,焦距,方向,拍摄时间等。这些元信息称为标签,每个标签都有一个由Exif格式标准决定的特定标签号。标签的完整列表可参考:https://exiv2.org/tags.html

二、exif中的旋转角度orientation

上面我们提到了exif中存储了一些图像元信息,其中就包括了旋转方向Orientation,常用的Orientation主要有8类,按照编号1-8含义如下表:

Orientation值含义
1旋转0°
2水平翻转
3顺时针旋转180°
4垂直翻转
5顺时针旋转90°+水平翻转
6顺时针旋转90°
7顺时针旋转90°+垂直翻转
8逆时针旋转90°

借用网络上比较流行的一张图,8个方向的图示如下:

三、使用canvas矫正照片旋转角度

在知道了Orientation值分别对应的含义后,我们需要矫正旋转角度让照片在所有的浏览器下保持一致,一般的做法是在上传图片时由后端解析出照片中的旋转角度并记录,然后抹除旋转角度存储到服务器,然后将储存的图片和解析出的角度传递给前端,前端可以利用canvas来矫正图片的旋转角度,代码如下:

function getOrientationAppliedImage(src, imgOrientation) {
  return new Promise((resolve, reject) => {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    loadImg(src).then((img) => {
      const { width, height } = img;
      const halfWidth = width / 2;
      const halfHeight = height / 2;
      canvas.width = width;
      canvas.height = height;

      const transform = (func, isSwitch = false) => {
        if (isSwitch) {
          canvas.width = height;
          canvas.height = width;
        }
        ctx.translate(canvas.width / 2, canvas.height / 2);
        func && func();
        ctx.drawImage(img, -halfWidth, -halfHeight);
      };

      switch (imgOrientation) {
        case 2:
          transform(() => {
            ctx.scale(-1, 1);
          });
          break;
        case 3:
          transform(() => {
            ctx.rotate(Math.PI);
          });
          break;
        case 4:
          transform(() => {
            ctx.scale(1, -1);
          });
          break;
        case 5:
          transform(() => {
            ctx.scale(-1, 1);
            ctx.rotate(Math.PI / 2);
          }, true);
          break;
        case 6:
          transform(() => {
            ctx.rotate(-Math.PI / 2);
          }, true);
          break;
        case 7:
          transform(() => {
            ctx.scale(1, -1);
            ctx.rotate(Math.PI / 2);
          }, true);
          break;
        case 8:
          transform(() => {
            ctx.rotate(Math.PI / 2);
          }, true);
          break;
        default:
          ctx.drawImage(img, 0, 0);
          break;
      }

      resolve(canvas.toDataURL());
    }).catch(err => reject);
  });
}

调用getOrientationAppliedImage方法并传入图片链接和解析得到的旋转角度即可得到校正后的图片。

四、写在最后

当然我们也可以选择在上传图片的时候由后端直接抹除并矫正图片的旋转角度,但是直接改原图是不是合理还是有待考量的。

  • 支付宝二维码 支付宝
  • 微信二维码 微信

本文地址: /exif-orientation.html

版权声明: 本文为原创文章,版权归 逐梦个人博客 所有,欢迎分享本文,转载请保留出处!

相关文章