Skip to main content

canvas 压缩图片

技术点

利用 canvas 绘制图片这个技术点可以快速进行图片压缩,以下会涉及到 createImageBitmapcreateObjectURLDataTransfer 等知识点,这是一个新颖的技术解决方案可供参考。

核心代码

const compressImage = async (file, quality = 1, type = file.type) => {
// 获取位图数据
const imageBitmap = await createImageBitmap(file);

// 绘制 canvas
const canvas = document.createElement('canvas');
// 获取 canvas 上下文
const ctx = canvas.getContext('2d');
// 设置 canvas 尺寸大小
canvas.width = imageBitmap.width;
canvas.height = imageBitmap.height;

// 在 canvas 上绘制图片
ctx.drawImage(imageBitmap, 0, 0);

// 创建 Blob 对象
const blob = await new Promise((resolve) => {
canvas.toBlob(resolve, type, quality);
});

// 将 blob 数据构造成 File 对象
return new File([blob], file.name, {
type: blob.type,
});
};

效果预览

const compressImage = async (file, quality = 1, type = file.type) => {
  // 获取位图数据
  const imageBitmap = await createImageBitmap(file);

  // 绘制 canvas
  const canvas = document.createElement('canvas');
  // 获取 canvas 上下文
  const ctx = canvas.getContext('2d');
  // 设置 canvas 尺寸大小
  canvas.width = imageBitmap.width;
  canvas.height = imageBitmap.height;

  // 在 canvas 上绘制图片
  ctx.drawImage(imageBitmap, 0, 0);

  // 创建 Blob 对象
  const blob = await new Promise((resolve) => {
    canvas.toBlob(resolve, type, quality);
  });

  // 将 blob 数据构造成 File 对象
  return new File([blob], file.name, {
    type: blob.type,
  });
};

// 计算文件尺寸大小
const getFileTotalSize = (file) => {
  return (file.size / 1024).toFixed(2);
};

// 通过 File 对象创建图片
const createPreviewImage = (file) => {
  const img = document.createElement('img');
  // 创建指定 File 内容的图片地址
  img.src = URL.createObjectURL(file);
  img.width = 300;
  img.onload = () => {
    // 释放 URL 对象
    URL.revokeObjectURL(img.src);
  };
  return img;
};

const input = document.querySelector('input');
const before = document.querySelector('#before');
const beforeImage = document.querySelector('#before-image');
const after = document.querySelector('#after');
const afterImage = document.querySelector('#after-image');

input.addEventListener(
  'change',
  async (evt) => {
    // 获取上传的文件列表
    const { files } = evt.target;

    // 上传的文件为空
    if (!files.length) return;

    // 用于存放文件数据
    const dataTransfer = new DataTransfer();

    for (const file of files) {
      // if (!file.type.startsWith('image')) {
      //   dataTransfer.items.add(file);
      //   continue;
      // }

      // 压缩一半大小(50%)
      const compressedImage = await compressImage(file, 0.5, 'image/jpeg');

      const beforeImage = createPreviewImage(file);
      const afterImage = createPreviewImage(compressedImage);
      before.innerText = `${getFileTotalSize(file)}KB`;
      before.appendChild(beforeImage);
      after.innerText = `${getFileTotalSize(compressedImage)}KB`;
      after.appendChild(afterImage);

      // 存储压缩后的文件
      dataTransfer.items.add(compressedImage);
    }

    // 更新选择后的结果文件
    evt.target.files = dataTransfer.files;
  },
  false
);