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

JS前端圖片最優(yōu)化壓縮方案

 更新時間:2022年09月15日 16:32:22   作者:涼城a  
這篇文章主要為大家介紹了JS前端圖片最優(yōu)化壓縮方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

上傳圖片/視頻/文件是我們經常會遇到的問題,但是一旦圖片過大就會導致不好的操作體驗。 圖片上傳是前端中常見的的業(yè)務場景。無論是前臺還是后臺,適當的對圖片進行壓縮處理, 可以顯著的提升用戶體驗。

而在后臺管理系統(tǒng)中,圖片壓縮不僅僅能夠提升后臺管理員操作體驗,更是可以防止后臺設置過大的圖片導致前臺圖片加載過久,從而影響用戶體驗。

壓縮圖片思考

壓縮圖片基本流程

  • input 讀取到 文件 ,使用 FileReader 將其轉換為 base64 編碼
  • 新建 img ,使其 src 指向剛剛的 base64
  • 新建 canvas ,將 img 畫到 canvas 上
  • 利用 canvas.toDataURL/toBlob 將 canvas 導出為 base64 或 Blob
  • 將 base64 或 Blob 轉化為 File 將這些步驟逐個拆解,我們會發(fā)現似乎在canvas.toDataURL時涉及到圖片質量,那咱們就從這里下手。

準備

HTMLCanvasElement.toDataURL()

HTMLCanvasElement.toDataURL() 方法返回一個包含圖片展示的 data URI ??梢允褂?type 參數其類型,默認為 PNG 格式。圖片的分辨率為96dpi。

  • 如果畫布的高度或寬度是0,那么會返回字符串“data:,”。
  • 如果傳入的類型非“image/png”,但是返回的值以“data:image/png”開頭,那么該傳入的類型是不支持的。

語法

canvas.toDataURL(type, encoderOptions);

參數

  • type 可選 圖片格式,默認為 image/png
  • encoderOptions 可選 在指定圖片格式為 image/jpeg 或 image/webp的情況下,可以從 0 到 1 的區(qū)間內選擇圖片的質量。如果超出取值范圍,將會使用默認值 0.92。其他參數會被忽略。 Chrome支持“image/webp”類型。

猜想

可能toDataURL(type,quality)的第二個參數(quality)越小,文件體積越小

實踐

先看下原圖信息大小是7.31kb

toDataURL(type,quality)quality默認0.92看看壓縮結果如何

<input id="fileInput" type="file" />
<img id="img" src="" alt="">
let fileId = document.getElementById('fileInput')
let img = document.getElementById('img')
fileId.onchange = function (e) {
  let file = e.target.files[0]
  compressImg(file, 0.92).then(res => {//compressImg方法見附錄
    console.log(res)
    img.src = window.URL.createObjectURL(res.file);
  })
}

compressImg方法見附錄

可以看到圖片大小為8.83kb壓縮后圖片反而變大了,這是怎么回事?

看來起初的猜想不完全正確,咱們繼續(xù)看看。

fileId.onchange = function (e) {
  let file = e.target.files[0]
  compressImg(file, 0.1).then(res => {//compressImg方法見附錄
    console.log(res)
    img.src = window.URL.createObjectURL(res.file);
  })
}

quality為0.1的時候,圖片僅有1.63kb,同樣的質量也下降了

繼續(xù)......A long time later

咱們用折線圖來看吧更直觀

我又拿了幾個圖片讓他們使用默認值0.92,結果都比原圖大

所以說默認值得到的圖片往往比原圖大

下面看看當quality為多少時對圖片的壓縮效率可以最大化

壓縮效率最大化,即:在不影響圖片質量的情況下最大化壓縮 嘗試了一系列的圖片之后我發(fā)現 當quality在0.2~0.5之間,圖片質量變化并不大,quality的值越小,壓縮效率越可觀(也就是在0.2左右時,壓縮圖片可以最大化,同時并不對圖片質量造成太大影響)

結論

經過實踐,可以得出結論這個默認值得到的圖片往往比原圖的圖片質量要高。

quality在0.2~0.5之間,圖片質量變化并不大,quality的值越小,壓縮效率越可觀(也就是在0.2左右時,壓縮圖片可以最大化,同時并不對圖片質量造成太大影響)

附錄

/**
 * 壓縮方法 
 * @param {string} file 文件
 * @param {Number} quality  0~1之間
*/
function compressImg(file, quality) {
  if (file[0]) {
    return Promise.all(Array.from(file).map(e => compressImg(e,
      quality))) // 如果是 file 數組返回 Promise 數組
  } else {
    return new Promise((resolve) => {
      const reader = new FileReader() // 創(chuàng)建 FileReader
      reader.onload = ({
        target: {
          result: src
        }
      }) => {
        const image = new Image() // 創(chuàng)建 img 元素
        image.onload = async () => {
          const canvas = document.createElement('canvas') // 創(chuàng)建 canvas 元素
          canvas.width = image.width
          canvas.height = image.height
          canvas.getContext('2d').drawImage(image, 0, 0, image.width, image.height) // 繪制 canvas
          const canvasURL = canvas.toDataURL('image/jpeg', quality)
          const buffer = atob(canvasURL.split(',')[1])
          let length = buffer.length
          const bufferArray = new Uint8Array(new ArrayBuffer(length))
          while (length--) {
            bufferArray[length] = buffer.charCodeAt(length)
          }
          const miniFile = new File([bufferArray], file.name, {
            type: 'image/jpeg'
          })
          resolve({
            file: miniFile,
            origin: file,
            beforeSrc: src,
            afterSrc: canvasURL,
            beforeKB: Number((file.size / 1024).toFixed(2)),
            afterKB: Number((miniFile.size / 1024).toFixed(2))
          })
        }
        image.src = src
      }
      reader.readAsDataURL(file)
    })
  }
}

優(yōu)化升級

使用過程中發(fā)現邊界問題,即圖片尺寸過大、 IOS 尺寸限制,png 透明圖變黑等問題

所以優(yōu)化了大尺寸圖片等比例縮小,這極大的提高了壓縮效率

舉個栗子,以一張大小14M,尺寸6016X4016的圖片為例

一個14M的原圖(6016X4016)不改變質量只改變尺寸的前提下壓縮后(1400X935)就剩139.62KB

可想而知,尺寸的限制能最大化提高壓縮效率

  /**
   * 壓縮圖片方法
   * @param {file} file 文件
   * @param {Number} quality 圖片質量(取值0-1之間默認0.92)
   */
  compressImg(file, quality) {
    var qualitys = 0.52
    console.log(parseInt((file.size / 1024).toFixed(2)))
    if (parseInt((file.size / 1024).toFixed(2)) < 1024) {
      qualitys = 0.85
    }
    if (5 * 1024 < parseInt((file.size / 1024).toFixed(2))) {
      qualitys = 0.92
    }
    if (quality) {
      qualitys = quality
    }
    if (file[0]) {
      return Promise.all(Array.from(file).map(e => this.compressImg(e,
        qualitys))) // 如果是 file 數組返回 Promise 數組
    } else {
      return new Promise((resolve) => {
        console.log(file)
        if ((file.size / 1024).toFixed(2) < 300) {
          resolve({
            file: file
          })
        } else {
          const reader = new FileReader() // 創(chuàng)建 FileReader
          reader.onload = ({
            target: {
              result: src
            }
          }) => {
            const image = new Image() // 創(chuàng)建 img 元素
            image.onload = async() => {
              const canvas = document.createElement('canvas') // 創(chuàng)建 canvas 元素
              const context = canvas.getContext('2d')
              var targetWidth = image.width
              var targetHeight = image.height
              var originWidth = image.width
              var originHeight = image.height
              if (1 * 1024 <= parseInt((file.size / 1024).toFixed(2)) && parseInt((file.size / 1024).toFixed(2)) <= 10 * 1024) {
                var maxWidth = 1600
                var maxHeight = 1600
                targetWidth = originWidth
                targetHeight = originHeight
                // 圖片尺寸超過的限制
                if (originWidth > maxWidth || originHeight > maxHeight) {
                  if (originWidth / originHeight > maxWidth / maxHeight) {
                    // 更寬,按照寬度限定尺寸
                    targetWidth = maxWidth
                    targetHeight = Math.round(maxWidth * (originHeight / originWidth))
                  } else {
                    targetHeight = maxHeight
                    targetWidth = Math.round(maxHeight * (originWidth / originHeight))
                  }
                }
              }
              if (10 * 1024 <= parseInt((file.size / 1024).toFixed(2)) && parseInt((file.size / 1024).toFixed(2)) <= 20 * 1024) {
                maxWidth = 1400
                maxHeight = 1400
                targetWidth = originWidth
                targetHeight = originHeight
                // 圖片尺寸超過的限制
                if (originWidth > maxWidth || originHeight > maxHeight) {
                  if (originWidth / originHeight > maxWidth / maxHeight) {
                    // 更寬,按照寬度限定尺寸
                    targetWidth = maxWidth
                    targetHeight = Math.round(maxWidth * (originHeight / originWidth))
                  } else {
                    targetHeight = maxHeight
                    targetWidth = Math.round(maxHeight * (originWidth / originHeight))
                  }
                }
              }
              canvas.width = targetWidth
              canvas.height = targetHeight
              context.clearRect(0, 0, targetWidth, targetHeight)
              context.drawImage(image, 0, 0, targetWidth, targetHeight) // 繪制 canvas
              const canvasURL = canvas.toDataURL('image/jpeg', qualitys)
              const buffer = atob(canvasURL.split(',')[1])
              let length = buffer.length
              const bufferArray = new Uint8Array(new ArrayBuffer(length))
              while (length--) {
                bufferArray[length] = buffer.charCodeAt(length)
              }
              const miniFile = new File([bufferArray], file.name, {
                type: 'image/jpeg'
              })
              console.log({
                file: miniFile,
                origin: file,
                beforeSrc: src,
                afterSrc: canvasURL,
                beforeKB: Number((file.size / 1024).toFixed(2)),
                afterKB: Number((miniFile.size / 1024).toFixed(2)),
                qualitys: qualitys
              })
              resolve({
                file: miniFile,
                origin: file,
                beforeSrc: src,
                afterSrc: canvasURL,
                beforeKB: Number((file.size / 1024).toFixed(2)),
                afterKB: Number((miniFile.size / 1024).toFixed(2))
              })
            }
            image.src = src
          }
          reader.readAsDataURL(file)
        }
      })
    }
  },

優(yōu)化升級 TS新寫法

最近很多小伙伴在問我有沒有TS版本的,今天剛好弄了下這一塊,稍微調整了下,相較于之前更加簡潔,性能也快了不少;

如果需要對尺寸壓縮,請自行添加尺寸處理方法,也很簡單,自行添加吧,方法寫的很簡潔明了了,就不多加贅述了,大家自取吧。

const fileToDataURL = (file: Blob): Promise<any> => {
  return new Promise((resolve) => {
    const reader = new FileReader()
    reader.onloadend = (e) => resolve((e.target as FileReader).result)
    reader.readAsDataURL(file)
  })
}
const dataURLToImage = (dataURL: string): Promise<HTMLImageElement> => {
  return new Promise((resolve) => {
    const img = new Image()
    img.onload = () => resolve(img)
    img.src = dataURL
  })
}
const canvastoFile = (canvas: HTMLCanvasElement, type: string, quality: number): Promise<Blob | null> => {
  return new Promise((resolve) => canvas.toBlob((blob) => resolve(blob), type, quality))
}
/**
 * 圖片壓縮方法
 * @param {Object}  file 圖片文件
 * @param {String} type 想壓縮成的文件類型
 * @param {Nubmber} quality 壓縮質量參數
 * @returns 壓縮后的新圖片
 */
export const compressionFile = async(file, type = 'image/jpeg', quality = 0.5) => {
  const fileName = file.name
  const canvas = document.createElement('canvas')
  const context = canvas.getContext('2d') as CanvasRenderingContext2D
  const base64 = await fileToDataURL(file)
  const img = await dataURLToImage(base64)
  canvas.width = img.width
  canvas.height = img.height
  context.clearRect(0, 0, img.width, img.height)
  context.drawImage(img, 0, 0, img.width, img.height)
  const blob = (await canvastoFile(canvas, type, quality)) as Blob // quality:0.5可根據實際情況計算
  const newFile = await new File([blob], fileName, {
    type: type
  })
  return newFile
}

以上就是JS前端圖片最優(yōu)化壓縮方案的詳細內容,更多關于JS前端圖片壓縮的資料請關注腳本之家其它相關文章!

相關文章

  • 前端深入理解Typescript泛型概念

    前端深入理解Typescript泛型概念

    這篇文章主要介紹了前端深入理解Typescript泛型概念,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • JavaScript去掉數組中的重復元素

    JavaScript去掉數組中的重復元素

    在寫程序過程中,經常會遇到去除數組中重復元素的需求。要實現這個功能其實并不難
    2011-01-01
  • 關于ECharts圖表顯示顏色修改方式

    關于ECharts圖表顯示顏色修改方式

    這篇文章主要介紹了關于ECharts圖表顯示顏色修改方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • D3.js 實現帶伸縮時間軸拓撲圖的示例代碼

    D3.js 實現帶伸縮時間軸拓撲圖的示例代碼

    這篇文章主要介紹了D3.js 實現帶伸縮時間軸拓撲圖的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • js實現純前端壓縮圖片

    js實現純前端壓縮圖片

    這篇文章主要為大家詳細介紹了js實現純前端壓縮圖片,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • JavaScript中使用正則匹配多條,且獲取每條中的分組數據

    JavaScript中使用正則匹配多條,且獲取每條中的分組數據

    該問題在使用Ajax遠程獲取某網頁數據時經常遇見 如果目標頁面是XML,就好辦了,實用XMLDOM可以很輕松完成任務。
    2010-11-11
  • JavaScript具有類似Lambda表達式編程能力的代碼(改進版)

    JavaScript具有類似Lambda表達式編程能力的代碼(改進版)

    在之前的一篇博文中我介紹了一種方法可以讓JavaScript具有一種近似于Lambda表達式的編程能力——但是它有一些缺點,其中妨礙它的使用的最主要的一條就是多了一層括號,讓代碼變得難以閱讀。
    2010-09-09
  • javascript中call,apply,bind函數用法示例

    javascript中call,apply,bind函數用法示例

    這篇文章主要介紹了javascript中call,apply,bind函數用法,結合實例形式分析了call,apply,bind函數的功能、使用方法與相關注意事項,需要的朋友可以參考下
    2016-12-12
  • JavaScript尾遞歸的實現及應用場景

    JavaScript尾遞歸的實現及應用場景

    本文主要介紹了JavaScript尾遞歸的實現及應用場景,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-05-05
  • PHP abstract與interface之間的區(qū)別

    PHP abstract與interface之間的區(qū)別

    本文是對PHP中abstract與interface之間的區(qū)別進行了詳細的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-11-11

最新評論