1#![deny(missing_docs)]
8
9use std::convert::TryFrom;
10use std::fmt::{Debug, Display, Formatter};
11use std::io::Error;
12use std::num::TryFromIntError;
13
14mod bit;
15mod decode;
16mod encode;
17
18#[cfg(feature = "fuzz")]
19pub mod fuzz;
20
21const B: u8 = 66;
22const M: u8 = 77;
23const COLOR_PALLET_SIZE: u32 = 2 * 4; const HEADER_SIZE: u32 = 2 + 12 + 40 + COLOR_PALLET_SIZE;
25
26#[derive(PartialEq, Eq, Clone)]
34pub struct Bmp {
35 rows: Vec<Vec<bool>>,
36}
37
38#[derive(Debug)]
40pub enum BmpError {
41 Generic,
43 Content,
45 Header,
47 Data,
49 Size(u16, u16),
51}
52
53impl Display for BmpError {
54 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55 write!(f, "{:?}", self)
56 }
57}
58
59impl Debug for Bmp {
60 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61 write!(f, "Bmp width={} height={}", self.width(), self.height(),)
62 }
63}
64
65impl std::error::Error for BmpError {}
66
67impl From<std::num::TryFromIntError> for BmpError {
68 fn from(_: TryFromIntError) -> Self {
69 BmpError::Generic
70 }
71}
72
73#[derive(Debug)]
74struct BmpHeader {
75 height: u16,
76 width: u16,
77 bg_is_zero: bool,
78}
79
80impl Bmp {
81 pub fn new(rows: Vec<Vec<bool>>) -> Result<Bmp, BmpError> {
84 if rows.is_empty() || rows[0].is_empty() || !rows.iter().all(|e| e.len() == rows[0].len()) {
85 Err(BmpError::Data)
86 } else {
87 check_size(u16::try_from(rows.len())?, u16::try_from(rows[0].len())?)?;
88 Ok(Bmp { rows })
89 }
90 }
91
92 pub fn height(&self) -> u16 {
94 self.rows.len() as u16
95 }
96
97 pub fn width(&self) -> u16 {
99 self.rows[0].len() as u16
100 }
101
102 pub fn get(&self, i: u16, j: u16) -> bool {
105 self.rows[i as usize][j as usize]
106 }
107
108 pub fn mul(&self, mul: u8) -> Result<Bmp, BmpError> {
111 if mul <= 1 {
112 return Err(BmpError::Generic);
113 }
114 let mul = mul as u16;
115 let new_width = self.width().checked_mul(mul).ok_or(BmpError::Generic)?;
116 let new_height = self.height().checked_mul(mul).ok_or(BmpError::Generic)?;
117 check_size(new_width, new_height)?;
118 let mut rows = Vec::with_capacity(new_height as usize);
119
120 let mul = mul as usize;
121 for i in 0..self.height() {
122 let mut row = Vec::with_capacity(new_width as usize);
123 for j in 0..self.width() {
124 row.extend(vec![self.get(i, j); mul]);
125 }
126 rows.extend(vec![row; mul]);
127 }
128
129 Ok(Bmp { rows })
130 }
131
132 pub fn div(&self, div: u8) -> Result<Bmp, BmpError> {
135 if div <= 1 {
136 return Err(BmpError::Generic);
137 }
138 let div = div as u16;
139 let new_height = self.height() / div;
140 let new_width = self.width() / div;
141 if new_height == 0 || new_width == 0 || self.height() % div != 0 || self.width() % div != 0
142 {
143 return Err(BmpError::Generic);
144 }
145 let mut new_rows = vec![];
146
147 let div = div as usize;
148 for rows in self.rows.chunks(div) {
149 let mut new_row = vec![];
150 for j in 0..div - 1 {
151 if rows[j] != rows[j + 1] {
152 return Err(BmpError::Generic);
153 }
154 }
155 for cols in rows[0].chunks(div) {
156 if cols.iter().all(|e| cols[0] == *e) {
157 new_row.push(cols[0]);
158 } else {
159 return Err(BmpError::Generic);
160 }
161 }
162 new_rows.push(new_row);
163 }
164 Ok(Bmp { rows: new_rows })
165 }
166
167 fn div_with_greater_possible(&self, greater_start: u8) -> Bmp {
168 for i in (2..greater_start).rev() {
169 if let Ok(bmp) = self.div(i) {
170 return bmp;
171 }
172 }
173 self.clone()
174 }
175
176 pub fn normalize(&self) -> Bmp {
179 self.remove_white_border().div_with_greater_possible(10)
180 }
181
182 pub fn add_white_border(&self, border_size: u8) -> Result<Bmp, BmpError> {
184 let double_border = border_size as u16 * 2;
185 let width = self
186 .width()
187 .checked_add(double_border)
188 .ok_or(BmpError::Generic)?;
189 let height = self
190 .height()
191 .checked_add(double_border)
192 .ok_or(BmpError::Generic)?;
193 check_size(width, height)?;
194 let mut new_rows = Vec::with_capacity(height as usize);
195 let border_size = border_size as usize;
196 new_rows.extend(vec![vec![false; width as usize]; border_size]);
197 for row in self.rows.iter() {
198 let mut new_row = Vec::with_capacity(width as usize);
199 new_row.extend(vec![false; border_size]);
200 new_row.extend(row);
201 new_row.extend(vec![false; border_size]);
202 new_rows.push(new_row);
203 }
204 new_rows.extend(vec![vec![false; width as usize]; border_size]);
205
206 Ok(Bmp { rows: new_rows })
207 }
208
209 pub fn remove_white_border(&self) -> Bmp {
211 let mut cur = self.clone();
212 loop {
213 match cur.remove_one_white_border() {
214 Ok(bmp) => cur = bmp,
215 Err(_) => return cur,
216 }
217 }
218 }
219
220 fn remove_one_white_border(&self) -> Result<Bmp, BmpError> {
221 if self.width() <= 2 || self.height() <= 2 {
222 return Err(BmpError::Generic);
223 }
224 let new_width = self.width() as usize - 2;
225 let new_height = self.height() as usize - 2;
226 let mut new_rows = vec![];
227 if self.rows[0].iter().all(|e| !*e)
228 && self.rows.last().unwrap().iter().all(|e| !*e)
229 && self.rows.iter().all(|r| !r[0])
230 && self.rows.iter().all(|r| !*r.last().unwrap())
231 {
232 for row in &self.rows[1..=new_height] {
233 new_rows.push(row[1..=new_width].to_vec())
234 }
235 Ok(Bmp { rows: new_rows })
236 } else {
237 Err(BmpError::Generic)
238 }
239 }
240
241 pub fn display(&self) -> StringOutput {
243 StringOutput(self)
244 }
245
246 pub fn inverse(&self) -> Bmp {
248 let mut new_vec = Vec::with_capacity(self.height() as usize);
249 for vec in self.rows.iter() {
250 new_vec.push(vec.iter().map(|e| !e).collect());
251 }
252 Bmp::new(new_vec).unwrap()
253 }
254}
255
256pub struct StringOutput<'a>(&'a Bmp);
258impl<'a> Display for StringOutput<'a> {
259 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
260 for row in self.0.rows.iter() {
261 for el in row.iter() {
262 if *el {
263 write!(f, "#")?;
264 } else {
265 write!(f, ".")?;
266 }
267 }
268 writeln!(f)?;
269 }
270 Ok(())
271 }
272}
273
274impl From<std::io::Error> for BmpError {
275 fn from(_: Error) -> Self {
276 BmpError::Generic
277 }
278}
279
280impl BmpHeader {
281 fn bytes_per_row(&self) -> u32 {
283 (self.width as u32 + 7) / 8
284 }
285
286 fn padding(&self) -> u32 {
288 (4 - self.bytes_per_row() % 4) % 4
289 }
290
291 fn bg_is_zero(&self) -> bool {
293 self.bg_is_zero
294 }
295}
296
297fn check_size(width: u16, height: u16) -> Result<u32, BmpError> {
300 let width_height = width as u32 * height as u32;
301 if width_height <= 1_000_000 && width > 0 && height > 0 {
302 Ok(width_height)
303 } else {
304 Err(BmpError::Size(width, height))
305 }
306}
307
308#[cfg(test)]
309mod test {
310 use crate::*;
311 use rand::Rng;
312 use std::fs::File;
313 use std::io::Cursor;
314
315 #[test]
316 fn test_data_matrix() {
317 assert!(Bmp::new(vec![]).is_err());
318 assert!(Bmp::new(vec![vec![true]]).is_ok());
319 assert!(Bmp::new(vec![vec![true], vec![true]]).is_ok());
320 assert!(Bmp::new(vec![vec![true], vec![true, false]]).is_err());
321 }
322
323 #[test]
324 fn test_padding() {
325 let mut header = BmpHeader {
326 height: 0,
327 width: 0,
328 bg_is_zero: false,
329 };
330 assert_eq!(header.padding(), 0);
331
332 header.width = 1;
333 assert_eq!(header.padding(), 3);
334
335 header.width = 9;
336 assert_eq!(header.padding(), 2);
337
338 header.width = 17;
339 assert_eq!(header.padding(), 1);
340
341 header.width = 25;
342 assert_eq!(header.padding(), 0);
343 }
344
345 #[test]
346 fn test_bytes_per_row() {
347 let mut header = BmpHeader {
348 height: 0,
349 width: 0,
350 bg_is_zero: false,
351 };
352 assert_eq!(header.bytes_per_row(), 0);
353
354 header.width = 1;
355 assert_eq!(header.bytes_per_row(), 1);
356
357 header.width = 8;
358 assert_eq!(header.bytes_per_row(), 1);
359
360 header.width = 9;
361 assert_eq!(header.bytes_per_row(), 2);
362 }
363
364 #[test]
365 fn test_mul() {
366 let data = Bmp::new(vec![vec![false, true], vec![false, true]]).unwrap();
367
368 let data_bigger = Bmp::new(vec![
369 vec![false, false, true, true],
370 vec![false, false, true, true],
371 vec![false, false, true, true],
372 vec![false, false, true, true],
373 ])
374 .unwrap();
375
376 assert_eq!(data.mul(2).unwrap(), data_bigger);
377
378 let data = Bmp::new(vec![vec![false, true], vec![false, false]]).unwrap();
379
380 let data_bigger = Bmp::new(vec![
381 vec![false, false, true, true],
382 vec![false, false, true, true],
383 vec![false, false, false, false],
384 vec![false, false, false, false],
385 ])
386 .unwrap();
387
388 assert_eq!(data.mul(2).unwrap(), data_bigger);
389 }
390
391 #[test]
392 fn test_div() {
393 let data = Bmp::new(vec![
394 vec![false, false, true, true],
395 vec![false, false, true, true],
396 vec![false, false, true, true],
397 vec![false, false, true, true],
398 ])
399 .unwrap();
400 let expected = Bmp::new(vec![vec![false, true], vec![false, true]]).unwrap();
401 assert_eq!(expected, data.div(2).unwrap());
402 }
403
404 #[test]
405 fn test_mul_div() {
406 let expected = random_bmp();
407 let mul = expected.mul(3).unwrap();
408 let div = mul.div(3).unwrap();
409 assert_eq!(expected, div);
410 }
411
412 #[test]
413 fn test_add_white_border() {
414 let data = Bmp::new(vec![vec![false]]).unwrap();
415 let data_bigger = Bmp::new(vec![vec![false; 5]; 5]).unwrap();
416
417 assert_eq!(data.add_white_border(2).unwrap(), data_bigger);
418 }
419
420 #[test]
421 fn test_rect() {
422 let rect = Bmp::new(vec![
423 vec![false, false],
424 vec![false, false],
425 vec![false, true],
426 ])
427 .unwrap();
428 rect.write(File::create("test_bmp/rect.bmp").unwrap())
429 .unwrap();
430 }
431
432 #[test]
433 fn test_bmp() {
434 let data_test1 = Bmp::new(vec![vec![false, true], vec![true, false]]).unwrap();
435 let bytes_test1 = Bmp::read(&mut File::open("test_bmp/test1.bmp").unwrap()).unwrap();
436 assert_eq!(data_test1, bytes_test1);
437
438 let bmp_test2 = data_test1.mul(3).unwrap().add_white_border(12).unwrap();
439 let bytes_test2 = Bmp::read(&mut File::open("test_bmp/test2.bmp").unwrap()).unwrap();
440 assert_eq!(
441 bmp_test2.display().to_string(),
442 bytes_test2.display().to_string()
443 );
444 }
445
446 #[test]
447 fn test_bmp_with_bg_is_zero() {
448 let bmp = Bmp::read(&mut File::open("test_bmp/qr-bolt11.bmp").unwrap()).unwrap();
449 let mut cursor = Cursor::new(vec![]);
450 bmp.write(&mut cursor).unwrap();
451 cursor.set_position(0);
452 let bmp2 = Bmp::read(cursor).unwrap();
453 assert_eq!(bmp, bmp2);
454 }
455
456 #[test]
457 fn test_monochrome_image() {
458 let expected = Bmp::new(
460 vec![
461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
462 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
463 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,
464 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
465 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1,
466 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
467 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
468 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1,
469 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
470 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
471 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
472 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
473 ]
474 .chunks(18)
475 .map(|r| r.iter().map(|e| *e == 0).collect())
476 .collect(),
477 )
478 .unwrap();
479
480 let bmp = Bmp::read(File::open("test_bmp/monochrome_image.bmp").unwrap()).unwrap();
481 assert_eq!(expected, bmp);
482 }
483
484 #[test]
485 fn test_rt() {
486 let expected = random_bmp();
487 let mut cursor = Cursor::new(vec![]);
488 expected.write(&mut cursor).unwrap();
489 cursor.set_position(0);
490 let bmp = Bmp::read(&mut cursor).unwrap();
491 assert_eq!(expected, bmp);
492 }
493
494 #[test]
495 fn test_get() {
496 let file = File::open("test_bmp/test1.bmp").unwrap();
497 let bmp = Bmp::read(file).unwrap();
498 assert!(!bmp.get(0, 0), "lower-left is not dark");
499 }
500
501 #[test]
502 fn test_remove_white_border() {
503 let bmp5 = Bmp::new(vec![vec![false; 5]; 5]).unwrap();
504 let bmp3 = Bmp::new(vec![vec![false; 3]; 3]).unwrap();
505 assert_eq!(bmp3, bmp5.remove_one_white_border().unwrap());
506 let bmp1 = Bmp::new(vec![vec![false]]).unwrap();
507 assert_eq!(bmp1, bmp3.remove_one_white_border().unwrap());
508 assert_eq!(bmp1, bmp5.remove_white_border());
509 }
510
511 #[test]
512 fn test_div_with_greater_possible() {
513 let bmp = Bmp::read(File::open("test_bmp/monochrome_image.bmp").unwrap()).unwrap();
514 let mul = bmp.mul(4).unwrap();
515 let div = mul.div_with_greater_possible(10);
516 assert_eq!(div, bmp);
517 }
518
519 #[test]
520 fn test_normalize() {
521 let bmp = Bmp::read(File::open("test_bmp/qr_not_normalized.bmp").unwrap()).unwrap();
522 let bmp_normalized = Bmp::read(File::open("test_bmp/qr_normalized.bmp").unwrap()).unwrap();
523 assert_eq!(bmp.normalize(), bmp_normalized);
524 }
525
526 #[test]
527 fn test_inverse() {
528 let bmp = random_bmp();
529 let inverted = bmp.inverse();
530 assert_ne!(bmp, inverted);
531 assert_eq!(bmp, inverted.inverse());
532 }
533
534 fn random_bmp() -> Bmp {
535 let mut rng = rand::thread_rng();
536 let width: u16 = rng.gen_range(1, 20);
537 let height: u16 = rng.gen_range(1, 20);
538 let mut data = vec![];
539 for _ in 0..height {
540 let row: Vec<bool> = (0..width).map(|_| rng.gen()).collect();
541 data.push(row);
542 }
543 Bmp::new(data).unwrap()
544 }
545}