canvas壓縮圖片的祕密

開篇

首先明確canvas只適合壓縮大的圖片,圖片size太小並不能有什麼用處。那麼爲何size太小canvas並不能壓縮呢canvas

  • 若是不壓縮質量,通過canvas的圖片變大了
  • 圖片在通過img標籤的時候方向改變了
  • 何時使用canvas壓縮

咱們來看看canvas toDataURL toBlob 方法

// 不壓縮,原畫質
canvas.toBlob(callback, "image/jpeg", {quality: 1});
canvas.toDataURL( "image/jpeg", {quality: 1});
複製代碼

圖片在通過canvas後變大了,口怕。咱們對比了兩組不一樣的數據,咱們發現原始圖片越大,變大的比例越小,若是一張圖片越小通過canvas的圖片變大的比例也就越大。那麼爲何會這樣呢bash

5.3M
5284528<6228026

229kb
229214<242046

60kb
60022<229214
複製代碼

圖片越小說明自己被壓縮的越厲害,其中存在的空白像素點越多,進過drawImage繪製的時候,drawImage纔不會去管空白像素,canvas自己繪製的是矢量圖因此沒有像素的概念,那麼通過canvas後空白像素也成了真實像素,因此就解釋了爲何會出現上面的狀況ui

選擇0.7的壓縮質量是比較正常的,可是小圖片仍是並不理想。對於手機拍攝的照片仍是能夠的。因此有很大的侷限性。this

那麼爲何不能將質量定義的更小呢?那麼就回答開篇的問題。spa

假設一張圖片中有1w個空白像素,到了canvas中就成真實像素了,canvas說咱們要壓縮點1w個像素,那麼 如今真實空白像素確實2w個,大小和原來同樣,像素比原來低。code

好了咱們繼續壓縮,咱們壓縮3w個空白如今,如今真實空白像素是4w個,大小也小了。想要拿到幾十kb的大小像素怎麼樣本身想一想。在canvas中基本都得拿到幾百kb的大小質量才能看。圖片

對於手機拍攝的圖片在通過img的時候方向改變了怎麼辦?

手機拍攝的四、5MB的圖片在img標籤中從豎屏變成了橫屏咱們該怎麼處理?get

在canvas壓縮中咱們確定要藉助img標籤去渲染圖片,那麼通過了img的時候方向改變了,咱們就須要在canvas中去rotate畫布,而後再開始繪製string

咱們怎麼知道圖片是否被旋轉了。咱們能夠藉助exif-js去獲取Orientation的值,而後再去旋轉畫布it

何時才使用壓縮呢?

顯然若是能壓縮對帶寬,存儲空間和請求速度都有好處,那麼根據上面的規律,咱們能夠講處理後的file和原始file作對比,選擇一個小的上傳

送上個人壓縮代碼

寫的很差,各位大佬能夠指點指點,讓個人代碼有所成長

// 圖像壓縮

import EXIF from 'exif-js'

// 獲取圖片信息
function getImageInfo(img, callback) {
  let Orientation = 1

  EXIF.getData(img, function () {
    Orientation = EXIF.getTag(this, 'Orientation');

    callback(Orientation)
  });
}

// 旋轉畫布
function rotate(ctx,Orientation){
  switch(Orientation){
    case 3:
      //旋轉180度
      ctx.rotate(Math.PI)
      break;
    case 6:
      //旋轉90度
      ctx.rotate(Math.PI/2)
      break;
    case 8:
      //旋轉270度
      ctx.rotate(Math.PI*1.5)
      break;
  }
}

// canvas 繪製圖片
function drawImage(img, quality, Orientation, callback) {
  const { width, height } = img
  //生成canvas
  var canvas = document.createElement("canvas");
  var ctx = canvas.getContext("2d");
  
  if(Orientation==3||Orientation==6){
    canvas.width = height
    canvas.height = width
  } else{
    canvas.width = width
    canvas.height = height  
  }
  if(Orientation!=1){
    ctx.translate(canvas.width/2,canvas.width/2);
    rotate(ctx, Orientation)
    ctx.translate(-canvas.width/2,-canvas.width/2);
  }
  

  ctx.drawImage(img, 0, 0);
  // 圖像質量
  if (!(quality && quality <= 1 && quality > 0)) {
    quality = 0.7
  }
  // quality值越小,所繪製出的圖像越模糊
  canvas.toBlob(callback, "image/jpeg", quality);
}

// 圖片渲染
function canvasDataURL(file, quality = 0.7, callback) {
  var img = new Image();
  img.src = window.URL.createObjectURL(file);

  img.onload = function () {
    getImageInfo(img, Orientation => {
      drawImage(img, quality, Orientation, callback)
    })
  };
}


function compressionImg(file, callback) {
  let newFile = null
  canvasDataURL(file, 0.7, blob => {
    // 處理後的file
    newFile = new File([blob], file.name, { type: blob.type })
    if (!newFile || newFile.size > file.size) {
      newFile = file
    }
    callback(newFile)
  });
}

export default compressionImg;
複製代碼
相關文章
相關標籤/搜索