前端图片压缩.md

80 阅读2分钟

场景:

web上传一组照片,供移动端展示(反过来也是)。图片太大时,对图片展示很不友好。比如web端上传一组3×3MB的照片,在小程序端展示时就要展示9MB大小的图像。流量消耗大,切网速慢的时候白屏时间会比较长,影响用户体验。所以最好对图片进行压缩处理。

解决方案:

参考链接

  1. 上传图片时前端先进行图片压缩,压缩后传给Server或上传CDN,移动端直接拿到图片不处理就可以展示。
  2. 上传图片时前端不处理直接传给Server,由Server处理,移动端展示。
  3. 上传图片时前端和Server都不处理,移动端展示的时候先对图片预处理再展示。

大部分情况推荐第一种。优点:上传节省时间、节省服务器存储空间、减少网络负担

前端图片鸭嗦

使用插件:js-image-compressor,一个js库,可以在客户端(浏览器)压缩图片,可以在上传时减少带宽,节约空间,提高首屏加载预览体验。

一、实现原理(略,后续补充)

二、安装:

npm/pnpm install js-image-compressor 

三、应用:

创建一个 compressImg.ts文件。

import ImageCompressor from 'js-image-compressor'

/**
 * 图片压缩
 * @notes 这里使用的api函数可以在MDN文档查到具体使用方式。
 * @description
 *  1.该函数用于图片压缩。接收一个File对象和一个最大大小(默认400KB)。
 *  2.如果文件大小小于等于目标大小,则不压缩,直接转换为Base64。
 *  3.若超过maxSize,则使用ImageCompressor库压缩图片至指定质量、最大宽度和高度,然后将结果转换为Base64。
 *  4.返回一个包含base64字符串和File对象的Promise。
 * @param file 待压缩的图片文件
 * @param maxSize 文件大小,最大值默认400kb
 * @returns
 */
export const compressImg = async (file: File, maxSize = 400): Promise<{ baseStr: string; file: File }> => {
  const convertToBase64 = (blob: Blob): Promise<string | ArrayBuffer | null> =>
    new Promise((resolve, reject) => {
      // 读取blob/file对象
      const reader = new FileReader()
      reader.readAsDataURL(blob)
      reader.onloadend = () => resolve(reader.result)
      reader.onerror = (error) => reject(error)
    })
  // 字节数
  const targetSize = maxSize * 1024
  if (file.size <= targetSize) {
    const base64Data = await convertToBase64(file)
    const baseStr = typeof base64Data === 'string' ? base64Data : ''
    return { baseStr, file: file }
  }
  return new Promise<{ baseStr: string; file: File }>((resolve, reject) => {
    new ImageCompressor({
      file,
      quality: 0.4,
      maxWidth: 4640,
      maxHeight: 4640,
      success(result: File) {
        // 这里的result是已经压缩过后的文件,可以打印对比一下与源文件的大小差异
        // console.log(result)
        convertToBase64(result)
          .then((base64Data) => {
            const baseStr = typeof base64Data === 'string' ? base64Data : ''
            resolve({ baseStr, file: result })
          })
          .catch((error) => {
            reject(error)
          })
      },
      error(err: Error) {
        reject(err)
      }
    })
  })
}

在其他需要的地方引入(Vue3 + typescript项目)

    // 导入
    import { compressImg } from '@/libs/utils/compressImg'
    // code ...
    // code ...
    const uploadImage = async (file: File) => {
        let compressData: { baseStr: string; file: File } = await compressImg(file)
        // 上传逻辑
        // code ...
    }