Decoding algorithm
The reference procedure a conforming decoder follows, and the closed set of errors it may raise.
Obtaining pixel data
The decoder MUST obtain an unmodified RGBA buffer of the PNG. In browsers this means decoding with colour management and alpha premultiplication disabled where the API allows it, then reading back through a 2D canvas:
const bitmap = await createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none',
})
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height)
const ctx = canvas.getContext('2d', { willReadFrequently: true })!
ctx.drawImage(bitmap, 0, 0)
const image = ctx.getImageData(0, 0, bitmap.width, bitmap.height)Where createImageBitmap options are unavailable (the loader uses a plain <img> for size), the alpha invariant of §4 guarantees correctness anyway; the options are belt-and-braces against colour-managed PNGs produced by non-conforming encoders.
Procedure
- Detect mode. For each mode in
[noise, lsb], read 12 bytes under that mapping (§4). Accept the first whose bytes 0–2 equal46 57 01. If none matches, fail withnot-a-container. - Parse header.
flags = h[3],length = uint32be(h[4..8]),crc = uint32be(h[8..12]). - Bound check. If
length > capacity(width, height, mode)fail withnot-a-container. - Read body. Read
12 + lengthbytes under the detected mapping and drop the first 12. - Verify. If
crc32(body) ≠ crcfail withbad-crc. - Decrypt if
flags & 0b01: obtain a password (fail withpassword-requiredif none), thenbody = decrypt(body, password)(fail withbad-passwordon tag mismatch). - Decompress if
flags & 0b10:body = inflate(body). - Decode text.
html = utf8decode(body). The result is the payload.
Error taxonomy
| Code | Meaning | User-facing guidance |
|---|---|---|
| not-a-container | No valid header under any mode, or impossible length | This PNG was not made with FWC-1 |
| bad-crc | Header valid, body corrupted | The image was re-encoded or altered; use the original file |
| password-required | Encrypted and no password supplied | Prompt for a password |
| bad-password | GCM authentication failed | Wrong password (or tampered data) |
| unsupported | Recognised magic but unknown version | Update the decoder |
Implementations MUST use exactly these five codes so that tooling built on one decoder can interpret failures from another. Additional human-readable messages MAY accompany a code.
Reported metadata
A successful decode SHOULD expose, alongside the payload: the detected mode, the raw flags byte, bodyBytes (as stored), rawBytes (after decompression), and the image size. These fields are what the Studio, the Unpack panel and the Showcase statistics display, and standardising them lets third-party inspectors show comparable numbers.