7

是否有可能以某种方式使用 nodejs 将 PNG 图像连接到 APNG 动画图像?

我只找到了 PHP 库:link

4

4 回答 4

4

没有库,但实现起来非常简单。Wikipedia中描述了将多个 PNG 文件合并为单个 APNG 的算法:

  1. 将第一个 PNG 文件的所有块作为构建基础。
  2. 在图像标题块 (IHDR) 之后插入动画控制块 (acTL)。
  3. 如果第一个 PNG 要成为动画的一部分,请在图像数据块 (IDAT) 之前插入一个帧控制块 (fcTL)。
  4. 对于每个剩余的帧,添加一个帧控制块 (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)
于 2016-08-31T08:23:04.887 回答
4

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 表示有损。

于 2017-12-22T21:13:49.293 回答
2

目前,不,它看起来不像。Wikipedia 列出了可用的软件,如您所见,不支持具有 Node 包装器的 ImageMagick。但是,您可能会发现您可以下载命令行工具 apngasm并使用 shell,如果您觉得值得您使用 Node 命令行包装器将其挂接到现有应用程序中child_processhttp://nodejs.org/api /child_process.html)。

于 2013-10-03T19:35:26.757 回答
1

我不确定nodejs,但你可以试试APNG-canvas。APNG 使用 HTML5 (-webkit-canvas)、JavaScript (jQuery)。

“APNG-canvas 是一个库,用于在支持画布的浏览器(Google Chrome、Internet Explorer 9、Apple Safari)中显示动画 PNG 文件。”

工作演示在这里。

于 2013-10-03T19:29:08.270 回答