Node 把 jpg 图片变成 apng 动图格式

168 阅读2分钟

jpg -> apng

graph LR
jpg链接 -->|下载远端图片 loadImage| jpg的buffer --> |将JPG转换为PNG convertJpgToPngBuffer| png --> |把png Buffer转换成原始RGBA图像数据 getPngFrame| rgba -->|UPNG.js生成APNG| UPNG.encode
// 下载远端jpg图片
function loadImage(url) {
  return new Promise((resolve, reject) => {
    https.get(url, (res) => {
      const data = [];
      res.on('data', (chunk) => {
        data.push(chunk);
      });
      res.on('end', () => {
        resolve(Buffer.concat(data));
      });
    }).on('error', (err) => {
      reject(err);
    });
  });
}

// 将JPG转换为PNG
const sharp = require('sharp');
async function convertJpgToPngBuffer(inputBuffer) {
  const pngBuffer = await sharp(inputBuffer).resize(300, 300).png().toBuffer();
  return pngBuffer;
}

// 把png Buffer转换成原始RGBA图像数据
const PNG = require('pngjs').PNG;
async function getPngFrame(pngBuffer) {
  return new Promise((resolve, reject) => {
    const png = new PNG();
    png.parse(pngBuffer, (error, data) => {
      if (error) {
        reject(error);
      } else {
        resolve(data.data.buffer);
      }
    });
  });
}


// 使用UPNG.js生成APNG
// ⚠️ UPNG.encode 里面的 frames 接受的是RGBA图像数据,这个需要注意
const UPNG = require('upng-js');
const apngArrayBuffer = UPNG.encode(frames, width, height, 0, delays);
const apngBuffer = Buffer.from(apngArrayBuffer); // 转换buffer可以推送到阿里云oss中

apng

APNG(Animated Portable Network Graphics)是一种支持动画的图像文件格式,基于 PNG(Portable Network Graphics)文件格式。APNG是对原始的PNG格式的扩展,允许帧序列嵌入在单个文件中,这与GIF图像的动画支持类似,但它提供了更好的压缩、全色彩(不限制为256色)以及包含透明度信息。


Buffer/ArrayBuffer

Buffer

在 Node.js 中,Buffer 类是用于处理二进制数据流的一个全局对象。Buffer 类创建一个包含字节数组的存储空间,允许你在内存中存储原始数据,并对这些数据进行读写操作。它主要用于操作文件系统、网络通信、或任何其他的 I/O 操作中的数据流和缓冲区。

ArrayBuffer

ArrayBuffer 是 JavaScript 中的一种基本数据类型,用于表示固定长度的原始二进制数据缓冲区。

// node 打印 ArrayBuffer, 
// const arrayBuffer = new ArrayBuffer(360000); 
// console.log(arrayBuffer);

ArrayBuffer {
    [Uint8Contents]: <ff 36 0a ff ff 36 0a ff ff 36 0a ff ff 36 0a ff ff 36 0a ff ff 36 0a ff fe 37 0a ff ff 36 09 ff ff 35 0a ff ff 36 0b ff ff 36 0a ff ff 36 0a ff fe 36 0a ff ff 36 09 ff ff 36 0a ff ff 36 0a ff ff 36 0b ff ff 36 0a ff ff 36 0a ff ff 36 0a ff fe 37 0a ff ff 36 0a ff ff 36 0a ff ff 36 0a ff ff 36 0a ff ... 359900 more bytes>,
    byteLength: 360000
},
  • ArrayBuffer 对象有 360000 字节的长度 (byteLength: 360000)。
  • Uint8Contents 通常是描述 ArrayBuffer 内容时用到的内部属性,在某些调试环境或日志输出中可能会看到这个标识。它表示 ArrayBuffer 中的内容可以用一个 Uint8Array 来访问。Uint8Array 是一个视图,它以8位无符号整数的形式展现 ArrayBuffer 中的二进制数据。这个 ArrayBuffer 可以通过 Uint8Array 或其他类型化数组访问,这些类型化数组可以提供对缓冲区中数据的视图,无需复制数据本身。
  • [Uint8Contents] 后面跟随的 <ff 36 0a ...> 表示了缓冲区中的内容,以十六进制形式展示。
  • 要从 ArrayBuffer 中读取数据,通常会使用类型化数组。
    const dataView = new Uint8Array(arrayBuffer);
    

全部代码参考