大体的思路是
利用FileReader,读取blob对象,或者是file对象,将图片转化为data uri的形式。
使用canvas,在页面上新建一个画布,利用canvas提供的API,将图片画入这个画布当中。
利用canvas.toDataURL(),进行图片的压缩,得到图片的data uri的值
上传文件。
我将以上步骤封装成一个方法:
compress(file, quality, callback) {
if (!window.FileReader || !window.Blob) {
return errorHandler('您的浏览器不支持图片压缩')();
}
var reader = new FileReader();
var mimeType = file.type || 'image/jpeg';
reader.onload = createImage;
reader.onerror = errorHandler('图片读取失败!');
reader.readAsDataURL(file);
function createImage() {
var dataURL = this.result;
var image = new Image();
image.onload = compressImage;
image.onerror = errorHandler('图片加载失败');
image.src = dataURL;
}
function compressImage() {
var canvas = document.createElement('canvas');
var ctx;
var dataURI;
var result;
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0);
dataURI = canvas.toDataURL(mimeType, quality);
result = dataURIToBlob(dataURI);
callback(null, result);
}
function dataURIToBlob(dataURI) {
var type = dataURI.match(/data:([^;]+)/)[1];
var base64 = dataURI.replace(/^[^,]+,/, '');
var byteString = atob(base64);
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// var blob = getBlob([ia]);
return new Blob([ia], {type: type});
}
function errorHandler(message) {
return function () {
var error = new Error('Compression Error:', message);
callback(error, null);
};
}
},
然后在在onchange事件中调用上面方法:
onUploadIdcard(e) {
var _this = this
let file = e.target.files[0];
var formData = new FormData();
_this.compress(file, 0.5, function (err, data) {
if (err) {
console.log(err);
return;
}
formData.append('file', data,'image.png');
$.ajax({
url: '你的接口',//这里是后台接口需要换掉
type: 'POST',
dataType: 'json',
cache: false,
data: formData,
processData: false,
contentType: false,
success: (res) => {
if (res.code === 200) {
}else if(res.code==40107){
}
},error: function(err) {
}
});
});
},
搞定
我这里设置的用 canvas重绘时 图像宽高不变,只改变质量,想改变宽高的可以修改canvas.width和canvas.height,改变质量就修改compress方法中的第二个参数0.5。
另外注意部分安卓机型不支持blob类型,会导致选择图片后无法上传,自动跳页;这里不能直接用new Blob();这时在dataURIToBlob方法中要改成兼容性写法:
function dataURIToBlob(dataURI) {
var type = dataURI.match(/data:([^;]+)/)[1];
var base64 = dataURI.replace(/^[^,]+,/, '');
var byteString = atob(base64);
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var blob;
try {
blob = new Blob([ia], {type: 'image/jpg'});
} catch (e) {
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
if(e.name === 'TypeError' && window.BlobBuilder){
var blobBuilder = new BlobBuilder();
blobBuilder.append(ia);
blob = blobBuilder.getBlob('image/jpg');
}
}
return blob
}
OK
还有就是iOS和部分Android机型拍照后图片自动旋转,原因在另一篇文章中说明了,这里要用到exif.js,
npm install exif-js --save
然后在当前页面
import Exif from 'exif-js'
在封装的compress方法开头用exif获取方向
let Orientation;
//去获取拍照时的信息,解决拍出来的照片旋转问题
Exif.getData(file, function(){
Orientation = Exif.getTag(this, 'Orientation');
});
修改compressImage() 方法,
function compressImage() {
var canvas = document.createElement('canvas');
var ctx;
var dataURI;
var result;
var degree = 0,drawWidth,drawHeight,width,height;
drawWidth = this.naturalWidth;
drawHeight = this.naturalHeight;
canvas.width=width=drawWidth;
canvas.height=height=drawHeight;
ctx = canvas.getContext('2d');
//判断图片方向,重置canvas大小,确定旋转角度,iphone默认的是home键在右方的横屏拍摄方式
if(Orientation != "" && Orientation != 1){
switch(Orientation){
//iphone横屏拍摄,此时home键在左侧
case 3:
degree=180;
drawWidth=-width;
drawHeight=-height;
break;
//iphone竖屏拍摄,此时home键在下方(正常拿手机的方向)
case 6:
canvas.width=height;
canvas.height=width;
degree=90;
drawWidth=width;
drawHeight=-height;
break;
//iphone竖屏拍摄,此时home键在上方
case 8:
canvas.width=height;
canvas.height=width;
degree=270;
drawWidth=-width;
drawHeight=height;
break;
}
}
//使用canvas旋转校正
ctx.rotate(degree*Math.PI/180);
ctx.drawImage(this, 0, 0, drawWidth, drawHeight);
dataURI = canvas.toDataURL(mimeType, quality);
result = dataURIToBlob(dataURI);
callback(null, result);
}