相信大家在做项目的时候会遇到在canvas里加入图片时,图片发生90°,180°的旋转。当时的你肯定时懵逼的,为毛。
其实这就是图片的EXIF搞的鬼。
什么是EXIF
简单来说,Exif 信息就是由数码相机在拍摄过程中采集一系列的信息,然后把信息放置在我们熟知的 JPEG/TIFF 文件的头部,也就是说 Exif信息是镶嵌在 JPEG/TIFF 图像文件格式内的一组拍摄参数,它就好像是傻瓜相机的日期打印功能一样,只不过 Exif信息所记录的资讯更为详尽和完备。Exif 所记录的元数据信息非常丰富,主要包含了以下几类信息:
- 拍摄日期
- 摄器材(机身、镜头、闪光灯等
- 拍摄参数(快门速度、光圈F值、ISO速度、焦距、测光模式等
- 图像处理参数(锐化、对比度、饱和度、白平衡等)
- 图像描述及版权信息
- GPS定位数据
- 缩略图
这里面就包含了图片的角度信息,就是说你用手机拍照时是不是倒着拍还是侧着拍,这些都是有记录的。
接下来就是教大家怎么获取图片内的exif信息
先给大家看看exif信息都存在哪里:(角度就在0x0112)
// 这里的获取exif要将图片转ArrayBuffer对象,这里假设获取了图片的baes64// 步骤一// base64转ArrayBuffer对象 ?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码转字符串 ?function getStringFromCharCode(dataView, start, length) { ???var str = ''; ???var i; ???for (i = start, length += start; i < length; i++) { ?????str += fromCharCode(dataView.getUint8(i)); ???} ???return str; ?}// 步骤三,获取jpg图片的exif的角度(在ios体现最明显) ?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 (IS_SAFARI_OR_UIWEBVIEW) { ???????????dataView.setUint16(offset, 1, littleEndian); ?????????} ?????????break; ???????} ?????} ???} ???return orientation; ?}
方法getStringFromCharCode(arrayBuffer)返回的orientation就是图片的方向也就是旋转的值,再对应下面的表,对图片进行处理
orientation值 | 旋转角度 |
---|---|
1 | 0° |
3 | 180° |
6 | 顺时针90° |
8 | 逆时针90° |
大家可以先判断图片Exif的orientation值再根据上表对应的旋转值,在canvas上对图片进行反方向旋转消除影响
之后我会对canvas上如何旋转进行详细讲解。