前端如何压缩png图片

43 阅读3分钟

FileReader

  FileReader 对象 允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

readAsDataURL

  readAsDataURL 方法 会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成 DONE,并触发 loadend 事件,同时 result 属性将包含一个 data:URL 格式的字符串(base64 编码)以表示所读取文件的内容。

示例:

function previewFile() {
  var preview = document.querySelector("img");
  var file = document.querySelector("input[type=file]").files[0];
  var reader = new FileReader();

  reader.addEventListener(
    "load",
    function () {
      preview.src = reader.result;
    },
    false
  );

  if (file) {
    reader.readAsDataURL(file);
  }
}

canvas

  Canvas 提供了一个通过 JavaScript 和 HTML 的<canvas>元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

drawImage

  Canvas 2D API 中的 CanvasRenderingContext2D.drawImage() 方法提供了多种在画布(Canvas)上绘制图像的方式。

drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

getImageData

  CanvasRenderingContext2D.getImageData() 返回一个 ImageData 对象,用来描述 canvas 区域隐含的像素数据,这个区域通过矩形表示,起始点为(sx, sy)、宽为 sw、高为 sh。

参数:

  • sx
    • 将要被提取的图像数据矩形区域的左上角 x 坐标。
  • sy
    • 将要被提取的图像数据矩形区域的左上角 y 坐标。
  • sw
    • 将要被提取的图像数据矩形区域的宽度。
  • sh
    • 将要被提取的图像数据矩形区域的高度。

返回值:

  • 一个 ImageData 对象,包含 canvas 给定的矩形图像数据。

UPNG

  一个小型,快速和先进的 PNG / APNG 编码器和解码器。开源地址:github.com/photopea/UP…

完整代码

declare var UPNG: {
  encode: (
    imgs: ArrayBuffer[],
    w: number,
    h: number,
    cnum: number,
    dels?: number[]
  ) => ArrayBuffer;
};

interface Options {
  file: File;
  cnum?: number;
  success?: (base64: string) => void;
}

// 定义一个函数,参数是一个 ArrayBuffer 对象
function arrayBufferToBase64(buffer) {
  // 初始化一个空字符串,用于存储二进制数据
  var binary = "";

  // 创建一个新的 Uint8Array 对象,它的内容是参数 buffer 的一个浅拷贝
  // Uint8Array 是一个类型化数组,用于表示 8 位无符号整数的数组
  var bytes = new Uint8Array(buffer);

  // 获取这个 Uint8Array 的长度(即字节数)
  var len = bytes.byteLength;

  // 遍历这个 Uint8Array
  for (var i = 0; i < len; i++) {
    // 将每个字节转换为字符,然后添加到 binary 字符串中
    // String.fromCharCode 函数接收一个 Unicode 值,然后返回一个字符串
    binary += String.fromCharCode(bytes[i]);
  }

  // 使用 window.btoa 函数将 binary 字符串转换为 Base64 格式
  // btoa 是 "binary to ASCII" 的缩写
  return window.btoa(binary);
}

/**
 * 适用于png
 */
class CompressImage {
  options: Options;
  fileReader = new FileReader();
  constructor(options: Options) {
    this.options = options;
    this.createBase64();
  }

  createBase64() {
    this.fileReader.readAsDataURL(this.options.file);
    this.fileReader.onload = (e) => {
      this.compress(e.target.result as string);
    };
  }

  compress(base64: string) {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const img = new Image();
    img.src = base64;
    img.onload = () => {
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.drawImage(img, 0, 0, img.width, img.height);
      const dta = ctx.getImageData(0, 0, img.width, img.height).data;
      const png = UPNG.encode(
        [dta.buffer],
        img.width,
        img.height,
        this.options.cnum
      );
      const newBase64 = "data:image/png;base64," + arrayBufferToBase64(png);
      this.options.success(newBase64);
    };
  }
}

const file = document.querySelector("#file") as HTMLInputElement;

file.addEventListener("change", (e) => {
  const target = e.target as HTMLInputElement;
  const fileObject = target.files[0];
  if (fileObject) {
    new CompressImage({
      file: fileObject,
      cnum: 256, // 将其设置为零以进行无损压缩,或写入图像中允许的颜色数。较小的值生成较小的文件。0表示无损,256表示有损。
      success: (base64) => {
        document.body.innerHTML = `<img src='${base64}' />`;
      },
    });
  }
});

对应源代码链接