initial commit

This commit is contained in:
2026-09-25 23:32:29 +02:00
commit fff8b677f8
114 changed files with 84233 additions and 0 deletions
+836
View File
@@ -0,0 +1,836 @@
package pdf
// CCITTFaxDecode -- ITU-T T.4 (Group 3) and T.6 (Group 4) facsimile coding.
//
// ISO 32000-2, 7.4.6. The filter reconstructs a bi-level image that was
// encoded with the one-dimensional modified Huffman code (MH), the
// two-dimensional modified READ code (MR), or the pure two-dimensional
// modified modified READ code (MMR / Group 4).
//
// OUTPUT CONVENTION -- image.odin depends on this, so it is stated precisely:
//
// * One bit per pixel, most significant bit first within each byte, so
// pixel `x` of a row lives in bit `7 - (x & 7)` of byte `x >> 3`.
// * Each row starts on a byte boundary; the trailing bits of the last byte
// of a row are padding and are set to the white value.
// * With `black_is_1 == false` (the default, /BlackIs1 false) a black pixel
// is a 0 bit and a white pixel is a 1 bit. With `black_is_1 == true` the
// two are exchanged.
//
// That is exactly the 1-bit-per-component sample array an image XObject
// expects *before* /Decode is applied, which is why /BlackIs1 lives in the
// filter's parameters rather than in the image dictionary.
//
// The returned buffer holds `len(out) / ((columns + 7) / 8)` rows. That may be
// fewer than `p.rows` when the data runs out early: the filter returns the
// rows it managed to decode rather than failing, so a truncated fax still
// shows what was received. Callers that need exactly `p.rows` rows must pad.
// ---------------------------------------------------------------------------
// Limits
//
// Every one of these bounds a quantity that came out of the file.
// ---------------------------------------------------------------------------
// A row wider than this is not an image anyone scanned. T.4 defines paper
// widths up to 2432 pixels and its make-up codes stop at 2560; a 600 dpi A3
// scan reaches ~10000. 65536 is far past all of them and still keeps the two
// `columns + 8` changing-element lines to about a megabyte.
@(private)
MAX_CCITT_COLUMNS :: 1 << 16
// Rows decoded before the filter gives up. A2 at 400 dpi is ~9000 rows, so
// this is only ever reached by a stream designed to be reached.
@(private)
MAX_CCITT_ROWS :: 1 << 20
// Total decoded bytes. Matches MAX_BITMAP_PIXELS at one bit per pixel, so an
// image this filter accepts is one the rasteriser would also accept.
@(private)
MAX_CCITT_BYTES :: MAX_BITMAP_PIXELS / 8
// Fill bits tolerated before an EOL. T.4 allows fill of any length; a real
// encoder uses it to pad a line out to the minimum transmission time, which
// at 2400 baud is a few hundred bits, never tens of thousands.
@(private)
MAX_CCITT_FILL_BITS :: 1 << 16
// Make-up codes chained before a terminating code. T.4 needs at most one for
// widths up to 2623 and the extended codes let an encoder chain more for
// wider images; 64 of them already codes a run of 163840.
@(private)
MAX_CCITT_MAKEUP_CHAIN :: 64
// Ccitt_Params mirrors the CCITTFaxDecode parameter dictionary
// (ISO 32000-2, table 12). The zero value is *not* the PDF default: use
// `ccitt_default_params` or set `columns` and `end_of_block` yourself.
Ccitt_Params :: struct {
// /K. Negative: pure two-dimensional (Group 4, MMR). Zero: pure
// one-dimensional (Group 3 1-D, MH). Positive: mixed, each line tagged
// one- or two-dimensional after its EOL.
k: int,
// /Columns, pixels per row. Default 1728.
columns: int,
// /Rows. Zero means "unknown": decode until the data runs out or an RTC.
rows: int,
// /BlackIs1. False (the default) means a 0 bit is black.
black_is_1: bool,
// /EncodedByteAlign: every encoded line begins on a byte boundary.
byte_align: bool,
// /EndOfLine: the encoded data is expected to carry EOL codes. EOLs are
// accepted whether or not this is set -- producers set it inconsistently
// and an EOL is unambiguous in the bit stream -- so it only records the
// producer's intent.
end_of_line: bool,
// /EndOfBlock. Default true. When false the caller is asserting that
// `rows` is authoritative and that whatever follows the image is not
// ours to interpret. An RTC/EOFB still ends decoding either way, because
// no valid image data can follow one.
end_of_block: bool,
}
// ccitt_default_params returns the parameter defaults of ISO 32000-2 table 12.
ccitt_default_params :: proc() -> Ccitt_Params {
return Ccitt_Params{k = 0, columns = 1728, rows = 0, black_is_1 = false,
byte_align = false, end_of_line = false, end_of_block = true}
}
// ---------------------------------------------------------------------------
// Bit reader
//
// Reads MSB-first and pads with zero bits past the end of the data, so a
// peek near the end never has to be special-cased; `ccitt_bits_left` is what
// decides whether a code is really there.
// ---------------------------------------------------------------------------
@(private)
Ccitt_Bits :: struct {
data: []byte,
pos: int, // bit offset from the start of `data`
end: int, // len(data) * 8
}
@(private)
ccitt_bits_make :: proc(data: []byte) -> Ccitt_Bits {
return Ccitt_Bits{data = data, pos = 0, end = len(data) * 8}
}
@(private)
ccitt_bits_left :: proc(b: ^Ccitt_Bits) -> int {
return b.end - b.pos
}
// ccitt_bits_peek returns the next `n` bits (n <= 24) without consuming them.
@(private)
ccitt_bits_peek :: proc(b: ^Ccitt_Bits, n: int) -> u32 {
if n <= 0 {
return 0
}
n := n
if n > 24 {
n = 24
}
// Four bytes cover any 24-bit read starting at any bit offset.
i := b.pos >> 3
acc: u32 = 0
for k in 0 ..< 4 {
v: u32 = 0
if i + k < len(b.data) {
v = u32(b.data[i + k])
}
acc = acc << 8 | v
}
acc <<= uint(b.pos & 7)
return acc >> uint(32 - n)
}
@(private)
ccitt_bits_skip :: proc(b: ^Ccitt_Bits, n: int) {
b.pos += n
if b.pos > b.end {
b.pos = b.end
}
}
// ccitt_bits_align moves to the next byte boundary (/EncodedByteAlign).
@(private)
ccitt_bits_align :: proc(b: ^Ccitt_Bits) {
b.pos = min((b.pos + 7) & ~int(7), b.end)
}
// ---------------------------------------------------------------------------
// Run-length codes
// ---------------------------------------------------------------------------
@(private)
Ccitt_Code :: struct {
bits: u8, // code length
code: u16, // the code, right-aligned in `bits` bits
run: u16, // run length it stands for
}
// White run lengths: T.4 tables 1 and 3, plus the shared extended make-up codes of table 3.
@(private, rodata)
CCITT_WHITE := [104]Ccitt_Code{
{bits = 4, code = 0b0111, run = 2},
{bits = 4, code = 0b1000, run = 3},
{bits = 4, code = 0b1011, run = 4},
{bits = 4, code = 0b1100, run = 5},
{bits = 4, code = 0b1110, run = 6},
{bits = 4, code = 0b1111, run = 7},
{bits = 5, code = 0b00111, run = 10},
{bits = 5, code = 0b01000, run = 11},
{bits = 5, code = 0b10010, run = 128},
{bits = 5, code = 0b10011, run = 8},
{bits = 5, code = 0b10100, run = 9},
{bits = 5, code = 0b11011, run = 64},
{bits = 6, code = 0b000011, run = 13},
{bits = 6, code = 0b000111, run = 1},
{bits = 6, code = 0b001000, run = 12},
{bits = 6, code = 0b010111, run = 192},
{bits = 6, code = 0b011000, run = 1664},
{bits = 6, code = 0b101010, run = 16},
{bits = 6, code = 0b101011, run = 17},
{bits = 6, code = 0b110100, run = 14},
{bits = 6, code = 0b110101, run = 15},
{bits = 7, code = 0b0000011, run = 22},
{bits = 7, code = 0b0000100, run = 23},
{bits = 7, code = 0b0001000, run = 20},
{bits = 7, code = 0b0001100, run = 19},
{bits = 7, code = 0b0010011, run = 26},
{bits = 7, code = 0b0010111, run = 21},
{bits = 7, code = 0b0011000, run = 28},
{bits = 7, code = 0b0100100, run = 27},
{bits = 7, code = 0b0100111, run = 18},
{bits = 7, code = 0b0101000, run = 24},
{bits = 7, code = 0b0101011, run = 25},
{bits = 7, code = 0b0110111, run = 256},
{bits = 8, code = 0b00000010, run = 29},
{bits = 8, code = 0b00000011, run = 30},
{bits = 8, code = 0b00000100, run = 45},
{bits = 8, code = 0b00000101, run = 46},
{bits = 8, code = 0b00001010, run = 47},
{bits = 8, code = 0b00001011, run = 48},
{bits = 8, code = 0b00010010, run = 33},
{bits = 8, code = 0b00010011, run = 34},
{bits = 8, code = 0b00010100, run = 35},
{bits = 8, code = 0b00010101, run = 36},
{bits = 8, code = 0b00010110, run = 37},
{bits = 8, code = 0b00010111, run = 38},
{bits = 8, code = 0b00011010, run = 31},
{bits = 8, code = 0b00011011, run = 32},
{bits = 8, code = 0b00100100, run = 53},
{bits = 8, code = 0b00100101, run = 54},
{bits = 8, code = 0b00101000, run = 39},
{bits = 8, code = 0b00101001, run = 40},
{bits = 8, code = 0b00101010, run = 41},
{bits = 8, code = 0b00101011, run = 42},
{bits = 8, code = 0b00101100, run = 43},
{bits = 8, code = 0b00101101, run = 44},
{bits = 8, code = 0b00110010, run = 61},
{bits = 8, code = 0b00110011, run = 62},
{bits = 8, code = 0b00110100, run = 63},
{bits = 8, code = 0b00110101, run = 0},
{bits = 8, code = 0b00110110, run = 320},
{bits = 8, code = 0b00110111, run = 384},
{bits = 8, code = 0b01001010, run = 59},
{bits = 8, code = 0b01001011, run = 60},
{bits = 8, code = 0b01010010, run = 49},
{bits = 8, code = 0b01010011, run = 50},
{bits = 8, code = 0b01010100, run = 51},
{bits = 8, code = 0b01010101, run = 52},
{bits = 8, code = 0b01011000, run = 55},
{bits = 8, code = 0b01011001, run = 56},
{bits = 8, code = 0b01011010, run = 57},
{bits = 8, code = 0b01011011, run = 58},
{bits = 8, code = 0b01100100, run = 448},
{bits = 8, code = 0b01100101, run = 512},
{bits = 8, code = 0b01100111, run = 640},
{bits = 8, code = 0b01101000, run = 576},
{bits = 9, code = 0b010011000, run = 1472},
{bits = 9, code = 0b010011001, run = 1536},
{bits = 9, code = 0b010011010, run = 1600},
{bits = 9, code = 0b010011011, run = 1728},
{bits = 9, code = 0b011001100, run = 704},
{bits = 9, code = 0b011001101, run = 768},
{bits = 9, code = 0b011010010, run = 832},
{bits = 9, code = 0b011010011, run = 896},
{bits = 9, code = 0b011010100, run = 960},
{bits = 9, code = 0b011010101, run = 1024},
{bits = 9, code = 0b011010110, run = 1088},
{bits = 9, code = 0b011010111, run = 1152},
{bits = 9, code = 0b011011000, run = 1216},
{bits = 9, code = 0b011011001, run = 1280},
{bits = 9, code = 0b011011010, run = 1344},
{bits = 9, code = 0b011011011, run = 1408},
{bits = 11, code = 0b00000001000, run = 1792},
{bits = 11, code = 0b00000001100, run = 1856},
{bits = 11, code = 0b00000001101, run = 1920},
{bits = 12, code = 0b000000010010, run = 1984},
{bits = 12, code = 0b000000010011, run = 2048},
{bits = 12, code = 0b000000010100, run = 2112},
{bits = 12, code = 0b000000010101, run = 2176},
{bits = 12, code = 0b000000010110, run = 2240},
{bits = 12, code = 0b000000010111, run = 2304},
{bits = 12, code = 0b000000011100, run = 2368},
{bits = 12, code = 0b000000011101, run = 2432},
{bits = 12, code = 0b000000011110, run = 2496},
{bits = 12, code = 0b000000011111, run = 2560},
}
// Black run lengths: T.4 tables 2 and 3, plus the shared extended make-up codes.
@(private, rodata)
CCITT_BLACK := [104]Ccitt_Code{
{bits = 2, code = 0b10, run = 3},
{bits = 2, code = 0b11, run = 2},
{bits = 3, code = 0b010, run = 1},
{bits = 3, code = 0b011, run = 4},
{bits = 4, code = 0b0010, run = 6},
{bits = 4, code = 0b0011, run = 5},
{bits = 5, code = 0b00011, run = 7},
{bits = 6, code = 0b000100, run = 9},
{bits = 6, code = 0b000101, run = 8},
{bits = 7, code = 0b0000100, run = 10},
{bits = 7, code = 0b0000101, run = 11},
{bits = 7, code = 0b0000111, run = 12},
{bits = 8, code = 0b00000100, run = 13},
{bits = 8, code = 0b00000111, run = 14},
{bits = 9, code = 0b000011000, run = 15},
{bits = 10, code = 0b0000001000, run = 18},
{bits = 10, code = 0b0000001111, run = 64},
{bits = 10, code = 0b0000010111, run = 16},
{bits = 10, code = 0b0000011000, run = 17},
{bits = 10, code = 0b0000110111, run = 0},
{bits = 11, code = 0b00000001000, run = 1792},
{bits = 11, code = 0b00000001100, run = 1856},
{bits = 11, code = 0b00000001101, run = 1920},
{bits = 11, code = 0b00000010111, run = 24},
{bits = 11, code = 0b00000011000, run = 25},
{bits = 11, code = 0b00000101000, run = 23},
{bits = 11, code = 0b00000110111, run = 22},
{bits = 11, code = 0b00001100111, run = 19},
{bits = 11, code = 0b00001101000, run = 20},
{bits = 11, code = 0b00001101100, run = 21},
{bits = 12, code = 0b000000010010, run = 1984},
{bits = 12, code = 0b000000010011, run = 2048},
{bits = 12, code = 0b000000010100, run = 2112},
{bits = 12, code = 0b000000010101, run = 2176},
{bits = 12, code = 0b000000010110, run = 2240},
{bits = 12, code = 0b000000010111, run = 2304},
{bits = 12, code = 0b000000011100, run = 2368},
{bits = 12, code = 0b000000011101, run = 2432},
{bits = 12, code = 0b000000011110, run = 2496},
{bits = 12, code = 0b000000011111, run = 2560},
{bits = 12, code = 0b000000100100, run = 52},
{bits = 12, code = 0b000000100111, run = 55},
{bits = 12, code = 0b000000101000, run = 56},
{bits = 12, code = 0b000000101011, run = 59},
{bits = 12, code = 0b000000101100, run = 60},
{bits = 12, code = 0b000000110011, run = 320},
{bits = 12, code = 0b000000110100, run = 384},
{bits = 12, code = 0b000000110101, run = 448},
{bits = 12, code = 0b000000110111, run = 53},
{bits = 12, code = 0b000000111000, run = 54},
{bits = 12, code = 0b000001010010, run = 50},
{bits = 12, code = 0b000001010011, run = 51},
{bits = 12, code = 0b000001010100, run = 44},
{bits = 12, code = 0b000001010101, run = 45},
{bits = 12, code = 0b000001010110, run = 46},
{bits = 12, code = 0b000001010111, run = 47},
{bits = 12, code = 0b000001011000, run = 57},
{bits = 12, code = 0b000001011001, run = 58},
{bits = 12, code = 0b000001011010, run = 61},
{bits = 12, code = 0b000001011011, run = 256},
{bits = 12, code = 0b000001100100, run = 48},
{bits = 12, code = 0b000001100101, run = 49},
{bits = 12, code = 0b000001100110, run = 62},
{bits = 12, code = 0b000001100111, run = 63},
{bits = 12, code = 0b000001101000, run = 30},
{bits = 12, code = 0b000001101001, run = 31},
{bits = 12, code = 0b000001101010, run = 32},
{bits = 12, code = 0b000001101011, run = 33},
{bits = 12, code = 0b000001101100, run = 40},
{bits = 12, code = 0b000001101101, run = 41},
{bits = 12, code = 0b000011001000, run = 128},
{bits = 12, code = 0b000011001001, run = 192},
{bits = 12, code = 0b000011001010, run = 26},
{bits = 12, code = 0b000011001011, run = 27},
{bits = 12, code = 0b000011001100, run = 28},
{bits = 12, code = 0b000011001101, run = 29},
{bits = 12, code = 0b000011010010, run = 34},
{bits = 12, code = 0b000011010011, run = 35},
{bits = 12, code = 0b000011010100, run = 36},
{bits = 12, code = 0b000011010101, run = 37},
{bits = 12, code = 0b000011010110, run = 38},
{bits = 12, code = 0b000011010111, run = 39},
{bits = 12, code = 0b000011011010, run = 42},
{bits = 12, code = 0b000011011011, run = 43},
{bits = 13, code = 0b0000001001010, run = 640},
{bits = 13, code = 0b0000001001011, run = 704},
{bits = 13, code = 0b0000001001100, run = 768},
{bits = 13, code = 0b0000001001101, run = 832},
{bits = 13, code = 0b0000001010010, run = 1280},
{bits = 13, code = 0b0000001010011, run = 1344},
{bits = 13, code = 0b0000001010100, run = 1408},
{bits = 13, code = 0b0000001010101, run = 1472},
{bits = 13, code = 0b0000001011010, run = 1536},
{bits = 13, code = 0b0000001011011, run = 1600},
{bits = 13, code = 0b0000001100100, run = 1664},
{bits = 13, code = 0b0000001100101, run = 1728},
{bits = 13, code = 0b0000001101100, run = 512},
{bits = 13, code = 0b0000001101101, run = 576},
{bits = 13, code = 0b0000001110010, run = 896},
{bits = 13, code = 0b0000001110011, run = 960},
{bits = 13, code = 0b0000001110100, run = 1024},
{bits = 13, code = 0b0000001110101, run = 1088},
{bits = 13, code = 0b0000001110110, run = 1152},
{bits = 13, code = 0b0000001110111, run = 1216},
}
// ccitt_lookup reads one run-length code. The tables are sorted by code
// length, so peeking once per distinct length and walking them in order
// decodes the shortest matching code -- which, the code being prefix-free, is
// the only matching code.
@(private)
ccitt_lookup :: proc(b: ^Ccitt_Bits, table: []Ccitt_Code) -> (run: int, ok: bool) {
peeked_len := -1
peeked: u32 = 0
for e in table {
n := int(e.bits)
if n != peeked_len {
peeked_len = n
peeked = ccitt_bits_peek(b, n)
}
if u32(e.code) == peeked {
// The zero padding past the end of the data can complete a code
// that was never written; refuse it rather than invent pixels.
if ccitt_bits_left(b) < n {
return 0, false
}
b.pos += n
return int(e.run), true
}
}
return 0, false
}
// ccitt_run reads a complete run: zero or more make-up codes followed by one
// terminating code. The total is clamped to `limit`, which is the row width:
// a run longer than the row is malformed and clamping it is cheaper than
// carrying an overflowing position around.
@(private)
ccitt_run :: proc(b: ^Ccitt_Bits, black: bool, limit: int) -> (run: int, ok: bool) {
table := CCITT_WHITE[:]
if black {
table = CCITT_BLACK[:]
}
total := 0
for _ in 0 ..< MAX_CCITT_MAKEUP_CHAIN {
r, got := ccitt_lookup(b, table)
if !got {
return 0, false
}
total += r
if total > limit {
total = limit
}
if r < 64 {
return total, true
}
}
return 0, false
}
// ---------------------------------------------------------------------------
// Two-dimensional coding modes (T.4 table 4 / T.6)
// ---------------------------------------------------------------------------
@(private)
Ccitt_Mode :: enum u8 {
Pass, // 0001
Horizontal, // 001
V0, // 1
VR1, // 011
VR2, // 000011
VR3, // 0000011
VL1, // 010
VL2, // 000010
VL3, // 0000010
Extension, // 0000001 + 3 bits
Error,
}
@(private, rodata)
CCITT_VERTICAL_DELTA := [Ccitt_Mode]int{
.Pass = 0, .Horizontal = 0, .Extension = 0, .Error = 0,
.V0 = 0, .VR1 = 1, .VR2 = 2, .VR3 = 3, .VL1 = -1, .VL2 = -2, .VL3 = -3,
}
// ccitt_mode reads one 2-D mode code. All of them fit in seven bits, and no
// mode code has more than six leading zeros, so seven zero bits mean either an
// EOL or garbage -- either way, not a mode.
@(private)
ccitt_mode :: proc(b: ^Ccitt_Bits) -> (mode: Ccitt_Mode, ok: bool) {
v := ccitt_bits_peek(b, 7)
m: Ccitt_Mode
n: int
switch {
case v & 0b1000000 != 0: m, n = .V0, 1
case v >> 4 == 0b011: m, n = .VR1, 3
case v >> 4 == 0b010: m, n = .VL1, 3
case v >> 4 == 0b001: m, n = .Horizontal, 3
case v >> 3 == 0b0001: m, n = .Pass, 4
case v >> 1 == 0b000011: m, n = .VR2, 6
case v >> 1 == 0b000010: m, n = .VL2, 6
case v == 0b0000011: m, n = .VR3, 7
case v == 0b0000010: m, n = .VL3, 7
case v == 0b0000001: m, n = .Extension, 7
case: return .Error, false
}
if ccitt_bits_left(b) < n {
return .Error, false
}
b.pos += n
return m, true
}
// ccitt_try_eol consumes an EOL (eleven or more zero bits then a one) together
// with any fill that precedes it, and reports whether it found one. On failure
// the reader is left exactly where it was: no code in either run-length table
// has eight leading zeros, so a genuine code can never be mistaken for fill.
@(private)
ccitt_try_eol :: proc(b: ^Ccitt_Bits) -> bool {
save := b.pos
zeros := 0
for zeros < MAX_CCITT_FILL_BITS && ccitt_bits_left(b) > 0 && ccitt_bits_peek(b, 1) == 0 {
b.pos += 1
zeros += 1
}
if zeros >= 11 && ccitt_bits_left(b) > 0 && ccitt_bits_peek(b, 1) == 1 {
b.pos += 1
return true
}
b.pos = save
return false
}
// ---------------------------------------------------------------------------
// Rows
//
// A row is decoded into its changing elements: the positions, ascending, at
// which the colour changes, starting from white at pixel 0. Element 0, 2, 4 …
// are white-to-black transitions and 1, 3, 5 … are black-to-white ones. That
// is the form the 2-D coder needs for the *next* row's reference line, and it
// turns painting into a walk over black spans.
// ---------------------------------------------------------------------------
// ccitt_find_b locates b1, the first changing element on the reference line to
// the right of a0 whose colour is opposite to the current colour, and b2, the
// element after it. `cursor` is carried between calls within a row: a0 never
// decreases, so the scan never has to restart.
@(private)
ccitt_find_b :: proc(ref: []int, ref_n, columns, a0, color: int, cursor: ^int) -> (b1: int, b2: int) {
i := cursor^
if i < 0 {
i = 0
}
for i < ref_n && ref[i] <= a0 {
i += 1
}
cursor^ = i
// ref[i] has colour black for even i, white for odd i; we want the
// opposite of `color`, which is the same parity as `color` itself.
if (i & 1) != (color & 1) {
i += 1
}
b1 = columns
if i < ref_n {
b1 = ref[i]
}
b2 = columns
if i + 1 < ref_n {
b2 = ref[i + 1]
}
return
}
// ccitt_row_1d decodes one modified-Huffman row. `ok` is false when a code was
// unreadable, in which case the elements decoded so far are still returned.
@(private)
ccitt_row_1d :: proc(b: ^Ccitt_Bits, cur: []int, columns: int) -> (n: int, ok: bool) {
a0 := 0
black := false
// A row cannot hold more than `columns` runs of non-zero length, and a
// zero-length run costs at least eight bits, so this only ever fires on
// deliberately hostile data.
fuel := 2 * columns + 64
for a0 < columns && n < len(cur) && fuel > 0 {
fuel -= 1
run, got := ccitt_run(b, black, columns)
if !got {
return n, false
}
a0 = min(a0 + run, columns)
cur[n] = a0
n += 1
black = !black
}
return n, true
}
// ccitt_row_2d decodes one modified-READ row against reference line `ref`.
@(private)
ccitt_row_2d :: proc(b: ^Ccitt_Bits, cur: []int, ref: []int, ref_n, columns: int) -> (n: int, ok: bool) {
a0 := -1 // an imaginary white element just left of the row
black := false
cursor := 0
fuel := 2 * columns + 64
for a0 < columns && fuel > 0 {
fuel -= 1
color := 0
if black {
color = 1
}
mode, got := ccitt_mode(b)
if !got {
return n, false
}
switch mode {
case .Pass:
// The run continues past b2; no changing element is created.
_, b2 := ccitt_find_b(ref, ref_n, columns, a0, color, &cursor)
a0 = b2
case .Horizontal:
start := max(a0, 0)
r1, ok1 := ccitt_run(b, black, columns)
if !ok1 {
return n, false
}
r2, ok2 := ccitt_run(b, !black, columns)
if !ok2 {
return n, false
}
if n + 2 > len(cur) {
return n, false
}
a1 := min(start + r1, columns)
a2 := min(a1 + r2, columns)
cur[n] = a1
cur[n + 1] = a2
n += 2
a0 = a2
case .V0, .VR1, .VR2, .VR3, .VL1, .VL2, .VL3:
b1, _ := ccitt_find_b(ref, ref_n, columns, a0, color, &cursor)
a1 := clamp(b1 + CCITT_VERTICAL_DELTA[mode], 0, columns)
// A VL that would step left of a0 is malformed; pinning it to a0
// keeps the element list sorted, which the next row relies on.
a1 = max(a1, a0)
if n >= len(cur) {
return n, false
}
cur[n] = a1
n += 1
a0 = a1
black = !black
case .Extension:
// 2-D extensions (T.4 4.2.1.3.5) carry uncompressed mode, which
// no PDF producer emits. Stop here rather than desynchronise.
return n, false
case .Error:
return n, false
}
}
return n, true
}
// ccitt_paint sets pixels [from, to) of a packed 1-bpp row.
@(private)
ccitt_paint :: proc(row: []byte, from, to: int, one: bool) {
lo := max(from, 0)
hi := min(to, len(row) * 8)
fill: u8 = one ? 0xFF : 0x00
x := lo
for x < hi {
i := x >> 3
off := uint(x & 7)
if off == 0 && hi - x >= 8 {
last := i + (hi - x) / 8
for ; i < last; i += 1 {
row[i] = fill
}
x = last * 8
continue
}
n := min(8 - int(off), hi - x)
mask := u8(0xFF >> off) & u8(0xFF << uint(8 - int(off) - n))
if one {
row[i] |= mask
} else {
row[i] &~= mask
}
x += n
}
}
// ccitt_emit_row paints one row of packed output from its changing elements.
// A colour that never changes back runs to the end of the row -- which is what
// pass mode at the right margin means, and also the least surprising way to
// pad a row whose data ran out early.
@(private)
ccitt_emit_row :: proc(row: []byte, cur: []int, n, columns: int, black_is_1: bool) {
white: u8 = black_is_1 ? 0x00 : 0xFF
for i in 0 ..< len(row) {
row[i] = white
}
for i := 0; i < n; i += 2 {
start := cur[i]
stop := columns
if i + 1 < n {
stop = cur[i + 1]
}
ccitt_paint(row, start, stop, black_is_1)
}
}
// ---------------------------------------------------------------------------
// Entry point
// ---------------------------------------------------------------------------
// ccitt_columns is the width `ccitt_decode` actually decodes at, and
// ccitt_row_bytes the stride it lays its output rows out at.
//
// /Columns comes out of a file, so it cannot be used as written: a
// non-positive value means the format's own default -- 1728, the width of a
// fax page -- and anything past MAX_CCITT_COLUMNS is clamped to what this
// decoder will allocate for. Both are exposed because the image layer has to
// read the buffer back at exactly this stride, and deriving it there from the
// raw /Columns instead is how the two silently disagree and every row after
// the first starts at the wrong byte.
@(private)
ccitt_columns :: proc(p: Ccitt_Params) -> int {
columns := p.columns
if columns <= 0 {
columns = 1728
}
return min(columns, MAX_CCITT_COLUMNS)
}
@(private)
ccitt_row_bytes :: proc(p: Ccitt_Params) -> int {
return (ccitt_columns(p) + 7) / 8
}
// ccitt_decode decodes CCITTFaxDecode data to packed 1-bit-per-pixel rows.
// See the convention described at the top of this file.
//
// The result is allocated with `allocator` and belongs to the caller; free it
// with `delete`. So is the row buffer it grows out of, which is sized from
// /Rows -- a claim rather than a measurement -- and released again when not
// one row decodes. Give it scratch, not a Document arena, whose `delete` is a
// silent no-op that would keep the whole claim until `close`; `apply_filter`
// in filters.odin is where that is arranged.
//
// An error is returned only when not a single row could be
// decoded -- anything less is reported by returning fewer rows than `p.rows`.
ccitt_decode :: proc(data: []byte, p: Ccitt_Params, allocator := context.allocator) -> (out: []byte, err: Error) {
columns := ccitt_columns(p)
row_bytes := ccitt_row_bytes(p)
max_rows := MAX_CCITT_ROWS
if p.rows > 0 {
max_rows = min(max_rows, p.rows)
}
max_rows = min(max_rows, MAX_CCITT_BYTES / row_bytes)
// Every row consumes at least one bit (a lone V0), so the data itself caps
// the row count when /Rows is absent.
max_rows = min(max_rows, len(data) * 8)
if max_rows <= 0 {
return nil, .Bad_Ccitt_Data
}
// Two changing-element lines. `columns + 8` slots leave room for the
// zero-length runs a horizontal code may legally contain without the
// pushes ever running off the end.
slots := columns + 8
scratch, serr := make([]int, 2 * slots, context.allocator)
if serr != nil {
return nil, .Out_Of_Memory
}
defer delete(scratch, context.allocator)
ref := scratch[:slots]
cur := scratch[slots:]
ref_n := 0
init_rows := 8
if p.rows > 0 {
init_rows = min(p.rows, max_rows)
}
buf, berr := make([dynamic]byte, 0, init_rows * row_bytes, allocator)
if berr != nil {
return nil, .Out_Of_Memory
}
b := ccitt_bits_make(data)
two_d := p.k < 0
rows_done := 0
for rows_done < max_rows {
if p.byte_align {
ccitt_bits_align(&b)
}
// Fill, EOLs, and the 1-D/2-D tag bit that follows each EOL when
// /K > 0. Two EOLs with nothing between them are an RTC (G3) or an
// EOFB (G4): the image is over.
eols := 0
for eols < 2 {
if !ccitt_try_eol(&b) {
break
}
eols += 1
if p.k > 0 {
if ccitt_bits_left(&b) < 1 {
break
}
two_d = ccitt_bits_peek(&b, 1) == 0
b.pos += 1
}
}
if eols >= 2 || ccitt_bits_left(&b) <= 0 {
break
}
n, ok := 0, false
if two_d {
n, ok = ccitt_row_2d(&b, cur, ref, ref_n, columns)
} else {
n, ok = ccitt_row_1d(&b, cur, columns)
}
if n == 0 {
// Not even one changing element: an unknown code or the end of
// the data, not a row.
break
}
rerr := resize(&buf, len(buf) + row_bytes)
if rerr != nil {
break
}
ccitt_emit_row(buf[len(buf) - row_bytes:], cur, n, columns, p.black_is_1)
rows_done += 1
ref, cur = cur, ref
ref_n = n
if !ok {
break
}
}
if rows_done == 0 {
delete(buf)
return nil, .Bad_Ccitt_Data
}
_, _ = shrink(&buf)
return buf[:], .None
}