是否有可能以某种方式使用 nodejs 将 PNG 图像连接到 APNG 动画图像?
我只找到了 PHP 库:link
没有库,但实现起来非常简单。Wikipedia中描述了将多个 PNG 文件合并为单个 APNG 的算法:
- 将第一个 PNG 文件的所有块作为构建基础。
- 在图像标题块 (IHDR) 之后插入动画控制块 (acTL)。
- 如果第一个 PNG 要成为动画的一部分,请在图像数据块 (IDAT) 之前插入一个帧控制块 (fcTL)。
- 对于每个剩余的帧,添加一个帧控制块 (fcTL) 和一个帧数据块 (fdAT)。然后添加图像结束块(IEND)。帧数据块 (fdAT) 的内容取自其各自源图像的图像数据块 (IDAT)。
这是一个示例实现:
const fs = require('fs')
const crc32 = require('crc').crc32
function findChunk(buffer, type) {
let offset = 8
while (offset < buffer.length) {
let chunkLength = buffer.readUInt32BE(offset)
let chunkType = buffer.slice(offset + 4, offset + 8).toString('ascii')
if (chunkType === type) {
return buffer.slice(offset, offset + chunkLength + 12)
}
offset += 4 + 4 + chunkLength + 4
}
throw new Error(`Chunk "${type}" not found`)
}
const images = process.argv.slice(2).map(path => fs.readFileSync(path))
const actl = Buffer.alloc(20)
actl.writeUInt32BE(8, 0) // length of chunk
actl.write('acTL', 4) // type of chunk
actl.writeUInt32BE(images.length, 8) // number of frames
actl.writeUInt32BE(0, 12) // number of times to loop (0 - infinite)
actl.writeUInt32BE(crc32(actl.slice(4, 16)), 16) // crc
const frames = images.map((data, idx) => {
const ihdr = findChunk(data, 'IHDR')
const fctl = Buffer.alloc(38)
fctl.writeUInt32BE(26, 0) // length of chunk
fctl.write('fcTL', 4) // type of chunk
fctl.writeUInt32BE(idx ? idx * 2 - 1 : 0, 8) // sequence number
fctl.writeUInt32BE(ihdr.readUInt32BE(8), 12) // width
fctl.writeUInt32BE(ihdr.readUInt32BE(12), 16) // height
fctl.writeUInt32BE(0, 20) // x offset
fctl.writeUInt32BE(0, 24) // y offset
fctl.writeUInt16BE(1, 28) // frame delay - fraction numerator
fctl.writeUInt16BE(1, 30) // frame delay - fraction denominator
fctl.writeUInt8(0, 32) // dispose mode
fctl.writeUInt8(0, 33) // blend mode
fctl.writeUInt32BE(crc32(fctl.slice(4, 34)), 34) // crc
const idat = findChunk(data, 'IDAT')
// All IDAT chunks except first one are converted to fdAT chunks
let fdat;
if (idx === 0) {
fdat = idat
} else {
const length = idat.length + 4
fdat = Buffer.alloc(length)
fdat.writeUInt32BE(length - 12, 0) // length of chunk
fdat.write('fdAT', 4) // type of chunk
fdat.writeUInt32BE(idx * 2, 8) // sequence number
idat.copy(fdat, 12, 8) // image data
fdat.writeUInt32BE(crc32(4, length - 4), length - 4) // crc
}
return Buffer.concat([ fctl, fdat ])
})
const signature = Buffer.from('\211PNG\r\n\032\n', 'ascii')
const ihdr = findChunk(images[0], 'IHDR')
const iend = Buffer.from('0000000049454e44ae426082', 'hex')
const output = Buffer.concat([ signature, ihdr, actl, ...frames, iend ])
fs.writeFileSync('output.png', output)
UPNG.js可以解析和构建 APNG 文件 - https://github.com/photopea/UPNG.js
从自述文件 -
UPNG.js 支持 APNG 并且界面需要“帧”。
UPNG.encode(imgs, w, h, cnum, [dels])
imgs: array of frames. A frame is an ArrayBuffer containing the pixel data (RGBA, 8 bits per channel) w, h : width and height of the image cnum: number of colors in the result; 0: all colors (lossless PNG) dels: array of delays for each frame (only when 2 or more frames) returns an ArrayBuffer with binary data of a PNG file
UPNG.js 可以对 PNG 文件进行有损缩小,类似于 TinyPNG 和其他工具。它使用 k-means 算法执行颜色量化。
最后一个参数 cnum 允许有损压缩。将其设置为零以进行无损压缩,或在图像中写入允许的颜色数。较小的值会产生较小的文件。或者只使用 0 表示无损 / 256 表示有损。
目前,不,它看起来不像。Wikipedia 列出了可用的软件,如您所见,不支持具有 Node 包装器的 ImageMagick。但是,您可能会发现您可以下载命令行工具 apngasm并使用 shell,如果您觉得值得您使用 Node 命令行包装器将其挂接到现有应用程序中child_process
(http://nodejs.org/api /child_process.html)。
我不确定nodejs,但你可以试试APNG-canvas。APNG 使用 HTML5 (-webkit-canvas)、JavaScript (jQuery)。
“APNG-canvas 是一个库,用于在支持画布的浏览器(Google Chrome、Internet Explorer 9、Apple Safari)中显示动画 PNG 文件。”
工作演示在这里。