mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
LZW, ASCII85, ASCIIHex, RunLength, the TIFF and PNG predictors, bounded CCITT fax decoding (through hayro-ccitt) with Group 4 encoding (through fax), and the lossless JBIG2 encoder with its MQ coder, from pdfcraft-filters at PdfCraft revision 80e26e674d1aa33078e83c8139875047f3289eb6. The crate sits below craft-pdf and craft-tiff: it knows no container. The PDF filter chain, Flate and the bounded JBIG2 decoding entry are not part of it.
79 lines
5.9 KiB
Markdown
79 lines
5.9 KiB
Markdown
# craft-stream-codecs
|
||
|
||
Byte-stream and bi-level image codecs that PDF, PostScript and TIFF share. The crate knows no
|
||
container: a caller hands it bytes and parameters. A PDF `/Filter` chain (stage order, limits
|
||
across stages, Flate, accounting) belongs to `craft-pdf`, which builds on this crate; a TIFF
|
||
reader can use the same LZW, predictor, CCITT and JBIG2 code.
|
||
|
||
- **Licence:** MIT OR Apache-2.0. Written from ISO 32000-2 §7.4, TIFF 6.0 §14 (predictor 2) and
|
||
RFC 2083 §6 (PNG filters). CCITT Group 4 encoding (ITU-T T.6) is the `fax` crate's (MIT). CCITT
|
||
decoding (T.4 and T.6) is `hayro-ccitt`'s (MIT OR Apache-2.0), bounded here: this crate has
|
||
no CCITT decoder of its own, and no JBIG2 decoder (that is `hayro-jbig2`, which the tests
|
||
read the encoder's output back with). JBIG2 encoding
|
||
is written from the public ISO/IEC 14492 Final Committee Draft (WG1 N1359, 1999); Annex H.2
|
||
checks the arithmetic coder byte for byte.
|
||
- No `unsafe`. Never panics on input.
|
||
- From PdfCraft's `pdfcraft-filters` crate (revision `80e26e674d1aa33078e83c8139875047f3289eb6`):
|
||
its codec modules, moved whole. Its filter chain and Flate stay with the PDF code.
|
||
|
||
## API
|
||
|
||
```rust
|
||
pub struct Params { predictor, colors, bits_per_component, columns, early_change } // i64s; Default = 1, 1, 8, 1, 1
|
||
pub enum CodecError { Corrupt { filter, detail }, LimitExceeded(usize), Unsupported(String), Spent }
|
||
pub struct Failure { error, partial, discarded } // what a decoder decoded before it failed
|
||
pub type Step = Result<Vec<u8>, Failure>;
|
||
pay(work: &mut u64, steps) -> Result<(), CodecError> // an allowance shared across a run of images
|
||
|
||
lzw::decode(data, early_change, max) -> Step; lzw::encode(data, early_change) -> Vec<u8>
|
||
ascii85::decode(data, max) -> Step; ascii85::encode(data) -> Vec<u8>
|
||
asciihex::decode(data, max) -> Step; asciihex::encode(data) -> Vec<u8>
|
||
runlength::decode(data, max) -> Step; runlength::encode(data) -> Vec<u8>
|
||
predictor::decode(¶ms, data, name, rows) -> Step; predictor::encode(¶ms, data) -> Result<Vec<u8>, CodecError>
|
||
|
||
pub struct CcittParams { k, columns, rows, end_of_line, encoded_byte_align, end_of_block, black_is_1 }
|
||
decode_ccitt_within(data, ¶ms, max_rows, work: &mut u64) -> Result<Vec<u8>, CodecError>
|
||
encode_g4(data, columns, rows) -> Result<Vec<u8>, CodecError>
|
||
|
||
encode_jbig2_generic(data, columns, rows) -> Result<Vec<u8>, CodecError>
|
||
encode_jbig2(data, columns, rows) -> Result<Vec<u8>, CodecError>
|
||
encode_jbig2_shared(&[(data, columns, rows)]) -> Result<Option<SharedJbig2>, CodecError>
|
||
```
|
||
|
||
`max` bounds a decoder's output and gives `LimitExceeded`. `Corrupt` names the codec in `filter`
|
||
by its PDF filter name. Bi-level images are rows of 1-bit samples, most significant bit first,
|
||
each row on a new byte.
|
||
|
||
## Behaviour
|
||
|
||
| Codec | Decode | Encode |
|
||
|---|---|---|
|
||
| LZW | 9–12-bit MSB-first codes, clear (256), end (257), early change on or off; a missing end code or initial clear is tolerated; a full table stops growing | greedy, leading clear, clear when the table fills, end code |
|
||
| Predictors | 2 = TIFF (1/2/4/8/16 bits per component), 10–15 = PNG with per-row tags 0–4; partial final rows decoded; bad parameters or tags are `Corrupt`; with `rows`, data that is exactly that many rows without tag bytes is taken as the samples and reported as damage | 2, 10 None, 11 Sub, 12 Up, 13 Average, 14 Paeth, 15 per-row optimum |
|
||
| ASCIIHex | white space ignored, odd digit padded with 0, `>` ends (optional), other characters are `Corrupt` | upper case, newline every 64 digits, `>` |
|
||
| ASCII85 | `<~` prefix, `z`, white space, `~>` (or bare `~`, or none), final partial group; `z` inside a group, a 1-character final group, overflow or bad characters are `Corrupt` | `z` for zero groups, newline every 75 characters, `~>` |
|
||
| RunLength | 0–127 literal, 129–255 repeat, 128 ends (optional); a truncated run is `Corrupt` | runs of 2 or more repeat, literals up to 128, 128 |
|
||
| CCITT fax | Group 3 (1-D and 2-D) and Group 4 through `hayro-ccitt`, as rows of 1-bit samples, black 0 unless `black_is_1`, at most `max_rows` rows (fewer with `rows`), the rows before any damage, up to `MAX_CCITT_COLUMNS` (1,048,576) samples a row; the rows are paid for from `work` before they are decoded | `encode_g4`: Group 4 with an end-of-block mark, 0 bits coded black; up to `MAX_G4_COLUMNS` (32,767) samples a row |
|
||
| JBIG2 | not here: `hayro-jbig2` | `encode_jbig2_generic`: one immediate lossless generic region (template 0, typical prediction, MQ coder). `encode_jbig2`: the smaller of that and symbol coding (exact copies only, so the stream decodes to the same bits). `encode_jbig2_shared`: a group of images sharing one symbol dictionary (the PDF `/JBIG2Globals` data) |
|
||
|
||
The limits of the JBIG2 encoder (symbols per plan, instances per text region, marks, runs) are
|
||
those `hayro-jbig2` reads back; they are documented on the constants in `src/jbig2/symbols.rs`.
|
||
|
||
## Tests
|
||
|
||
- Unit tests per codec with hand-computed vectors (the ISO 32000-2 LZW example, PNG and TIFF rows).
|
||
- LZW is cross-checked against `weezl` (dev-dependency) in both directions for both early-change settings.
|
||
- `ccitt.rs`: decoding gives back the rows `encode_g4` was given; Group 3 layouts over seeded
|
||
pictures; Group 4 output decoded by `hayro-ccitt` matches the input bits, with property tests
|
||
over bitmaps of noise and of runs; any input returns rather than panics.
|
||
- `mq.rs`: the arithmetic coder reproduces Annex H.2's 30 bytes from its 256 decisions.
|
||
- `jbig2.rs`, `jbig2/symbols.rs`: output decoded by `hayro-jbig2` matches the input bits for
|
||
every coding, plan and strip size, with property tests; size and limit refusals.
|
||
|
||
## Not here
|
||
|
||
A bounded JBIG2 decoding entry (`decode_jbig2_within` in PdfCraft): it needs the caller-owned
|
||
work allowance PdfCraft added to its `hayro-jbig2` (`Image::decode_within`, `charge_reading`),
|
||
which the copy vendored here does not have yet. Flate (a container's choice of zlib settings and tolerances), DCT and JPEG 2000, CCITT Group 3
|
||
encoding.
|