通过exif信息校正手机拍摄图片的旋转问题

最新更新时间:2019年07月03日11:24:00
《猛戳-查看我的博客地图-总有你意想不到的惊喜》

本文内容:exif信息、获取图片角度信息、orientation的值和拍摄方向对照表、图片的方向校正

exif

Exif 信息,由数码相机在拍摄过程中采集一系列的信息,然后把信息放置在我们熟知的 JPEG/TIFF 文件的头部,也就是说 Exif信息是镶嵌在 JPEG/TIFF 图像文件格式内的一组拍摄参数,它就好像是傻瓜相机的日期打印功能一样,只不过 Exif信息所记录的资讯更为详尽和完备。Exif 所记录的元数据信息非常丰富,包含:拍摄日期、摄器材、拍摄参数、图像处理参数、图像描述及版权信息、GPS定位数据、缩略图等

获取图片角度信息
/**
 * base64转ArrayBuffer对象
 * @param base64
 * @return buffer
 */
function base64ToArrayBuffer(base64) {
  base64 = base64.replace(/^data\:([^\;]+)\;base64,/gmi, '');
  var binary = atob(base64);
  var len = binary.length;
  var buffer = new ArrayBuffer(len);
  var view = new Uint8Array(buffer);
  for (var i = 0; i < len; i++) {
    view[i] = binary.charCodeAt(i);
  }
  return buffer;
}

/**
 * Unicode码转字符串  ArrayBuffer对象 Unicode码转字符串
 * @param
 * @return
 */
function getStringFromCharCode(dataView, start, length) {
  var str = '';
  var i;
  for (i = start, length += start; i < length; i++) {
    str += String.fromCharCode(dataView.getUint8(i));
  }
  return str;
}

/**
 * 获取jpg图片的exif的角度
 * @param
 * @return
 */
function getOrientation(arrayBuffer) {
  var dataView = new DataView(arrayBuffer);
  var length = dataView.byteLength;
  var orientation;
  var exifIDCode;
  var tiffOffset;
  var firstIFDOffset;
  var littleEndian;
  var endianness;
  var app1Start;
  var ifdStart;
  var offset;
  var i;
  // Only handle JPEG image (start by 0xFFD8)
  if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
    offset = 2;
    while (offset < length) {
      if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
        app1Start = offset;
        break;
      }
      offset++;
    }
  }
  if (app1Start) {
    exifIDCode = app1Start + 4;
    tiffOffset = app1Start + 10;
    if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
      endianness = dataView.getUint16(tiffOffset);
      littleEndian = endianness === 0x4949;

      if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
        if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
          firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);

          if (firstIFDOffset >= 0x00000008) {
            ifdStart = tiffOffset + firstIFDOffset;
          }
        }
      }
    }
  }
  if (ifdStart) {
    length = dataView.getUint16(ifdStart, littleEndian);

    for (i = 0; i < length; i++) {
      offset = ifdStart + i * 12 + 2;
      if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) {

        // 8 is the offset of the current tag's value
        offset += 8;

        // Get the original orientation value
        orientation = dataView.getUint16(offset, littleEndian);

        // Override the orientation with its default value for Safari (#120)
        if (true) {
          dataView.setUint16(offset, 1, littleEndian);
        }
        break;
      }
    }
  }
  return orientation;
}
  • 获取方法
let orientation = getOrientation(base64ToArrayBuffer(base64));
console.log(orientation);//1 0°  3 180°  6 90°  8 -90°
orientation的值和拍摄方向对照表
拍摄方向orientation手机旋转方向预览修正值
在这里插入图片描述1-90°
在这里插入图片描述390°180°
在这里插入图片描述690°
在这里插入图片描述8180°-90°

注意:

  • 存储在手机中的照片如果被编辑旋转过,则无法获取orientation,orientation为undefined,iOS和Android实测;
  • 非数码相机(手机)拍摄的图片,则无法获取orientation,orientation为undefined;
图片的方向校正

我们期望的效果是,无论是从哪个方向(n*90°)拍摄的照片,在预览的时候始终是“向上的”

预览修正值 = 手机旋转方向 + 90°

/**
 * 校正图片方向
 * @param base64 校正前图片base64
 * @return base64 校正后“向上的”图片base64
 */
function getUpwardImage(base64){
  let orientation = getOrientation(base64ToArrayBuffer(base64));
  img.src = base64
  img.onload = function () {
    let width = img.width, height = img.height;
    let compressionRatio = 0.3;//图片压缩率 0~1 0最大压缩率 1不压缩
    if(orientation == 3){
      canvas.width = width;
      canvas.height = height;
      ctx.rotate(Math.PI);//预览修正值
      ctx.drawImage(img, -width, -height, width, height)
    }else if(orientation == 6){
      //注意:此处canvas的宽高互换
      canvas.width = height;
      canvas.height = width;
      ctx.rotate(Math.PI / 2);//预览修正值
      ctx.drawImage(img, 0, -height, width, height)
    }else if(orientation == 8){
      //注意:此处canvas的宽高互换
      canvas.width = height;
      canvas.height = width;
      ctx.rotate(-Math.PI / 2);//预览修正值
      ctx.drawImage(img, -width, 0, width, height)
    }else{
      //不旋转原图
      canvas.width = width;
      canvas.height = height;
      ctx.drawImage(img, 0, 0, width, height);
    }
    return canvas.toDataURL('image/jpeg', compressionRatio)
  };
}
借助第三方库获取exif信息
npm install exif-js --save

import { EXIF } from "exif-js";
EXIF.getData(document.getElementById('imgElement'), function() {
  const allMetaData = EXIF.getAllTags(this);
 
  let direction;
  if (allMetaData.GPSImgDirection) {
    const directionArry = allMetaData.GPSImgDirection; // 方位角
    direction = directionArry.numerator / directionArry.denominator;
  }
 
  let Longitude;
  if (allMetaData.GPSLongitude) {
    const LongitudeArry = allMetaData.GPSLongitude;
    const longLongitude =
      LongitudeArry[0].numerator / LongitudeArry[0].denominator +
      LongitudeArry[1].numerator / LongitudeArry[1].denominator / 60 +
      LongitudeArry[2].numerator / LongitudeArry[2].denominator / 3600;
    Longitude = longLongitude.toFixed(8);
  }
 
  let Latitude;
  if (allMetaData.GPSLatitude) {
    const LatitudeArry = allMetaData.GPSLatitude;
    const longLatitude =
      LatitudeArry[0].numerator / LatitudeArry[0].denominator +
      LatitudeArry[1].numerator / LatitudeArry[1].denominator / 60 +
      LatitudeArry[2].numerator / LatitudeArry[2].denominator / 3600;
    Latitude = longLatitude.toFixed(8);
  }
 
  console.log(direction, Longitude, Latitude);//方向 经度 纬度
});
相关组件

react图片预览组件,传入的所有图片,都以“向上的”形式显示

react-native图片预览组件,获取图片相关信息

参考资料

感谢阅读,欢迎评论^-^

打赏我吧^-^

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值