溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript中怎么實(shí)現(xiàn)圖片壓縮功能

發(fā)布時(shí)間:2021-08-09 15:08:41 來(lái)源:億速云 閱讀:181 作者:Leah 欄目:web開發(fā)

JavaScript中怎么實(shí)現(xiàn)圖片壓縮功能,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

壓縮思路

涉及到 JS 的圖片壓縮,我的想法是需要用到 Canvas 的繪圖能力,通過(guò)調(diào)整圖片的分辨率或者繪圖質(zhì)量來(lái)達(dá)到圖片壓縮的效果,實(shí)現(xiàn)思路如下:

  •  獲取上傳 Input 中的圖片對(duì)象 File

  •  將圖片轉(zhuǎn)換成 base64 格式

  •  base64 編碼的圖片通過(guò) Canvas 轉(zhuǎn)換壓縮,這里會(huì)用到的 Canvas 的 drawImage 以及 toDataURL 這兩個(gè) Api,一個(gè)調(diào)節(jié)圖片的分辨率的,一個(gè)是調(diào)節(jié)圖片壓縮質(zhì)量并且輸出的,后續(xù)會(huì)有詳細(xì)介紹

  •  轉(zhuǎn)換后的圖片生成對(duì)應(yīng)的新圖片,然后輸出

優(yōu)缺點(diǎn)介紹

不過(guò) Canvas 壓縮的方式也有著自己的優(yōu)缺點(diǎn):

  •  優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,參數(shù)可以配置化,自定義圖片的尺寸,指定區(qū)域裁剪等等。

  •  缺點(diǎn):只有 jpeg 、webp 支持原圖尺寸下圖片質(zhì)量的調(diào)整來(lái)達(dá)到壓縮圖片的效果,其他圖片格式,僅能通過(guò)調(diào)節(jié)尺寸來(lái)實(shí)現(xiàn)

代碼實(shí)現(xiàn)

<template>    <div class="container">      <input type="file" id="input-img" @change="compress" />      <a :download="fileName" :href="compressImg" >普通下載</a>      <button @click="downloadImg">兼容 IE 下載</button>      <div>        <img :src="compressImg" />      </div>    </div>  </template>  <script>  export default {    name: 'compress',    data: function() {      return {        compressImg: null,        fileName: null,      };    },    components: {},    methods: {      compress() {        // 獲取文件對(duì)象        const fileObj = document.querySelector('#input-img').files[0];        // 獲取文件名稱,后續(xù)下載重命名        this.fileName = `${new Date().getTime()}-${fileObj.name}`;        // 獲取文件后綴名        const fileNames = fileObj.name.split('.');        const type = fileNames[fileNames.length-1];        // 壓縮圖片        this.handleCompressImage(fileObj, type);      },      handleCompressImage(img, type) {        const vm = this;        let reader = new FileReader();        // 讀取文件        reader.readAsDataURL(img);        reader.onload = function(e) {          let image = new Image(); //新建一個(gè)img標(biāo)簽          image.src = e.target.result;          image.onload = function() {            let canvas = document.createElement('canvas');            let context = canvas.getContext('2d');            // 定義 canvas 大小,也就是壓縮后下載的圖片大小            let imageimageWidth = image.width; //壓縮后圖片的大小            let imageimageHeight = image.height;            canvas.width = imageWidth;            canvas.height = imageHeight;             // 圖片不壓縮,全部加載展示            context.drawImage(image, 0, 0);            // 圖片按壓縮尺寸載入            // let imageWidth = 500; //壓縮后圖片的大小            // let imageHeight = 200;            // context.drawImage(image, 0, 0, 500, 200);            // 圖片去截取指定位置載入            // context.drawImage(image,100, 100, 100, 100, 0, 0, imageWidth, imageHeight);            vm.compressImg = canvas.toDataURL(`image/${type}`);          };        };      },      // base64 圖片轉(zhuǎn) blob 后下載      downloadImg() {        let parts = this.compressImg.split(';base64,');        let contentType = parts[0].split(':')[1];        let raw = window.atob(parts[1]);        let rawrawLength = raw.length;        let uInt8Array = new Uint8Array(rawLength);        for(let i = 0; i < rawLength; ++i) {          uInt8Array[i] = raw.charCodeAt(i);        }        const blob = new Blob([uInt8Array], {type: contentType});        this.compressImg = URL.createObjectURL(blob);        if (window.navigator.msSaveOrOpenBlob) {          // 兼容 ie 的下載方式          window.navigator.msSaveOrOpenBlob(blob, this.fileName);        }else{          const a = document.createElement('a');          a.href = this.compressImg;          a.setAttribute('download', this.fileName);          a.click();        }      },    }  };  </script>

上面的代碼是可以直接拿來(lái)看效果的,不喜歡用 Vue 的也可以把代碼稍微調(diào)整一下,下面開始具體分解一下代碼的實(shí)現(xiàn)思路

Input 上傳 File 處理

將 File 對(duì)象通過(guò) FileReader 的 readAsDataURL 方法轉(zhuǎn)換為URL格式的字符串(base64 編碼)

const fileObj = document.querySelector('#input-img').files[0];  let reader = new FileReader();  // 讀取文件  reader.readAsDataURL(fileObj);

Canvas 處理 File 對(duì)象

建立一個(gè) Image 對(duì)象,一個(gè) canvas 畫布,設(shè)定自己想要下載的圖片尺寸,調(diào)用 drawImage 方法在 canvas 中繪制上傳的圖片

let image = new Image(); //新建一個(gè)img標(biāo)簽  image.src = e.target.result;  let canvas = document.createElement('canvas');  let context = canvas.getContext('2d');  context.drawImage(image, 0, 0);

Api 解析:drawImage

context.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

img

就是圖片對(duì)象,可以是頁(yè)面上獲取的 DOM 對(duì)象,也可以是虛擬 DOM 中的圖片對(duì)象。

JavaScript中怎么實(shí)現(xiàn)圖片壓縮功能

dx、dy、dWidth、dHeight

表示在 canvas 畫布上規(guī)劃出一片區(qū)域用來(lái)放置圖片,dx, dy 為繪圖位置在 Canvas 元素的 X 軸、Y 軸坐標(biāo),dWidth, dHeight 指在 Canvas 元素上繪制圖像的寬度和高度(如果不說(shuō)明, 在繪制時(shí)圖片的寬度和高度不會(huì)縮放)。

sx、sy、swidth、sheight

這 4 個(gè)參數(shù)是用來(lái)裁剪源圖片的,表示圖片在 canvas 畫布上顯示的大小和位置。sx, sy 表示在源圖片上裁剪位置的 X 軸、Y 軸坐標(biāo),然后以 swidth, sheight 尺寸來(lái)選擇一個(gè)區(qū)域范圍,裁剪出來(lái)的圖片作為最終在 Canvas 上顯示的圖片內(nèi)容( swidth, sheight 不說(shuō)明的情況下,整個(gè)矩形(裁剪)從坐標(biāo)的 sx 和 sy 開始,到圖片的右下角結(jié)束)。

以下為圖片繪制的實(shí)例:

context.drawImage(image, 0, 0, 100, 100);  context.drawImage(image, 300, 300, 200, 200);  context.drawImage(image, 0, 100, 150, 150, 300, 0, 150, 150);

JavaScript中怎么實(shí)現(xiàn)圖片壓縮功能

Api 中奇怪之處在于,sx、sy、swidth、sheight 為選填參數(shù),但位置在 dx、dy、dWidth、dHeight 之前。

Canvas 輸出圖片

調(diào)用 canvas 的 toDataURL 方法可以輸出 base64 格式的圖片。

canvas.toDataURL(`image/${type}`);

Api 解析:toDataURL

canvas.toDataURL(type, encoderOptions);

type 可選

圖片格式,默認(rèn)為 image/png。

encoderOptions 可選

在指定圖片格式為 image/jpeg 或 image/webp 的情況下,可以從 0 到 1 的區(qū)間內(nèi)選擇圖片的質(zhì)量。如果超出取值范圍,將會(huì)使用默認(rèn)值 0.92。其他參數(shù)會(huì)被忽略。

a 標(biāo)簽的下載

調(diào)用 <a> 標(biāo)簽的 download 屬性,即可完成圖片的下載。

Api 解析:download

// href 下載必填  <a download="filename" href="href"> 下載 </a>

filename

選填,規(guī)定作為文件名來(lái)使用的文本。

href

文件的下載地址。

非主流瀏覽器下載處理

到此可以解決 Chroma 、 Firefox 和 Safari(自測(cè)支持) 瀏覽器的下載功能,因?yàn)?IE 等瀏覽器不支持 download 屬性,所以需要進(jìn)行其他方式的下載,也就有了代碼中的后續(xù)內(nèi)容

// base64 圖片轉(zhuǎn) blob 后下載  downloadImg() {    let parts = this.compressImg.split(';base64,');    let contentType = parts[0].split(':')[1];    let raw = window.atob(parts[1]);    let rawrawLength = raw.length;    let uInt8Array = new Uint8Array(rawLength);    for(let i = 0; i < rawLength; ++i) {      uInt8Array[i] = raw.charCodeAt(i);    }    const blob = new Blob([uInt8Array], {type: contentType});    this.compressImg = URL.createObjectURL(blob);    if (window.navigator.msSaveOrOpenBlob) {      // 兼容 ie 的下載方式      window.navigator.msSaveOrOpenBlob(blob, this.fileName);    }else{      const a = document.createElement('a');      a.href = this.compressImg;      a.setAttribute('download', this.fileName);      a.click();    }  }
  •  將之前 canvas 生成的 base64 數(shù)據(jù)拆分后,通過(guò) atob 方法解碼

  •  將解碼后的數(shù)據(jù)轉(zhuǎn)換成 Uint8Array 格式的無(wú)符號(hào)整形數(shù)組

  •  轉(zhuǎn)換后的數(shù)組來(lái)生成一個(gè) Blob 數(shù)據(jù)對(duì)象,通過(guò) URL.createObjectURL(blob) 來(lái)生成一個(gè)臨時(shí)的 DOM 對(duì)象

  •  之后 IE 類瀏覽器可以調(diào)用 window.navigator.msSaveOrOpenBlob 方法來(lái)執(zhí)行下載,其他瀏覽器也可以繼續(xù)通過(guò) <a> 標(biāo)簽的 download 屬性來(lái)進(jìn)行下載

Api 解析:atob

base-64 解碼使用方法是 atob()。

window.atob(encodedStr)

encodedStr

必需,是一個(gè)通過(guò) btoa() 方法編碼的字符串,btoa() 是 base64 編碼的使用方法。

Api 解析:Uint8Array

new Uint8Array(length)

length

創(chuàng)建初始化為 0 的,包含 length 個(gè)元素的無(wú)符號(hào)整型數(shù)組。

Api 解析:Blob

Blob 對(duì)象表示一個(gè)不可變、原始數(shù)據(jù)的類文件對(duì)象。

// 構(gòu)造函數(shù)允許通過(guò)其它對(duì)象創(chuàng)建 Blob 對(duì)象  new Blob([obj],{type:createType})

obj

字符串內(nèi)容

createType

要構(gòu)造的類型

兼容性 IE 10 以上

Api 解析:createObjectURL

靜態(tài)方法會(huì)創(chuàng)建一個(gè) DOMString。

objectURL = URL.createObjectURL(object);

object

用于創(chuàng)建 URL 的 File 對(duì)象、Blob 對(duì)象或者 MediaSource 對(duì)象。

Api 解析:window.navigator

// 官方已不建議使用的文件下載方式,僅針對(duì) ie 且兼容性 10 以上  // msSaveBlob 僅提供下載  // msSaveOrOpenBlob 支持下載和打開  window.navigator.msSaveOrOpenBlob(blob, fileName);

關(guān)于JavaScript中怎么實(shí)現(xiàn)圖片壓縮功能問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI