Repository
lib-image
The images, PNG and the compression under it for Kinogaki Studio, in Rust with no dependencies beyond std and no unsafe code.
- GitHub
- kinogaki/lib-image
- Folder
libs/lib-image/- Crates
- 3
- Rust lines
- 3,449 in src, 721 in tests
Crates
| Crate | What it is | Files | Lines | Test lines |
|---|---|---|---|---|
kinogaki-deflate | DEFLATE (RFC 1951) and zlib (RFC 1950) compression and decompression, with the CRC-32 and Adler-32 checksums the formats around them use. | 8 | 2,181 | 526 |
kinogaki-image | The owned image every lib-image format decodes to and encodes from. | 3 | 336 | 0 |
kinogaki-png | PNG images (ISO/IEC 15948, W3C PNG Third Edition) over kinogaki_deflate. | 4 | 932 | 195 |
README
lib-image
The images, PNG and the compression under it for Kinogaki Studio, in Rust with no dependencies beyond std and no unsafe code. Studio's tools and captures write and read PNGs through it, and its JPEG and OpenEXR format plugins build their codecs on its image and DEFLATE.
Crates
| Crate | Path | What |
|---|---|---|
kinogaki-image | crates/image | The shared Image (interleaved samples: U8, U16, U32, F16, F32), exact half-float conversion, to_rgba8 for display. |
kinogaki-deflate | crates/deflate | DEFLATE and zlib compression and decompression, CRC-32, Adler-32, bounded for hostile streams (a truncated stream fails at its end, output stays within DEFLATE's 1032:1, a stop flag ends a decode). Shared by PNG, OpenEXR's ZIP compression and FBX. |
kinogaki-png | crates/png | PNG decode (every color type, 1–16 bits, interlaced, tRNS; its chunks read first, so a caller knows what decoding takes) and encode (8/16-bit grey, grey+alpha, RGB, RGBA), with the sRGB or iCCP chunk saying a display. |
The image shape
Every codec decodes to an owned image and encodes from one (kinogaki-image, re-exported by kinogaki-png):
Samples are interleaved, rows top to bottom, straight (not premultiplied) alpha. Integer samples are display-referred, float samples scene-linear. Image::to_rgba8 gives 8-bit RGBA for display (floats through the sRGB curve).
Checks
Independent oracles (local only, never dependencies): tools/zlib_oracle.py (Python's zlib) and tools/png_oracle.py (Pillow) write the test fixtures and check this library's output; see docs/ARCHITECTURE.md. What PNG leaves out is listed in docs/FORMATS.md.
Licence
MIT OR Apache-2.0, at your option: see LICENSE-MIT and LICENSE-APACHE.
Its documents
The repository's architecture document as written there (code blocks and links left out), and the opening of each other document.
lib-image architecture (libs/lib-image/docs/ARCHITECTURE.md)
lib-image architecture
One Cargo workspace. Owned code forbids unsafe (workspace lint) and the crates depend on nothing beyond std and each other (kinogaki-png → kinogaki-deflate, kinogaki-image). JPEG and OpenEXR are Kinogaki Studio's format plugins, each with its codec, over kinogaki-image (and kinogaki-deflate for OpenEXR's zlib).
kinogaki-image (crates/image)
| File | Responsibility |
|---|---|
lib.rs | Image, Samples (U8, U16, U32, F16 bits, F32), Image::new (checked), to_rgba8 |
half.rs | binary16 ↔ binary32, exact: every half round-trips, floats round to nearest even (tested over all 65 536 halves and every halfway point) |
srgb.rs | linear float → sRGB byte by binary search over the 255 code boundaries: exact rounding without a power per sample |
kinogaki-deflate (crates/deflate)
| File | Responsibility |
|---|---|
lib.rs | public API: deflate/inflate (raw), zlib_compress/zlib_decompress, Level, Error |
checksum.rs | CRC-32 (slicing by eight), Adler-32 (sixteen lanes per block, summed without overflow checks so they vectorize) |
tables.rs | RFC 1951 constants and the length/distance symbol tables |
inflate/mod.rs | decoder: blocks, an output kept a match and a chunk longer than written, up to three literals per refill, the next symbol looked up before the refill when the bits left hold its index; matches copied in 16- or 8-byte chunks, periods under eight bytes as 16-byte patterns |
inflate/bits.rs | the bit reader: a 64-bit buffer refilled a word at a time, zeros counted past the end so a truncated stream fails |
inflate/table.rs | two-level Huffman tables (11-bit first level for literals/lengths, 10 for distances) whose entries carry a literal, or a base, and the bits they take with their extra bits, so one shift consumes a length or a distance whole; a dynamic block's built in place, the first level doubled a code length at a time; the fixed block's |
huffman.rs | encoder code lengths: two-queue Huffman construction, length limiting by Kraft rebalancing, canonical codes |
deflate.rs | encoder: hash chains over 4-byte prefixes in a 32 KiB window, lazy matching, blocks of 32 768 symbols written as the cheapest of dynamic, fixed or stored |
Levels: Fast (chain 4, no lazy matching), Balanced (chain 128, lazy below 16, nice 128: zlib level 6's parameters), Small (chain 2048, full lazy matching).
Decoding is bounded, since a stream may be hostile: every call takes an output limit; a stream that reads past its end fails as Truncated within a few bytes of its end rather than decoding the zero bits the reader supplies there (the fast loop stops once the reader is eight bytes past the input, and the careful one checks every symbol); output never passes 1032 bytes for each byte of input, the most DEFLATE codes (a 258-byte match in two bits), so a claimed size larger than that is TooLarge at once; and zlib_decompress_until stops with Stopped once its caller's flag is raised, looked at every block and every megabyte of output.
kinogaki-png (crates/png)
| File | Responsibility |
|---|---|
lib.rs | Image, Samples, Error, Image::to_rgba8 |
encode.rs | encode: one IDAT, adaptive per-row filter (libpng's minimum sum of magnitudes) |
decode.rs | Png::read: chunk walk with CRC checks, IHDR/PLTE/tRNS/IDAT/IEND, the sizes decoding takes (checked against overflow) before anything is inflated; Png::decode: Adam7, sample unpacking, a stop flag looked at every row; 8-bit RGBA unfilters in the decompressed buffer itself; decode both at once, under a pixel limit |
filter.rs | the five filters, Paeth in its threshold form for decoding |
Tests and oracles
crates/deflate/tests/streams.rs: zlib-made streams (levels 0–9, a 512-byte window, many small dynamic blocks) decompress; round trips at every level over edge inputs (empty, 258/259-byte runs, a match at exactly 32 768 bytes, incompressible data) and seeded random data up to 400 000 bytes (exact limits, an unknown size, appended to a caller's bytes); hand-written streams with a match of every distance 1–40 and others up to 32 768, of every length 3–40 and around each chunk size, last in the stream (at exactly its limit, and one byte short) or followed by literals; stored blocks between fixed blocks, matches reaching across them; output within 10% of zlib's size at levels 1/6/9; every truncation and 20 000 bit flips fail cleanly; hostile dynamic blocks: one whose all-zero code is a literal, cut after its header, failsTruncatedhaving written under a kilobyte (it once decoded zeros up to the caller's limit), and one of two-bit 258-byte matches, DEFLATE's most output a byte, decodes whole; a raised stop flag ends a decode.inflate/table.rs's unit tests: every 15-bit input decodes, through both table levels, to the canonical code it starts with, for the fixed codes, a lone one-bit code and random complete codes up to 15 bits.tools/zlib_oracle.py check DIRdecompresses this library's zlib output with Python's zlib (KINOGAKI_DEFLATE_ORACLE_DIR=DIR cargo test -p kinogaki-deflate --test streams): 42/42 identical.crates/png/tests/images.rs: every color type × bit depth × interlace method (30 files from the independent Python encoder intools/png_oracle.py, filters cycling through all five types, IDAT split over chunks, tRNS where allowed) decodes to the RGBA the specification gives; 5 Pillow-written files decode as Pillow reads them; round trips; truncations and corruption fail cleanly;Png::readsays what decoding takes before it starts, sizes past memory's addresses are refused there, and a raised stop flag ends a decode.tools/png_oracle.py check DIRreads this library's PNGs with Pillow (KINOGAKI_PNG_ORACLE_DIR=DIR cargo test -p kinogaki-png --test images).
Benchmarks (libs/lib-image/docs/BENCHMARKS.md)
Apple M4 Max, macOS, release builds (thin LTO, one codegen unit). Other agents' builds were running, so each figure is the minimum of many runs, all variants interleaved. The harnesses live outside the repository (they link other libraries); their cases are listed so they can be rebuilt.
Format coverage (libs/lib-image/docs/FORMATS.md)
What each crate reads and writes, and what it leaves out.
