大體的思路是
利用FileReader,讀取blob對象,或者是file對象,將圖片轉(zhuǎn)化為data uri的形式。
使用canvas,在頁面上新建一個畫布,利用canvas提供的API,將圖片畫入這個畫布當(dāng)中。
利用canvas.toDataURL(),進(jìn)行圖片的壓縮,得到圖片的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事件中調(diào)用上面方法:
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) {
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? });
? ? ? ? ? });
? ? ? },
搞定
我這里設(shè)置的用 canvas重繪時 圖像寬高不變,只改變質(zhì)量,想改變寬高的可以修改canvas.width和canvas.height,改變質(zhì)量就修改compress方法中的第二個參數(shù)0.5。
另外注意部分安卓機(jī)型不支持blob類型,會導(dǎo)致選擇圖片后無法上傳,自動跳頁;這里不能直接用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機(jī)型拍照后圖片自動旋轉(zhuǎn),原因在另一篇文章中說明了,這里要用到exif.js,
npm install exif-js --save
然后在當(dāng)前頁面
import Exif from 'exif-js'
在封裝的compress方法開頭用exif獲取方向
let Orientation;
//去獲取拍照時的信息,解決拍出來的照片旋轉(zhuǎn)問題?
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大小,確定旋轉(zhuǎn)角度,iphone默認(rèn)的是home鍵在右方的橫屏拍攝方式
? ? ? ? ? ? ? if(Orientation != "" && Orientation != 1){
? ? ? ? ? ? ? ? ? switch(Orientation){
? ? ? ? ? ? ? ? ? ? ? ? //iphone橫屏拍攝,此時home鍵在左側(cè)
? ? ? ? ? ? ? ? ? ? ? case 3:
? ? ? ? ? ? ? ? ? ? ? ? ? ? degree=180;
? ? ? ? ? ? ? ? ? ? ? ? ? ? drawWidth=-width;
? ? ? ? ? ? ? ? ? ? ? ? ? ? drawHeight=-height;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? //iphone豎屏拍攝,此時home鍵在下方(正常拿手機(jī)的方向)
? ? ? ? ? ? ? ? ? ? ? ? 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旋轉(zhuǎn)校正
? ? ? ? ? ? ? ctx.rotate(degree*Math.PI/180);
? ? ? ? ? ? ? ctx.drawImage(this, 0, 0, drawWidth, drawHeight);
? ? ? ? ? ? ? dataURI = canvas.toDataURL(mimeType, quality);
? ? ? ? ? ? ? result = dataURIToBlob(dataURI);
? ? ? ? ? ? ? callback(null, result);
? ? ? ? ? }