FWC-1§7Normative

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

  1. Detect mode. For each mode in [noise, lsb], read 12 bytes under that mapping (§4). Accept the first whose bytes 0–2 equal 46 57 01. If none matches, fail with not-a-container.
  2. Parse header. flags = h[3], length = uint32be(h[4..8]), crc = uint32be(h[8..12]).
  3. Bound check. If length > capacity(width, height, mode) fail with not-a-container.
  4. Read body. Read 12 + length bytes under the detected mapping and drop the first 12.
  5. Verify. If crc32(body) ≠ crc fail with bad-crc.
  6. Decrypt if flags & 0b01: obtain a password (fail with password-required if none), then body = decrypt(body, password) (fail with bad-password on tag mismatch).
  7. Decompress if flags & 0b10: body = inflate(body).
  8. Decode text. html = utf8decode(body). The result is the payload.

Error taxonomy

CodeMeaningUser-facing guidance
not-a-containerNo valid header under any mode, or impossible lengthThis PNG was not made with FWC-1
bad-crcHeader valid, body corruptedThe image was re-encoded or altered; use the original file
password-requiredEncrypted and no password suppliedPrompt for a password
bad-passwordGCM authentication failedWrong password (or tampered data)
unsupportedRecognised magic but unknown versionUpdate 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.