在學習前端你的小伙伴都在迷茫遇到問題,找不到老師怎么辦?這些也是小猿圈web前端老師擔心的,以后每天小猿圈都會為大家分享一些關于學習前端中的一些小問題,今天分享的是利用canvas實現圖片壓縮方法。
項目中做身份證識別時,需要傳送圖片的base64格式編碼,但是手機拍攝的照片都太大了,轉成base64簡直可怕,因此找了一下解決辦法。
涉及到的知識點
onchange事件是在上傳完文件之后觸發
使用files屬性獲取到上傳的文件對象
readAsDataURL用于轉換成base64編碼
區分canvas的畫布和繪畫環境:
畫布:對應代碼中的cvs,可以設置畫布width,height;
繪畫環境:對應代碼中的ctx,可以設置fillStyle,fillRect等;
使用canvas自帶的drawImage()方法將圖片畫到canvas上
想取到壓縮后圖片的base64可以使用canvas自帶的toDataURL()方法
完整代碼
<!DOCTYPEhtml>
<htmllang="en">
<head>
<metacharset="UTF-8">
<metaname="viewport"content="width=device-width,initial-scale=1.0">
<metahttp-equiv="X-UA-Compatible"content="ie=edge">
<title>Document</title>
</head>
<body>
<inputtype="file"onchange="loadImg(this)">
<hr>
<div>800×449,544KB</div>
<imgsrc=""alt="">
<hr>
<div>400×224,157KB</div>
<canvas></canvas>
<script>
//上傳圖片
functionloadImg(me){
letimg=document.querySelector('img');
letcvs=document.querySelector('canvas');
letfile=me.files[0];//獲取到文件對象
//上傳的圖片大于500KB時才壓縮
if(file&&(file.size/1024>500)){
letreader=newFileReader();
reader.readAsDataURL(file);//轉成base64編碼
reader.onload=function(e){
letnaturalBase64=e.target.result;//獲取base64編碼,這是原圖的
img.src=naturalBase64;
img.onload=function(){
letratio=img.naturalWidth/img.naturalHeight;//獲取原圖比例,為了等比壓縮
cvs.width=400;
cvs.height=cvs.width/ratio;
letctx=cvs.getContext('2d');
ctx.drawImage(img,0,0,cvs.width,cvs.height);//畫在canvas上
//壓縮后新圖的base64
letzipBase64=cvs.toDataURL();
}
}
}
}
</script>
</body>
</html>
關于壓縮后的圖片大小
這里提供一個開箱即用的方法,baseStr是一個完整的Base64編碼
代碼:
functioncalcBase(baseStr){
vartag='base64,';
baseStr=baseStr.substring(baseStr.indexOf(tag)+tag.length);
vareqTagIndex=baseStr.indexOf('=');
baseStr=eqTagIndex!=-1?baseStr.substring(0,eqTagIndex):baseStr;
varstrLen=baseStr.length;
varfileSize=strLen-(strLen/8)*2;
console.log("文件大小:"+(fileSize/1024).toFixed(1)+'KB');
}
今天的知識點就分享到這里了,有需要的朋友歡迎點贊評論轉發,想了解更多web前端開發內容的朋友可以關注小猿圈的每天的動態,會不定時更新很多更好的內容奉獻給大家,希望對你的學習有所幫助。
朱哥,昨天試了幾把圖片上傳的功能,感覺還不錯,不過有個小問題!"
老朱:“什么問題?”
小白:“小圖片上傳還好說,大圖片上傳的時候經常會卡頓一下。”
老朱:“恩,很多人上傳圖片的時候都是直接上傳原圖的,很多相機照的原圖大小都在4M左右,上傳的圖片如果都是這么大,不但用戶覺得你的網站速度慢,還非常占服務器空間。”
小白:“哦,確實是,很多人壓根不知道自己上傳的圖片到底有多大。”
老朱:“所以我們要讓用戶進行傻瓜式操作,圖片壓縮的功能就必不可少。今天我們就用canvas來做一下圖片壓縮的處理。我們在昨天的基礎上增加canvas功能就可以了。”
老朱:“在縮略圖下面增加一個canvas,canvas有一個toDataURL方法,可以把當前的canvas繪制的內容進行圖片壓縮并轉換為base64編碼,有了base64編碼我們就可以發送給圖片上傳的php頁面進行圖片上傳了。”
老朱繼續說道:“知道了壓縮的方法,我們只需要解決如果把選擇的文件繪制到canvas上面就可以了。還記得我們之前繪制圖片的時候用到的Image對象么?”
“記得,繪制圖像的時候需要實例化一個Image對象,然后設定Image對象的圖片地址src,當圖片加載完成以后把圖片繪制到canvas上。”
老朱:“恩,流程還記得,不錯。Image對象的src屬性也可以接收圖片base64編碼,因此我們可以這樣來做。”
“這里我把canvas的寬度設定在500像素,高度根據圖片高度進行等比例變化,你可以看一下繪制的效果。”
你看看這張圖片的原始大小信息:
“現在通過imgdata=canvas.toDataURL('image/jpeg',0.3);把canvas信息壓縮并轉為base64編碼存到imgdata里面,然后通過jQuery的ajax把imgdata發送給圖片上傳的php頁面就可以了。”
“通過canvas上傳以后圖片的大小下降到9.65K,應該說是沒非常理想了。通過canvas壓縮后上傳最大的好處是圖片在客戶端進行處理,處理好以后再往服務器發送,這樣傳輸的數據大小就非常小了。”
老朱最后說:“剛剛我們通過canvas實現了圖片壓縮上傳,真正開發的時候情況會比這個稍微復雜點,我跟你大概說一下,你記住就行了。1、動態生成canvas,這樣做的好處是canvas不會顯示在頁面上。2、判斷圖片大小,如果圖片大小比較小不用壓縮直接上傳就可以,圖片大再進行壓縮。3、有時你可能需要隱藏input file,比如上傳頭像的功能,用戶點擊頭像進行選擇圖片上傳,這時就需要通過點擊頭像的事件調用input file的點擊事件來選擇圖片。這幾個技巧你有時間了可以自己實現一下,不是特別麻煩,我們之前學過的知識足夠你解決它們了。”
想學H5的朋友可以關注老爐,您的關注是我持續更新《小白HTML5成長之路》的動力!
下截圖:
點擊文件選擇框,我們不妨選一張尺寸比較大的圖片,例如下面這種2M多的釣魚收獲照:
于是圖片歘歘歘地傳上去了:
此時我們點擊最終上傳完畢的圖片地址,會發現原來2M多3000多像素寬的圖片被限制為400像素寬了:
保存到本地會發現圖片尺寸已經變成只有70K了:
以上就是圖片前端壓縮并上傳demo的完整演示。
二、實現原理
要想使用JS實現圖片的壓縮效果,原理其實很簡單,核心API就是使用canvas的drawImage()方法。
Canvas本質上就是一張位圖,而drawImage()方法可以把一張大大的圖片繪制在小小的Canvas畫布上,不久等同于圖片尺寸壓縮了?
對于本案例的壓縮,使用的5個參數的API方法:
context.drawImage(img, dx, dy, dWidth, dHeight);復制代碼
各參數具體含義可以參見“Canvas API中文文檔-drawImage”,這里不展開。
舉例:
一張圖片(假設圖片對象是img)的原始尺寸是4000*3000,現在需要把尺寸限制為400*300大小,很簡單,原理如下代碼示意:
var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); canvas.width = 400; canvas.height = 300; // 核心JS就這個 context.drawImage(img,0,0,400,300);復制代碼
把大圖片畫在一張小畫布上,壓縮就這么實現了,是不是簡單的有點超乎想象。
三、如果想要上傳或下載?
如果想要上傳圖片或者下載圖片,可以使用canvas.toDataURL()或者canvas.toBlob()方法先進行轉換。
1. canvas.toDataURL()
語法如下:canvas.toDataURL(mimeType, qualityArgument)復制代碼
可以把畫布轉換成base64格式信息圖像信息,純字符的圖片表示法。
其中:
mimeType表示canvas導出來的base64圖片的類型,默認是png格式,也即是默認值是'image/png',我們也可以指定為jpg格式'image/jpeg'或者webp等格式。file對象中的file.type就是文件的mimeType類型,在轉換時候正好可以直接拿來用(如果有file對象)。
qualityArgument表示導出的圖片質量,只要導出為jpg和webp格式的時候此參數才有效果,默認值是0.92,是一個比較合理的圖片質量輸出參數,通常情況下,我們無需再設定。
更多關于toDataURL()方法的信息可以參見“Canvas API中文文檔-toDataURL()”。
2. canvas.toBlob()方法
語法如下:canvas.toBlob(callback, mimeType, qualityArgument)復制代碼
可以把畫布轉換成Blob文件,通常用在文件上傳中,因為是二進制的,對后端更加友好。
和toDataURL()方法相比,toBlob()方法是異步的,因此多了個callback參數,這個callback回調方法默認的第一個參數就是轉換好的blob文件信息,本文一開始的demo案例中的文件上傳就是將canvas圖片轉換成二進制的blob文件,然后再ajax上傳的,代碼如下:
// canvas轉為blob并上傳 canvas.toBlob(function (blob) { // 圖片ajax上傳 var xhr = new XMLHttpRequest(); // 開始上傳 xhr.open("POST", 'upload.php', true); xhr.send(blob); });復制代碼
更多關于toBlob()方法的信息可以參見“Canvas API中文文檔-toBlob()”。
一旦有了可傳輸的圖像數據,上傳下載就好實現了。例如下載前端壓縮好的圖片,可以參考我上一篇在掘金發布的文章:“純JS生成并下載各種文本文件或圖片”。
四、總結
經過“圖片→canvas壓縮→圖片”三步曲,我們完成了圖片前端壓縮功能。
作者:張鑫旭
鏈接:https://juejin.im/post/5bec3c6cf265da614312a0fa
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。