openCV.js和canvas压缩图片大比拼

2,026 阅读6分钟

在web应用中,图片通常是必不可少的一部分,我们经常需要处理图片。但是,图片往往比较大,导致加载时间较长。因此,我们需要对图片进行压缩,以减小文件大小,同时保证图片的质量。本文将介绍如何使用canvas和openCV.js来压缩图片。

一、使用Canvas压缩图片

一种压缩图片的方法是使用HTML5的canvas元素。canvas元素允许您在网页上绘制图形和图片。要使用canvas压缩图片,您可以将图片绘制到canvas元素上,然后将canvas导出为压缩后的图片。

1.压缩原理

使用canvas压缩图片的底层原理是将原始图片的像素数据读取到内存中,然后使用canvas的2D上下文对象将像素数据绘制到canvas元素上。在绘制时,可以通过调整canvas的大小来压缩图片的尺寸,从而减小文件大小。此外,可以通过调整toBlob方法的第三个参数来控制压缩质量,进一步减小文件大小。最终,使用toBlob方法将canvas元素上绘制的结果转换为Blob对象,即压缩后的图片。

2.代码实现

实现步骤如下:

  1. 使用FileReader对象读取文件内容。
  2. 当文件内容读取完成后,将其作为src传递给Image对象,并将其加载到内存中。
  3. 当图像加载完成后,创建一个canvas元素,并使用2D上下文对象将图像绘制到canvas元素上。
  4. 调整canvas的大小以压缩图片,并使用toBlob方法将canvas元素上的图像转换为Blob对象。

函数compressWithCanvas接受四个参数:文件对象、最大宽度、最大高度和压缩质量。该函数返回一个promise对象,该对象在压缩完成时解析为Blob对象。

以下是使用canvas压缩图片的完整代码实现:

const compressWithCanvas = async (file, maxWidth, maxHeight, quality) => {
  try {
    const dataUrl = await new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => resolve(reader.result);
      reader.onerror = (error) => reject(error);
    });
    const img = await new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => resolve(img);
      img.onerror = (error) => reject(error);
      img.src = dataUrl;
    });
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    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;
      }
    }
    canvas.width = width;
    canvas.height = height;
    ctx.drawImage(img, 0, 0, width, height);
    const blob = await new Promise((resolve) => {
      canvas.toBlob((blob) => resolve(blob), file.type, quality);
    });
    return blob;
  } catch (error) {
    throw error;
  }
};

将文件、最大宽度、最大高度和质量作为参数传递。函数将返回一个Promise对象,该对象在压缩完成时解析为Blob对象。以下是使用此函数的示例代码:

//调用compressWithCanvas方法
const file = document.getElementById('input').files[0];
const maxWidth = 800;
const maxHeight = 600;
const quality = 0.7;
compressWithCanvas(file, maxWidth, maxHeight, quality)
  .then((blob) => {
    // Do something with the compressed image blob
  })
  .catch((error) => {
    // Handle any errors that occurred during compression
  });

二、使用openCV.js压缩图片

另一种压缩图片的方法是使用openCV.js。OpenCV.js是一个JavaScript库,可以在网络应用中使用OpenCV,一个流行的计算机视觉库。OpenCV.js提供了一个名为imencode的函数,可用于压缩图片。

1. 压缩原理

使用Uint8ArrayarrayBuffer将文件内容读取到内存中,然后使用cv.imreadAsync将图像转换为矩阵。接着,使用cv.imencode函数压缩图像,并将压缩后的数据转换为Blob对象,最后返回该对象。

cv.imreadAsync函数用于将图像数据读取到内存中,并转换为OpenCV中的矩阵格式。该函数接受一个Uint8Array类型的参数,该参数包含图像数据。函数返回一个Promise对象,该对象在读取完成后解析为OpenCV中的Mat对象。

cv.imencode函数用于压缩图像并将其转换为Blob对象。该函数接受四个参数:文件扩展名、输入图像、输出缓冲区和压缩参数。输出缓冲区是一个Mat对象,用于存储压缩后的图像数据。压缩参数是一个数组,用于指定压缩选项。例如,可以使用[cv.IMWRITE_JPEG_QUALITY, quality]来指定JPEG格式的压缩质量。该函数返回一个布尔值,表示是否成功压缩图像。

2. 代码实现

使用openCV.js压缩图片的实现步骤如下:

  1. 加载openCV.js
  2. 使用Uint8ArrayarrayBuffer将文件内容读取到内存中。
  3. 使用cv.imreadAsync将图像转换为矩阵。
  4. 使用cv.imencode函数压缩图像。可以通过更改函数的参数来调整压缩级别。参数越高,图片的压缩程度越小,文件大小越大。
  5. 将压缩后的数据转换为Blob对象。

以下是使用openCV.js压缩图片的完整代码实现:

在代码中加载 opencv.js

<script async src="<https://docs.opencv.org/master/opencv.js>" type="text/javascript">
</script>

在这里,JavaScript文件的URL是 https://docs.opencv.org/master/opencv.js。下载和加载该文件可能需要一些时间。然后,您可以调用 cv.imreadAsynccv.imencode 等函数来完成图像的压缩处理。

const compressWithOpenCV = async (file, quality) => {
  try {
    const imgData = new Uint8Array(await file.arrayBuffer());
    const img = await cv.imreadAsync(imgData);
    const result = new cv.Mat();
    cv.imencode('.jpg', img, result, [cv.IMWRITE_JPEG_QUALITY, quality]);
    const blob = new Blob([result.data], { type: 'image/jpeg' });
    img.delete();
    result.delete();
    return blob;
  } catch (error) {
    throw error;
  }
};

其中,file是要压缩的文件,quality是压缩质量,通常在0到100之间。函数将返回一个Promise对象,该对象在压缩完成时解析为Blob对象。

调用compressWithOpenCV方法:

try {
  const file = document.getElementById('input').files[0];
  const quality = 80;
  const blob = await compressWithOpenCV(file, quality);
  // 处理压缩后的图片blob对象
} catch (error) {
  // 处理压缩过程中的错误
}

三、两种压缩方法的优缺点

在选择压缩图片的方法时,需要考虑应用程序的具体要求和限制条件。如果只需要简单地压缩JPEG和PNG格式的图片,使用canvas是一个不错的选择。如果需要处理各种格式的图片,并且需要更细致地控制压缩质量,使用openCV.js是一个更好的选择。

  • 使用Canvas压缩图片

    使用canvas压缩图片的优点是它是HTML5的标准元素,无需任何库或框架即可使用。此外,它的使用非常简单,只需要几行代码即可完成压缩。

    它的缺点是它只能压缩JPEG和PNG格式的图像,虽然Canvas可以使用toBlob方法将图像转换为Blob对象,但是它的压缩质量受到浏览器支持的限制,无法进行更细致的控制。

  • 使用openCV.js压缩图片

    使用openCV.js压缩图片的优点是它可以处理各种格式的图像,包括JPEG、PNG和BMP等常见格式,还支持其他一些图像格式TIFF (.tif, .tiff)和WebP (.webp)等。此外,它提供了更多的压缩选项,可以更细致地控制压缩质量。

    它的缺点是它需要加载一个较大的JavaScript库,因此它可能不适合于需要快速加载的应用程序。不支持直接压缩GIF格式的图片,如果需要压缩GIF格式的图片,需要考虑使用其他库或工具来处理。

四、写在文末

随着人工智能和机器学习技术的不断发展,图片压缩技术也可以更加智能化。例如,可以使用机器学习算法来自动识别和压缩不同类型的图像,以提高压缩效率和质量。这些新技术和算法将使图片压缩技术更加智能化和自动化,为应用提供更好的用户体验。