input调起ios摄像头拍照旋转问题解决思路
背景input标签调起ios原生摄像头拍照时,上传照片发现照片向左旋转了90度旋转的原因:手机拍照会给图片添加一个Orientaion信息(即拍照方向),如下:用ios手机拍照,系统会给图片加上一个方向的属性, ios相机默认的拍照方向是后摄Home键在右为正,前摄Home键在左为正。1代表正常的拍摄角度,ios横屏下拍摄、安卓机无论横屏竖屏拍摄,Orientaion的值都为1;但是ios竖屏拍摄
背景
input标签调起ios原生摄像头拍照时,上传照片发现照片向左旋转了90度
旋转的原因:
手机拍照会给图片添加一个Orientaion信息(即拍照方向),如下:
用ios手机拍照,系统会给图片加上一个方向的属性, ios相机默认的拍照方向是后摄Home键在右为正,前摄Home键在左为正。
1代表正常的拍摄角度,ios横屏下拍摄、安卓机无论横屏竖屏拍摄,Orientaion的值都为1;但是ios竖屏拍摄,Orientaion的值为6,即竖着拍出的照片被添加了一个顺时针旋转90°的拍照方向,显示的时候其实就是横着拍的照片顺时针旋转90°而成。当我们对拍出来的照片进行处理后(比如压缩),这个拍摄方向Orientaion信息就会丢失,显示的效果自然回到横屏状态,看起来像是逆时针旋转了90°。
受之于鱼不如授之于渔 我提出三种解决思路
第一种解决思路:
1、利用exif-js获取file拍摄方向信息Orientation
2、创建canvas,ctx = canvas.getContext(‘2d’);
3、根据Orientation,经过ctx.rotate(旋转)、 ctx.drawImage(手动绘图)
4、canvas.toBlob 创建文件流,再传给服务端
这也是网上的大神通用的解决办法
- 缺点(推荐指数:3星)
- 很多人卡在了第一步,获取到的Orientation=undefined; 首先获取图片信息只对拍摄方式的照片生效,不要在本地上传图片进行调试;其次获取Orientation时,要在回调函数内获取,如下代码
- 需要熟悉canvas知识
- 第三部rotate、drawImage方法如果没有掌握的很好,最后的绘图步骤会让你抓狂
- 第四部创建的文件流会超级大,需要很久的上传时长,尽管可以控制转换质量使之变小,但也会大大失桢
// 只对即时拍摄的照片生效,file为文件流,非base64
ExifObj.getData(file, function () {
const Orientation = ExifObj.getTag(file, 'Orientation');
// 在这里获取
});
// 不要在这里获取
第二种解决思路:
如果没有特殊要求,请不要对图片进行二次处理,例如进行压缩,最简单快捷地解决问题;
第三种解决思路:(推荐指数:5星)
思路:既然经处理后的图片方向信息丢失,那我们可以手动再次添加方向不就解决问题了嘛
- 如果图片必须经过处理,在处理前请先利用exif-js缓存照片方向信息
- 处理后利用piexif手动对处理后的文件添加方向信息
- 最后向服务器发送文件流或base64信息-保存
- 缺点:最后添加的方向信息可能会使图片的size增加,但完全规避了方法一繁琐的步骤及开发成本
npm i exif-js
npm i piexif
...
import React, { useState, useEffect, FC } from 'react';
import Exif from 'exif-js';
import * as piexif from 'piexif';
import { IExif, IExifElement, TagValues } from 'piexif';
interface IProps {
history: any; // TS内容 可不写
}
const AppView: FC<IProps> = props => {
const ExifObj = Exif;
const Piexif = piexif;
const [orientation, setOrientation] = useState<number>(1); // 初始化方向
useEffect(() => {
ExifObj.getData(file, function () {
setOrientation(ExifObj.getTag(file, 'Orientation')); // 先获取方向信息file为文件流
// ——————————————————————————
// 这里是图片文件处理过程,省略1w行代码...
// ——————————————————————————
// 开始利用piexif写图片方向信息
let zeroth: IExifElement = {};
zeroth[TagValues.ImageIFD.Orientation] = orientation;
let exifObj: IExif = { '0th': zeroth }; // 重新写方向
let exifStr = Piexif.dump(exifObj); //获取需要写信息的合法字符串格式
let resultBase64 = Piexif.insert(exifStr, file); //将exif信息插入到base64中,此时的file为处理后的文件流,非base64,服务端如果需要base64格式则直接上传即可
// 若服务器需要文件流格式(blob),仍需要转化为blob
const blobfilr = base64ToBlob(resultBase64);
// 发送ajax
});
}, [])
const base64ToBlob = base64 => {
const parts = base64.split(';base64,');
const contentType = parts[0].split(':')[1];
const raw = window.atob(parts[1]);
const rawLength = raw.length;
const uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; i += 1) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
};
}
如果真的解决了你的问题或对你有启发,回来点个赞吧
参考文献:
【npm官网】https://www.npmjs.com/package/piexif
【前端开发仓库】http://code.ciaoca.com/javascript/exif-js/
【zoukankan】http://t.zoukankan.com/ranyonsue-p-10830688.html
更多推荐
所有评论(0)