2013-08-18 79 views
6

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

我发现只有PHP库:link

+0

我想你会发现你需要根据应用程序支持部分维基百科的内容: http://en.wikipedia.org/wiki/APNG#Application_support –

回答

2

我不知道有关的NodeJS,但你可以尝试APNG-canvas。 APNG使用HTML5(-webkit-canvas),JavaScript(jQuery)。 “

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

工作demo在这里。

+1

这个库不支持创建APNG文件。 – 1j01

2

没有这个库,但实现起来非常简单。在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) 
0

UPNG.js可以解析,并建立APNG文件 - https://github.com/photopea/UPNG.js

自述 -

UPNG。 js支持APNG,接口期望“帧”。

UPNG.encode(IMGS,W,H,CNUM,[德尔斯])

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代表损耗。