Compress and encode data as Portable Network Graphics (PNG) image
It can be useful to encode data or application state into an image file for sharing easily - compared to JSON or ZIP format, which might not be possible to upload to a discussion forum.
Such images are sometimes called "cartridges", referring to retro game ROM cards.
The data is gzip
compressed using the Compression Streams API, well-supported by browsers and server-side JavaScript runtimes. The PNG format uses the same algorithm, but I found that the compression ratio is dramatically better when the data is compressed before encoding as image.
Each byte of the given data is written into the color channels (red/green/blue) of an image. The opacity (alpha) channel is not used because it can change color values.
In the browser, this encoded buffer can be turned into an image element and downloaded as a PNG file. On the server, it can be written to a file.
npm install --save png-compressor
import { encode, decode } from 'png-compressor'
const object = { key: 'value' }
const pngImage = await encode(object)
const decoded = await decode(pngImage)
assert.deepEqual(decoded, object)
import { encodeBinary, decodeBinary } from 'png-compressor'
const buffer = new ArrayBuffer(8)
const pngImage = await encodeBinary(buffer)
const decoded = await decodeBinary(pngImage)
assert.deepEqual(decoded, buffer)
import * as png from 'png-compressor'
const object = { key: 'value' }
const image = await png.encodeToImage(object)
Or pass an image element as second argument to render into it.
const image = document.createElement('img')
await png.encodeToImage(object, image)
const blob = await png.encodeToBlob(object)
png.downloadImage(blob, 'example.png')
import fs from 'node:fs/promises'
import * as png from 'png-compressor'
const object = { key: 'value' }
const encoded = await png.encode(source)
await fs.writeFile('test.png', Buffer.from(encoded))
const buffer = await fs.readFile('test.png')
const decoded = await png.decode(buffer.buffer)