EXIF处理照片信息
最近在处理人脸照片时遇到一个奇怪现象,iphone 自拍照片总是显示未识别到人脸,Android 机则未出现任何问题。经过一番排查测试发现,iphone 手机在自拍时生成的人脸照片尽管显示是正常的,但是当转成 base64 格式之后恢复,自动逆时针旋转 45 度。导致人脸识别时,旋转之后的照片是无法检测出人脸的,带来极为糟糕的使用体验;所以需要在图片传给后端之前做一次复位操作。
解决方案就是读取照片中的方向信息,将旋转的照片进行复位;这里的读取信息使用开源的 exif-js,复位操作由于图片转 base64 格式一般使用 canvas 画布显示,所以旋转操作用 canvas 上下文的 rotate()或者 transform()皆可。
下图展示了照片 exif 方向参数的八种位置:
经过测试,苹果手机前置摄像头直立拍照对应 6 号位,摄像头在右横向拍照对应 1 号位(常规位置),摄像头在左横向拍照对应 8 号位(需要转 180 度)
示例代码如下:
let imgObj = new Image();
imgObj.src = imagesrc;
setTimeout(){()=>{
let orientation; //方向参数
EXIF.getData(imgObj, function() {
orientation = EXIF.getTag(this, 'Orientation');
}
let imgWidth = imgObj.width; //图片宽度
let imgHeight = imgObj.height; //图片高度
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let ratio = imgWidth/imgHeight;
if(imgWidth>imgHeight && imgWidth>750){
imgWidth = 750;
imgHeight = Math.ceil(750/ratio);
}else if(imgWidth<imgHeight && imgHeight>1350){
imgWidth = Math.ceil(1350/ratio);
imgHeight = 1350;
}
if(orientation == 6){
canvas.width = imgHeight;
canvas.height = imgWidth;
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(imgObj, 0, -imgHeight, imgWidth, imgHeight);
//画布以(0,-imgHeight)为焦点顺时针旋转90度,此时宽为图片高,高为图片宽
}else if(orientation == 3) {
canvas.width = imgWidth;
canvas.height = imgHeight;
ctx.rotate(180 * Math.PI / 180);
ctx.drawImage(imgObj, -imgWidth, -imgHeight, imgWidth, imgHeight);
}else {
canvas.width = imgWidth;
canvas.height = imgHeight;
ctx.drawImage(imgObj, 0, 0, imgWidth, imgHeight);
}
let database64 = canvas.toDataURL("image/jpeg",0.6)
},500}
p.s. exif-js 代码库存在一个类型校验缺陷,使用时需要修正一下,如下所示
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!