2013-08-18 107 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代表損耗。