最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript實(shí)現(xiàn)壓縮圖片至指定大小

 更新時間:2025年05月04日 10:14:31   作者:視覺CG  
這篇文章主要為大家詳細(xì)介紹了如何使用JavaScript實(shí)現(xiàn)壓縮圖片至指定大小,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

完整代碼

yaSuoImg.js

/**
 * 加載圖片
 * @param {URL} url 圖片地址
 * @returns {Promise.<Image>}
 */
const loadImageAsync = (url) => {
    return new Promise((resolve, reject) => {
        const image = new Image();
        image.src = url;
        image.onload = function () {
            resolve(image);
        };

        image.onerror = function (err) {
            reject(new Error("出錯 " + err));
        };
    });
}

/**
 * 圖片壓縮
 * @param {File} file 拾取的圖片文件File
 * @param {Number} [maxSizeKB=300] 超過maxSizeKB啟動壓縮(KB)
 * @param {String} [imgType="webp"] 壓縮后的圖片格式,推薦webp,既無損壓縮
 * @param {Number} [opy=.9] 清晰度 0-1 推薦0.9,既不失真,又可壓縮圖片內(nèi)存
 * @return {Promise.<Base64URLString>}
 */
export const compress = async (file, maxSizeKB = 300, imgType = 'webp', opy = .9) => {
    const canvas            = document.createElement("canvas"),
          context           = canvas.getContext("2d"),
          image             = await loadImageAsync(URL.createObjectURL(file)),
          { height, width } = image;

    if (file.size > maxSizeKB * 1024) {
        let   rate       = 0;                 // 壓縮率 
        const fileSizeKB = file.size / 1024;  // 文件大小KB, file.size給的是字節(jié)Byte
        
        if (fileSizeKB > maxSizeKB) { // 當(dāng)圖片大小超標(biāo),才進(jìn)行壓縮
            rate = (fileSizeKB - maxSizeKB) / fileSizeKB; // 計算壓縮率
        }

        // 糾正因子,不加會導(dǎo)致壓縮出的文件太小
        const factor        = 0,
              cvWidth       = width * (1 - rate + factor),
              cvHeight      = height * (1 - rate + factor);
              canvas.height = cvHeight;
              canvas.width  = cvWidth;

        context.clearRect(0, 0, cvWidth, cvHeight);
        context.drawImage(image, 0, 0, cvWidth, cvHeight);
    } else {
        canvas.height = height;
        canvas.width  = width;
        opy           = .7
        context.clearRect(0, 0, width, height);
        context.drawImage(image, 0, 0, width, height);
    }
    URL.revokeObjectURL(file)//釋放內(nèi)存
    return canvas.toDataURL(`image/${imgType}`, opy);
} 

具體使用

import { compress } from "/yaSuoImg.js";
const  imgBlobSrc = await compress(file);

方法補(bǔ)充

1.JS將base64圖片壓縮至指定大小

在開發(fā)中,通常在上傳圖片時,由于各種限制,需要將上傳的圖片壓縮到某一大小范圍內(nèi)才能上傳。在此提供以下方法實(shí)現(xiàn)該需求,復(fù)制可用。

壓縮圖片原理

通過原生的input標(biāo)簽?zāi)玫揭蟼鞯膱D片文件

將圖片文件file對象轉(zhuǎn)化成圖片base64

根據(jù)圖片base64創(chuàng)建img圖片對象

在canvas上繪制該HTMLImageElement

通過不斷降低圖片質(zhì)量指數(shù)來達(dá)到壓縮圖片大小的目的

封裝

將以上代碼封裝為一個js文件,這里命名為compressImg.js,放置在utils文件夾下

/**
 * 壓縮圖片到指定大小
 * @param baseImg base64圖片
 * @param maxSize 單位kb
 */
export function compressImgBySize (baseImg, maxSize = 200) {
  return new Promise((resolve) => {
  	// 計算圖片大小
    const strLength = baseImg.length
    const fileLength = parseInt(strLength - (strLength / 8) * 2)
    let size = parseInt((fileLength / 1024).toFixed(2))

	// 判斷圖片是否符合指定大小要求
    if (size <= maxSize) {
      resolve(baseImg)
      return
    }

	// 創(chuàng)建image對象
    const img = new Image()
    if (baseImg.indexOf('data:image/') !== -1) {
      img.src = baseImg
   	} else {
      img.src = 'data:image/jpeg;base64,' + baseImg
	}
	
    img.onload = () => {
      // 把image對象 轉(zhuǎn)換為 canvas對象
      const canvas = imgToCanvas(img)
      let resUrl = ''
      // 圖片質(zhì)量,范圍:0 ~ 1
      let quality = 0.9
      
      // 當(dāng)圖片大小大于指定maxSize,圖片質(zhì)量大于0時繼續(xù)通過降低圖片資料來壓縮
      while (size > maxSize && quality > 0) {
      	// 在canvas上繪制該HTMLImageElement,得到圖片base64
        resUrl = canvas.toDataURL('image/jpeg', quality).replace(/^data:image\/\w+;base64,/, '')
        const resLength = resUrl.length
        // 計算繪制出的base64圖片大小
        const resFileLength = parseInt(resLength - (resLength / 8) * 2)
        size = parseInt((resFileLength / 1024).toFixed(2))
        // 降低圖片質(zhì)量
        quality = (quality - 0.1).toFixed(1)
      }
      resolve(resUrl)
    }
    img.onerror = () => {
      resolve(baseImg)
    }
  })
}

// 把image 轉(zhuǎn)換為 canvas對象
export function imgToCanvas (image) {
  var canvas = document.createElement('canvas')
  canvas.width = image.width
  canvas.height = image.height
  canvas.getContext('2d').drawImage(image, 0, 0)
  return canvas
}

在需要使用圖片壓縮的.vue文件中引入并使用,如下

// 注意引入路徑是否正確
import { compressImgBySize } from '@/utils/compressImg'

// this.applyFile[0].content 為指定的base64格式照片
// 1200 指將圖片壓縮到1200kb大小以下
compressImgBySize('file文件對象', 1200).then(baseImg => {
	// 輸出圖片base64
	console.log(baseImg)
})

2.js壓縮圖片到指定大小

代碼如下:

import React from 'react';
import PropTypes from 'prop-types';
import styles from './upload.less';
 
import compress from './compress';
 
class Upload extends React.Component {
  constructor(props) {
    super(props);
    this.fileInput = React.createRef();
    this.state = {
      fileObjs: [], // item { originFile, compressBase64, compressFile }
    };
  }
 
  getFileUrl(file) {
    let url;
    const agent = navigator.userAgent;
    if (agent.indexOf('MSIE') >= 1) {
      url = file.value;
    } else if (agent.indexOf('Firefox') > 0 || agent.indexOf('Chrome') > 0) {
      url = window.URL.createObjectURL(file);
    }
    return url;
  }
 
  compressCallBack(file, fileObj, result) {
    const { fileObjs } = this.state;
    file.compressing = false; // 壓縮完成
    fileObj.compressBase64 = result.compressBase64;
    fileObj.compressFile = result.compressFile;
    this.setState({ fileObjs: [...fileObjs] });
    if (fileObjs.length && fileObjs.every(fileObjItem => fileObjItem.compressBase64)) {
      console.log('全部壓縮完成', fileObjs);
    }
  }
 
  onInputChange(e) {
    const { fileObjs } = this.state;
    Object.keys(e.target.files).forEach((key) => {
      const file = e.target.files[key];
 
      // 驗(yàn)證圖片格式
      const type = file.name.split('.')[1];
      if (type !== 'png' && type !== 'jpg' && type !== 'jpeg') {
        console.warn('請上傳png,jpg,jpeg格式的圖片!');
        e.target.value = '';
        return;
      }
 
      file.url = this.getFileUrl(file);
      file.compressing = true; // 壓縮狀態(tài),開始壓縮
 
      const fileObj = { originFile: file, compressBase64: null, compressFile: null };
      fileObjs.push(fileObj);
 
      // 壓縮圖片的方法, maxSize單位為kb
      compress(file, 200).then((res) => {
        this.compressCallBack(file, fileObj, res);
      }, (err) => {
        // 壓縮失敗,則返回原圖片的信息
        this.compressCallBack(file, fileObj, err);
      });
    });
 
    this.setState({ fileObjs: [...fileObjs] });
    e.target.value = '';
  }
 
  render() {
    const { fileObjs } = this.state;
    return (
      <div
        className={styles.uploadContainer}
      >
        <div className={styles.gridItem}>
          <div
            className={styles.inputContainer}
            onClick={() => {
              this.fileInput.current.click();
            }}
          >
            <span className={styles.uploadIcon}>+</span>
            <input
              className={styles.fileInput}
              ref={this.fileInput}
              type="file"
              name="file"
              multiple="multiple"
              accept="image/*"
              onChange={e => this.onInputChange(e)}
            />
          </div>
        </div>
        {
          fileObjs.map(fileObj => (
            <div className={styles.gridItem}>
              <img
                src={fileObj.compressBase64 ? fileObj.compressBase64 : fileObj.originFile.url}
                className={fileObj.originFile.compressing && styles.filter}
              />
              {
                fileObj.originFile.compressing ?
                  <div className={styles.progressContainer}>
                    <div className={styles.progress}>
                      <div className={styles.progressHighlight} />
                    </div>
                  </div> : ''
              }
            </div>
          ))
        }
      </div>);
  }
}
 
Upload.propTypes = {
  dispatch: PropTypes.func.isRequired,
};
 
export default Upload;

圖片壓縮主要代碼compress.js

 
// 將File(Blob)對象轉(zhuǎn)變?yōu)橐粋€dataURL字符串, 即base64格式
const fileToDataURL = file => new Promise((resolve) => {
  const reader = new FileReader();
  reader.onloadend = e => resolve(e.target.result);
  reader.readAsDataURL(file);
});
 
// 將dataURL字符串轉(zhuǎn)變?yōu)閕mage對象,即base64轉(zhuǎn)img對象
const dataURLToImage = dataURL => new Promise((resolve) => {
  const img = new Image();
  img.onload = () => resolve(img);
  img.src = dataURL;
});
 
// 將一個canvas對象轉(zhuǎn)變?yōu)橐粋€File(Blob)對象
const canvastoFile = (canvas, type, quality) => new Promise(resolve => canvas.toBlob(blob => resolve(blob), type, quality));
 
const compress = (originfile, maxSize) => new Promise(async (resolve, reject) => {
  const originSize = originfile.size / 1024; // 單位為kb
  console.log('圖片指定最大尺寸為', maxSize, '原始尺寸為:', originSize);
 
  // 將原圖片轉(zhuǎn)換成base64
  const base64 = await fileToDataURL(originfile);
 
  // 縮放圖片需要的canvas
  const canvas = document.createElement('canvas');
  const context = canvas.getContext('2d');
 
  // 小于maxSize,則不需要壓縮,直接返回
  if (originSize < maxSize) {
    resolve({ compressBase64: base64, compressFile: originfile });
    console.log(`圖片小于指定大小:${maxSize}KB,不用壓縮`);
    return;
  }
 
 
  const img = await dataURLToImage(base64);
 
  const scale = 1;
  const originWidth = img.width;
  const originHeight = img.height;
  const targetWidth = originWidth * scale;
  const targetHeight = originHeight * scale;
 
  canvas.width = targetWidth;
  canvas.height = targetHeight;
  context.clearRect(0, 0, targetWidth, targetHeight);
  context.drawImage(img, 0, 0, targetWidth, targetHeight);
 
  // 將Canvas對象轉(zhuǎn)變?yōu)閐ataURL字符串,即壓縮后圖片的base64格式
  // const compressedBase64 = canvas.toDataURL('image/jpeg', 0.1);
  // 經(jīng)過我的對比,通過scale控制圖片的拉伸來壓縮圖片,能夠壓縮jpg,png等格式的圖片
  // 通過canvastoFile方法傳遞quality來壓縮圖片,只能壓縮jpeg類型的圖片,png等格式不支持
  // scale的壓縮效果沒有canvastoFile好
  // 在壓縮到指定大小時,通過scale壓縮的圖片比通過quality壓縮的圖片模糊的多
  // 壓縮的思路,用二分法找最佳的壓縮點(diǎn)
  // 這里為了規(guī)避浮點(diǎn)數(shù)計算的弊端,將quality轉(zhuǎn)為整數(shù)再計算;
  // const preQuality = 100;
  const maxQualitySize = { quality: 100, size: Number.MAX_SAFE_INTEGER };
  const minQualitySize = { quality: 0, size: 0 };
  let quality = 100;
  let count = 0; // 壓縮次數(shù)
  let compressFinish = false; // 壓縮完成
  let invalidDesc = '';
  let compressBlob = null;
 
  // 二分法最多嘗試8次即可覆蓋全部可能
  while (!compressFinish && count < 12) {
    compressBlob = await canvastoFile(canvas, 'image/jpeg', quality / 100);
    const compressSize = compressBlob.size / 1024;
    count++;
    if (compressSize === maxSize) {
      console.log(`壓縮完成,總共壓縮了${count}次`);
      compressFinish = true;
      return;
    }
    if (compressSize > maxSize) {
      maxQualitySize.quality = quality;
      maxQualitySize.size = compressSize;
    }
    if (compressSize < maxSize) {
      minQualitySize.quality = quality;
      minQualitySize.size = compressSize;
    }
    console.log(`第${count}次壓縮,壓縮后大小${compressSize},quality參數(shù):${quality}`);
 
    quality = Math.ceil((maxQualitySize.quality + minQualitySize.quality) / 2);
 
    if (maxQualitySize.quality - minQualitySize.quality < 2) {
      if (!minQualitySize.size && quality) {
        quality = minQualitySize.quality;
      } else if (!minQualitySize.size && !quality) {
        compressFinish = true;
        invalidDesc = '壓縮失敗,無法壓縮到指定大小';
        console.log(`壓縮完成,總共壓縮了${count}次`);
      } else if (minQualitySize.size > maxSize) {
        compressFinish = true;
        invalidDesc = '壓縮失敗,無法壓縮到指定大小';
        console.log(`壓縮完成,總共壓縮了${count}次`);
      } else {
        console.log(`壓縮完成,總共壓縮了${count}次`);
        compressFinish = true;
        quality = minQualitySize.quality;
      }
    }
  }
 
  if (invalidDesc) {
    // 壓縮失敗,則返回原始圖片的信息
    console.log(`壓縮失敗,無法壓縮到指定大?。?{maxSize}KB`);
    reject({ msg: invalidDesc, compressBase64: base64, compressFile: originfile });
    return;
  }
 
  compressBlob = await canvastoFile(canvas, 'image/jpeg', quality / 100);
  const compressSize = compressBlob.size / 1024;
  console.log(`最后一次壓縮(即第${count + 1}次),quality為:${quality},大小:${compressSize}`);
  const compressedBase64 = await fileToDataURL(compressBlob);
 
  const compressedFile = new File([compressBlob], originfile.name, { type: 'image/jpeg' });
 
  resolve({ compressFile: compressedFile, compressBase64: compressedBase64 });
});
 
 
export default compress;

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

相關(guān)文章

  • js實(shí)現(xiàn)3D圖片展示效果

    js實(shí)現(xiàn)3D圖片展示效果

    本文主要介紹了js實(shí)現(xiàn)3D圖片展示效果的實(shí)例,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • Javascript新手入門之字符串拼接與變量的應(yīng)用

    Javascript新手入門之字符串拼接與變量的應(yīng)用

    這篇文章主要給大家介紹了關(guān)于Javascript新手入門之字符串拼接與變量應(yīng)用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • typescript中的extends和infer使用及詳解

    typescript中的extends和infer使用及詳解

    文章解釋了TypeScript中的約束、逆變、協(xié)變、交叉類型、可選鏈等概念,通過實(shí)例展示了infer、extends、as等關(guān)鍵字的使用方法,并列舉了加法、減法、乘法、除法、數(shù)組長度判斷等示例,最后總結(jié)了TypeScript的使用經(jīng)驗(yàn)
    2026-04-04
  • javascript實(shí)現(xiàn)五星評價代碼(源碼下載)

    javascript實(shí)現(xiàn)五星評價代碼(源碼下載)

    大家在淘寶購物之后,都會對賣家的服務(wù)進(jìn)行評論,那么五星評價代碼是怎么實(shí)現(xiàn)的呢?下面小編給大家介紹基于Javascript實(shí)現(xiàn)五星評價代碼,有需要的朋友可以參考下
    2015-08-08
  • javascript中直接寫php代碼的方法

    javascript中直接寫php代碼的方法

    這篇文章介紹了javascript中直接寫php代碼的方法,有需要的朋友可以參考一下
    2013-07-07
  • 你可能不知道的CORS跨域資源共享

    你可能不知道的CORS跨域資源共享

    這篇文章主要給大家介紹了關(guān)于CORS跨域資源共享的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用CORS具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • js案例之鼠標(biāo)跟隨jquery版(實(shí)例講解)

    js案例之鼠標(biāo)跟隨jquery版(實(shí)例講解)

    下面小編就為大家?guī)硪黄猨s案例之鼠標(biāo)跟隨jquery版(實(shí)例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • javascript實(shí)現(xiàn)表單隔行變色

    javascript實(shí)現(xiàn)表單隔行變色

    這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)表單隔行變色,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • 微信小程序中this.data與this.setData的區(qū)別詳解

    微信小程序中this.data與this.setData的區(qū)別詳解

    這篇文章主要給大家介紹了關(guān)于微信小程序中this.data與this.setData區(qū)別的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧
    2018-09-09
  • 詳解wepy開發(fā)小程序踩過的坑(小結(jié))

    詳解wepy開發(fā)小程序踩過的坑(小結(jié))

    這篇文章主要介紹了詳解wepy開發(fā)小程序踩過的坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05

最新評論

姚安县| 江源县| 河曲县| 沅陵县| 遂宁市| 高唐县| 永登县| 高碑店市| 鹤岗市| 穆棱市| 滨海县| 忻城县| 宝坻区| 巩留县| 正蓝旗| 分宜县| 电白县| 台州市| 怀集县| 新晃| 分宜县| 马山县| 浦县| 丰宁| 昌图县| 石柱| 河北区| 肇州县| 永春县| 当阳市| 昌邑市| 安陆市| 咸丰县| 长沙县| 广宗县| 农安县| 钦州市| 修水县| 平阳县| 沾益县| 聂荣县|