• 前端图片压缩解决办法


    问题产生背景

    在某一h5的项目,要求上传的图片格式为 base64 , 问题是用户上传的图片基本都在MB 级别,转base64 以后,图片的体积会增大30%以上,随着图片的体积增加,转换的base64 格式文件体积越大,如果此时前端不对用户上传的图片体积进行压缩,可能会导致服务器压力过大,从而崩溃;

    解决办法

    1、使用纯 js 解决

    解决思路:
    1、通过 input 文件选择框拿到要上传的图片文件file
    2、FileReader.readAsDataURL() 读取 file 内容。完成后 result 属性中将包含一个 data: URL格式的 Base64字符串以表示所读取文件的内容。
    3、创建一个 img 标签,将 FileReader 对象返回的 base64 格式 url 给到一个 img 标签
    4、img.onload() 函数中获取图片的尺寸,再通过 canvas.drawImage() 绘制图像,设置尺寸或者图像的质量等
    canvas.toDataURL(file.type, quality) 设置图像的质量,将 canvas 转换为图片 base64 格式
    代码如下所示:

    compressImg(file) {
        const reader = new FileReader();
            // readAsDataURL 方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成DONE,并触发 loadend (en-US) 事件,
            // 同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。
            reader.readAsDataURL(file);
            reader.onload = () => {
              const img = new Image();
              img.src = reader.result;
              img.onload = () => {
                // 图片的宽高
                const w = img.width;
                const h = img.height;
                const canvas = document.createElement("canvas");
                // canvas对图片进行裁剪,这里设置为图片的原始尺寸
                canvas.width = w;
                canvas.height = h;
                const ctx = canvas.getContext("2d");
                // canvas中,png转jpg会变黑底,所以先给canvas铺一张白底
                ctx.fillStyle = "#fff";
                // fillRect()方法绘制一个填充了内容的矩形,这个矩形的开始点(左上点)在
                // (x, y) ,它的宽度和高度分别由width 和 height 确定,填充样式由当前的fillStyle 决定。
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                // 绘制图像
                ctx.drawImage(img, 0, 0, w, h);
                // canvas转图片达到图片压缩效果
                // 返回一个包含图片展示的 data URI base64 在指定图片格式为 image/jpeg 或 image/webp的情况下,
                // 可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。
                const dataUrl = canvas.toDataURL("image/jpeg", 0.8);
                // base64格式文件转成Blob文件格式
                return blobFile = dataURLtoBlob(dataUrl);
                // 拿到这个blobFile文件就可以上传给服务端
                console.log("压缩后的file----------", blobFile);
              };
            };
    }
        // canvas生成的格式为base64,如果需要Blob格式可按如下进行转化
        dataURLtoBlob(dataurl) {
          const arr = dataurl.split(","),
            mime = arr[0].match(/:(.*?);/)[1],
            bstr = atob(arr[1]);
          let n = bstr.length;
          const u8arr = new Uint8Array(n);
          while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
          }
          return new Blob([u8arr], { type: mime });
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    使用以上方法存在缺点:

    • 压缩后的格式只能是 jpeg 格式,如果需要其他格式的可能需要优化或者用别的方法

    2、插件 js-image-compressor

    在使用中,我们可以根据自身需求自定义配置压缩比(quality)、输出图片类型(mimeType)、宽(width)、高(height)、最大宽(maxWidth)、最大高(maxHeight)、最小宽(minWidth)、最大高(minHeight)、png转jpeg阈值(convertSize)、是否矫正jpeg方向(redressOrientation)和是否宽松模式(loose)。
    ● 是否矫正jpeg方向(redressOrientation),jpeg 格式图片在某些iOS浏览器会按其方向呈现图像,这个选项可以控制恢复初始方向,默认为 true;
    ● 是否宽松模式(loose)、的意思是控制当压缩的图片 size 大于源图片,输出源图片,否则输出压缩后图片,默认是 true。
    以下是标准配置:

    var options = {
      file: file,
      quality: 0.6,
      mimeType: 'image/jpeg',
      maxWidth: 2000,
      maxHeight: 2000,
      width: 1000,
      height: 1000,
      minWidth: 500,
      minHeight: 500,
      convertSize: Infinity,
      loose: true,
      redressOrientation: true,
      // 压缩前回调
      beforeCompress: function (result) {
        console.log('压缩之前图片尺寸大小: ', result.size);
        console.log('mime 类型: ', result.type);
      },
      // 压缩成功回调
      success: function (result) {
        console.log('压缩之后图片尺寸大小: ', result.size);
        console.log('mime 类型: ', result.type);
        console.log('实际压缩率: ', ((file.size - result.size) / file.size * 100).toFixed(2) + '%');
      },
      // 发生错误
      error: function (msg) {
        console.error(msg);
      }
    };
    new ImageCompressor(options);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    以上就是插件式的解决办法,更详细的文档,可以在 gitbhub 的官方文档上查看;插件式解决办法已经在项目中实践,推荐大家使用~~

    写在最后

    以上提供的插件式解决办法已经在项目中实践,但是存在的问题是,插件控制的压缩率和实际的压缩率有一定的出入(不同格式的图片出入有一定差异),因此压缩率不好严格控制,有更好解决办法的朋友欢迎评论区交流;

    🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞

  • 相关阅读:
    pnpm新建vite+vue3项目
    C++编译报错:does not name a type
    增值税发票税控开票软件数据接口规范
    R语言使用原生包(基础导入包、graphics)中的boxplot函数可视化箱图(box plot)
    【如何获取数据库表的字段并拼接】
    【AI视野·今日NLP 自然语言处理论文速览 第八十二期】Tue, 5 Mar 2024
    Java枚举详解
    Tmux 简单使用
    阿里为了双十一,整理亿级JVM性能优化文档,竟被GitHub“抢开”
    JavaWeb[总结]
  • 原文地址:https://blog.csdn.net/qq_44588612/article/details/127985259