问题背景
最近在做的项目中,不管是移动端还是后台系统都涉及到了手机照片压缩上传的问题,做完功能测试的时候发现图片回显的时候有些顺时针旋转了90°(竖拍照片,不管是ios还是android都存在这问题),后来百度了一下才知道是跟图片的EXIF(可交换图像文件格式)中的Orientation(旋转参数)有关,那么问题就好处理了,我们可以获取上传图片的Orientation值,根据不同的值对图片做旋转处理。
Orientation旋转参数的介绍与获取
可交换图像文件格式(Exchangeable image file format,官方简称Exif),是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。只要是数码相机(包括手机)拍出来的照片都带有这个参数,旋转的方向有四种情况。exif.js可以帮助我们获取Orientation值(exif.js读取图像的元数据),后来我以import EXIF from './exif.js'方式引入发现文件中的EXIF方法并没有对外暴露出来,因此稍稍改写了一下。这是新的exif.js(你们可以引用这个exif.js)
引用exif.js后,获取Orientation的核心代码,记得先var Orientation声明Orientation
EXIF.getData(img, function () {//获取照片Orientation,主要是修复竖拍照片顺时针旋转90°的问题(Orientation:6)
EXIF.getAllTags(this);
Orientation = EXIF.getTag(this, 'Orientation');
});
canvas 的 rotate() 方法对不同的Orientation值旋转处理
ctx.rotate(angle);
方法介绍参照canvas rotate()
旋转的中心点默认是canvas 的起点,即圆点位置(0, 0)。旋转的原理如下图:
旋转之后,如果从圆点(0, 0)进行 drawImage(),那么画出来的位置就是在左图中的旋转90°后的位置,不在可视区域。旋转之后,坐标轴也跟着旋转了,想要显示在可视区域呢,需要将 ( 0, 0 ) 点往 y 轴的反方向移 y 个单位,此时的起始点则为 ( x, -y )(这种情况就是我们使用手机竖拍图片上传后顺时针旋转90°的情况)。
同理,可以获得旋转 -90°后的起始点为 ( -x, y ),旋转 180 度后的起始点为 ( -x, -y )。
核心代码如下
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 设置 canvas 的宽度和高度
// canvas.width = w;
// canvas.height = h;
// ctx.drawImage(img, 0, 0, w, h);
if (Orientation == 3) {
canvas.width = w;
canvas.height = h;
ctx.rotate(Math.PI);
ctx.drawImage(img, 0, 0, -w, -h);
} else if (Orientation == 8) {
canvas.width = h;
canvas.height = w;
ctx.rotate(Math.PI * 3 / 2);
ctx.drawImage(img, 0, 0, -w, h);
} else if (Orientation == 6) {
canvas.width = h;
canvas.height = w;
ctx.rotate(Math.PI / 2);
ctx.drawImage(img, 0, 0, w, -h);
} else {
canvas.width = w;
canvas.height = h;
ctx.drawImage(img, 0, 0, w, h);
}
图片压缩
随着手机拍照像素越来越高,照片大小越来越大。图片上传的压缩一般是:第一是对上传的图片宽高做大小限制。
// 不要超出最大宽度
var w = Math.min(_this.maxWidth, img.width);
// 高度按比例计算
var h = img.height * (w / img.width);
第二是通过canvas.toDataURL(type, encoderOptions)方法设置压缩比,方法参考canvas.toDataUrl()
核心代码如下:
setQuality: function (file) {
//alert(file.size+','+this.maxSize);
if (file.size < 1024 * 1024) {//0-1mb
this.quality = 0.4;
}
if (file.size < 1024 * 1024 && file.size > 1024 * 1024 * 2) {//1-2mb
this.quality = 0.3;
}
if (file.size < 1024 * 1024 * 3 && file.size > 1024 * 1024 * 2) {//2-3mb
this.quality = 0.2;
}
if (file.size < 1024 * 1024 * 4 && file.size > 1024 * 1024 * 3) {//3-4mb
this.quality = 0.15;
}
if (file.size < 1024 * 1024 * 5 && file.size > 1024 * 1024 * 4) {//4-5mb
this.quality = 0.12;
}
if (file.size < 1024 * 1024 * 6 && file.size > 1024 * 1024 * 5) {//5-6mb
this.quality = 0.11;
}
if (file.size < 1024 * 1024 * 7 && file.size > 1024 * 1024 * 6) {//6-7mb
this.quality = 0.1;
}
if (file.size < 1024 * 1024 * 8 && file.size > 1024 * 1024 * 7) {//7-8mb
this.quality = 0.08;
}
if (file.size < 1024 * 1024 * 10 && file.size > 1024 * 1024 * 8) {//8-10mb
this.quality = 0.06;
}
}
var base64 = canvas.toDataURL('image/jpeg', _this.quality);
setTimeout(function () {
_this.imgData[id].uploadFiles.push(base64);
_this.imgData[id].filesLength = _this.imgData[id].uploadFiles.length;
}, 100);
小结
拍照上传功能可拆分为图片压缩以及对获取到数码图片Orientation值进行相应的处理。这是小白第一次写技术贴,可能我写得并不是我想表达的,写得不好的地方请各位大神指点,有疑问的可以留言交流。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。