* Encode an RGBA pixel buffer as PNG. Minimal encoder: 8-bit depth, * color type 6 (RGBA), filter 0 (none) on every scanline, single IDAT.
(px: Uint8Array, width: number, height: number)
| 305 | * color type 6 (RGBA), filter 0 (none) on every scanline, single IDAT. |
| 306 | */ |
| 307 | function encodePng(px: Uint8Array, width: number, height: number): Buffer { |
| 308 | // IHDR |
| 309 | const ihdr = Buffer.alloc(13) |
| 310 | ihdr.writeUInt32BE(width, 0) |
| 311 | ihdr.writeUInt32BE(height, 4) |
| 312 | ihdr[8] = 8 // bit depth |
| 313 | ihdr[9] = 6 // color type: RGBA |
| 314 | ihdr[10] = 0 // compression: deflate |
| 315 | ihdr[11] = 0 // filter method |
| 316 | ihdr[12] = 0 // interlace: none |
| 317 | |
| 318 | // IDAT: each scanline prefixed with filter byte 0. |
| 319 | const stride = width * 4 |
| 320 | const raw = Buffer.alloc(height * (stride + 1)) |
| 321 | for (let y = 0; y < height; y++) { |
| 322 | const dst = y * (stride + 1) |
| 323 | raw[dst] = 0 |
| 324 | raw.set(px.subarray(y * stride, (y + 1) * stride), dst + 1) |
| 325 | } |
| 326 | const idat = deflateSync(raw) |
| 327 | |
| 328 | return Buffer.concat([ |
| 329 | PNG_SIG, |
| 330 | chunk('IHDR', ihdr), |
| 331 | chunk('IDAT', idat), |
| 332 | chunk('IEND', new Uint8Array(0)), |
| 333 | ]) |
| 334 | } |
| 335 |