1. 程式人生 > 其它 >利用canvas中toDataURL()將圖片轉為dataURL(base64)的方法詳解

利用canvas中toDataURL()將圖片轉為dataURL(base64)的方法詳解

將圖片轉為base64的好處

將圖片轉換為Base64編碼,可以讓你很方便地在沒有上傳檔案的條件下將圖片插入其它的網頁、編輯器中。 這對於一些小的圖片是極為方便的,因為你不需要再去尋找一個儲存圖片的地方。

將圖片轉換成base64編碼的,在web網上一般用於小圖片上,不僅可以減少圖片的請求數量(集合到js、css程式碼中),還可以防止因為一些相對路徑等問題導致圖片404錯誤。

引言

假設一個應用場景:由於某些特殊原因從服務端請求到圖片路徑,要求通過該路徑獲取對應圖片的 base64 dataURL。在這個場景中,我們首先推斷該圖片路徑是可訪問的,同時還需要一種將圖片轉換到 dataURL 的方法。

我們如何實現它呢?

dataURL

先大致回顧下正統的 dataURL 的語法,這有助於我們檢驗轉換後的內容是否正確。一個完整的 dataURI 應該是這樣的:

data:[<mediatype>][;base64],<data>

其中mediatype聲明瞭檔案型別,遵循MIME規則,如“image/png”、“text/plain”;之後是編碼型別,這裡我們只涉及 base64;緊接著就是檔案編碼後的內容了。我們常常在 HTML 裡看到img標籤的src會這樣寫:

src="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7"

這個img引用的就是以 base64 編碼的 dataURL 了,只要瀏覽器支援,就可以被解碼成 gif 圖片並渲染出來。

.toDataURL()

FileReader物件也有類似的方法,比如.readAsDataURL() ,然而它只接受file或blob型別,而這兩種型別一般只能通過<input[type=file]>元素的files屬性獲取,或者用Blob()建構函式手工建立一個新的物件。尷尬的是我們當前只有圖片路徑,受制於瀏覽器的安全策略, <input[type=file]>的files屬性是隻讀的,而Blob()建構函式只接受檔案內容,兩種方式都無法通過圖片路徑直接獲取。上文中假設的應用場景迫使我們必先考慮如何通過路徑獲取到圖片內容。<img>是可以的,並且可以被繪製到<canvas>中,而<canvas>正巧擁有.toDataURL()

方法。

萬事具備,我們只需要把<img>獲取到的圖片放到<canvas>裡再通過.toDataURL()方法轉化下,就可以得到以 base64 編碼的 dataURL。來看這個方法的語法:

canvas.toDataURL([type, encoderOptions]);

canvas是DOM元素<canvas>物件;引數type指定圖片型別,如果指定的型別不被支援則以預設值image/png替代;encoderOptions可以為image/jpeg或image/webp型別的圖片設定圖片質量,取值0-1,超出則以預設值0.92替代。

需要注意的是:在轉換成 dataURL 前必須先確保圖片成功載入到,於是.toDataURL()方法應該寫在<img>的onload非同步事件中。現在就來實現一個功能函式:

 function getBase64(url){
  //通過建構函式來建立的 img 例項,在賦予 src 值後就會立刻下載圖片,相比 createElement() 建立 <img> 省去了 append(),也就避免了文件冗餘和汙染
  var Img = new Image(),
   dataURL='';
  Img.src=url;
  Img.onload=function(){ //要先確保圖片完整獲取到,這是個非同步事件
   var canvas = document.createElement("canvas"), //建立canvas元素
    width=Img.width, //確保canvas的尺寸和圖片一樣
    height=Img.height;
   canvas.width=width;
   canvas.height=height;
   canvas.getContext("2d").drawImage(Img,0,0,width,height); //將圖片繪製到canvas中
   dataURL=canvas.toDataURL('image/jpeg'); //轉換圖片為dataURL
  };
 }

一個可供隨時呼叫的轉換函式完成了,它會在圖片被載入後返回一整個 dataURL 字串。

完善

onload事件確保了轉換任務在載入後執行,卻又帶來了新問題——dataURL 只有在圖片載入完成後才會返回,我們無法確定圖片什麼時候完成載入。如果後續要對 dataURL 做相關處理(比如傳遞到其他伺服器)的話,新增一個回撥是必要的,這能確保後續處理任務在成功得到 dataURL 之後執行,我們需要修改getBase64() 

 function getBase64(url,callback){ //新增一個回撥引數
  ...
  Img.onload=function(){
   ...
   canvas.getContext("2d").drawImage(Img,0,0,width,height);
   dataURL=canvas.toDataURL('image/jpeg');
   callback?callback(dataURL):null; //呼叫回撥函式
  };
 }

在執行時添加回調:

 getBase64('//upload.jianshu.io/users/upload_avatars/555630/fdd1b798e6b0.jpg',(dataURL)=>{
  console.log(dataURL);
 });

就是這樣,如果不考慮相容性的話,或許我們可以用 promise 和 generator 來實現,再新增一些錯誤處理就更完美了。

 

原文連結:https://www.jb51.net/article/128554.htm