///|
/// Minimal PNG encoder for screenshots captured by the offscreen renderer.
///
/// `moui screenshot` receives raw RGBA rows from a generated render package;
/// this module adds the PNG container (signature, IHDR, IDAT, IEND) and deflates
/// the scanlines through the toolchain's zlib. Scanlines use filter 0 so the
/// bytes are exactly what the renderer produced, keeping the encoder small and
/// deterministic.

///|
/// CRC-32 (ISO-HDLC) over a byte buffer, the checksum PNG chunks carry.
fn png_crc32(data : Bytes) -> UInt32 {
  let mut crc = 0xFFFFFFFFU
  for index in 0..> 1) ^ 0xEDB88320U
      } else {
        crc = crc >> 1
      }
    }
  }
  crc ^ 0xFFFFFFFFU
}

///|
fn png_write_signature(out : @buffer.Buffer) -> Unit {
  out.write_bytes(b"\x89PNG\r\n\x1a\n")
}

///|
fn png_write_chunk(out : @buffer.Buffer, kind : Bytes, data : Bytes) -> Unit {
  out.write_int_be(data.length())
  let crc_input = @buffer.Buffer()
  crc_input.write_bytes(kind)
  crc_input.write_bytes(data)
  let crc = png_crc32(crc_input.to_bytes())
  out.write_bytes(kind)
  out.write_bytes(data)
  out.write_uint_be(crc)
}

///|
/// Encode `pixels` (RGBA, `row_bytes` may include padding) as an 8-bit RGBA PNG.
fn png_encode_rgba(
  width : Int32,
  height : Int32,
  row_bytes : Int32,
  pixels : Bytes,
) -> Bytes raise {
  guard width > 0 && height > 0 else {
    fail("png_encode_rgba: width and height must be positive")
  }
  guard row_bytes >= width * 4 else {
    fail("png_encode_rgba: row_bytes must hold a full RGBA row")
  }
  let required = row_bytes * height
  guard pixels.length() >= required else {
    fail("png_encode_rgba: pixel buffer is shorter than row_bytes * height")
  }
  let raw = @buffer.Buffer()
  for y in 0..