1use 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 Alignment,
26 Padding,
28 ZeroWidth,
30 DataSize,
32 SymbolSize,
34}
35
36pub trait Bit: Clone + Copy + PartialEq + core::fmt::Debug {
38 const LOW: Self;
39 const HIGH: Self;
40}
41
42#[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 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 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 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 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 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 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 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 bits[idx(h - 1, j)] = M::HIGH;
205 }
206 for j in (0..w).step_by(2) {
207 bits[idx(0, j)] = M::HIGH;
209 }
210 for i in 0..h {
211 bits[idx(i, 0)] = M::HIGH;
213 }
214 for i in (1..h).step_by(2) {
215 bits[idx(i, w - 1)] = M::HIGH;
217 }
218
219 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 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 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 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 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 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 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 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 if !(i < nrow || j < ncol) {
382 break;
383 }
384 }
385 }
386
387 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 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 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 pub fn new_with_codewords(data: &[u8], symbol_size: SymbolSize) -> Self {
486 let mut m = Self::new(symbol_size);
488 m.copy_from_codewords(data);
489 m
490 }
491
492 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 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
525pub 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 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 pub fn width(&self) -> usize {
571 self.width
572 }
573
574 pub fn height(&self) -> usize {
576 self.bits.len() / self.width
577 }
578
579 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 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}