前端 JS 压缩图片的思绪(附源码)

打印 上一主题 下一主题

主题 686|帖子 686|积分 2058

前言

信赖大家都做过图片上传相干的功能,在图片上传的过程中,不知道大家有没有考虑过文件体积的问题,如果我们直接将原图片上传,可以图片体积比较大,一是上传速率较慢,二是前端举行渲染时速率也比较慢,比较影响客户的体验感。所以在不影响清晰度的情况下,前端可以在上传前对图片的巨细体积举行压缩,压缩到一个比较符合的巨细举行上传,本文就带大家一起来看看前端 JS 如何实现图片压缩,有需要的小伙伴抓紧收藏一下吧!
原理(必看)

省流:主要利用 canvas的 drawImage 方法先绘制为 canvas 图像,再结合 toDataURL 转化为DataURl 举行存储图片链接。
drawImage简单先容

   Canvas 2D API 中的 CanvasRenderingContext2D.drawImage() 方法提供了多种在画布Canvas)上绘制图像的方式。
  用法如下:
   CanvasRenderingContext2D.drawImage() - Web API 接口参考 | MDN (mozilla.org)
  语法如下:
  1. drawImage(image, dx, dy);
  2. drawImage(image, dx, dy, dWidth, dHeight);
  3. drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
复制代码
 我们利用第二种举行绘制,参数寄义如下:
image:绘制到上下文的元素。
dx:image 的左上角在目标画布上 X 轴坐标。
dy:image 的左上角在目标画布上 Y 轴坐标。
dWidth:image 在目标画布上绘制的宽度。答应对绘制的 image 举行缩放。如果不说明,在绘制时 image 宽度不会缩放。
dHeight:image 在目标画布上绘制的高度。答应对绘制的 image 举行缩放。如果不说明,在绘制时 image 高度不会缩放。
简单示例

注意:如果随意的修改图像的尺寸,会导致图像失真,我们可以先获取到图像资源的原始尺寸,然后举行等比缩放,意思就是当我们确定设置宽度之后,高度要举行等比调解。公式就是交叉相乘积相称。
           // 如果宽度设置为 500, 那么高度也应该举行等比缩放
        // naturalWidth         =>  500
        // naturalHeight        =>  X
        // naturalWidth * X     =   naturalHeight * 500
         //  计算得出高度
        X =   naturalHeight * 500 / naturalWidth
  1.   var can = document.querySelector('canvas')
  2.   var context = can.getContext('2d')   
  3.   var imgDom = new Image();
  4.     imgDom.src = './img.jpg';
  5.     imgDom.onload = function () {
  6.         // 注意:图像绘制时,必须保证资源已经加载完成
  7.         console.log('图片的原始宽度', imgDom.naturalWidth);
  8.         console.log('图片的原始高度', imgDom.naturalHeight);
  9.         context.drawImage(
  10.             imgDom,
  11.             0, 0,
  12.             500, imgDom.naturalHeight * 500 / imgDom.naturalWidth
  13.         );
  14.     }
复制代码
toDataURL简单先容

我们将图片绘制到 canvas 之后,还需要将 canvas 转化为 Data URl,转化为 DataURl 之后可以表现到我们的屏幕上面,也可以存放到后端服务器,利用 canvas 所提供的 toDataURL 实例方法即可。
​ 官方解释:HTMLCanvasElement.toDataURL() 方法返回一个包含图片展示的 data URI ​
   HTMLCanvasElement.toDataURL() - Web API 接口参考 | MDN (mozilla.org)
  语法:canvas.toDataURL(type, encoderOptions);
type(可选):图片格式,默以为 image/png
encoderOptions(可选):在指定图片格式为 image/jpeg 或 image/webp 的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会利用默认值 0.92。其他参数会被忽略。
简单示例 

  1.        // 获取压缩后的图片数据
  2.       can.width = imgDom.naturalWidth
  3.       can.height = imgDom.naturalHeight
  4.       const compressedData = can.toDataURL('image/jpeg', 0.6) // 可调整质量参数
  5.       console.log('compressedData: ', compressedData)
复制代码
转化后 DataURL 结果如下 

实现

先奉上全部代码,方便大家看,下面举行解释!
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <title>图片压缩上传</title>
  5.     <meta charset="UTF-8">
  6. </head>
  7. <body>
  8.     <input type="file" id="fileInput" accept="image/*">
  9.     <button onclick="compressAndUpload()">压缩并上传图片</button>
  10.     <canvas id="canvas" style="display: none;"></canvas>
  11.     <script>
  12.         function compressAndUpload() {
  13.             const fileInput = document.getElementById('fileInput');
  14.             const file = fileInput.files[0];
  15.             if (!file) {
  16.                 alert('请先选择要上传的图片');
  17.                 return;
  18.             }
  19.             const reader = new FileReader();
  20.             reader.onload = function () {
  21.                 const img = new Image();
  22.                 img.src = reader.result;
  23.                 img.onload = function () {
  24.                     const canvas = document.getElementById('canvas');
  25.                     const ctx = canvas.getContext('2d');
  26.                     const maxWidth = 800; // 设置最大宽度为800像素
  27.                     let width = img.width;
  28.                     let height = img.height;
  29.                     // 判断是否需要缩放
  30.                     if (width > maxWidth) {
  31.                         height *= maxWidth / width;
  32.                         width = maxWidth;
  33.                     }
  34.                     // 设置 canvas 的宽高
  35.                     canvas.width = width;
  36.                     canvas.height = height;
  37.                     // 将图片绘制到 canvas 上
  38.                     ctx.drawImage(img, 0, 0, width, height);
  39.                     // 获取压缩后的图片数据
  40.                     const compressedData = canvas.toDataURL('image/jpeg', 0.7); // 可调整质量参数
  41.                     // 创建一个新的压缩后的 File 对象
  42.                     const compressedFile = dataURItoBlob(compressedData, file.type);
  43.                     compressedFile.lastModifiedDate = file.lastModifiedDate;
  44.                     compressedFile.name = file.name;
  45.                     // 上传压缩后的图片文件
  46.                     uploadImage(compressedFile);
  47.                 };
  48.             };
  49.             reader.readAsDataURL(file);
  50.         }
  51.         function dataURItoBlob(dataURI, mimeType) {
  52.             const binary = atob(dataURI.split(',')[1]);
  53.             const array = [];
  54.             for (let i = 0; i < binary.length; i++) {
  55.                 array.push(binary.charCodeAt(i));
  56.             }
  57.             return new Blob([new Uint8Array(array)], { type: mimeType });
  58.         }
  59.         function uploadImage(compressedFile) {
  60.             const formData = new FormData();
  61.             formData.append('image', compressedFile);
  62.             fetch('/upload', {
  63.                 method: 'POST',
  64.                 body: formData
  65.             })
  66.             .then(response => {
  67.                 if (response.ok) {
  68.                     console.log('图片上传成功');
  69.                 } else {
  70.                     console.error('图片上传失败');
  71.                 }
  72.             })
  73.             .catch(error => {
  74.                 console.error('发生错误:', error);
  75.             });
  76.         }
  77.     </script>
  78. </body>
  79. </html>
复制代码
我们看一下压缩前后体积对比,压缩前550290,压缩后31523,缩小了十几倍,这个压缩还是很明显的。

 起首我们看这三行代码

我们先初始化一个 reader 是一个 FileReader 对象的实例 
reader.readAsDataURL(file),这行代码的作用是将选择的文件读取为 Data URI 格式的字符串。
当执行 reader.readAsDataURL(file) 时,会发生以下几件事情:
   

  • FileReader 对象开始异步读取 file 中的数据。
  • 一旦读取完成,FileReader 的 onload 事件将被触发。
  • 读取的结果将存储在 FileReader 对象的 result 属性中,格式为 Data URI 字符串。
  看一下 FileReader 对象的 result  的打印结果,为 Data URL格式

最终我们将读取出来的 Data URI 字符串赋值给 Image 的 src,也就是下面这行代码,然后等候 img 加载完毕开始对 img 举行压缩,具体怎么压缩上面已经简单演示过。
  1.           const img = new Image()
  2.           img.src = reader.result
  3.           img.onload = function () {}
复制代码
接下来我们设置了一个最大宽度为800,然后判断当前图片宽度是否大于该值,如果大于举行缩放计算,小于就不举行等比缩放计算。末了将计算出的值利用 drawImage 绘制到 canvas 上面。
  1.                     const maxWidth = 800; // 设置最大宽度为800像素
  2.                     let width = img.width;
  3.                     let height = img.height;
  4.                     // 判断是否需要缩放
  5.                     if (width > maxWidth) {
  6.                         height *= maxWidth / width;
  7.                         width = maxWidth;
  8.                     }
  9.                     // 设置 canvas 的宽高
  10.                     canvas.width = width;
  11.                     canvas.height = height;
  12.                     // 将图片绘制到 canvas 上
  13.                     ctx.drawImage(img, 0, 0, width, height);
复制代码
现在我们将 canvas 转化成Data URI 字符串,canvas.toDataURL('image/jpeg', 0.7),这行代码的作用是将 canvas 上绘制的图像数据导出为 JPEG 格式的 Data URI 字符串,并设置图像质量为 0.7。
  1. // 获取压缩后的图片数据
  2. const compressedData = canvas.toDataURL('image/jpeg', 0.7); // 可调整
复制代码
我们看一下 compressedData,是一个Data URI 字符串,着实到这里就可以了,我们可以将 Data URI 传到后端举行存储起来,也可以转化为文件格式举行存储,我这里选择利用文件格式举行存储,不需要的可以不利用下面的方式。

接下来就是创建一个新的压缩后的 File 对象
  1.       const compressedFile = dataURItoBlob(compressedData, file.type)
  2.       compressedFile.lastModifiedDate = file.lastModifiedDate
  3.       compressedFile.name = file.name
  4.       function dataURItoBlob(dataURI, mimeType) {
  5.         const binary = atob(dataURI.split(',')[1])
  6.         const array = []
  7.         for (let i = 0; i < binary.length; i++) {
  8.           array.push(binary.charCodeAt(i))
  9.         }
  10.         return new Blob([new Uint8Array(array)], { type: mimeType })
  11.       }
复制代码
新的文件对象

末了直接利用 FormData 举行上传即可,这一块就不说了。
总结

前端实现图片压缩主要是利用的 canvas 来实现,实现思绪为利用 canvas 的 drawImage 方法先绘制为 canvas 图像,再结合 toDataURL 转化为 DataURl 举行存储图片链接以及压缩图像质量。在toDataURL 中可以调解图像质量,需要注意的是我们在压缩图像时要注意等宽高缩放,否则会导致图像出现失真的情况。



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

去皮卡多

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表