1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! DotCode (AIM ISS DotCode Rev 4.0) encoder and structural decoder.
//!
//! DotCode is a sparse 2D *dot matrix* designed for high-speed industrial printing
//! (thermal/inkjet). Data is compacted into a stream of base-113 codewords through a
//! Code 128-style Code Set A/B/C state machine (with a binary/byte mode reached via
//! an upper-shift or binary latch), protected by Reed–Solomon error correction over
//! the prime field GF(113), then folded onto a checkerboard of dots.
//!
//! Layout:
//! - `tables` — the 9-bit Annex C dot patterns and their reverse lookup.
//! - `rs` — GF(113) prime-field arithmetic and Reed–Solomon encoding.
//! - [`encode`] — the A/B/C/binary encodation, sizing, padding, masking and fold.
//! - [`decode`] — the inverse: unfold, un-mask, RS-verify and segment reconstruction.
//!
//! ## Coordinate / checkerboard convention
//!
//! The output is an [`Encoding::Matrix`](crate::output::Encoding::Matrix) of
//! `width × height` modules where a **dark module is a printed dot**. Only cells with
//! `(x + y)` even carry a dot ("checkerboard"); all other cells are always light.
//! `width + height` is always odd, so exactly one dimension is odd. The codeword bit
//! stream (2 mask bits followed by 9 bits per codeword, then lit-dot padding) is
//! folded horizontally when the height is odd and vertically when the width is odd,
//! with six reserved corner dots carrying the final six bits — matching AIM ISS
//! DotCode Rev 4.0 Annex A. [`BitMatrix::get(x, y)`](crate::output::BitMatrix::get)
//! is column `x`, row `y`.
//!
//! ## Lossless round-trip
//!
//! [`DotCodeMeta`] pins the exact **unmasked data codewords** (post-padding),
//! the symbol `width`/`height`, and the data `mask` (`0..=3`). The encoder renders
//! straight from these — applying the mask, appending the Reed–Solomon check words,
//! and folding — so `encode(decode(x)) == x` byte-for-byte regardless of how the
//! same payload could otherwise have been encoded. The payload [`Segment`]s carried
//! alongside are a human-readable reconstruction and are not consulted on re-encode.
//!
//! ## Deviations / cut scope
//!
//! - **Data-mask corner-forcing** (the masks 4–7 fallback that lights the six corner
//! dots) is not applied. Those masks rely on Reed–Solomon correction to repair the
//! overwritten dots; the encoder instead always emits a spec-valid mask `0..=3`,
//! keeping the round-trip exact. Mask selection otherwise matches the reference
//! scoring of masks `0..=3`.
//! - **Structured Append** and multi-segment **ECI** planning are not implemented in
//! the fresh-input builder (single-segment ECI is). Reader-init (FNC3) is decodable
//! but not exposed as a build option.
//! - The decoder verifies the Reed–Solomon check words but does not perform error
//! correction (it targets clean, encoder-produced module data).
//!
//! [`Symbol`]: crate::Symbol
//! [`Segment`]: crate::Segment
//! [`BitMatrix`]: crate::output::BitMatrix
pub use DotCodeDecoder;
pub use DotCodeEncoder;
/// Minimum symbol dimension (modules) in either axis.
pub const MIN_SIZE: usize = 5;
/// Maximum symbol dimension (modules) in either axis.
pub const MAX_SIZE: usize = 200;
/// Parameters required to re-encode a DotCode symbol identically (lossless
/// round-trip).
///
/// [`DotCodeMeta::codewords`] is the exact sequence of **unmasked** data codewords
/// (each `0..=112`), including any padding codewords, in symbol order. Together with
/// the geometry and mask this fully determines the module matrix: the encoder
/// applies the mask, appends the GF(113) Reed–Solomon check words and folds the
/// result onto the checkerboard.