datamatrix/
placement.rs

1//! Arrangement of bits in a Data Matrix symbol.
2//!
3//! The module contains the struct [MatrixMap] which can be used to
4//! to iterate over the bit
5//! positions of each codeword in the final symbol, i.e., how the black squares are
6//! mapped to the encoded data as bytes. This is used to write
7//! the encoded data into a bitmap, and also to read it from a bitmap.
8//!
9//! An abstract bitmap struct [Bitmap] is the final output of encoding and the input
10//! for decoding. It also contains helpers for rendering.
11use alloc::{string::String, vec, vec::Vec};
12
13use crate::symbol_size::{SymbolList, SymbolSize};
14
15#[cfg(test)]
16use pretty_assertions::assert_eq;
17
18mod path;
19
20pub use path::PathSegment;
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum BitmapConversionError {
24    /// The alignment pattern is not correct.
25    Alignment,
26    /// The padding pattern is not correct.
27    Padding,
28    /// The width was zero.
29    ZeroWidth,
30    /// The provided data does not fit the given width.
31    DataSize,
32    /// No symbol size was found matching the data size.
33    SymbolSize,
34}
35
36/// Abstract "bit" type used in [MatrixMap].
37pub trait Bit: Clone + Copy + PartialEq + core::fmt::Debug {
38    const LOW: Self;
39    const HIGH: Self;
40}
41
42/// Representation of the bits in a Data Matrix symbol without alignment patterns.
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct MatrixMap<B: Bit> {
45    entries: Vec<B>,
46    width: usize,
47    height: usize,
48    extra_vertical_alignments: usize,
49    extra_horizontal_alignments: usize,
50    has_padding: bool,
51}
52
53impl<M: Bit> MatrixMap<M> {
54    /// Create a new, empty matrix for the given symbol size.
55    pub fn new(size: SymbolSize) -> Self {
56        let setup = size.block_setup();
57        let w = setup.content_width();
58        let h = setup.content_height();
59        Self {
60            entries: vec![M::LOW; w * h],
61            width: w,
62            height: h,
63            extra_vertical_alignments: setup.extra_vertical_alignments,
64            extra_horizontal_alignments: setup.extra_horizontal_alignments,
65            has_padding: size.has_padding_modules(),
66        }
67    }
68
69    /// Read the data from a bitmap.
70    ///
71    /// The argument `bits` shall reprersent a rectangular image, enumerated starting
72    /// from the top left corner in row-major order. The alignment patterns must be included.
73    pub fn try_from_bits(
74        bits: &[M],
75        width: usize,
76    ) -> Result<(Self, SymbolSize), BitmapConversionError>
77    where
78        M: PartialEq,
79    {
80        if width == 0 {
81            return Err(BitmapConversionError::ZeroWidth);
82        }
83        if bits.len() % width != 0 {
84            return Err(BitmapConversionError::DataSize);
85        }
86        let height = bits.len() / width;
87        let size = SymbolList::all()
88            .iter()
89            .find(|s| {
90                let bs = s.block_setup();
91                bs.width == width && bs.height == height
92            })
93            .ok_or(BitmapConversionError::SymbolSize)?;
94        let setup = size.block_setup();
95        let w = setup.content_width();
96        let h = setup.content_height();
97        let mut entries = Vec::with_capacity(w * h);
98
99        let blk_h = h / (setup.extra_horizontal_alignments + 1);
100        let blk_w = w / (setup.extra_vertical_alignments + 1);
101
102        for row_chunk in bits.chunks((blk_h + 2) * width) {
103            debug_assert_eq!(row_chunk.len(), (blk_h + 2) * width);
104
105            // first row must be alternating, the one before all HIGH
106            let first_row = &row_chunk[..width];
107            let last_row = &row_chunk[(blk_h + 1) * width..];
108            debug_assert_eq!(last_row.len(), width);
109            let alignment_ok = last_row.iter().all(|b| *b == M::HIGH)
110                && first_row
111                    .iter()
112                    .zip([M::HIGH, M::LOW].into_iter().cycle())
113                    .all(|(a, b)| *a == b);
114            if !alignment_ok {
115                return Err(BitmapConversionError::Alignment);
116            }
117
118            let rows = &row_chunk[width..(blk_h + 1) * width];
119            debug_assert_eq!(rows.len(), blk_h * width);
120            debug_assert_eq!(width % (blk_w + 2), 0);
121            let mut alignment_bit = M::LOW;
122            for (j, row) in rows.chunks(blk_w + 2).enumerate() {
123                debug_assert_eq!(row.len(), blk_w + 2);
124                if j % (setup.extra_vertical_alignments + 1) == 0 {
125                    alignment_bit = if alignment_bit == M::LOW {
126                        M::HIGH
127                    } else {
128                        M::LOW
129                    };
130                }
131                let alignment_ok = row[0] == M::HIGH && row[blk_w + 1] == alignment_bit;
132                if !alignment_ok {
133                    return Err(BitmapConversionError::Alignment);
134                }
135                entries.extend_from_slice(&row[1..blk_w + 1]);
136                debug_assert_eq!(row[1..=blk_w].len(), blk_w);
137            }
138        }
139        debug_assert_eq!(entries.len(), w * h);
140
141        if size.has_padding_modules() {
142            let padding_ok = entries[entries.len() - 2..] == [M::LOW, M::HIGH]
143                && entries[entries.len() - w - 2..entries.len() - w] == [M::HIGH, M::LOW];
144            if !padding_ok {
145                return Err(BitmapConversionError::Padding);
146            }
147        }
148
149        let matrix_map = Self {
150            entries,
151            width: w,
152            height: h,
153            extra_vertical_alignments: setup.extra_vertical_alignments,
154            extra_horizontal_alignments: setup.extra_horizontal_alignments,
155            has_padding: size.has_padding_modules(),
156        };
157        Ok((matrix_map, size))
158    }
159
160    /// Write a 4x4 padding pattern in the lower right corner if needed.
161    pub fn write_padding(&mut self) {
162        if self.has_padding {
163            *self.bit_mut(self.height - 2, self.width - 2) = M::HIGH;
164            *self.bit_mut(self.height - 1, self.width - 1) = M::HIGH;
165        }
166    }
167
168    /// Get the content of the matrix as a bitmap with alignment patterns added.
169    pub fn bitmap(&self) -> Bitmap<M> {
170        let h = self.height + 2 + 2 * self.extra_horizontal_alignments;
171        let w = self.width + 2 + 2 * self.extra_vertical_alignments;
172        let mut bits = vec![M::LOW; h * w];
173
174        let idx = |i: usize, j: usize| i * w + j;
175
176        // draw horizontal alignments
177        let extra_hor = self.extra_horizontal_alignments;
178        let blk_h = (h - 2 * (extra_hor + 1)) / (extra_hor + 1);
179        for i in 0..extra_hor {
180            let rows_before = 1 + (blk_h + 2) * i + blk_h;
181            for j in 0..w {
182                bits[idx(rows_before, j)] = M::HIGH;
183            }
184            for j in (0..w).step_by(2) {
185                bits[idx(rows_before + 1, j)] = M::HIGH;
186            }
187        }
188
189        // draw vertical alignments
190        let extra_ver = self.extra_vertical_alignments;
191        let blk_w = (w - 2 * (extra_ver + 1)) / (extra_ver + 1);
192        for j in 0..extra_ver {
193            let cols_before = 1 + (blk_w + 2) * j + blk_w;
194            for i in 1..h {
195                bits[idx(i, cols_before + 1)] = M::HIGH;
196            }
197            for i in (1..h).step_by(2) {
198                bits[idx(i, cols_before)] = M::HIGH;
199            }
200        }
201
202        for j in 0..w {
203            // draw bottom alignment
204            bits[idx(h - 1, j)] = M::HIGH;
205        }
206        for j in (0..w).step_by(2) {
207            // draw top alignment
208            bits[idx(0, j)] = M::HIGH;
209        }
210        for i in 0..h {
211            // draw left alignment
212            bits[idx(i, 0)] = M::HIGH;
213        }
214        for i in (1..h).step_by(2) {
215            // draw right alignment
216            bits[idx(i, w - 1)] = M::HIGH;
217        }
218
219        // copy the data
220        for (b_i, b) in self.entries.iter().enumerate() {
221            let mut i = b_i / self.width;
222            i += 1 + (i / blk_h) * 2;
223            let mut j = b_i % self.width;
224            j += 1 + (j / blk_w) * 2;
225            bits[idx(i, j)] = *b;
226        }
227
228        Bitmap { width: w, bits }
229    }
230
231    /// Traverse the symbol in codeword order and call the function for each position.
232    ///
233    /// The codeword index is given as the first
234    /// argument to `visit`.
235    ///
236    /// The second argument of `visit` contains the bits of the codewords, most significant
237    /// first.
238    pub fn traverse_mut<F>(&mut self, mut visit_fn: F)
239    where
240        F: FnMut(usize, [&mut M; 8]),
241    {
242        IndexTraversal {
243            width: self.width,
244            height: self.height,
245        }
246        .run(|idx, indices| {
247            visit_fn(idx, self.bits_mut(indices));
248        });
249    }
250
251    /// Nonmutable version of [traverse_mut](Self::traverse_mut).
252    pub fn traverse<F>(&self, mut visit_fn: F)
253    where
254        F: FnMut(usize, [M; 8]),
255    {
256        IndexTraversal {
257            width: self.width,
258            height: self.height,
259        }
260        .run(|idx, indices| {
261            let values = [
262                self.entries[indices[0]],
263                self.entries[indices[1]],
264                self.entries[indices[2]],
265                self.entries[indices[3]],
266                self.entries[indices[4]],
267                self.entries[indices[5]],
268                self.entries[indices[6]],
269                self.entries[indices[7]],
270            ];
271            visit_fn(idx, values);
272        });
273    }
274
275    fn bit_mut(&mut self, i: usize, j: usize) -> &mut M {
276        &mut self.entries[self.width * i + j]
277    }
278
279    /// Get mutable references to the indices specified in `indices`.
280    fn bits_mut(&mut self, indices: [usize; 8]) -> [&mut M; 8] {
281        let mut refs = [None, None, None, None, None, None, None, None];
282        let mut perm: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
283        perm.sort_unstable_by_key(|i| indices[*i as usize]);
284
285        let mut prev = 0;
286        let mut rest: &mut [M] = &mut self.entries;
287        for perm_idx in &perm {
288            let idx = indices[*perm_idx as usize];
289            let (e, new_rest) = rest[(idx - prev)..].split_first_mut().unwrap();
290            refs[*perm_idx as usize] = Some(e);
291            rest = new_rest;
292            prev = idx + 1;
293        }
294
295        [
296            refs[0].take().unwrap(),
297            refs[1].take().unwrap(),
298            refs[2].take().unwrap(),
299            refs[3].take().unwrap(),
300            refs[4].take().unwrap(),
301            refs[5].take().unwrap(),
302            refs[6].take().unwrap(),
303            refs[7].take().unwrap(),
304        ]
305    }
306}
307
308struct IndexTraversal {
309    width: usize,
310    height: usize,
311}
312
313impl IndexTraversal {
314    fn run<F>(&self, mut visit_fn: F)
315    where
316        F: FnMut(usize, [usize; 8]),
317    {
318        let nrow = self.height as isize;
319        let ncol = self.width as isize;
320        let mut visited = vec![false; (nrow * ncol) as usize];
321
322        // starting in the correct location for first character, bit 8
323        let mut i = 4;
324        let mut j = 0;
325        let mut codeword_idx = 0;
326
327        macro_rules! visit {
328            ($indices:expr) => {
329                let ii = $indices;
330                for v in ii {
331                    visited[v] = true;
332                }
333                visit_fn(codeword_idx, ii);
334                codeword_idx += 1;
335            };
336        }
337
338        loop {
339            // repeatedly first check for one of the special corner cases
340            if i == nrow && j == 0 {
341                visit!(self.corner1());
342            }
343            if i == nrow - 2 && j == 0 && ncol % 4 != 0 {
344                visit!(self.corner2());
345            }
346            if i == nrow - 2 && j == 0 && ncol % 8 == 4 {
347                visit!(self.corner3());
348            }
349            if i == nrow + 4 && j == 2 && ncol % 8 == 0 {
350                visit!(self.corner4());
351            }
352            // sweep upward diagonally
353            loop {
354                if i < nrow && j >= 0 && !visited[(i * ncol + j) as usize] {
355                    visit!(self.utah(i, j));
356                }
357                i -= 2;
358                j += 2;
359                if !(i >= 0 && j < ncol) {
360                    break;
361                }
362            }
363            i += 1;
364            j += 3;
365
366            // sweep downward diagonally
367            loop {
368                if i >= 0 && j < ncol && !visited[(i * ncol + j) as usize] {
369                    visit!(self.utah(i, j));
370                }
371                i += 2;
372                j -= 2;
373                if !(i < nrow && j >= 0) {
374                    break;
375                }
376            }
377            i += 3;
378            j += 1;
379
380            // until entire map is traversed
381            if !(i < nrow || j < ncol) {
382                break;
383            }
384        }
385    }
386
387    /// Compute index with wrapping
388    fn idx(&self, mut i: isize, mut j: isize) -> usize {
389        let h = self.height as isize;
390        let w = self.width as isize;
391        if i < 0 {
392            i += h;
393            j += 4 - ((h + 4) % 8);
394        }
395        if j < 0 {
396            j += w;
397            i += 4 - ((w + 4) % 8);
398        }
399        // this is needed for DMRE sizes
400        if i >= h {
401            i -= h;
402        }
403        debug_assert!(i >= 0 && i < h);
404        debug_assert!(j >= 0 && j < w);
405        (i * w + j) as usize
406    }
407
408    /// Compute indices for utah-shaped symbol (the standard symbol)
409    fn utah(&self, i: isize, j: isize) -> [usize; 8] {
410        [
411            self.idx(i - 2, j - 2),
412            self.idx(i - 2, j - 1),
413            self.idx(i - 1, j - 2),
414            self.idx(i - 1, j - 1),
415            self.idx(i - 1, j),
416            self.idx(i, j - 2),
417            self.idx(i, j - 1),
418            self.idx(i, j),
419        ]
420    }
421
422    fn corner1(&self) -> [usize; 8] {
423        let h = self.height as isize;
424        let w = self.width as isize;
425        [
426            self.idx(h - 1, 0),
427            self.idx(h - 1, 1),
428            self.idx(h - 1, 2),
429            self.idx(0, w - 2),
430            self.idx(0, w - 1),
431            self.idx(1, w - 1),
432            self.idx(2, w - 1),
433            self.idx(3, w - 1),
434        ]
435    }
436
437    fn corner2(&self) -> [usize; 8] {
438        let h = self.height as isize;
439        let w = self.width as isize;
440        [
441            self.idx(h - 3, 0),
442            self.idx(h - 2, 0),
443            self.idx(h - 1, 0),
444            self.idx(0, w - 4),
445            self.idx(0, w - 3),
446            self.idx(0, w - 2),
447            self.idx(0, w - 1),
448            self.idx(1, w - 1),
449        ]
450    }
451
452    fn corner3(&self) -> [usize; 8] {
453        let h = self.height as isize;
454        let w = self.width as isize;
455        [
456            self.idx(h - 3, 0),
457            self.idx(h - 2, 0),
458            self.idx(h - 1, 0),
459            self.idx(0, w - 2),
460            self.idx(0, w - 1),
461            self.idx(1, w - 1),
462            self.idx(2, w - 1),
463            self.idx(3, w - 1),
464        ]
465    }
466
467    fn corner4(&self) -> [usize; 8] {
468        let h = self.height as isize;
469        let w = self.width as isize;
470        [
471            self.idx(h - 1, 0),
472            self.idx(h - 1, w - 1),
473            self.idx(0, w - 3),
474            self.idx(0, w - 2),
475            self.idx(0, w - 1),
476            self.idx(1, w - 3),
477            self.idx(1, w - 2),
478            self.idx(1, w - 1),
479        ]
480    }
481}
482
483impl MatrixMap<bool> {
484    /// Create a MatrixMap and fills with codewords.
485    pub fn new_with_codewords(data: &[u8], symbol_size: SymbolSize) -> Self {
486        // FIXME: Should not panic if data is too short
487        let mut m = Self::new(symbol_size);
488        m.copy_from_codewords(data);
489        m
490    }
491
492    /// Copy the data from the codewords to the corresponding positions.
493    ///
494    /// Also writes a padding pattern if necessary.
495    ///
496    /// # Panics
497    ///
498    /// Panics if the data is too short.
499    fn copy_from_codewords(&mut self, data: &[u8]) {
500        self.traverse_mut(|idx, bits| {
501            let mut codeword = data[idx];
502            for bit in bits.into_iter().rev() {
503                *bit = codeword & 1 == 1;
504                codeword >>= 1;
505            }
506        });
507        self.write_padding();
508    }
509
510    /// Extract the codewords.
511    ///
512    /// This includes the error correction codewords.
513    pub fn codewords(&self) -> Vec<u8> {
514        let mut data = vec![0; self.entries.len() / 8];
515        self.traverse(|idx, bits| {
516            let codeword = &mut data[idx];
517            for bit in bits {
518                *codeword = (*codeword << 1) | (bit as u8);
519            }
520        });
521        data
522    }
523}
524
525/// An abstract bitmap.
526///
527/// Contains helpers for rendering the content. For rendering targets which
528/// use something similar to pixels try [pixels()](Self::pixels), while
529/// vector formats might profit from [path()][Self::path].
530pub struct Bitmap<M> {
531    width: usize,
532    bits: Vec<M>,
533}
534
535impl Bit for bool {
536    const LOW: bool = false;
537    const HIGH: bool = true;
538}
539
540impl<B: Bit> Bitmap<B> {
541    /// Create a new Bitmap.
542    ///
543    /// This allows you to use the rendering helpers also for, say, QR codes:
544    ///
545    /// ```rust
546    /// # use datamatrix::placement::Bitmap;
547    /// use qrcode::{QrCode, Color};
548    ///
549    /// let code = QrCode::new(b"Hello, World!!").unwrap();
550    /// let width = code.width();
551    /// let bits = code.into_colors().into_iter().map(|c| c == Color::Dark);
552    /// let bitmap = Bitmap::new(bits, width);
553    /// print!("{}", bitmap.unicode());
554    /// ```
555    ///
556    /// # Panics
557    ///
558    /// Panics if `width` is zero or does not evenly divide the number of bits
559    /// returned by `bits`.
560    pub fn new<T>(bits: T, width: usize) -> Self
561    where
562        T: IntoIterator<Item = B>,
563    {
564        let bits = Vec::from_iter(bits);
565        assert_eq!(bits.len() % width, 0);
566        Self { width, bits }
567    }
568
569    /// Return the width of the bitmap (no quiet zone included).
570    pub fn width(&self) -> usize {
571        self.width
572    }
573
574    /// Return the height of the bitmap (no quiet zone included).
575    pub fn height(&self) -> usize {
576        self.bits.len() / self.width
577    }
578
579    /// Compute a unicode representation ("ASCII art").
580    ///
581    /// This is intended as a demo functionality. It might look weird
582    /// if the line height is wrong or if you are not using a monospaced font.
583    pub fn unicode(&self) -> String {
584        const BORDER: usize = 1;
585        const INVERT: bool = false;
586        const CHAR: [char; 4] = [' ', '▄', '▀', '█'];
587        let height = self.height();
588        let get = |i: usize, j: usize| -> usize {
589            let res =
590                if i < BORDER || i >= BORDER + height || j < BORDER || j >= BORDER + self.width {
591                    B::LOW
592                } else if i - BORDER < height && j - BORDER < self.width {
593                    self.bits[(i - BORDER) * self.width + (j - BORDER)]
594                } else {
595                    B::LOW
596                };
597            if res == B::HIGH {
598                1
599            } else {
600                0
601            }
602        };
603        let mut out =
604            String::with_capacity((height + 2 * BORDER) * (self.width + 1 + 2 * BORDER) * 3 / 2);
605        for i in (0..height + 2 * BORDER).step_by(2) {
606            for j in 0..(self.width + 2 * BORDER) {
607                let idx = (get(i, j) << 1) | get(i + 1, j);
608                out.push(CHAR[if INVERT { (!idx) & 0b11 } else { idx }]);
609            }
610            out.push('\n');
611        }
612        out
613    }
614
615    /// Get an iterator over the "black" pixels' coordinates `(x, y)`.
616    ///
617    /// A black pixel refers to one of the tiny black squares a Data Matrix
618    /// is usually made of. Depending on your target, such a pixel
619    /// may be rendered using multiple image pixels, or whatever you use
620    /// to visualize the Data Matrix.
621    ///
622    /// The coordinate system is centered in the top left corner starting
623    /// in `(0, 0)` with a horizontal x-axis and vertical y-axis.
624    /// The pixels are returned in order, incrementing x before y.
625    ///
626    /// A quiet zone is not included in the coordinates but one must
627    /// be added when rendering: The minimum free space required around the Data Matrix
628    /// has to have the width/height of one "black" pixel.
629    /// The quiet zone should have the background's color.
630    ///
631    /// A Data Matrix can be either rendered using dark color on a light background,
632    /// or the other way around. More details on contrast, size, etc. can be found in the referenced
633    /// standards mentioned in the specification.
634    ///
635    /// # Example
636    ///
637    /// ```rust
638    /// # use datamatrix::{DataMatrix, SymbolSize};
639    /// let code = DataMatrix::encode(b"Foo", SymbolSize::Square10)?;
640    /// for (x, y) in code.bitmap().pixels() {
641    ///     // place square/circle at (x, y) to render this Data Matrix
642    /// }
643    /// # Ok::<(), datamatrix::data::DataEncodingError>(())
644    /// ```
645    pub fn pixels(&self) -> impl Iterator<Item = (usize, usize)> + '_ {
646        let w = self.width();
647        self.bits
648            .iter()
649            .enumerate()
650            .filter(|(_i, b)| **b == B::HIGH)
651            .map(move |(i, _b)| (i % w, i / w))
652    }
653
654    #[doc(hidden)]
655    pub fn bits(&self) -> &[B] {
656        &self.bits
657    }
658}
659
660#[cfg(test)]
661mod tests {
662    use alloc::vec::Vec;
663
664    impl super::Bit for (u16, u8) {
665        const LOW: Self = (0, 0);
666        const HIGH: Self = (0, 1);
667    }
668
669    pub fn log(s: super::SymbolSize) -> Vec<(u16, u8)> {
670        let mut m = super::MatrixMap::<(u16, u8)>::new(s);
671        m.traverse_mut(|cw, bits| {
672            for i in 0..8 {
673                *bits[i as usize] = ((cw + 1) as u16, (i + 1) as u8);
674            }
675        });
676        m.write_padding();
677        m.entries
678    }
679}
680
681#[test]
682fn test_12x12() {
683    let log = tests::log(SymbolSize::Square12);
684    #[rustfmt::skip]
685    let should = [
686        (2,1), (2,2), (3,6), (3,7), (3,8), (4,3), (4,4), (4,5), (1,1), (1,2),
687        (2,3), (2,4), (2,5), (5,1), (5,2), (4,6), (4,7), (4,8), (1,3), (1,4),
688        (2,6), (2,7), (2,8), (5,3), (5,4), (5,5), (10,1), (10,2), (1,6), (1,7),
689        (1,5), (6,1), (6,2), (5,6), (5,7), (5,8), (10,3), (10,4), (10,5), (7,1),
690        (1,8), (6,3), (6,4), (6,5), (9,1), (9,2), (10,6), (10,7), (10,8), (7,3),
691        (7,2), (6,6), (6,7), (6,8), (9,3), (9,4), (9,5), (11,1), (11,2), (7,6),
692        (7,4), (7,5), (8,1), (8,2), (9,6), (9,7), (9,8), (11,3), (11,4), (11,5),
693        (7,7), (7,8), (8,3), (8,4), (8,5), (12,1), (12,2), (11,6), (11,7), (11,8),
694        (3,1), (3,2), (8,6), (8,7), (8,8), (12,3), (12,4), (12,5), (0,1), (0,0),
695        (3,3), (3,4), (3,5), (4,1), (4,2), (12,6), (12,7), (12,8), (0,0), (0,1)
696    ];
697    assert_eq!(&log, &should);
698}
699
700#[test]
701fn test_10x10() {
702    let log = tests::log(SymbolSize::Square10);
703    #[rustfmt::skip]
704    let should = [
705        (2,1), (2,2), (3,6), (3,7), (3,8), (4,3), (4,4), (4,5),
706        (2,3), (2,4), (2,5), (5,1), (5,2), (4,6), (4,7), (4,8),
707        (2,6), (2,7), (2,8), (5,3), (5,4), (5,5), (1,1), (1,2),
708        (1,5), (6,1), (6,2), (5,6), (5,7), (5,8), (1,3), (1,4),
709        (1,8), (6,3), (6,4), (6,5), (8,1), (8,2), (1,6), (1,7),
710        (7,2), (6,6), (6,7), (6,8), (8,3), (8,4), (8,5), (7,1),
711        (7,4), (7,5), (3,1), (3,2), (8,6), (8,7), (8,8), (7,3),
712        (7,7), (7,8), (3,3), (3,4), (3,5), (4,1), (4,2), (7,6),
713    ];
714    assert_eq!(&log, &should);
715}
716
717#[test]
718fn test_8x32() {
719    let log = tests::log(SymbolSize::Rect8x32);
720    #[rustfmt::skip]
721    let should = [
722        (2,1), (2,2), (3,6), (3,7), (3,8), (4,3), (4,4), (4,5), (8,1), (8,2), (9,6), (9,7), (9,8), (10,3), (10,4), (10,5), (14,1), (14,2), (15,6), (15,7), (15,8), (16,3), (16,4), (16,5), (20,1), (20,2), (1,4), (1,5),
723        (2,3), (2,4), (2,5), (5,1), (5,2), (4,6), (4,7), (4,8), (8,3), (8,4), (8,5), (11,1), (11,2), (10,6), (10,7), (10,8), (14,3), (14,4), (14,5), (17,1), (17,2), (16,6), (16,7), (16,8), (20,3), (20,4), (20,5), (1,6),
724        (2,6), (2,7), (2,8), (5,3), (5,4), (5,5), (7,1), (7,2), (8,6), (8,7), (8,8), (11,3), (11,4), (11,5), (13,1), (13,2), (14,6), (14,7), (14,8), (17,3), (17,4), (17,5), (19,1), (19,2), (20,6), (20,7), (20,8), (1,7),
725        (1,1), (6,1), (6,2), (5,6), (5,7), (5,8), (7,3), (7,4), (7,5), (12,1), (12,2), (11,6), (11,7), (11,8), (13,3), (13,4), (13,5), (18,1), (18,2), (17,6), (17,7), (17,8), (19,3), (19,4), (19,5), (21,1), (21,2), (1,8),
726        (1,2), (6,3), (6,4), (6,5), (3,1), (3,2), (7,6), (7,7), (7,8), (12,3), (12,4), (12,5), (9,1), (9,2), (13,6), (13,7), (13,8), (18,3), (18,4), (18,5), (15,1), (15,2), (19,6), (19,7), (19,8), (21,3), (21,4), (21,5),
727        (1,3), (6,6), (6,7), (6,8), (3,3), (3,4), (3,5), (4,1), (4,2), (12,6), (12,7), (12,8), (9,3), (9,4), (9,5), (10,1), (10,2), (18,6), (18,7), (18,8), (15,3), (15,4), (15,5), (16,1), (16,2), (21,6), (21,7), (21,8),
728    ];
729    assert_eq!(&log, &should);
730}
731
732#[test]
733fn test_from_bits_all() {
734    let mut random_map = crate::test::random_maps();
735    for size in SymbolList::all() {
736        let map = random_map(size);
737        let bitmap = map.bitmap();
738        let (map2, _size) = MatrixMap::try_from_bits(&bitmap.bits, bitmap.width).unwrap();
739        assert_eq!(map.entries, map2.entries);
740    }
741}
742
743#[test]
744fn test_bitmap_new() {
745    Bitmap::new(vec![true, false], 2);
746    Bitmap::new([true, false], 2);
747    let data = &[true, false];
748    Bitmap::new(data.iter().cloned(), 2);
749}