欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端JS壓縮圖片的原理詳解(附源碼)

 更新時(shí)間:2024年06月12日 10:25:45   作者:JacksonChen_  
上傳圖片/視頻/文件是我們經(jīng)常會遇到的問題,但是一旦圖片過大就會導(dǎo)致不好的操作體驗(yàn),下面這篇文章主要給大家介紹了關(guān)于前端JS壓縮圖片原理及實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下

前言

相信大家都做過圖片上傳相關(guān)的功能,在圖片上傳的過程中,不知道大家有沒有考慮過文件體積的問題,如果我們直接將原圖片上傳,可以圖片體積比較大,一是上傳速度較慢,二是前端進(jìn)行渲染時(shí)速度也比較慢,比較影響客戶的體驗(yàn)感。所以在不影響清晰度的情況下,前端可以在上傳前對圖片的大小體積進(jìn)行壓縮,壓縮到一個(gè)比較合適的大小進(jìn)行上傳,本文就帶大家一起來看看前端 JS 如何實(shí)現(xiàn)圖片壓縮,有需要的小伙伴抓緊收藏一下吧!

原理(必看)

省流:主要使用 canvas的 drawImage 方法先繪制為 canvas 圖像,再結(jié)合 toDataURL 轉(zhuǎn)化為DataURl 進(jìn)行存儲圖片鏈接。

drawImage簡單介紹

Canvas 2D API 中的 CanvasRenderingContext2D.drawImage() 方法提供了多種在畫布Canvas)上繪制圖像的方式。

用法如下:

CanvasRenderingContext2D.drawImage() - Web API 接口參考 | MDN (mozilla.org)

語法如下:

drawImage(image, dx, dy);
drawImage(image, dx, dy, dWidth, dHeight);
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

 我們使用第二種進(jìn)行繪制,參數(shù)含義如下:

  • image:繪制到上下文的元素。
  • dximage 的左上角在目標(biāo)畫布上 X 軸坐標(biāo)。
  • dy:image 的左上角在目標(biāo)畫布上 Y 軸坐標(biāo)。
  • dWidth:image 在目標(biāo)畫布上繪制的寬度。允許對繪制的 image 進(jìn)行縮放。如果不說明,在繪制時(shí) image 寬度不會縮放。
  • dHeight:image 在目標(biāo)畫布上繪制的高度。允許對繪制的 image 進(jìn)行縮放。如果不說明,在繪制時(shí) image 高度不會縮放。

簡單示例

注意:如果隨意的修改圖像的尺寸,會導(dǎo)致圖像失真,我們可以先獲取到圖像資源的原始尺寸,然后進(jìn)行等比縮放,意思就是當(dāng)我們確定設(shè)置寬度之后,高度要進(jìn)行等比調(diào)整。公式就是交叉相乘積相等。

        // 如果寬度設(shè)置為 500, 那么高度也應(yīng)該進(jìn)行等比縮放
        // naturalWidth         =>  500
        // naturalHeight        =>  X
        // naturalWidth * X     =   naturalHeight * 500

       //  計(jì)算得出高度
        X =   naturalHeight * 500 / naturalWidth

  var can = document.querySelector('canvas')
  var context = can.getContext('2d')   
  var imgDom = new Image();
    imgDom.src = './img.jpg';
    imgDom.onload = function () {
        // 注意:圖像繪制時(shí),必須保證資源已經(jīng)加載完成
        console.log('圖片的原始寬度', imgDom.naturalWidth);
        console.log('圖片的原始高度', imgDom.naturalHeight);

        context.drawImage(
            imgDom,
            0, 0,
            500, imgDom.naturalHeight * 500 / imgDom.naturalWidth
        );
    }

toDataURL簡單介紹

我們將圖片繪制到 canvas 之后,還需要將 canvas 轉(zhuǎn)化為 Data URl,轉(zhuǎn)化為 DataURl 之后可以顯示到我們的屏幕上面,也可以存放到后端服務(wù)器,使用 canvas 所提供的 toDataURL 實(shí)例方法即可。

? 官方解釋:HTMLCanvasElement.toDataURL() 方法返回一個(gè)包含圖片展示的 data URI ?

HTMLCanvasElement.toDataURL() - Web API 接口參考 | MDN (mozilla.org)

語法:canvas.toDataURL(type, encoderOptions);

type(可選):圖片格式,默認(rèn)為 image/png

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

簡單示例 

       // 獲取壓縮后的圖片數(shù)據(jù)
      can.width = imgDom.naturalWidth
      can.height = imgDom.naturalHeight

      const compressedData = can.toDataURL('image/jpeg', 0.6) // 可調(diào)整質(zhì)量參數(shù)
      console.log('compressedData: ', compressedData)

轉(zhuǎn)化后 DataURL 結(jié)果如下 

實(shí)現(xiàn)

先奉上全部代碼,方便大家看,下面進(jìn)行解釋!

<!DOCTYPE html>
<html>
<head>
    <title>圖片壓縮上傳</title>
    <meta charset="UTF-8">
</head>
<body>
    <input type="file" id="fileInput" accept="image/*">
    <button onclick="compressAndUpload()">壓縮并上傳圖片</button>
    <canvas id="canvas" style="display: none;"></canvas>
    <script>
        function compressAndUpload() {
            const fileInput = document.getElementById('fileInput');
            const file = fileInput.files[0];
            if (!file) {
                alert('請先選擇要上傳的圖片');
                return;
            }
            const reader = new FileReader();
            reader.onload = function () {
                const img = new Image();
                img.src = reader.result;
                img.onload = function () {
                    const canvas = document.getElementById('canvas');
                    const ctx = canvas.getContext('2d');
                    const maxWidth = 800; // 設(shè)置最大寬度為800像素
                    let width = img.width;
                    let height = img.height;

                    // 判斷是否需要縮放
                    if (width > maxWidth) {
                        height *= maxWidth / width;
                        width = maxWidth;
                    }
                    // 設(shè)置 canvas 的寬高
                    canvas.width = width;
                    canvas.height = height;

                    // 將圖片繪制到 canvas 上
                    ctx.drawImage(img, 0, 0, width, height);
                    // 獲取壓縮后的圖片數(shù)據(jù)
                    const compressedData = canvas.toDataURL('image/jpeg', 0.7); // 可調(diào)整質(zhì)量參數(shù)

                    // 創(chuàng)建一個(gè)新的壓縮后的 File 對象
                    const compressedFile = dataURItoBlob(compressedData, file.type);
                    compressedFile.lastModifiedDate = file.lastModifiedDate;
                    compressedFile.name = file.name;

                    // 上傳壓縮后的圖片文件
                    uploadImage(compressedFile);
                };
            };
            reader.readAsDataURL(file);
        }

        function dataURItoBlob(dataURI, mimeType) {
            const binary = atob(dataURI.split(',')[1]);
            const array = [];
            for (let i = 0; i < binary.length; i++) {
                array.push(binary.charCodeAt(i));
            }
            return new Blob([new Uint8Array(array)], { type: mimeType });
        }

        function uploadImage(compressedFile) {
            const formData = new FormData();
            formData.append('image', compressedFile);

            fetch('/upload', {
                method: 'POST',
                body: formData
            })
            .then(response => {
                if (response.ok) {
                    console.log('圖片上傳成功');
                } else {
                    console.error('圖片上傳失敗');
                }
            })
            .catch(error => {
                console.error('發(fā)生錯誤:', error);
            });
        }
    </script>
</body>
</html>

我們看一下壓縮前后體積對比,壓縮前550290,壓縮后31523,縮小了十幾倍,這個(gè)壓縮還是很明顯的。

 首先我們看這三行代碼

我們先初始化一個(gè) reader 是一個(gè) FileReader 對象的實(shí)例 

reader.readAsDataURL(file),這行代碼的作用是將選擇的文件讀取為 Data URI 格式的字符串。

當(dāng)執(zhí)行 reader.readAsDataURL(file) 時(shí),會發(fā)生以下幾件事情:

FileReader 對象開始異步讀取 file 中的數(shù)據(jù)。

一旦讀取完成,FileReader 的 onload 事件將被觸發(fā)。

讀取的結(jié)果將存儲在 FileReader 對象的 result 屬性中,格式為 Data URI 字符串。

看一下 FileReader 對象的 result  的打印結(jié)果,為 Data URL格式

最終我們將讀取出來的 Data URI 字符串賦值給 Image 的 src,也就是下面這行代碼,然后等待 img 加載完畢開始對 img 進(jìn)行壓縮,具體怎么壓縮上面已經(jīng)簡單演示過。

          const img = new Image()
          img.src = reader.result
          img.onload = function () {}

接下來我們設(shè)置了一個(gè)最大寬度為800,然后判斷當(dāng)前圖片寬度是否大于該值,如果大于進(jìn)行縮放計(jì)算,小于就不進(jìn)行等比縮放計(jì)算。最后將計(jì)算出的值使用 drawImage 繪制到 canvas 上面。

                    const maxWidth = 800; // 設(shè)置最大寬度為800像素
                    let width = img.width;
                    let height = img.height;

                    // 判斷是否需要縮放
                    if (width > maxWidth) {
                        height *= maxWidth / width;
                        width = maxWidth;
                    }

                    // 設(shè)置 canvas 的寬高
                    canvas.width = width;
                    canvas.height = height;

                    // 將圖片繪制到 canvas 上
                    ctx.drawImage(img, 0, 0, width, height);

現(xiàn)在我們將 canvas 轉(zhuǎn)化成Data URI 字符串,canvas.toDataURL('image/jpeg', 0.7),這行代碼的作用是將 canvas 上繪制的圖像數(shù)據(jù)導(dǎo)出為 JPEG 格式的 Data URI 字符串,并設(shè)置圖像質(zhì)量為 0.7。

// 獲取壓縮后的圖片數(shù)據(jù)
const compressedData = canvas.toDataURL('image/jpeg', 0.7); // 可調(diào)整

我們看一下 compressedData,是一個(gè)Data URI 字符串,其實(shí)到這里就可以了,我們可以將 Data URI 傳到后端進(jìn)行存儲起來,也可以轉(zhuǎn)化為文件格式進(jìn)行存儲,我這里選擇使用文件格式進(jìn)行存儲,不需要的可以不使用下面的方式。

接下來就是創(chuàng)建一個(gè)新的壓縮后的 File 對象

      const compressedFile = dataURItoBlob(compressedData, file.type)
      compressedFile.lastModifiedDate = file.lastModifiedDate
      compressedFile.name = file.name

      function dataURItoBlob(dataURI, mimeType) {
        const binary = atob(dataURI.split(',')[1])
        const array = []
        for (let i = 0; i < binary.length; i++) {
          array.push(binary.charCodeAt(i))
        }
        return new Blob([new Uint8Array(array)], { type: mimeType })
      }

新的文件對象

最后直接使用 FormData 進(jìn)行上傳即可,這一塊就不說了。

總結(jié)

前端實(shí)現(xiàn)圖片壓縮主要是利用的 canvas 來實(shí)現(xiàn),實(shí)現(xiàn)思路為使用 canvas 的 drawImage 方法先繪制為 canvas 圖像,再結(jié)合 toDataURL 轉(zhuǎn)化為 DataURl 進(jìn)行存儲圖片鏈接以及壓縮圖像質(zhì)量。在toDataURL 中可以調(diào)整圖像質(zhì)量,需要注意的是我們在壓縮圖像時(shí)要注意等寬高縮放,否則會導(dǎo)致圖像出現(xiàn)失真的情況。

到此這篇關(guān)于前端JS壓縮圖片的文章就介紹到這了,更多相關(guān)前端JS壓縮圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用 JavaScript 在沒有插件的情況下輸入文本掩碼的示例詳解

    使用 JavaScript 在沒有插件的情況下輸入文本掩碼的示例詳解

    這篇文章主要介紹了使用 JavaScript 在沒有插件的情況下輸入文本掩碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • Bootstrap網(wǎng)頁布局網(wǎng)格的實(shí)現(xiàn)

    Bootstrap網(wǎng)頁布局網(wǎng)格的實(shí)現(xiàn)

    柵格就是網(wǎng)格,本文詳細(xì)的介紹了Bootstrap網(wǎng)頁布局網(wǎng)格的原理和實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • 在webstorm中配置less的方法詳解

    在webstorm中配置less的方法詳解

    這篇文章主要介紹了在webstorm中配置less的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2020-09-09
  • 微信小程序排坑指南詳解

    微信小程序排坑指南詳解

    這篇文章主要為大家詳細(xì)介紹了微信小程序排坑指南,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • JavaScript cookie原理及使用實(shí)例

    JavaScript cookie原理及使用實(shí)例

    這篇文章主要介紹了JavaScript cookie原理及使用實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • JS實(shí)現(xiàn)Tab欄切換的兩種方式案例詳解

    JS實(shí)現(xiàn)Tab欄切換的兩種方式案例詳解

    這篇文章主要介紹了JS實(shí)現(xiàn)Tab欄切換的兩種方式,一種是面向過程的寫法,一種是面向?qū)ο蟮膶懛ǎ疚慕o大家分享詳細(xì)案例代碼,需要的朋友可以參考下
    2022-08-08
  • 怎樣在CocosCreator中使用游戲手柄

    怎樣在CocosCreator中使用游戲手柄

    這篇文章主要介紹了怎樣使用CocosCreator的游戲手柄,每一個(gè)步驟都挺詳細(xì),資源可以隨便找一些,希望同學(xué)們看完,一定要試一下
    2021-04-04
  • js 數(shù)組實(shí)現(xiàn)一個(gè)類似ruby的迭代器

    js 數(shù)組實(shí)現(xiàn)一個(gè)類似ruby的迭代器

    今天突然發(fā)現(xiàn)js的數(shù)組處理起來真是麻煩,代碼一些就是一大堆,相比起ruby的迭代器來真是遜色不少。
    2009-10-10
  • js的map、flatMap和find、filter的使用詳解

    js的map、flatMap和find、filter的使用詳解

    map和flatMap都是返回一個(gè)新數(shù)組,map不會改變數(shù)組長度,flatMap可以改變長度,find和filter都是過濾操作,find只會返回第一個(gè)找到的值,而filter會返回全部符合要求的對象
    2024-12-12
  • js實(shí)現(xiàn)獲取鼠標(biāo)當(dāng)前的位置

    js實(shí)現(xiàn)獲取鼠標(biāo)當(dāng)前的位置

    本文主要介紹了利用javascript實(shí)現(xiàn)獲取鼠標(biāo)當(dāng)前的位置的具體方法,具有很好的參考作用,需要的朋友可以看看
    2016-12-12

最新評論