如何在浏览器中使用Javascript压缩图像?

175

概述:

是否有一种方法可以在上传之前直接通过浏览器压缩图像(多数为JPEG、PNG和GIF)?我相信JavaScript可以做到,但是我找不到实现的方法。


下面是我想要实现的完整场景:

  • 用户登录我的网站,并通过input type="file"元素选择图像,
  • 通过JavaScript获取此图像,并进行某些验证,例如正确的文件格式、最大文件大小等,
  • 如果一切正常,则在页面上显示图像预览,
  • 用户可以进行一些基本操作,例如按照预定义比例旋转图像90°/-90°、裁剪图像,或上传另一个图像并返回第1步,
  • 当用户满意时,编辑后的图像被压缩并"保存"在本地(不是保存到文件,而是在浏览器内存/页面中),
  • 用户填写包含姓名、年龄等数据的表单,
  • 用户点击“完成”按钮,然后将包含数据和压缩图像的表单发送到服务器(不使用AJAX),

直到最后一步,整个过程都应该在客户端完成,并且应该兼容最新版本的Chrome和Firefox、Safari 5+以及IE 8+。如果可能,只使用JavaScript(但我相信这是不可能的)。

我还没有编写任何代码,但我已经考虑过了。可以通过File API从本地读取文件,可以使用Canvas元素预览和编辑图像,但我找不到一种方法来对图像进行压缩

根据 html5please.comcaniuse.com 的说法,由于 IE 浏览器的存在支持这些浏览器相当困难,但可以使用诸如 FlashCanvasFileReader 等 polyfill 来实现。
其实,目标是减少文件大小,因此我认为图像压缩是一个解决方案。但是,我知道上传的图像将在我的网站上显示,并且每次在同一个位置上显示,并且我知道此显示区域的尺寸(例如 200x400)。因此,我可以调整图像大小以适应这些尺寸,从而减小文件大小。我不知道这种技术的压缩比率会是多少。
你怎么看?你有什么建议告诉我吗?你知道是否有任何 JavaScript 方式在浏览器端压缩图像吗?感谢您的回复。

1
这可能会有所帮助:https://www.sitelint.com/blog/how-to-compress-the-image-on-the-client-side-before-uploading/ - Cezary Tomczyk
@AhmedSuror 总有改进的空间。你认为文档的哪个部分可以改进? - undefined
@CezaryTomczyk 我按照他们网站上唯一的一步操作来使用它,但是没有成功!没有足够的文档来说明如何实施它! - undefined
@CezaryTomczyk 不,我在一个ASP.Net Core项目中使用它,并且按照文档中所述包含了脚本,但是无法进一步进行! - undefined
@CezaryTomczyk 谢谢你的帮助 ❤️,我会尝试提出一个问题。 - undefined
显示剩余3条评论
15个回答

3

Compressor.js

https://github.com/fengyuanchen/compressorjs

import axios from 'axios';
import Compressor from 'compressorjs';

document.getElementById('file').addEventListener('change', (e) => {
  const file = e.target.files[0];

  if (!file) {
    return;
  }

  new Compressor(file, {
    quality: 0.6,

    // The compression process is asynchronous,
    // which means you have to access the `result` in the `success` hook function.
    success(result) {
      const formData = new FormData();

      // The third parameter is required for server
      formData.append('file', result, result.name);

      // Send the compressed image file to server with XMLHttpRequest.
      axios.post('/path/to/upload', formData).then(() => {
        console.log('Upload success');
      });
    },
    error(err) {
      console.log(err.message);
    },
  });
});


1
无法读取未定义的属性(读取“0”) 非常感谢!我之前不知道服务器需要第三个参数,现在这个错误已经修复了,谢谢! - wisetap.com

2

您可以使用HTML的<canvas>元素压缩图像:

function compressImage(imgToCompress, resizingFactor, quality) {
  // resizing the image
  const canvas = document.createElement("canvas");
  const context = canvas.getContext("2d");
  
  const originalWidth = imgToCompress.width;
  const originalHeight = imgToCompress.height;
  
  const canvasWidth = originalWidth * resizingFactor;
  const canvasHeight = originalHeight * resizingFactor;
  
  canvas.width = canvasWidth;
  canvas.height = canvasHeight;
  
  context.drawImage(
    imgToCompress,
    0,
    0,
    originalWidth * resizingFactor,
    originalHeight * resizingFactor
  );
  
  // reducing the quality of the image
  canvas.toBlob(
    (blob) => {
      if (blob) {
        // showing the compressed image
        resizedImage.src = URL.createObjectURL(resizedImageBlob);
      }
    },
    "image/jpeg",
    quality
  );
}

请参阅此博客文章,了解详细说明:https://img.ly/blog/how-to-compress-an-image-before-uploading-it-in-javascript/

(该文章介绍如何在JavaScript上传图像之前进行压缩。)

1
当图像来自输入且您需要一个base64字符串时,您可以尝试以下方法:
async function compressImage(input, maxWidth, maxHeight, quality) {
  const file = input.files[0];
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = event => {
      const img = new Image();
      img.src = event.target.result;
      img.onload = () => {
        let width = img.width;
        let height = img.height;

        if (width > height) {
          if (width > maxWidth) {
            height *= maxWidth / width;
            width = maxWidth;
          }
        } else {
          if (height > maxHeight) {
            width *= maxHeight / height;
            height = maxHeight;
          }
        }

        const canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, width, height);
        const base64String = canvas.toDataURL('image/jpeg', quality);
        resolve(base64String);
      };
    };
    reader.onerror = error => reject(error);
  });
}


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

1

i improved the function a head to be this :

var minifyImg = function(dataUrl,newWidth,imageType="image/jpeg",resolve,imageArguments=0.7){
    var image, oldWidth, oldHeight, newHeight, canvas, ctx, newDataUrl;
    (new Promise(function(resolve){
      image = new Image(); image.src = dataUrl;
      log(image);
      resolve('Done : ');
    })).then((d)=>{
      oldWidth = image.width; oldHeight = image.height;
      log([oldWidth,oldHeight]);
      newHeight = Math.floor(oldHeight / oldWidth * newWidth);
      log(d+' '+newHeight);

      canvas = document.createElement("canvas");
      canvas.width = newWidth; canvas.height = newHeight;
      log(canvas);
      ctx = canvas.getContext("2d");
      ctx.drawImage(image, 0, 0, newWidth, newHeight);
      //log(ctx);
      newDataUrl = canvas.toDataURL(imageType, imageArguments);
      resolve(newDataUrl);
    });
  };

它的使用:

minifyImg(<--DATAURL_HERE-->,<--new width-->,<--type like image/jpeg-->,(data)=>{
   console.log(data); // the new DATAURL
});

享受 ;)


0

1
without reducing the quality - lifeisbeautiful

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接