這篇文章主要講解了“web前端圖片壓縮、方向糾正、預(yù)覽、上傳插件的方法是什么”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“web前端圖片壓縮、方向糾正、預(yù)覽、上傳插件的方法是什么”吧!

成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供曲靖網(wǎng)站建設(shè)、曲靖做網(wǎng)站、曲靖網(wǎng)站設(shè)計(jì)、曲靖網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、曲靖企業(yè)網(wǎng)站模板建站服務(wù),10多年曲靖做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
實(shí)現(xiàn)原理
壓縮圖片并且上傳主要用到filereader、canvas 以及 formdata 這三個(gè)h6的api和插件EXIF.js。邏輯并不難。整個(gè)過程就是:
(1)用戶使用input file上傳圖片的時(shí)候,用filereader讀取用戶上傳的圖片數(shù)據(jù)(base64格式)
?(2)把圖片數(shù)據(jù)傳入img對(duì)象,然后將img繪制到canvas上,用EXIF.js對(duì)圖片方向進(jìn)行糾正,再調(diào)用canvas.toDataURL對(duì)圖片進(jìn)行壓縮,獲取到壓縮后的base64格式圖片數(shù)據(jù),轉(zhuǎn)成二進(jìn)制
?(3)獲取到壓縮后的圖片二進(jìn)制數(shù)據(jù),預(yù)覽。
?(4)將壓縮后的圖片二進(jìn)制數(shù)據(jù)塞入formdata,再通過XmlHttpRequest提交formdata
如此四步,就完成了圖片的壓縮、方向糾正、預(yù)覽和上傳。
插件設(shè)計(jì)思考
考慮到在實(shí)際項(xiàng)目中,可能用不同的開發(fā)框架(vue.js/JQ/react.js/angular.js/anu.js等),圖片預(yù)覽的UI樣式也可能不同,圖片數(shù)據(jù)上傳方法可能不同。因?yàn)閳D片壓縮和方向糾正這兩塊的邏輯多變性比較低,我們這里把圖片壓縮和方向糾正抽離出來,封裝為一個(gè)插件庫。
【一】獲取圖片數(shù)據(jù)
先是獲取圖片數(shù)據(jù),也就是監(jiān)聽input file的change事件,然后獲取到用來壓縮上傳的文件對(duì)象files,將files傳到【圖片壓縮、方向糾正插件】中進(jìn)行處理。
這時(shí)候根據(jù)每個(gè)人的需求,也可以預(yù)覽未壓縮的圖片。
//監(jiān)聽上傳組件input的onchange事件,壓縮圖片,糾正圖片方向,同時(shí)獲取壓縮后的圖片
filechooser.onchange = function () {
var fileList = this.files;
//預(yù)覽壓縮前的圖片
var files = Array.prototype.slice.call(fileList);
files.forEach(function (file, i) {
var reader = new FileReader();
reader.onload = function () {
var li = document.createElement("li")
li.style.backgroundImage = 'url('+this.result+')';
document.querySelector('.img_list').appendChild(li)
}
reader.readAsDataURL(file);
});
//處理圖片列表,getCompressiveFileList接受處理后的圖片數(shù)據(jù)列表
//下面兩行代碼為圖片壓縮、方向糾正插件的用法,具體實(shí)現(xiàn)細(xì)節(jié)請(qǐng)繼續(xù)往下閱讀 ~_~ ↓↓↓
var process = window.lzImgProcess();
process(fileList, getCompressiveFileList);
}【二】圖片壓縮、方向糾正插件實(shí)現(xiàn)
上面做完圖片數(shù)據(jù)的獲取后,就可以做process壓縮圖片的方法了。而壓縮圖片也并不是直接把圖片繪制到canvas再調(diào)用一下toDataURL就行的。
在IOS中,canvas繪制圖片是有兩個(gè)限制的:
首先是圖片的大小,如果圖片的大小超過兩百萬像素,圖片也是無法繪制到canvas上的,調(diào)用drawImage的時(shí)候不會(huì)報(bào)錯(cuò),但是你用toDataURL獲取圖片數(shù)據(jù)的時(shí)候獲取到的是空的圖片數(shù)據(jù)。
再者就是canvas的大小有限制,如果canvas的大小大于大概五百萬像素(即寬高乘積)的時(shí)候,不僅圖片畫不出來,其他什么東西也都是畫不出來的。
應(yīng)對(duì)上面兩種限制,我把圖片寬度、高度壓縮控制在1000px以內(nèi),這樣圖片最大就不超過兩百萬像素了。在前端開發(fā)中,1000px*1000px基本可以滿足絕大部分的需求了。當(dāng)然了還有更完美的瓦片式繪制的方法,我們這里就說瓦片式繪制方法了。
如此一來就解決了IOS上的兩種限制了。
除了上面所述的限制,還有兩個(gè)坑,一個(gè)就是canvas的toDataURL是只能壓縮jpg的(這句話的詳細(xì)解釋可以看下面的Tip講解),當(dāng)用戶上傳的圖片是png的話,就需要轉(zhuǎn)成jpg,也就是統(tǒng)一用canvas.toDataURL('image/jpeg', 0.5) , 類型統(tǒng)一設(shè)成jpeg,而壓縮比就自己控制了。
另一個(gè)就是如果是png轉(zhuǎn)jpg,繪制到canvas上的時(shí)候,canvas存在透明區(qū)域的話,當(dāng)轉(zhuǎn)成jpg的時(shí)候透明區(qū)域會(huì)變成黑色,因?yàn)閏anvas的透明像素默認(rèn)為rgba(0,0,0,0),所以轉(zhuǎn)成jpg就變成rgba(0,0,0,1)了,也就是透明背景會(huì)變成了黑色。解決辦法就是繪制之前在canvas上鋪一層白色的底色。
在壓縮圖片之前,我們判斷圖片角度,如果圖片角度不正確,還需要用EXIF.js把圖片角度糾正過來。
壓縮完圖片,把base64的圖片數(shù)據(jù)轉(zhuǎn)成二進(jìn)制數(shù)據(jù)存儲(chǔ)到暫存區(qū)中,等待被getBlobList獲取使用。
Tip: canvas的toDataURL是只能壓縮jpg這句話我可能說的不清楚,我想表達(dá)的意思是這個(gè)api無論是jpeg還是png,最后導(dǎo)出的時(shí)候,都跟jpeg沒啥差別了。因?yàn)閜ng圖片的透明性質(zhì)在canvas中是無效的,會(huì)被canvas添加默認(rèn)的黑色背景,我在文中講解的時(shí)候,用白色背景處理了,所以最后導(dǎo)出的圖片,無論你設(shè)置的是png還是jpeg都跟jpeg沒啥區(qū)別了,因?yàn)闊o法保持png的透明度性質(zhì)了
(function(window) {
/**
*
* 作者:混沌傳奇
*
* 郵箱地址:iot-pro_lizeng@foxmail.com
*
* 日期:2017-10-26
*
* 插件功能:壓縮圖片&&糾正圖片方向&&返回二進(jìn)制(Blob)圖片元數(shù)據(jù)組成的列表
*
*/
window.lzImgProcess = function () {
var Orientation = '', //圖片方向角
blobList = [], //壓縮后的二進(jìn)制圖片數(shù)據(jù)列表
canvas = document.createElement("canvas"), //用于壓縮圖片(糾正圖片方向)的canvas
ctx = canvas.getContext('2d'),
file_type = 'image/jpeg', //圖片類型
qlty = 0.5, //圖片壓縮品質(zhì),默認(rèn)是0.5,可選范圍是0-1的數(shù)字類型的值,可配置
imgWH = 1000; //壓縮后的圖片的最大寬度和高度,默認(rèn)是1000px,可配置
/**
* @actionName process,
* 方法功能:壓縮圖片&&糾正圖片方向&&返回二進(jìn)制(Blob)圖片元數(shù)據(jù)
*
* @param fileList,傳入函數(shù)的文件列表對(duì)象,fileList對(duì)象是來自用戶在一個(gè)<input>元素上選擇文件后返回的FileList對(duì)象
* 注意:圖片類型必須是jpeg||png
* 比如:<input id="uploadImage" onchange="loadImageFile();" />
* function loadImageFile() {
* //獲取返回的fileList對(duì)象
* var fileList = document.getElementById("uploadImage").files;
* }
* @param getBlobList [Blob],獲取壓縮結(jié)果的鉤子函數(shù),接受一個(gè)參數(shù)。
* 功能:在圖片壓縮完畢后,獲取壓縮后的二進(jìn)制圖片數(shù)據(jù)對(duì)象組成的數(shù)組,參數(shù)即:壓縮后的二進(jìn)制圖片數(shù)據(jù)(blob)組成的list
*
* @param quality,傳入函數(shù)的圖片壓縮比率(品質(zhì)),可選范圍0-1的數(shù)字類型的值,默認(rèn)是0.5
*
* @param WH,傳入函數(shù)的圖片壓縮后的最大圖片寬度和高度,默認(rèn)是1000,單位是px,可自由配置。
* 注意:最好不要超過1000,數(shù)字過大,容易導(dǎo)致canvas壓縮失敗。由于沒做瓦片處理,所以有這個(gè)限制。1000*1000的圖片在前端中,基本也夠用了。
*
*/
function process (fileList, getBlobList, quality, WH) {
blobList = []; //初始化blobList
// 判斷參數(shù)fileList的長(zhǎng)度是否大于0
if (!fileList.length){
console.log('警告:傳進(jìn)方法process的參數(shù)fileList長(zhǎng)度必須大于零!!!')
return;
}
//如果quality參數(shù)有值,則把quality賦值給qlty(圖片壓縮的品質(zhì))
if(quality)
qlty = quality;
//如果WH參數(shù)有值,則把WH賦值給imgWH(壓縮后的圖片的最大寬度和高度)
if(WH&&WH<1000&&WH>0){
imgWH = WH;
}
// 把傳進(jìn)來的fileList轉(zhuǎn)為數(shù)組類型
var files = Array.prototype.slice.call(fileList);
files.forEach(function (file, i) {
if (!/\/(?:jpeg|png)/i.test(file.type)){
console.log('警告:圖片必須是jpeg||png類型!!!');
return;
}
// file_type = file.type;
var reader = new FileReader();
// 獲取圖片壓縮前大小,打印圖片壓縮前大小
var size = file.size/1024 > 1024 ? (~~(10*file.size/1024/1024))/10 + "MB" : ~~(file.size/1024) + "KB";
// console.log('size:', size)
reader.onload = function () {
var img = new Image();
img.src = this.result;
// 圖片加載完畢之后進(jìn)行壓縮
if (img.complete) {
callback();
} else {
img.onload = callback;
}
function callback() {
//獲取照片方向角屬性,用戶旋轉(zhuǎn)控制
EXIF.getData(img, function() {
// alert(EXIF.pretty(this));
EXIF.getAllTags(this);
// alert(EXIF.getTag(this, 'Orientation'));
Orientation = EXIF.getTag(this, 'Orientation');
console.log('Orientation:', Orientation)
if(Orientation == ""||Orientation == undefined||Orientation == null){
Orientation = 1;
}
});
//獲取壓縮后的圖片二進(jìn)制數(shù)據(jù)
var data = GetImgCompress(img);
//將二進(jìn)制數(shù)據(jù)塞入到二進(jìn)制數(shù)據(jù)列表中
blobList.push(data);
//將壓縮后的二進(jìn)制圖片數(shù)據(jù)對(duì)象(blob)組成的list通過鉤子函數(shù)返回出去
if(blobList.length===files.length){
if(getBlobList)
getBlobList(blobList);
}
img = null;
}
};
reader.readAsDataURL(file);
})
}
/**
* @actionName GetImgCompress,
* 功能:判斷上傳圖片的方向,如果不是正確的,進(jìn)行修正,并對(duì)圖片進(jìn)行壓縮,壓縮完后,返回壓縮后的二進(jìn)制圖片數(shù)據(jù)
*
* @param img, 用來壓縮的圖片對(duì)象
*
* @returns 返回的壓縮后的二進(jìn)制圖片數(shù)據(jù)
*/
function GetImgCompress(img){
//如果方向角不為1,都需要進(jìn)行旋轉(zhuǎn)
if(Orientation != 1){
switch(Orientation){
case 6://需要順時(shí)針90度旋轉(zhuǎn)
rotateImg(img,'right',canvas);
break;
case 8://需要逆時(shí)針90度旋轉(zhuǎn)
rotateImg(img,'left',canvas);
break;
case 3://需要180度旋轉(zhuǎn)
rotateImg(img,'right2',canvas);//轉(zhuǎn)兩次
break;
}
}else{
//不做旋轉(zhuǎn)
rotateImg(img,'no',canvas);
}
var ndata;
ndata = canvas.toDataURL(file_type, qlty);
//打印壓縮前后的大小,以及壓縮比率
// var initSize = img.src.length;
// console.log('壓縮前:' + initSize);
// console.log('壓縮后:' + ndata.length, 'base64數(shù)據(jù)', ndata);
// console.log('壓縮率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");
//將壓縮后的base64數(shù)據(jù)轉(zhuǎn)為二進(jìn)制數(shù)據(jù)
ndata = dataURItoBlob(ndata);
//清除canvas畫布的寬高
canvas.width = canvas.height = 0;
return ndata;
}
/**
* @actionName rotateImg,
* 功能:對(duì)圖片旋轉(zhuǎn)處理
*
* @param img, 用來矯正方向的圖片對(duì)象
*
* @param direction, 旋轉(zhuǎn)方向
*
* @param canvas, 用來繪制圖片的cavas畫布對(duì)象
*/
function rotateImg(img, direction,canvas) {
//最小與最大旋轉(zhuǎn)方向,圖片旋轉(zhuǎn)4次后回到原方向
var min_step = 0;
var max_step = 3;
if (img == null)return;
//img的高度和寬度不能在img元素隱藏后獲取,否則會(huì)出錯(cuò)
var height = img.height;
var width = img.width;
if(width>imgWH || height>imgWH){
var ratio = ~~(height/width*10)/10;
if(width>height){
width = imgWH;
height = imgWH*ratio;
}else{
height = imgWH;
width = height/ratio;
}
img.width = width;
img.height = height;
}
var step = 2;
if (step == null) {
step = min_step;
}
if (direction == 'no'){
step = 0;
} else if (direction == 'left') {
step++;
//旋轉(zhuǎn)到原位置,即超過最大值
step > max_step && (step = min_step);
} else if (direction == 'right') {
step--;
step < min_step && (step = max_step);
} else {
//旋轉(zhuǎn)180度
}
//旋轉(zhuǎn)角度以弧度值為參數(shù)
var degree = step * 90 * Math.PI / 180;
switch (step) {
case 0:
canvas.width = width;
canvas.height = height;
// 鋪底色
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
break;
case 1:
canvas.width = height;
canvas.height = width;
// 鋪底色
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, height, width);
ctx.rotate(degree);
ctx.drawImage(img, 0, -height, width, height);
break;
case 2:
canvas.width = width;
canvas.height = height;
// 鋪底色
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
ctx.rotate(degree);
ctx.drawImage(img, -width, -height, width, height);
break;
case 3:
canvas.width = height;
canvas.height = width;
// 鋪底色
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, height, width);
ctx.rotate(degree);
ctx.drawImage(img, -width, 0, width, height);
break;
}
}
/**
* dataURL to blob, ref to https://gist.github.com/fupslot/5015897
* @param dataURI,圖片的base64格式數(shù)據(jù)
* @returns {Blob}
*/
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: mimeString});
}
/**
* 返回一個(gè)process方法
*
* process方法:用來壓縮圖片數(shù)據(jù),在壓縮圖片的同時(shí),默認(rèn)會(huì)調(diào)用correctOrientation方法糾正圖片方向。
*
*/
return process;
}
})(window)Exif.js 提供了 JavaScript 讀取圖像的原始數(shù)據(jù)的功能擴(kuò)展,例如:拍照方向、相機(jī)設(shè)備型號(hào)、拍攝時(shí)間、ISO 感光度、GPS 地理位置等數(shù)據(jù)。
Exif.js官方github 倉庫地址:
github.com/exif-js/exi…
【三】獲取壓縮后的圖片二進(jìn)制數(shù)據(jù),預(yù)覽圖片
完成圖片壓縮后,就可以獲取壓縮后的圖片二進(jìn)制數(shù)據(jù)了,把獲取到的圖片二進(jìn)制數(shù)據(jù)存起來;獲取到數(shù)據(jù)后,可以拿來預(yù)覽。
由于實(shí)際項(xiàng)目中,每個(gè)項(xiàng)目的UI樣式設(shè)計(jì)可能不一樣,開發(fā)者可以根據(jù)自己的UI樣式來預(yù)覽圖片。
//獲取壓縮后的圖片
function getCompressiveFileList(fileList) {
blobFileList = fileList;
// console.log('fileBlobList:', fileList);
fileList.forEach(function (blob) {
var reader = new FileReader();
reader.onload = function () {
var li = document.createElement("LI")
li.style.backgroundImage = 'url('+this.result+')';
document.querySelector('.imgCompress_list').appendChild(li)
}
reader.readAsDataURL(blob);
})
}【四】提交圖片數(shù)據(jù)到后臺(tái)
new一個(gè)formdata對(duì)象,將上一步獲取到的 blobFileList 圖片二進(jìn)制數(shù)據(jù) append 到 formdata中,用任意你喜歡的ajax庫進(jìn)行上傳。當(dāng)然也可以用原生ajax上傳。
//將壓縮后的二進(jìn)制圖片數(shù)據(jù)流append到formdata對(duì)象中上傳到后臺(tái)服務(wù)器 //注意:上傳的是formdata對(duì)象,后臺(tái)接口接收的時(shí)候,也要從formdata對(duì)象中讀取二進(jìn)制數(shù)據(jù)流 function formUpData(blobFiles){ var formData = new FormData(); formData.append("files", blobFiles); var xhr = new XMLHttpRequest(); //鏈接你自己上傳圖片接口即可,這里的接口地址,是我寫的示例,不可真實(shí)使用,講解意義更大 xhr.open('post', 'http://xxx/welcome/index/'); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { console.log('上傳成功!'); } }; xhr.send(formData); }
感謝各位的閱讀,以上就是“web前端圖片壓縮、方向糾正、預(yù)覽、上傳插件的方法是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)web前端圖片壓縮、方向糾正、預(yù)覽、上傳插件的方法是什么這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
文章標(biāo)題:web前端圖片壓縮、方向糾正、預(yù)覽、上傳插件的方法是什么
URL分享:http://chinadenli.net/article32/iidgpc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、網(wǎng)站設(shè)計(jì)公司、動(dòng)態(tài)網(wǎng)站、網(wǎng)站排名、Google、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)