1use std::fs;
2use std::convert::TryInto;
3use std::collections::VecDeque;
4use std::fmt;
5use std::collections::HashMap;
6use std::io::Write;
7use std::f64::consts::PI;
8const HEADER_OFFSET: usize = 14;
20
21#[derive(PartialEq)]
23pub enum ErrorKind {
24 NotFound,
25 OutOfBounds,
26 Unsupported,
27 DoesNotExist,
28 WrongFileType,
29 UseExtraBitMasks,
30 FailedToWrite,
31 Missing,
32 InvalidParameter(String)
33}
34
35impl ErrorKind {
36 fn get_text(&self) -> String {
37 match &*self {
38 ErrorKind::NotFound => "File not found".to_string(),
39 ErrorKind::OutOfBounds => "x or y coord exceeds width or height of image".to_string(),
40 ErrorKind::Unsupported => "File is unsupported".to_string(),
41 ErrorKind::DoesNotExist => "Requested object does not exist".to_string(),
42 ErrorKind::WrongFileType => "Wrong file type. Must be a .bmp file".to_string(),
43 ErrorKind::UseExtraBitMasks => "Use extra bit masks instead".to_string(),
44 ErrorKind::FailedToWrite => "Failed to write to file".to_string(),
45 ErrorKind::Missing => "Missing expected parameter or object".to_string(),
46 ErrorKind::InvalidParameter(reason) => "Invalid Parameter: ".to_owned()+reason,
47 }
48 }
49}
50
51impl fmt::Debug for ErrorKind {
52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 write!(f, "{:?}", self.get_text())
54 }
55}
56
57impl fmt::Display for ErrorKind {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 write!(f, "Error: {}", self.get_text())
60 }
61}
62
63pub enum RGBAChannel {
65 Red,
66 Green,
67 Blue,
68 Alpha,
69}
70
71#[derive(Debug)]
73pub struct PixelDiff {
74 pub coord: [u16; 2],
75 pub color1: Option<[u8; 4]>,
76 pub color2: Option<[u8; 4]>,
77}
78
79#[derive(Debug)]
81pub struct ImageDiff {
82 pub image1_size: [u32; 2],
83 pub image2_size: [u32; 2],
84 pub diff: Vec<PixelDiff>,
85}
86
87impl IntoIterator for ImageDiff {
88 type Item = PixelDiff;
89 type IntoIter = std::vec::IntoIter<Self::Item>;
90
91 fn into_iter(self) -> Self::IntoIter {
92 self.diff.into_iter()
93 }
94}
95
96impl std::ops::Index<usize> for ImageDiff {
97 type Output = PixelDiff;
98
99 fn index(&self, index: usize) -> &Self::Output {
100 &self.diff[index]
101 }
102}
103
104impl ImageDiff {
105 pub fn is_same_size(&self) -> bool {
106 if self.image1_size == self.image2_size {
107 true
108 } else {
109 false
110 }
111 }
112}
113
114#[allow(non_snake_case)]
117#[derive(Clone)]
118pub struct BITMAPFILEHEADER {
119 pub bfType: String,
120 pub bfSize: u32,
121 pub bfReserved1: Vec<u8>,
122 pub bfReserved2: Vec<u8>,
123 pub bfOffBits: u32,
124}
125
126impl IntoIterator for BITMAPFILEHEADER {
127 type Item = u8;
128 type IntoIter = std::array::IntoIter<u8, 14>;
129
130 fn into_iter(self) -> Self::IntoIter {
131 let bytes_vec = [self.bfType.as_bytes(), &self.bfSize.to_le_bytes(), &BMP::vec_to_2u8_array(self.bfReserved1), &BMP::vec_to_2u8_array(self.bfReserved2), &self.bfOffBits.to_le_bytes()].concat();
132 let mut bytes_array: [u8; 14] = [0u8; 14];
133 for i in 0..bytes_vec.len() {
135 bytes_array[i] = bytes_vec[i];
136 }
137 return IntoIterator::into_iter(bytes_array);
140 }
141}
142
143#[allow(non_snake_case)]
237#[derive(Clone)]
238pub struct DIBHEADER {
239 pub size: u32,
240 pub width: u32,
241 pub height: i32,
242 pub planes: u16,
243 pub bitcount: u16,
244 pub compression: Option<String>,
245 pub sizeimage: Option<u32>,
246 pub XPelsPerMeter: Option<u32>,
247 pub YPelsPerMeter: Option<u32>,
248 pub ClrUsed: Option<u32>,
249 pub ClrImportant: Option<u32>,
250 pub RedMask: Option<u32>,
251 pub GreenMask: Option<u32>,
252 pub BlueMask: Option<u32>,
253 pub AlphaMask: Option<u32>,
254 pub CSType: Option<String>,
255 pub Endpoints: Option<[[i32; 3]; 3]>,
256 pub GammaRed: Option<u32>,
257 pub GammaGreen: Option<u32>,
258 pub GammaBlue: Option<u32>,
259 pub Intent: Option<String>,
260 pub ProfileData: Option<u16>,
261 pub ProfileSize: Option<u16>,
262 pub Reserved: Option<Vec<u8>>,
263}
264
265impl IntoIterator for DIBHEADER {
267 type Item = u8;
269 type IntoIter = std::array::IntoIter<u8, 124>;
270
271 fn into_iter(self) -> Self::IntoIter {
272 let mut bytes_vec = [&self.size.to_le_bytes()[..], &self.width.to_le_bytes(), &self.height.to_le_bytes(), &self.planes.to_le_bytes(), &self.bitcount.to_le_bytes()].concat();
274 if self.size > 12 {
275 let compression_table: HashMap<String, u32> = HashMap::from([
276 ("BI_RGB".to_string(), 0),
277 ("BI_RLE8".to_string(), 1),
278 ("BI_RLE4".to_string(), 2),
279 ("BI_BITFIELDS".to_string(), 3),
280 ("BI_JPEG".to_string(), 4),
281 ("BI_PNG".to_string(), 5),
282 ("BI_ALPHABITFIELDS".to_string(), 6)
283 ]);
284 let compression: u32 = *compression_table.get(&self.compression.unwrap()).unwrap();
285 bytes_vec.append(&mut [&compression.to_le_bytes()[..], &self.sizeimage.unwrap().to_le_bytes(), &self.XPelsPerMeter.unwrap().to_le_bytes(), &self.YPelsPerMeter.unwrap().to_le_bytes(), &self.ClrUsed.unwrap().to_le_bytes(), &self.ClrImportant.unwrap().to_le_bytes()].concat());
286 }
287 if self.size > 40 {
288 let mut endpoints_l: [u8; 36] = [0u8; 36];
289 let endpoints = self.Endpoints.unwrap();
290 for i in 0..3 {
292 for ii in 0..3 {
293 endpoints_l[(i*3+ii*4) as usize] = endpoints[i as usize][ii as usize].to_le_bytes()[0];
295 endpoints_l[(i*3+ii*4+1) as usize] = endpoints[i as usize][ii as usize].to_le_bytes()[1];
296 endpoints_l[(i*3+ii*4+2) as usize] = endpoints[i as usize][ii as usize].to_le_bytes()[2];
297 endpoints_l[(i*3+ii*4+3) as usize] = endpoints[i as usize][ii as usize].to_le_bytes()[3];
298 }
299 }
300 bytes_vec.append(&mut [&self.RedMask.unwrap().to_le_bytes(), &self.GreenMask.unwrap().to_le_bytes(), &self.BlueMask.unwrap().to_le_bytes(), &self.AlphaMask.unwrap().to_le_bytes(), self.CSType.unwrap().as_bytes(), &endpoints_l[..], &self.GammaRed.unwrap().to_le_bytes(), &self.GammaGreen.unwrap().to_le_bytes(), &self.GammaBlue.unwrap().to_le_bytes()].concat());
303 }
304 if self.size > 108 {
305 let mut reserved_l: [u8; 4] = [0u8; 4];
307 let reserved = self.Reserved.unwrap();
308 for i in 0..4 {
309 reserved_l[i as usize] = reserved[i as usize];
310 }
311 let intent_table: HashMap<String, u32> = HashMap::from([
313 ("LCS_GM_ABS_COLORIMETRIC".to_string(), 0),
314 ("LCS_GM_BUSINESS".to_string(), 1),
315 ("LCS_WINDOWS_COLOR_SPACE".to_string(), 2),
316 ("LCS_GM_GRAPHICS".to_string(), 3),
317 ("LCS_GM_IMAGES".to_string(), 4)
318 ]);
319 let intent: u32 = *intent_table.get(&self.Intent.unwrap()).unwrap();
320 bytes_vec.append(&mut [&intent.to_le_bytes()[..], &self.ProfileData.unwrap().to_le_bytes(), &self.ProfileSize.unwrap().to_le_bytes(), &reserved_l[..]].concat());
321 }
322 let mut bytes_array: [u8; 124] = [0u8; 124];
323 for i in 0..bytes_vec.len() {
325 bytes_array[i] = bytes_vec[i];
326 }
327 return IntoIterator::into_iter(bytes_array);
330 }
331}
332
333pub enum ColorTable {
336 RGBTRIPLE(Vec<[u8; 3]>),
337 RGBQUAD(Vec<[u8; 4]>),
338}
339
340#[allow(non_camel_case_types)]
342pub struct BI_BITFIELDS_MASKS {
343 pub red: u32,
344 pub green: u32,
345 pub blue: u32,
346}
347
348#[allow(non_camel_case_types)]
349pub struct BI_ALPHABITFIELDS_MASKS {
350 pub red: u32,
351 pub green: u32,
352 pub blue: u32,
353 pub alpha: u32,
354}
355
356#[allow(non_camel_case_types)]
357enum EXTRA_BIT_MASKS {
358 BI_BITFIELDS_MASKS(BI_BITFIELDS_MASKS),
359 BI_ALPHABITFIELDS_MASKS(BI_ALPHABITFIELDS_MASKS),
360}
361
362pub struct BMP {
367 pub contents: Vec<u8>,
368 from_file: bool,
369 }
372
373impl PartialEq for BMP {
374 fn eq(&self, other: &BMP) -> bool {
375 self.contents == other.contents
376 }
377}
378
379impl Clone for BMP {
380 fn clone(&self) -> BMP {
381 let mut clone_bmp = BMP::new(1, 1, None);
382 clone_bmp.contents = self.contents.to_vec();
383 return clone_bmp;
384 }
385}
386
387impl BMP {
388 pub fn new(height: i32, width: u32, default_color: Option<[u8; 4]>) -> BMP {
390 let mut contents = Vec::new();
391 let offset: u32 = 14+124;
393 let size: u32 = offset+(height.abs() as u32 * width)*4;
394 let file_header = BITMAPFILEHEADER {
395 bfType: "BM".to_string(),
396 bfSize: size,
397 bfReserved1: vec![0, 0],
398 bfReserved2: vec![0, 0],
399 bfOffBits: offset,
400 };
401 contents.extend(file_header);
403 let dib_header = DIBHEADER {
405 size: 124,
406 width: width,
407 height: height,
408 planes: 1,
409 bitcount: 32,
410 compression: Some("BI_BITFIELDS".to_string()),
411 sizeimage: Some(size),
412 XPelsPerMeter: Some(3780),
414 YPelsPerMeter: Some(3780),
415 ClrUsed: Some(0),
417 ClrImportant: Some(0),
418 RedMask: Some(16711680),
420 GreenMask: Some(65280),
421 BlueMask: Some(255),
422 AlphaMask: Some(4278190080),
423 CSType: Some("BGRs".to_string()),
425 Endpoints: Some([[687194752, 354334816, 32212256], [322122560, 644245120, 107374144], [161061280, 64424508, 848256036]]),
427 GammaRed: Some(0),
428 GammaGreen: Some(0),
429 GammaBlue: Some(0),
430 Intent: Some("LCS_GM_IMAGES".to_string()),
431 ProfileData: Some(0),
432 ProfileSize: Some(0),
433 Reserved: Some(vec![0, 0, 0, 0]),
434 };
435 contents.extend(dib_header);
436 for _pixel_num in 0..(width*height as u32) {
439 if default_color.is_some() {
441 let mut bgr_default_color = default_color.unwrap().clone();
443 bgr_default_color[0] = default_color.unwrap()[2];
444 bgr_default_color[2] = default_color.unwrap()[0];
445 contents.extend(bgr_default_color);
446 } else {
447 contents.extend([255, 255, 255, 255]);
448 }
449 }
450 return BMP { contents: contents, from_file: false };
452 }
453 pub fn new_from_file(file_path: &str) -> Result<BMP, ErrorKind> {
455 let contents = fs::read(file_path).map_err(|_| ErrorKind::NotFound)?;
456 Ok(BMP { contents: contents, from_file: true })
457 }
458 fn bytes_to_int(bytes: [u8; 4]) -> u32 {
460 u32::from_le_bytes(bytes)
461 }
462 fn two_bytes_to_int(bytes: [u8; 2]) -> u16 {
463 u16::from_le_bytes(bytes)
464 }
465 fn byte_to_int(byte: u8) -> u8 {
466 u8::from_le_bytes([byte])
467 }
468 fn two_bytes_to_signed_int(bytes: [u8; 2]) -> i16 {
469 i16::from_le_bytes(bytes)
470 }
471 fn bytes_to_signed_int(bytes: [u8; 4]) -> i32 {
472 i32::from_le_bytes(bytes)
473 }
474 fn bytes_to_string(bytes: &[u8]) -> String {
475 String::from_utf8_lossy(&bytes).to_string()
476 }
477 pub fn num_bytes_to_kilobytes(bytes: u32) -> u32 {
479 bytes/1024
481 }
482 fn vec_to_4u8_array(vector: Vec<u8>) -> [u8; 4] {
483 let mut array: [u8; 4] = [0u8; 4];
484 for i in 0..vector.len() {
486 array[i] = vector[i];
487 }
488 return array;
489 }
490 fn vec_to_2u8_array(vector: Vec<u8>) -> [u8; 2] {
491 let mut array: [u8; 2] = [0u8; 2];
492 for i in 0..vector.len() {
494 array[i] = vector[i];
495 }
496 return array;
497 }
498 fn vec_to_1u8_array(vector: Vec<u8>) -> [u8; 1] {
499 let mut array: [u8; 1] = [0u8; 1];
500 for i in 0..vector.len() {
502 array[i] = vector[i];
503 }
504 return array;
505 }
506 fn int_to_compression(int: u32) -> String {
507 let compression_table: HashMap<u32, String> = HashMap::from([
508 (0, "BI_RGB".to_string()),
509 (1, "BI_RLE8".to_string()),
510 (2, "BI_RLE4".to_string()),
511 (3, "BI_BITFIELDS".to_string()),
512 (4, "BI_JPEG".to_string()),
513 (5, "BI_PNG".to_string()),
514 (6, "BI_ALPHABITFIELDS".to_string())
515 ]);
516 return compression_table.get(&int).unwrap().to_string();
517 }
518 fn int_to_intent(int: u32) -> String {
519 let intent_table: HashMap<u32, String> = HashMap::from([
520 (0, "LCS_GM_ABS_COLORIMETRIC".to_string()),
521 (1, "LCS_GM_BUSINESS".to_string()),
522 (2, "LCS_WINDOWS_COLOR_SPACE".to_string()),
523 (3, "LCS_GM_GRAPHICS".to_string()),
524 (4, "LCS_GM_IMAGES".to_string())
525 ]);
526 return intent_table.get(&int).unwrap().to_string();
527 }
528 fn deg_to_rad(deg: f64) -> f64 {
530 return deg/180.0*PI;
531 }
532 fn rotate_point(rad: f64, point: [u16; 2], center: [u16; 2]) -> (i32, i32) {
533 let x2: i32 = ((f64::from(point[0])-f64::from(center[0])) * rad.cos() - (f64::from(point[1])-f64::from(center[1])) * rad.sin()).round() as i32 + i32::from(center[0]);
535 let y2: i32 = ((f64::from(point[1])-f64::from(center[1])) * rad.cos() + (f64::from(point[0])-f64::from(center[0])) * rad.sin()).round() as i32 + i32::from(center[1]);
537 return (x2, y2);
538 }
539 pub fn point_in_enclosure(point: [u16; 2], enclosure: &Vec<[u16; 2]>) -> bool {
541 if enclosure.contains(&point) {
544 return false;
545 }
546 let same_y_count_right = enclosure.into_iter().filter(|item| {
548 item[1] == point[1] && item[0] > point[0]
549 }).count();
550 return same_y_count_right % 2 == 1;
552 }
553 fn alpha_to_percentage(alpha: u8) -> f64 {
555 return (f64::from(alpha)/255.0).into();
557 }
558 fn percentage_to_alpha(percentage: f64) -> u8 {
559 return (percentage * 255.0).round() as u8;
560 }
561 pub fn rgba_to_hex(rgba: [u8; 4]) -> String {
611 let hex_chars: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
612 let mut hex: String = String::new();
613 for i in 0..rgba.len() {
615 let num = rgba[i];
616 hex += &hex_chars[(f64::from(num) / 16.0).floor() as usize].to_string();
617 hex += &hex_chars[(num % 16) as usize].to_string();
618 }
619 return hex;
620 }
621 pub fn hex_to_rgba(hex: String) -> [u8; 4] {
623 let hex_chars: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
624 let mut rgba: [u8; 4] = [0; 4];
625 let mut current_num: u8 = 0;
626 for (i, c) in hex.chars().enumerate() {
627 if i%2 == 0 {
628 current_num += 16*hex_chars.iter().position(|c_h| c_h == &c).unwrap() as u8;
629 } else {
630 current_num += hex_chars.iter().position(|c_h| c_h == &c).unwrap() as u8;
631 rgba[(i as f64 / 2.0).floor() as usize] = current_num;
632 current_num = 0;
633 }
634 }
635 return rgba;
636 }
637 pub fn hsl_to_rgb(hsl: [f64; 3]) -> Result<[u8; 3], ErrorKind> {
639 let hue = hsl[0];
641 let sat = hsl[1];
642 let lig = hsl[2];
643 if hue > 360.0 || hue < 0.0 {
644 return Err(ErrorKind::InvalidParameter("Hue cannot be greater than 360 or less than 0".to_string()));
645 } else if sat > 1.0 || sat < 0.0 {
646 return Err(ErrorKind::InvalidParameter("Saturation cannot be greater than 1 or less than 0".to_string()));
647 } else if lig > 1.0 || lig < 0.0 {
648 return Err(ErrorKind::InvalidParameter("Lightness cannot be greater than 1 or less than 0".to_string()));
649 }
650 let chroma: f64 = (1.0 - (2.0 * lig - 1.0).abs()) * sat;
652 let hprime: f64 = hue / 60.0;
654 let x: f64 = chroma * (1.0 - (hprime % 2.0 - 1.0).abs());
656 let color1: [f64; 3];
657 if hprime < 1.0 {
658 color1 = [chroma, x, 0.0];
660 } else if hprime < 2.0 {
661 color1 = [x, chroma, 0.0];
663 } else if hprime < 3.0 {
664 color1 = [0.0, chroma, x];
666 } else if hprime < 4.0 {
667 color1 = [0.0, x, chroma];
669 } else if hprime < 5.0 {
670 color1 = [x, 0.0, chroma];
672 } else {
673 color1 = [chroma, 0.0, x];
676 }
677 let m: f64 = lig - chroma / 2.0;
679 let rgb_color: [u8; 3] = [(255.0 * (color1[0] + m)).round() as u8, (255.0 * (color1[1] + m)).round() as u8, (255.0 * (color1[2] + m)).round() as u8];
680 return Ok(rgb_color);
681 }
682 pub fn composite_colors(color1: [u8; 4], color2: [u8; 4]) -> [u8; 4] {
683 let a1 = BMP::alpha_to_percentage(color1[3]);
685 let a2 = BMP::alpha_to_percentage(color2[3]);
686 let a0 = a1+a2*(1.0 - a1);
688 let c0_0: f64 = (f64::from(color1[0])*a1 + f64::from(color2[0])*a2*(1.0-a1))/a0;
690 let c0_1: f64 = (f64::from(color1[1])*a1 + f64::from(color2[1])*a2*(1.0-a1))/a0;
691 let c0_2: f64 = (f64::from(color1[2])*a1 + f64::from(color2[2])*a2*(1.0-a1))/a0;
692 return [c0_0.round() as u8, c0_1.round() as u8, c0_2.round() as u8, BMP::percentage_to_alpha(a0)];
693 }
694 pub fn rgb_to_grayscale(rgba: [u8; 4]) -> [u8; 4] {
695 let gray: u8 = (0.2126*f64::from(rgba[0]) + 0.7152*f64::from(rgba[1]) + 0.0722*f64::from(rgba[2])).round() as u8;
698 return [gray, gray, gray, rgba[3]];
699 }
700 fn get_header_bytes(&self) -> &[u8; 14] {
702 self.contents[..14].try_into().unwrap()
704 }
705 pub fn get_header(&self) -> BITMAPFILEHEADER {
707 let header_bytes: &[u8; 14] = self.get_header_bytes();
708 return BITMAPFILEHEADER {
709 bfType: BMP::bytes_to_string(&header_bytes[..2]),
710 bfSize: BMP::bytes_to_int(header_bytes[2..6].try_into().unwrap()),
711 bfReserved1: header_bytes[6..8].try_into().unwrap(),
712 bfReserved2: header_bytes[8..10].try_into().unwrap(),
713 bfOffBits: BMP::bytes_to_int(header_bytes[10..14].try_into().unwrap()),
714 };
715 }
716 pub fn get_offset(&self) -> u32 {
718 self.get_header().bfOffBits
719 }
720 pub fn get_size(&self, use_header: bool) -> u32 {
722 if use_header {
723 return self.get_header().bfSize;
724 } else {
725 return self.contents.len().try_into().unwrap();
726 }
727 }
728 pub fn diff(bmp1: &BMP, bmp2: &BMP) -> Result<ImageDiff, ErrorKind> {
731 let dib_header1 = bmp1.get_dib_header();
734 let dib_header1 = match dib_header1 {
735 Ok(returned_dib_header) => returned_dib_header,
736 Err(e) => return Err(e),
737 };
738 let dib_header2 = bmp2.get_dib_header();
739 let dib_header2 = match dib_header2 {
740 Ok(returned_dib_header) => returned_dib_header,
741 Err(e) => return Err(e),
742 };
743 let pixel_data1 = bmp1.get_pixel_data();
744 let pixel_data1 = match pixel_data1 {
745 Ok(returned_pixel_data) => returned_pixel_data,
746 Err(e) => return Err(e),
747 };
748 let pixel_data2 = bmp2.get_pixel_data();
749 let pixel_data2 = match pixel_data2 {
750 Ok(returned_pixel_data) => returned_pixel_data,
751 Err(e) => return Err(e),
752 };
753 let largest_height: u32;
754 if dib_header1.height.abs() > dib_header2.height.abs() {
755 largest_height = dib_header1.height.abs() as u32;
756 } else {
757 largest_height = dib_header2.height.abs() as u32;
760 }
761 let largest_width: u32;
762 if dib_header1.width > dib_header2.width {
763 largest_width = dib_header1.width;
764 } else {
765 largest_width = dib_header2.width;
766 }
767 let mut diff_pixels: Vec<PixelDiff> = Vec::new();
769 for y in 0..largest_height {
770 for x in 0..largest_width {
771 let color1: Option<[u8; 4]>;
772 let color2: Option<[u8; 4]>;
773 if x >= dib_header1.width || y >= dib_header1.height.abs() as u32 {
774 color1 = None;
775 } else {
776 color1 = Some(bmp1.get_color_of_px_efficient(x as usize, y as usize, &dib_header1, &pixel_data1).unwrap());
777 }
778 if x >= dib_header2.width || y >= dib_header2.height.abs() as u32 {
779 color2 = None;
780 } else {
781 color2 = Some(bmp2.get_color_of_px_efficient(x as usize, y as usize, &dib_header2, &pixel_data2).unwrap());
782 }
783 if color1 != color2 {
784 diff_pixels.push(PixelDiff {
785 coord: [x as u16, y as u16],
786 color1,
787 color2,
788 });
789 }
790 }
791 }
792 return Ok(ImageDiff {
793 image1_size: [dib_header1.width, dib_header1.height.abs() as u32],
794 image2_size: [dib_header2.width, dib_header2.height.abs() as u32],
795 diff: diff_pixels,
796 });
797 }
798 pub fn is_from_file(&self) -> bool {
801 self.from_file
802 }
803 pub fn get_dib_header(&self) -> Result<DIBHEADER, ErrorKind> {
809 let dib_size: u32 = BMP::bytes_to_int(self.contents[HEADER_OFFSET..HEADER_OFFSET+4].try_into().unwrap());
813 let dib_header: DIBHEADER;
814 match dib_size {
815 12 => {
816 dib_header = DIBHEADER {
818 size: dib_size,
819 width: u32::from(BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+4..HEADER_OFFSET+6].try_into().unwrap())),
820 height: i32::from(BMP::two_bytes_to_signed_int(self.contents[HEADER_OFFSET+6..HEADER_OFFSET+8].try_into().unwrap())),
821 planes: BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+8..HEADER_OFFSET+10].try_into().unwrap()),
822 bitcount: BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+10..HEADER_OFFSET+12].try_into().unwrap()),
823 compression: None,
824 sizeimage: None,
825 XPelsPerMeter: None,
826 YPelsPerMeter: None,
827 ClrUsed: None,
828 ClrImportant: None,
829 RedMask: None,
830 GreenMask: None,
831 BlueMask: None,
832 AlphaMask: None,
833 CSType: None,
834 Endpoints: None,
835 GammaRed: None,
836 GammaGreen: None,
837 GammaBlue: None,
838 Intent: None,
839 ProfileData: None,
840 ProfileSize: None,
841 Reserved: None,
842 };
843 },
844 40 => {
845 dib_header = DIBHEADER {
847 size: dib_size,
848 width: BMP::bytes_to_int(self.contents[HEADER_OFFSET+4..HEADER_OFFSET+8].try_into().unwrap()),
849 height: BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+8..HEADER_OFFSET+12].try_into().unwrap()),
850 planes: BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+12..HEADER_OFFSET+14].try_into().unwrap()),
851 bitcount: BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+14..HEADER_OFFSET+16].try_into().unwrap()),
852 compression: Some(BMP::int_to_compression(BMP::bytes_to_int(self.contents[HEADER_OFFSET+16..HEADER_OFFSET+20].try_into().unwrap()))),
853 sizeimage: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+20..HEADER_OFFSET+24].try_into().unwrap())),
854 XPelsPerMeter: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+24..HEADER_OFFSET+28].try_into().unwrap())),
855 YPelsPerMeter: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+28..HEADER_OFFSET+32].try_into().unwrap())),
856 ClrUsed: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+32..HEADER_OFFSET+36].try_into().unwrap())),
857 ClrImportant: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+36..HEADER_OFFSET+40].try_into().unwrap())),
858 RedMask: None,
859 GreenMask: None,
860 BlueMask: None,
861 AlphaMask: None,
862 CSType: None,
863 Endpoints: None,
864 GammaRed: None,
865 GammaGreen: None,
866 GammaBlue: None,
867 Intent: None,
868 ProfileData: None,
869 ProfileSize: None,
870 Reserved: None,
871 };
872 },
873 108 => {
874 dib_header = DIBHEADER {
876 size: dib_size,
877 width: BMP::bytes_to_int(self.contents[HEADER_OFFSET+4..HEADER_OFFSET+8].try_into().unwrap()),
878 height: BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+8..HEADER_OFFSET+12].try_into().unwrap()),
879 planes: BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+12..HEADER_OFFSET+14].try_into().unwrap()),
880 bitcount: BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+14..HEADER_OFFSET+16].try_into().unwrap()),
881 compression: Some(BMP::int_to_compression(BMP::bytes_to_int(self.contents[HEADER_OFFSET+16..HEADER_OFFSET+20].try_into().unwrap()))),
882 sizeimage: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+20..HEADER_OFFSET+24].try_into().unwrap())),
883 XPelsPerMeter: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+24..HEADER_OFFSET+28].try_into().unwrap())),
884 YPelsPerMeter: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+28..HEADER_OFFSET+32].try_into().unwrap())),
885 ClrUsed: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+32..HEADER_OFFSET+36].try_into().unwrap())),
886 ClrImportant: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+36..HEADER_OFFSET+40].try_into().unwrap())),
887 RedMask: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+40..HEADER_OFFSET+44].try_into().unwrap())),
888 GreenMask: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+44..HEADER_OFFSET+48].try_into().unwrap())),
889 BlueMask: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+48..HEADER_OFFSET+52].try_into().unwrap())),
890 AlphaMask: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+52..HEADER_OFFSET+56].try_into().unwrap())),
891 CSType: Some(BMP::bytes_to_string(&self.contents[HEADER_OFFSET+56..HEADER_OFFSET+60])),
892 Endpoints: Some([[BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+60..HEADER_OFFSET+64].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+64..HEADER_OFFSET+68].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+68..HEADER_OFFSET+72].try_into().unwrap())], [BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+72..HEADER_OFFSET+76].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+76..HEADER_OFFSET+80].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+80..HEADER_OFFSET+84].try_into().unwrap())], [BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+84..HEADER_OFFSET+88].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+88..HEADER_OFFSET+92].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+92..HEADER_OFFSET+96].try_into().unwrap())]]),
894 GammaRed: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+96..HEADER_OFFSET+100].try_into().unwrap())),
895 GammaGreen: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+100..HEADER_OFFSET+104].try_into().unwrap())),
896 GammaBlue: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+104..HEADER_OFFSET+108].try_into().unwrap())),
897 Intent: None,
898 ProfileData: None,
899 ProfileSize: None,
900 Reserved: None,
901 };
902 },
903 124 => {
904 dib_header = DIBHEADER {
909 size: dib_size,
910 width: BMP::bytes_to_int(self.contents[HEADER_OFFSET+4..HEADER_OFFSET+8].try_into().unwrap()),
911 height: BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+8..HEADER_OFFSET+12].try_into().unwrap()),
912 planes: BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+12..HEADER_OFFSET+14].try_into().unwrap()),
913 bitcount: BMP::two_bytes_to_int(self.contents[HEADER_OFFSET+14..HEADER_OFFSET+16].try_into().unwrap()),
914 compression: Some(BMP::int_to_compression(BMP::bytes_to_int(self.contents[HEADER_OFFSET+16..HEADER_OFFSET+20].try_into().unwrap()))),
915 sizeimage: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+20..HEADER_OFFSET+24].try_into().unwrap())),
916 XPelsPerMeter: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+24..HEADER_OFFSET+28].try_into().unwrap())),
917 YPelsPerMeter: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+28..HEADER_OFFSET+32].try_into().unwrap())),
918 ClrUsed: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+32..HEADER_OFFSET+36].try_into().unwrap())),
919 ClrImportant: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+36..HEADER_OFFSET+40].try_into().unwrap())),
920 RedMask: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+40..HEADER_OFFSET+44].try_into().unwrap())),
921 GreenMask: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+44..HEADER_OFFSET+48].try_into().unwrap())),
922 BlueMask: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+48..HEADER_OFFSET+52].try_into().unwrap())),
923 AlphaMask: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+52..HEADER_OFFSET+56].try_into().unwrap())),
924 CSType: Some(BMP::bytes_to_string(&self.contents[HEADER_OFFSET+56..HEADER_OFFSET+60])),
925 Endpoints: Some([[BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+60..HEADER_OFFSET+64].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+64..HEADER_OFFSET+68].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+68..HEADER_OFFSET+72].try_into().unwrap())], [BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+72..HEADER_OFFSET+76].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+76..HEADER_OFFSET+80].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+80..HEADER_OFFSET+84].try_into().unwrap())], [BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+84..HEADER_OFFSET+88].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+88..HEADER_OFFSET+92].try_into().unwrap()), BMP::bytes_to_signed_int(self.contents[HEADER_OFFSET+92..HEADER_OFFSET+96].try_into().unwrap())]]),
927 GammaRed: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+96..HEADER_OFFSET+100].try_into().unwrap())),
928 GammaGreen: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+100..HEADER_OFFSET+104].try_into().unwrap())),
929 GammaBlue: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+104..HEADER_OFFSET+108].try_into().unwrap())),
930 Intent: Some(BMP::int_to_intent(BMP::bytes_to_int(self.contents[HEADER_OFFSET+108..HEADER_OFFSET+112].try_into().unwrap()))),
931 ProfileData: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+112..HEADER_OFFSET+116].try_into().unwrap()) as u16),
933 ProfileSize: Some(BMP::bytes_to_int(self.contents[HEADER_OFFSET+116..HEADER_OFFSET+120].try_into().unwrap()) as u16),
934 Reserved: Some(self.contents[HEADER_OFFSET+120..HEADER_OFFSET+124].try_into().unwrap()),
935 };
936 },
937 _ => {
938 return Err(ErrorKind::Unsupported);
940 },
941 }
942 return Ok(dib_header);
943 }
944 fn get_extra_bit_masks(&self) -> Result<EXTRA_BIT_MASKS, ErrorKind> {
946 let dib_header = self.get_dib_header();
948 let dib_header = match dib_header {
949 Ok(returned_dib_header) => returned_dib_header,
950 Err(e) => return Err(e),
951 };
952 match dib_header.size {
953 40 => {
954 const TOTAL_OFFSET: usize = 54;
957 let compression = dib_header.compression.unwrap();
958 if compression == "BI_BITFIELDS" {
959 return Ok(EXTRA_BIT_MASKS::BI_BITFIELDS_MASKS(BI_BITFIELDS_MASKS {
960 red: BMP::bytes_to_int(self.contents[TOTAL_OFFSET..TOTAL_OFFSET+4].try_into().unwrap()),
961 green: BMP::bytes_to_int(self.contents[TOTAL_OFFSET+4..TOTAL_OFFSET+8].try_into().unwrap()),
962 blue: BMP::bytes_to_int(self.contents[TOTAL_OFFSET+8..TOTAL_OFFSET+12].try_into().unwrap()),
963 }));
964 } else if compression == "BI_ALPHABITFIELDS" {
965 return Ok(EXTRA_BIT_MASKS::BI_ALPHABITFIELDS_MASKS(BI_ALPHABITFIELDS_MASKS {
966 red: BMP::bytes_to_int(self.contents[TOTAL_OFFSET..TOTAL_OFFSET+4].try_into().unwrap()),
967 green: BMP::bytes_to_int(self.contents[TOTAL_OFFSET+4..TOTAL_OFFSET+8].try_into().unwrap()),
968 blue: BMP::bytes_to_int(self.contents[TOTAL_OFFSET+8..TOTAL_OFFSET+12].try_into().unwrap()),
969 alpha: BMP::bytes_to_int(self.contents[TOTAL_OFFSET+12..TOTAL_OFFSET+16].try_into().unwrap()),
970 }));
971 } else {
972 return Err(ErrorKind::DoesNotExist);
973 }
974 },
975 _ => return Err(ErrorKind::DoesNotExist),
976 }
977 }
978 fn get_color_table(&self) -> Result<ColorTable, ErrorKind> {
983 let dib_header = self.get_dib_header();
984 let dib_header = match dib_header {
985 Ok(returned_dib_header) => returned_dib_header,
986 Err(e) => return Err(e),
987 };
988 let mut offset: u32 = 14;
991 let end: u32;
993 let data_type: &str;
995 match dib_header.size {
997 12 => {
1001 offset += dib_header.size;
1003 end = self.get_header().bfOffBits;
1004 data_type = "rgbtriple";
1006 },
1007 40 | 108 | 124 => {
1008 offset += dib_header.size;
1010 end = self.get_header().bfOffBits;
1011 let compression = dib_header.compression.unwrap();
1015 if compression == "BI_BITFIELDS" && (dib_header.bitcount == 16 || dib_header.bitcount == 32) {
1016 return Err(ErrorKind::UseExtraBitMasks);
1018 } else if compression == "BI_RGB" && dib_header.bitcount >= 16 {
1019 return Err(ErrorKind::DoesNotExist);
1022 } else {
1023 data_type = "rgbquad";
1024 }
1025 },
1026 _ => {
1027 return Err(ErrorKind::DoesNotExist);
1028 },
1029 };
1030 let color_table: ColorTable;
1031 if data_type == "rgbtriple" {
1032 let mut color_table_vec: Vec::<[u8; 3]> = Vec::new();
1033 for i in 0..(f64::from((end-offset)/3).floor() as i64) {
1035 let ii = i as u32;
1036 color_table_vec.push([BMP::byte_to_int(self.contents[(offset+ii*3) as usize]) as u8, BMP::byte_to_int(self.contents[(offset+ii*3+1) as usize]) as u8, BMP::byte_to_int(self.contents[(offset+ii*3+2) as usize]) as u8]);
1037 }
1038 color_table = ColorTable::RGBTRIPLE(color_table_vec);
1039 } else {
1040 let mut color_table_vec: Vec::<[u8; 4]> = Vec::new();
1041 for i in 0..(f64::from((end-offset)/4).floor() as i64) {
1043 let ii = i as u32;
1044 color_table_vec.push([BMP::byte_to_int(self.contents[(offset+ii*4) as usize]) as u8, BMP::byte_to_int(self.contents[(offset+ii*4+1) as usize]) as u8, BMP::byte_to_int(self.contents[(offset+ii*4+2) as usize]) as u8, BMP::byte_to_int(self.contents[(offset+ii*4+3) as usize]) as u8]);
1045 }
1046 color_table = ColorTable::RGBQUAD(color_table_vec);
1047 }
1048 return Ok(color_table);
1049 }
1050 pub fn get_pixel_data(&self) -> Result<VecDeque<Vec<Vec<u8>>>, ErrorKind> {
1055 let dib_header = self.get_dib_header();
1058 let dib_header = match dib_header {
1059 Ok(returned_dib_header) => returned_dib_header,
1060 Err(e) => return Err(e),
1061 };
1062 let mut rows: VecDeque<Vec<Vec<u8>>> = VecDeque::new();
1069 let header = self.get_header();
1070 if dib_header.height < 0 {
1071 let row_length = f64::from(dib_header.bitcount*dib_header.width as u16/32).ceil() as u32 * 4;
1076 let rows_num = (self.contents.len() as u32-header.bfOffBits)/row_length;
1078 for row_num in 0..rows_num {
1079 let mut row: Vec<Vec<u8>> = Vec::new();
1081 for pixel in 0..dib_header.width {
1082 if dib_header.bitcount >= 8 {
1083 let start: u32 = (header.bfOffBits)+(row_num)*row_length+(pixel)*((dib_header.bitcount/8) as u32);
1084 row.push(self.contents[start as usize..(start+(dib_header.bitcount/8) as u32) as usize].to_vec());
1085 } else {
1086 let start: u32 = (header.bfOffBits)+(row_num)*row_length+(pixel)*(((dib_header.bitcount/8) as f64).ceil() as u32);
1088 let byte: u8 = self.contents[start as usize];
1089 if dib_header.bitcount == 1 {
1090 let split_bits: [u8; 8] = [byte >> 7, (byte & 0b01000000) >> 6, (byte & 0b00100000) >> 5, (byte & 0b00010000) >> 4, (byte & 0b00001000) >> 3, (byte & 0b00000100) >> 2, (byte & 0b00000010) >> 1, byte & 0b00000001];
1091 row.push(vec![split_bits[(pixel % ((8/dib_header.bitcount) as u32)) as usize]]);
1092 } else if dib_header.bitcount == 2 {
1093 let split_bits: [u8; 4] = [byte >> 6, (byte & 0b00110000) >> 4, (byte & 0b00001100) >> 2, byte & 0b00000011];
1094 row.push(vec![split_bits[(pixel % ((8/dib_header.bitcount) as u32)) as usize]]);
1095 } else if dib_header.bitcount == 4 {
1096 let split_bits: [u8; 2] = [byte >> 4, byte & 0b00001111];
1097 row.push(vec![split_bits[(pixel % ((8/dib_header.bitcount) as u32)) as usize]]);
1098 }
1099 }
1100 }
1101 rows.push_back(row);
1102 }
1103 } else if dib_header.height > 0 {
1105 let row_length = f64::from(dib_header.bitcount*dib_header.width as u16/32).ceil() as u32 * 4;
1109 let rows_num: u32 = (self.contents.len() as u32-header.bfOffBits)/row_length;
1110 for row_num in 0..rows_num {
1111 let mut row: Vec<Vec<u8>> = Vec::new();
1112 for pixel in 0..dib_header.width {
1113 if dib_header.bitcount >= 8 {
1114 let start: u32 = (header.bfOffBits)+row_num*row_length+pixel*((dib_header.bitcount/8) as u32);
1115 row.push(self.contents[start as usize..(start+(dib_header.bitcount/8) as u32) as usize].to_vec());
1116 } else {
1117 let start: u32 = (header.bfOffBits)+row_num*row_length+pixel*(((dib_header.bitcount/8) as f64).ceil() as u32);
1119 let byte: u8 = self.contents[start as usize];
1120 if dib_header.bitcount == 1 {
1121 let split_bits: [u8; 8] = [byte >> 7, (byte & 0b01000000) >> 6, (byte & 0b00100000) >> 5, (byte & 0b00010000) >> 4, (byte & 0b00001000) >> 3, (byte & 0b00000100) >> 2, (byte & 0b00000010) >> 1, byte & 0b00000001];
1122 row.push(vec![split_bits[(pixel % ((8/dib_header.bitcount) as u32)) as usize]]);
1123 } else if dib_header.bitcount == 2 {
1124 let split_bits: [u8; 4] = [byte >> 6, (byte & 0b00110000) >> 4, (byte & 0b00001100) >> 2, byte & 0b00000011];
1125 row.push(vec![split_bits[(pixel % ((8/dib_header.bitcount) as u32)) as usize]]);
1126 } else if dib_header.bitcount == 4 {
1127 let split_bits: [u8; 2] = [byte >> 4, byte & 0b00001111];
1128 row.push(vec![split_bits[(pixel % ((8/dib_header.bitcount) as u32)) as usize]]);
1129 }
1130 }
1131 }
1132 rows.push_front(row);
1133 }
1134 }
1135 return Ok(rows);
1136 }
1137 fn get_color_profile(&self) -> Result<Vec<u8>, ErrorKind> {
1140 let dib_header = self.get_dib_header();
1145 let dib_header = match dib_header {
1146 Ok(returned_dib_header) => returned_dib_header,
1147 Err(e) => return Err(e),
1148 };
1149 match dib_header.size {
1150 124 => {
1151 let cstype = dib_header.CSType.unwrap();
1152 if cstype == "PROFILE_EMBEDDED" || cstype == "PROFILE_LINKED" {
1153 return Ok(self.contents[dib_header.ProfileData.unwrap() as usize..].to_vec());
1154 } else {
1156 return Err(ErrorKind::DoesNotExist);
1157 }
1158 },
1159 _ => return Err(ErrorKind::DoesNotExist),
1160 }
1161 }
1166 pub fn get_color_of_pixel(&self, x: usize, y: usize) -> Result<[u8; 4], ErrorKind> {
1170 let dib_header = self.get_dib_header();
1171 let dib_header = match dib_header {
1172 Ok(returned_dib_header) => returned_dib_header,
1173 Err(e) => return Err(e),
1174 };
1175 if x >= (dib_header.width as usize) || y >= (dib_header.height as usize) {
1176 return Err(ErrorKind::OutOfBounds);
1177 }
1178 let pixel_data = self.get_pixel_data();
1180 let pixel_data = match pixel_data {
1181 Ok(returned_pixel_data) => returned_pixel_data,
1182 Err(e) => return Err(e),
1183 };
1184 let pixel: &Vec<u8> = &pixel_data[y][x];
1185 let pixel: Vec<u8> = pixel.to_vec();
1186 if dib_header.bitcount == 16 {
1192 let compression = dib_header.compression.unwrap();
1193 if compression == "BI_BITFIELDS" && (dib_header.RedMask.is_some() && dib_header.GreenMask.is_some() && dib_header.BlueMask.is_some()) {
1194 let rgba: [u8; 4];
1197 let red_mask: u32 = dib_header.RedMask.unwrap();
1199 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1201 if red_mask < blue_mask {
1202 rgba = [BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), 255];
1204 } else {
1205 rgba = [BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[0]), 255];
1207 }
1208 return Ok(rgba);
1209 } else {
1210 return Ok([0, 0, 0, 255]);
1214 }
1215 } else if dib_header.bitcount == 24 {
1216 let rgba: [u8; 4] = [BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[0]), 255];
1220 return Ok(rgba);
1221 } else if dib_header.bitcount == 32 {
1222 let compression = dib_header.compression.unwrap();
1224 if (compression == "BI_BITFIELDS" || compression == "BI_ALPHABITFIELDS") && (dib_header.RedMask.is_some() && dib_header.GreenMask.is_some() && dib_header.BlueMask.is_some()) {
1225 let rgba: [u8; 4];
1230 let red_mask: u32 = dib_header.RedMask.unwrap();
1231 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1233 let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1234 if alpha_mask < red_mask {
1235 if red_mask < blue_mask {
1237 rgba = [BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[3]), BMP::byte_to_int(pixel[0])];
1239 } else {
1240 rgba = [BMP::byte_to_int(pixel[3]), BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[0])];
1242 }
1243 } else {
1244 if red_mask < blue_mask {
1246 rgba = [BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[3])];
1248 } else {
1249 rgba = [BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[3])];
1251 }
1252 }
1253 return Ok(rgba);
1254 } else {
1255 let rgba: [u8; 4] = [BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[3])];
1256 return Ok(rgba);
1257 }
1258 } else {
1259 let color_table = self.get_color_table();
1261 let color_table = match color_table {
1262 Ok(returned_color_table) => returned_color_table,
1263 Err(e) => return Err(e),
1264 };
1265 let index;
1267 if dib_header.bitcount == 16 {
1268 index = BMP::two_bytes_to_int(BMP::vec_to_2u8_array(pixel));
1269 } else {
1270 index = u16::from(BMP::byte_to_int(pixel[0]));
1271 }
1272 let rgba: [u8; 4];
1273 match color_table {
1274 ColorTable::RGBTRIPLE(vec) => {
1275 let rgb: [u8; 3] = vec[index as usize];
1276 let mut rgb = rgb.to_vec();
1278 rgb.push(255);
1279 rgba = BMP::vec_to_4u8_array(rgb);
1280 },
1281 ColorTable::RGBQUAD(vec) => {
1282 rgba = vec[index as usize];
1283 }
1284 }
1285 return Ok(rgba);
1286 }
1287 }
1288 pub fn get_color_of_px(&self, x: usize, y: usize) -> Result<[u8; 4], ErrorKind> {
1289 self.get_color_of_pixel(x, y)
1290 }
1291 pub fn get_color_of_pixel_efficient(&self, x: usize, y: usize, dib_header: &DIBHEADER, pixel_data: &VecDeque<Vec<Vec<u8>>>) -> Result<[u8; 4], ErrorKind> {
1293 if x >= (dib_header.width as usize) || y >= (dib_header.height as usize) {
1294 return Err(ErrorKind::OutOfBounds);
1295 }
1296 let pixel: &Vec<u8> = &pixel_data[y][x];
1297 let pixel: Vec<u8> = pixel.to_vec();
1298 if dib_header.bitcount == 16 {
1304 let compression = dib_header.compression.as_ref().unwrap();
1305 if compression == "BI_BITFIELDS" && (dib_header.RedMask.is_some() && dib_header.GreenMask.is_some() && dib_header.BlueMask.is_some()) {
1306 let rgba: [u8; 4];
1309 let red_mask: u32 = dib_header.RedMask.unwrap();
1311 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1313 if red_mask < blue_mask {
1314 rgba = [BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), 255];
1316 } else {
1317 rgba = [BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[0]), 255];
1319 }
1320 return Ok(rgba);
1321 } else {
1322 return Ok([0, 0, 0, 255]);
1326 }
1327 } else if dib_header.bitcount == 24 {
1328 let rgba: [u8; 4] = [BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[0]), 255];
1332 return Ok(rgba);
1333 } else if dib_header.bitcount == 32 {
1334 let compression = dib_header.compression.as_ref().unwrap();
1336 if (compression == "BI_BITFIELDS" || compression == "BI_ALPHABITFIELDS") && (dib_header.RedMask.is_some() && dib_header.GreenMask.is_some() && dib_header.BlueMask.is_some()) {
1337 let rgba: [u8; 4];
1342 let red_mask: u32 = dib_header.RedMask.unwrap();
1343 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1345 let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1346 if alpha_mask < red_mask {
1347 if red_mask < blue_mask {
1349 rgba = [BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[3]), BMP::byte_to_int(pixel[0])];
1351 } else {
1352 rgba = [BMP::byte_to_int(pixel[3]), BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[0])];
1354 }
1355 } else {
1356 if red_mask < blue_mask {
1358 rgba = [BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[3])];
1360 } else {
1361 rgba = [BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[3])];
1363 }
1364 }
1365 return Ok(rgba);
1366 } else {
1367 let rgba: [u8; 4] = [BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), BMP::byte_to_int(pixel[3])];
1368 return Ok(rgba);
1369 }
1370 } else {
1371 let color_table = self.get_color_table();
1373 let color_table = match color_table {
1374 Ok(returned_color_table) => returned_color_table,
1375 Err(e) => return Err(e),
1376 };
1377 let index;
1379 if dib_header.bitcount == 16 {
1380 index = BMP::two_bytes_to_int(BMP::vec_to_2u8_array(pixel));
1381 } else {
1382 index = u16::from(BMP::byte_to_int(pixel[0]));
1383 }
1384 let rgba: [u8; 4];
1385 match color_table {
1386 ColorTable::RGBTRIPLE(vec) => {
1387 let rgb: [u8; 3] = vec[index as usize];
1388 let mut rgb = rgb.to_vec();
1390 rgb.push(255);
1391 rgba = BMP::vec_to_4u8_array(rgb);
1392 },
1393 ColorTable::RGBQUAD(vec) => {
1394 rgba = vec[index as usize];
1395 }
1396 }
1397 return Ok(rgba);
1398 }
1399 }
1400 pub fn get_color_of_px_efficient(&self, x: usize, y: usize, dib_header: &DIBHEADER, pixel_data: &VecDeque<Vec<Vec<u8>>>) -> Result<[u8; 4], ErrorKind> {
1401 self.get_color_of_pixel_efficient(x, y, dib_header, pixel_data)
1402 }
1403 pub fn get_format(&self) -> String {
1407 let dib_header = self.get_dib_header().unwrap();
1408 if dib_header.bitcount == 16 {
1409 let compression = dib_header.compression.unwrap();
1410 if compression == "BI_BITFIELDS" && (dib_header.RedMask.is_some() && dib_header.GreenMask.is_some() && dib_header.BlueMask.is_some()) {
1411 let red_mask: u32 = dib_header.RedMask.unwrap();
1415 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1417 if red_mask < blue_mask {
1418 return "rgb".to_string();
1420 } else {
1421 return "brg".to_string();
1423 }
1424 } else {
1425 return "rgb".to_string();
1429 }
1430 } else if dib_header.bitcount == 24 {
1431 return "bgr".to_string();
1432 } else if dib_header.bitcount == 32 {
1433 let compression = dib_header.compression.unwrap();
1435 if (compression == "BI_BITFIELDS" || compression == "BI_ALPHABITFIELDS") && (dib_header.RedMask.is_some() && dib_header.GreenMask.is_some() && dib_header.BlueMask.is_some()) {
1436 let red_mask: u32 = dib_header.RedMask.unwrap();
1437 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1439 let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1440 if alpha_mask < red_mask {
1441 if red_mask < blue_mask {
1443 return "argb".to_string();
1445 } else {
1446 return "abgr".to_string();
1448 }
1449 } else {
1450 if red_mask < blue_mask {
1452 return "rgba".to_string();
1454 } else {
1455 return "bgra".to_string();
1457 }
1458 }
1459 } else {
1460 return "rgba".to_string();
1461 }
1462 } else {
1463 return "color table".to_string();
1464 }
1465 }
1466 pub fn change_color_of_pixel(&mut self, x: u16, mut y: u16, new_color: [u8; 4]) -> Result<(), ErrorKind> {
1472 let dib_header = self.get_dib_header();
1475 let dib_header = match dib_header {
1476 Ok(returned_dib_header) => returned_dib_header,
1477 Err(e) => return Err(e),
1478 };
1479 if u32::from(x) >= dib_header.width || i32::from(y) >= dib_header.height {
1480 return Err(ErrorKind::OutOfBounds);
1481 }
1482 let header = self.get_header();
1483 let bitcount = dib_header.bitcount;
1485 if bitcount != 24 && bitcount != 32 {
1487 return Err(ErrorKind::Unsupported);
1489 }
1490 if dib_header.height > 0 {
1492 y = dib_header.height as u16 - y - 1;
1494 }
1495 let row_length = (f64::from((bitcount/8) as u16*dib_header.width as u16/4).ceil() as u32 * 4) as u16;
1497 let start = u32::from(y)*u32::from(row_length)+header.bfOffBits+(bitcount/8) as u32*u32::from(x);
1500 if bitcount == 24 {
1504 self.contents[start as usize] = new_color[2];
1507 self.contents[(start+1) as usize] = new_color[1];
1508 self.contents[(start+2) as usize] = new_color[0];
1509 } else if bitcount == 32 {
1510 let red_mask: u32 = dib_header.RedMask.unwrap();
1511 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1513 let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1514 if alpha_mask < red_mask {
1516 if red_mask < blue_mask {
1518 self.contents[start as usize] = new_color[3];
1520 self.contents[(start+1) as usize] = new_color[0];
1521 self.contents[(start+2) as usize] = new_color[1];
1522 self.contents[(start+3) as usize] = new_color[2];
1523 } else {
1524 self.contents[start as usize] = new_color[3];
1526 self.contents[(start+1) as usize] = new_color[2];
1527 self.contents[(start+2) as usize] = new_color[1];
1528 self.contents[(start+3) as usize] = new_color[0];
1529 }
1530 } else {
1531 if red_mask < blue_mask {
1533 self.contents[start as usize] = new_color[0];
1535 self.contents[(start+1) as usize] = new_color[1];
1536 self.contents[(start+2) as usize] = new_color[2];
1537 self.contents[(start+3) as usize] = new_color[3];
1538 } else {
1539 self.contents[start as usize] = new_color[2];
1541 self.contents[(start+1) as usize] = new_color[1];
1542 self.contents[(start+2) as usize] = new_color[0];
1543 self.contents[(start+3) as usize] = new_color[3];
1544 }
1545 }
1546 }
1547 return Ok(());
1548 }
1549 pub fn change_color_of_pixel_efficient(&mut self, x: u16, mut y: u16, new_color: [u8; 4], dib_header: &DIBHEADER, header: &BITMAPFILEHEADER) -> Result<(), ErrorKind> {
1551 if u32::from(x) >= dib_header.width || i32::from(y) >= dib_header.height {
1552 return Err(ErrorKind::OutOfBounds);
1553 }
1554 let bitcount = dib_header.bitcount;
1556 if bitcount != 24 && bitcount != 32 {
1558 return Err(ErrorKind::Unsupported);
1560 }
1561 if dib_header.height > 0 {
1563 y = dib_header.height as u16 - y - 1;
1565 }
1566 let row_length = (f64::from((bitcount/8) as u16*dib_header.width as u16/4).ceil() as u32 * 4) as u16;
1568 let start = u32::from(y)*u32::from(row_length)+header.bfOffBits+(bitcount/8) as u32*x as u32;
1571 if bitcount == 24 {
1575 self.contents[start as usize] = new_color[2];
1578 self.contents[(start+1) as usize] = new_color[1];
1579 self.contents[(start+2) as usize] = new_color[0];
1580 } else if bitcount == 32 {
1581 let red_mask: u32 = dib_header.RedMask.unwrap();
1582 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1584 let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1585 if alpha_mask < red_mask {
1587 if red_mask < blue_mask {
1589 self.contents[start as usize] = new_color[3];
1591 self.contents[(start+1) as usize] = new_color[0];
1592 self.contents[(start+2) as usize] = new_color[1];
1593 self.contents[(start+3) as usize] = new_color[2];
1594 } else {
1595 self.contents[start as usize] = new_color[3];
1597 self.contents[(start+1) as usize] = new_color[2];
1598 self.contents[(start+2) as usize] = new_color[1];
1599 self.contents[(start+3) as usize] = new_color[0];
1600 }
1601 } else {
1602 if red_mask < blue_mask {
1604 self.contents[start as usize] = new_color[0];
1606 self.contents[(start+1) as usize] = new_color[1];
1607 self.contents[(start+2) as usize] = new_color[2];
1608 self.contents[(start+3) as usize] = new_color[3];
1609 } else {
1610 self.contents[start as usize] = new_color[2];
1612 self.contents[(start+1) as usize] = new_color[1];
1613 self.contents[(start+2) as usize] = new_color[0];
1614 self.contents[(start+3) as usize] = new_color[3];
1615 }
1616 }
1617 }
1618 return Ok(());
1619 }
1620 pub fn change_color_of_pixels(&mut self, pixels: Vec<[u16; 2]>, new_color: [u8; 4]) -> Result<(), ErrorKind> {
1623 let dib_header = self.get_dib_header();
1626 let dib_header = match dib_header {
1627 Ok(returned_dib_header) => returned_dib_header,
1628 Err(e) => return Err(e),
1629 };
1630 let header = self.get_header();
1631 let bitcount = dib_header.bitcount;
1632 if bitcount != 24 && bitcount != 32 {
1633 return Err(ErrorKind::Unsupported);
1634 }
1635 let row_length = (f64::from((bitcount/8) as u16*dib_header.width as u16/4).ceil() as u32 * 4) as u16;
1636 for pixel in pixels {
1637 let x = pixel[0];
1638 let mut y = pixel[1];
1639 if dib_header.height > 0 {
1640 y = dib_header.height as u16 - y - 1;
1641 }
1642 let start = y*row_length+header.bfOffBits as u16+(bitcount/8)*x;
1643 if bitcount == 24 {
1644 self.contents[start as usize] = new_color[2];
1645 self.contents[(start+1) as usize] = new_color[1];
1646 self.contents[(start+2) as usize] = new_color[0];
1647 } else if bitcount == 32 {
1648 let red_mask: u32 = dib_header.RedMask.unwrap();
1649 let blue_mask: u32 = dib_header.BlueMask.unwrap();
1650 let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1651 if alpha_mask < red_mask {
1652 if red_mask < blue_mask {
1653 self.contents[start as usize] = new_color[3];
1655 self.contents[(start+1) as usize] = new_color[0];
1656 self.contents[(start+2) as usize] = new_color[1];
1657 self.contents[(start+3) as usize] = new_color[2];
1658 } else {
1659 self.contents[start as usize] = new_color[3];
1661 self.contents[(start+1) as usize] = new_color[2];
1662 self.contents[(start+2) as usize] = new_color[1];
1663 self.contents[(start+3) as usize] = new_color[0];
1664 }
1665 } else {
1666 if red_mask < blue_mask {
1667 self.contents[start as usize] = new_color[0];
1669 self.contents[(start+1) as usize] = new_color[1];
1670 self.contents[(start+2) as usize] = new_color[2];
1671 self.contents[(start+3) as usize] = new_color[3];
1672 } else {
1673 self.contents[start as usize] = new_color[2];
1675 self.contents[(start+1) as usize] = new_color[1];
1676 self.contents[(start+2) as usize] = new_color[0];
1677 self.contents[(start+3) as usize] = new_color[3];
1678 }
1679 }
1680 }
1681 }
1682 return Ok(());
1683 }
1684 pub fn draw_image(&mut self, x: u16, y: u16, bmp2: BMP) -> Result<(), ErrorKind> {
1687 let dib_header = self.get_dib_header().unwrap();
1688 let pixel_data = self.get_pixel_data();
1689 let pixel_data = match pixel_data {
1690 Ok(returned_pixel_data) => returned_pixel_data,
1691 Err(e) => return Err(e),
1692 };
1693 let bmp2_dib_header = bmp2.get_dib_header().unwrap();
1695 let bmp2_height = (bmp2_dib_header.height).abs();
1696 let bmp2_width = bmp2_dib_header.width;
1697 let bmp2_pixel_data = bmp2.get_pixel_data();
1698 let bmp2_pixel_data = match bmp2_pixel_data {
1699 Ok(returned_pixel_data) => returned_pixel_data,
1700 Err(e) => return Err(e),
1701 };
1702 for i in 0..bmp2_height {
1703 for j in 0..bmp2_width {
1704 let new_pixel = [x+j as u16, y+i as u16];
1705 let old_color = self.get_color_of_px_efficient(i as usize, j as usize, &dib_header, &pixel_data).unwrap();
1706 let new_color = bmp2.get_color_of_px_efficient(i as usize, j as usize, &bmp2_dib_header, &bmp2_pixel_data).unwrap();
1707 if old_color[3] == 255 && new_color[3] == 255 {
1708 self.change_color_of_pixel(new_pixel[0], new_pixel[1], new_color)?;
1709 } else {
1710 self.change_color_of_pixel(new_pixel[0], new_pixel[1], BMP::composite_colors(new_color, old_color))?;
1711 }
1712 }
1713 }
1714 return Ok(());
1715 }
1716 pub fn change_opacity(&mut self, opacity: u8) -> Result<(), ErrorKind> {
1718 let dib_header = self.get_dib_header();
1720 let dib_header = match dib_header {
1721 Ok(returned_dib_header) => returned_dib_header,
1722 Err(e) => return Err(e),
1723 };
1724 let height: u16 = dib_header.height.abs() as u16;
1725 let width: u16 = dib_header.width as u16;
1726 let pixel_data = self.get_pixel_data();
1727 let pixel_data = match pixel_data {
1728 Ok(returned_pixel_data) => returned_pixel_data,
1729 Err(e) => return Err(e),
1730 };
1731 for y in 0..height {
1733 for x in 0..width {
1734 let old_color = self.get_color_of_px_efficient(x as usize, y as usize, &dib_header, &pixel_data);
1736 let old_color: [u8; 4] = match old_color {
1737 Ok(returned_color) => returned_color,
1738 Err(e) => return Err(e),
1739 };
1740 let new_fill: [u8; 4] = [old_color[0], old_color[1], old_color[2], opacity];
1741 self.change_color_of_pixel(x, y, new_fill)?;
1743 }
1744 }
1745 return Ok(());
1746 }
1747 pub fn invert(&mut self, invert_alpha: Option<bool>) -> Result<(), ErrorKind> {
1749 let dib_header = self.get_dib_header();
1751 let dib_header = match dib_header {
1752 Ok(returned_dib_header) => returned_dib_header,
1753 Err(e) => return Err(e),
1754 };
1755 let height: u16 = dib_header.height.abs() as u16;
1756 let width: u16 = dib_header.width as u16;
1757 let pixel_data = self.get_pixel_data();
1758 let pixel_data = match pixel_data {
1759 Ok(returned_pixel_data) => returned_pixel_data,
1760 Err(e) => return Err(e),
1761 };
1762 let header = self.get_header();
1763 for y in 0..height {
1765 for x in 0..width {
1766 let old_color = self.get_color_of_px_efficient(x as usize, y as usize, &dib_header, &pixel_data);
1769 let old_color: [u8; 4] = match old_color {
1770 Ok(returned_color) => returned_color,
1771 Err(e) => return Err(e),
1772 };
1773 let mut new_fill: [u8; 4] = [255 - old_color[0], 255 - old_color[1], 255 - old_color[2], old_color[3]];
1774 if invert_alpha.is_some() {
1775 let invert_alpha_unwrapped = invert_alpha.unwrap();
1776 if invert_alpha_unwrapped {
1777 new_fill = [255 - old_color[0], 255 - old_color[1], 255 - old_color[2], 255 - old_color[3]];
1778 }
1779 }
1780 self.change_color_of_pixel_efficient(x, y, new_fill, &dib_header, &header)?;
1782 }
1783 }
1784 return Ok(());
1785 }
1786 pub fn translate(&mut self, x: i16, y: i16) -> Result<(), ErrorKind> {
1789 let dib_header = self.get_dib_header();
1790 let dib_header = match dib_header {
1791 Ok(returned_dib_header) => returned_dib_header,
1792 Err(e) => return Err(e),
1793 };
1794 let og_bmp: BMP = self.clone();
1796 let height = dib_header.height.abs() as i16;
1797 let width = dib_header.width as i16;
1798 let og_pixel_data = self.get_pixel_data();
1799 let og_pixel_data = match og_pixel_data {
1800 Ok(returned_pixel_data) => returned_pixel_data,
1801 Err(e) => return Err(e),
1802 };
1803 self.contents = BMP::new(dib_header.height, dib_header.width, Some([255, 255, 255, 0])).contents;
1805 for row in 0..height {
1806 for column in 0..width {
1807 let temp_x: i16 = column+x;
1808 let temp_y: i16 = row+y;
1809 if temp_y < 0 || temp_y >= height || temp_x < 0 || temp_x >= width {
1810 continue;
1811 }
1812 let color = og_bmp.get_color_of_px_efficient(column as usize, row as usize, &dib_header, &og_pixel_data).unwrap();
1813 self.change_color_of_pixel(temp_x as u16, temp_y as u16, color)?;
1814 }
1815 }
1816 return Ok(());
1817 }
1818 pub fn rotate(&mut self, deg: f64, center_option: Option<[u16; 2]>) -> Result<(), ErrorKind> {
1820 let center: [u16; 2];
1821 if center_option.is_none() {
1822 center = [0, 0];
1823 } else {
1824 center = center_option.unwrap();
1825 }
1826 let rad: f64 = BMP::deg_to_rad(deg);
1828 let dib_header = self.get_dib_header();
1829 let dib_header = match dib_header {
1830 Ok(returned_dib_header) => returned_dib_header,
1831 Err(e) => return Err(e),
1832 };
1833 let og_bmp: BMP = self.clone();
1834 let height = dib_header.height.abs() as u16;
1835 let width = dib_header.width as u16;
1836 let og_pixel_data = self.get_pixel_data();
1837 let og_pixel_data = match og_pixel_data {
1838 Ok(returned_pixel_data) => returned_pixel_data,
1839 Err(e) => return Err(e),
1840 };
1841 self.contents = BMP::new(dib_header.height, dib_header.width, Some([255, 255, 255, 0])).contents;
1842 for row in 0..height {
1843 for column in 0..width {
1844 let (x2, y2) = BMP::rotate_point(rad, [column, row], center);
1845 if y2 < 0 || y2 >= i32::from(height) || x2 < 0 || x2 >= i32::from(width) {
1847 continue;
1848 }
1849 let color = og_bmp.get_color_of_px_efficient(column as usize, row as usize, &dib_header, &og_pixel_data).unwrap();
1851 self.change_color_of_pixel(x2 as u16, y2 as u16, color)?;
1853 }
1854 }
1856 return Ok(());
1857 }
1858 pub fn separable_blur(&mut self, radius: u8, gen_distribution: impl Fn(u8, u8) -> u16, horizontal: Option<bool>, vertical: Option<bool>) -> Result<(), ErrorKind> {
1860 let mut do_horizontal: bool = true;
1865 let mut do_vertical: bool = true;
1866 if horizontal.is_some() {
1867 do_horizontal = horizontal.unwrap();
1868 }
1869 if vertical.is_some() {
1870 do_vertical = vertical.unwrap();
1871 }
1872 let dib_header = self.get_dib_header();
1873 let dib_header = match dib_header {
1874 Ok(returned_dib_header) => returned_dib_header,
1875 Err(e) => return Err(e),
1876 };
1877 let height: u16 = dib_header.height.abs() as u16;
1878 let width: u16 = dib_header.width as u16;
1879 if radius > 16 || radius == 0 {
1880 return Err(ErrorKind::InvalidParameter("Blur/filter radius is invalid since bigger than 16 or is 0".to_string()));
1881 }
1882 let pixel_data = self.get_pixel_data();
1885 let pixel_data = match pixel_data {
1886 Ok(returned_pixel_data) => returned_pixel_data,
1887 Err(e) => return Err(e),
1888 };
1889 if do_horizontal {
1890 let mut weights: Vec<u16> = Vec::new();
1892 for l in 0..radius {
1893 weights.push(gen_distribution(radius, radius-l));
1895 }
1896 weights.push(gen_distribution(radius, 0));
1897 for r in 0..radius {
1898 weights.push(gen_distribution(radius, r+1));
1900 }
1901 for y in 0..height {
1902 for x in 0..width {
1903 let mut total_weight: u16 = 0;
1904 for w in &weights {
1905 total_weight += w;
1906 }
1907 let mut total_weight_h = total_weight;
1908 for hl_b in 1..radius+1 {
1910 if x < u16::from(hl_b) {
1911 total_weight_h -= weights[(radius-hl_b) as usize];
1913 }
1914 }
1915 for hr_b in 1..radius+1 {
1916 if x+u16::from(hr_b) >= width {
1917 total_weight_h -= weights[(radius+hr_b) as usize];
1919 }
1920 }
1921 let mut new_r_h: f64 = 0.0;
1923 let mut new_g_h: f64 = 0.0;
1924 let mut new_b_h: f64 = 0.0;
1925 let mut new_a_h: f64 = 0.0;
1926 for hl in 1..radius+1 {
1927 if x >= u16::from(hl) {
1928 let hl_color = self.get_color_of_px_efficient((x-u16::from(hl)) as usize, y as usize, &dib_header, &pixel_data).unwrap();
1930 new_r_h += hl_color[0] as f64 * (weights[(radius-hl) as usize] as f64) / total_weight_h as f64;
1931 new_g_h += hl_color[1] as f64 * (weights[(radius-hl) as usize] as f64) / total_weight_h as f64;
1932 new_b_h += hl_color[2] as f64 * (weights[(radius-hl) as usize] as f64) / total_weight_h as f64;
1933 new_a_h += hl_color[3] as f64 * (weights[(radius-hl) as usize] as f64) / total_weight_h as f64;
1934 }
1935 }
1936 let center_color = self.get_color_of_px_efficient(x as usize, y as usize, &dib_header, &pixel_data).unwrap();
1937 new_r_h += center_color[0] as f64 * (weights[(radius) as usize] as f64) / total_weight_h as f64;
1938 new_g_h += center_color[1] as f64 * (weights[(radius) as usize] as f64) / total_weight_h as f64;
1939 new_b_h += center_color[2] as f64 * (weights[(radius) as usize] as f64) / total_weight_h as f64;
1940 new_a_h += center_color[3] as f64 * (weights[(radius) as usize] as f64) / total_weight_h as f64;
1941 for hr in 1..radius+1 {
1942 if x+u16::from(hr) < width {
1943 let hr_color = self.get_color_of_px_efficient((x+u16::from(hr)) as usize, y as usize, &dib_header, &pixel_data).unwrap();
1945 new_r_h += hr_color[0] as f64 * (weights[(radius-hr) as usize] as f64) / total_weight_h as f64;
1946 new_g_h += hr_color[1] as f64 * (weights[(radius-hr) as usize] as f64) / total_weight_h as f64;
1947 new_b_h += hr_color[2] as f64 * (weights[(radius-hr) as usize] as f64) / total_weight_h as f64;
1948 new_a_h += hr_color[3] as f64 * (weights[(radius-hr) as usize] as f64) / total_weight_h as f64;
1949 }
1950 }
1951 let new_color: [u8; 4] = [new_r_h.round() as u8, new_g_h.round() as u8, new_b_h.round() as u8, new_a_h.round() as u8];
1953 self.change_color_of_pixel(x, y, new_color).unwrap();
1955 }
1956 }
1957 }
1958 let pixel_data = self.get_pixel_data();
1961 let pixel_data = match pixel_data {
1962 Ok(returned_pixel_data) => returned_pixel_data,
1963 Err(e) => return Err(e),
1964 };
1965 if do_vertical {
1966 let mut weights: Vec<u16> = Vec::new();
1968 for l in 0..radius {
1969 weights.push(gen_distribution(radius, radius-l));
1971 }
1972 weights.push(gen_distribution(radius, 0));
1973 for r in 0..radius {
1974 weights.push(gen_distribution(radius, r+1));
1976 }
1977 for y in 0..height {
1978 for x in 0..width {
1979 let mut total_weight: u16 = 0;
1980 for w in &weights {
1981 total_weight += w;
1982 }
1983 let mut total_weight_v = total_weight;
1984 for vu_b in 1..radius+1 {
1986 if y < u16::from(vu_b) {
1987 total_weight_v -= weights[(radius-vu_b) as usize];
1989 }
1990 }
1991 for vd_b in 1..radius+1 {
1992 if y+u16::from(vd_b) >= height {
1993 total_weight_v -= weights[(radius+vd_b) as usize];
1995 }
1996 }
1997 let mut new_r_h: f64 = 0.0;
1999 let mut new_g_h: f64 = 0.0;
2000 let mut new_b_h: f64 = 0.0;
2001 let mut new_a_h: f64 = 0.0;
2002 for vu in 1..radius+1 {
2003 if y >= u16::from(vu) {
2004 let vu_color = self.get_color_of_px_efficient(x as usize, (y-u16::from(vu)) as usize, &dib_header, &pixel_data).unwrap();
2006 new_r_h += f64::from(vu_color[0]) * f64::from(weights[(radius-vu) as usize]) / f64::from(total_weight_v);
2007 new_g_h += f64::from(vu_color[1]) * f64::from(weights[(radius-vu) as usize]) / f64::from(total_weight_v);
2008 new_b_h += f64::from(vu_color[2]) * f64::from(weights[(radius-vu) as usize]) / f64::from(total_weight_v);
2009 new_a_h += f64::from(vu_color[3]) * f64::from(weights[(radius-vu) as usize]) / f64::from(total_weight_v);
2010 }
2011 }
2012 let center_color = self.get_color_of_px_efficient(x as usize, y as usize, &dib_header, &pixel_data).unwrap();
2014 new_r_h += f64::from(center_color[0]) * f64::from(weights[(radius) as usize]) / f64::from(total_weight_v);
2015 new_g_h += f64::from(center_color[1]) * f64::from(weights[(radius) as usize]) / f64::from(total_weight_v);
2016 new_b_h += f64::from(center_color[2]) * f64::from(weights[(radius) as usize]) / f64::from(total_weight_v);
2017 new_a_h += f64::from(center_color[3]) * f64::from(weights[(radius) as usize]) / f64::from(total_weight_v);
2018 for vd in 1..radius+1 {
2019 if y+u16::from(vd) < height {
2020 let vd_color = self.get_color_of_px_efficient(x as usize, (y+u16::from(vd)) as usize, &dib_header, &pixel_data).unwrap();
2022 new_r_h += f64::from(vd_color[0]) * f64::from(weights[(radius-vd) as usize]) / f64::from(total_weight_v);
2023 new_g_h += f64::from(vd_color[1]) * f64::from(weights[(radius-vd) as usize]) / f64::from(total_weight_v);
2024 new_b_h += f64::from(vd_color[2]) * f64::from(weights[(radius-vd) as usize]) / f64::from(total_weight_v);
2025 new_a_h += f64::from(vd_color[3]) * f64::from(weights[(radius-vd) as usize]) / f64::from(total_weight_v);
2026 }
2027 }
2028 let new_color: [u8; 4] = [new_r_h.round() as u8, new_g_h.round() as u8, new_b_h.round() as u8, new_a_h.round() as u8];
2030 self.change_color_of_pixel(x, y, new_color).unwrap();
2032 }
2033 }
2034 }
2035 return Ok(());
2036 }
2037 pub fn box_blur(&mut self, radius: u8) -> Result<(), ErrorKind> {
2045 let gen_box_distribution = |_radius: u8, _distance: u8| -> u16 {
2047 1u16
2048 };
2049 return self.separable_blur(radius, gen_box_distribution, None, None);
2050 }
2051 pub fn gaussian_blur(&mut self, radius: u8) -> Result<(), ErrorKind> {
2057 let gen_gaussian_distribution = |radius: u8, distance: u8| -> u16 {
2059 if distance == radius {
2061 return 1u16;
2063 }
2064 let n = radius*2+1-1;
2066 let k = radius-distance;
2067 let mut term: f64 = 1.0;
2068 for i in 1..radius+2 {
2069 term = term * ((n+1-i) as f64/f64::from(i));
2070 if i == k {
2071 break;
2072 }
2073 }
2074 return term as u16;
2075 };
2076 return self.separable_blur(radius, gen_gaussian_distribution, None, None);
2077 }
2078 pub fn grayscale(&mut self) -> Result<(), ErrorKind> {
2081 let dib_header = self.get_dib_header();
2082 let dib_header = match dib_header {
2083 Ok(returned_dib_header) => returned_dib_header,
2084 Err(e) => return Err(e),
2085 };
2086 let height: u16 = dib_header.height.abs() as u16;
2087 let width: u16 = dib_header.width as u16;
2088 let pixel_data = self.get_pixel_data();
2089 let pixel_data = match pixel_data {
2090 Ok(returned_pixel_data) => returned_pixel_data,
2091 Err(e) => return Err(e),
2092 };
2093 let header = self.get_header();
2094 for y in 0..height {
2096 for x in 0..width {
2097 let old_color = self.get_color_of_px_efficient(x as usize, y as usize, &dib_header, &pixel_data);
2100 let old_color: [u8; 4] = match old_color {
2101 Ok(returned_color) => returned_color,
2102 Err(e) => return Err(e),
2103 };
2104 self.change_color_of_pixel_efficient(x, y, BMP::rgb_to_grayscale(old_color), &dib_header, &header)?;
2106 }
2107 }
2108 return Ok(());
2109 }
2110 pub fn greyscale(&mut self) -> Result<(), ErrorKind> {
2111 self.grayscale()
2113 }
2114 pub fn channel_grayscale(&mut self, channel: RGBAChannel) -> Result<(), ErrorKind> {
2116 let dib_header = self.get_dib_header();
2118 let dib_header = match dib_header {
2119 Ok(returned_dib_header) => returned_dib_header,
2120 Err(e) => return Err(e),
2121 };
2122 let height: u16 = dib_header.height.abs() as u16;
2123 let width: u16 = dib_header.width as u16;
2124 let pixel_data = self.get_pixel_data();
2125 let pixel_data = match pixel_data {
2126 Ok(returned_pixel_data) => returned_pixel_data,
2127 Err(e) => return Err(e),
2128 };
2129 let header = self.get_header();
2130 for y in 0..height {
2132 for x in 0..width {
2133 let old_color = self.get_color_of_px_efficient(x as usize, y as usize, &dib_header, &pixel_data);
2136 let old_color: [u8; 4] = match old_color {
2137 Ok(returned_color) => returned_color,
2138 Err(e) => return Err(e),
2139 };
2140 let use_color: u8;
2141 match channel {
2142 RGBAChannel::Red => use_color = old_color[0],
2143 RGBAChannel::Green => use_color = old_color[1],
2144 RGBAChannel::Blue => use_color = old_color[2],
2145 RGBAChannel::Alpha => {
2146 use_color = old_color[3];
2147 self.change_color_of_pixel_efficient(x, y, [use_color, use_color, use_color, use_color], &dib_header, &header)?;
2148 return Ok(());
2149 },
2150 }
2151 self.change_color_of_pixel_efficient(x, y, [use_color, use_color, use_color, old_color[3]], &dib_header, &header)?;
2153 }
2154 }
2155 return Ok(());
2156 }
2157 pub fn surround_filter(&mut self, radius: u8, get_new_pixel: impl Fn(Vec<[u8; 4]>) -> [u8; 4]) -> Result<(), ErrorKind> {
2158 let dib_header = self.get_dib_header();
2160 let dib_header = match dib_header {
2161 Ok(returned_dib_header) => returned_dib_header,
2162 Err(e) => return Err(e),
2163 };
2164 let height: u16 = dib_header.height.abs() as u16;
2165 let width: u16 = dib_header.width as u16;
2166 if radius > 16 || radius == 0 {
2167 return Err(ErrorKind::InvalidParameter("Blur/filter radius is invalid since bigger than 16 or is 0".to_string()));
2168 }
2169 let pixel_data = self.get_pixel_data();
2170 let pixel_data = match pixel_data {
2171 Ok(returned_pixel_data) => returned_pixel_data,
2172 Err(e) => return Err(e),
2173 };
2174 let header = self.get_header();
2175 for y in 0..height {
2176 for x in 0..width {
2177 let mut surrounding_colors: Vec<[u8; 4]> = Vec::new();
2178 let rows: i16 = i16::from(radius*2+1);
2180 for row in 0..rows {
2181 let row_y = y as i16-(i16::from(radius)-row);
2182 if row_y < 0 {
2183 continue;
2184 } else if row_y as u16 >= height {
2185 continue;
2186 }
2187 for left_num in 1..u16::from(radius+1) {
2189 if (i32::from(x)-i32::from(left_num)) < 0 {
2190 continue;
2191 }
2192 let left_pixel_color = self.get_color_of_pixel_efficient((x-left_num) as usize, row_y as usize, &dib_header, &pixel_data)?;
2193 surrounding_colors.push(left_pixel_color);
2194 }
2195 let center_pixel_color = self.get_color_of_pixel_efficient(x as usize, row_y as usize, &dib_header, &pixel_data)?;
2197 surrounding_colors.push(center_pixel_color);
2198 for right_num in 1..u16::from(radius+1) {
2200 if (x+right_num) >= width {
2201 continue;
2202 }
2203 let right_pixel_color = self.get_color_of_pixel_efficient((x+right_num) as usize, row_y as usize, &dib_header, &pixel_data)?;
2204 surrounding_colors.push(right_pixel_color);
2205 }
2206 }
2207 self.change_color_of_pixel_efficient(x, y, get_new_pixel(surrounding_colors), &dib_header, &header)?;
2208 }
2209 }
2210 return Ok(());
2211 }
2212 pub fn median_filter(&mut self, radius: u8) -> Result<(), ErrorKind> {
2218 let get_median_pixel = |surrounding_pixels: Vec<[u8; 4]>| -> [u8; 4] {
2220 let iter_surrounding = (&surrounding_pixels).into_iter();
2221 let mut r_vec = iter_surrounding.clone().map(|item| item[0]).collect::<Vec<u8>>();
2222 r_vec.sort();
2223 let mut g_vec = iter_surrounding.clone().map(|item| item[1]).collect::<Vec<u8>>();
2224 g_vec.sort();
2225 let mut b_vec = iter_surrounding.clone().map(|item| item[2]).collect::<Vec<u8>>();
2226 b_vec.sort();
2227 let mut a_vec = iter_surrounding.clone().map(|item| item[3]).collect::<Vec<u8>>();
2228 a_vec.sort();
2229 [r_vec[r_vec.len()/2], g_vec[g_vec.len()/2], b_vec[b_vec.len()/2], a_vec[a_vec.len()/2]]
2232 };
2233 return self.surround_filter(radius, get_median_pixel);
2234 }
2235 pub fn mean_filter(&mut self, radius: u8) -> Result<(), ErrorKind> {
2237 let get_mean_pixel = |surrounding_pixels: Vec<[u8; 4]>| -> [u8; 4] {
2238 let iter_surrounding = (&surrounding_pixels).into_iter();
2239 let total_r: f64 = f64::from(iter_surrounding.clone().map(|item| u16::from(item[0])).reduce(|prev_total, current| prev_total+current).unwrap());
2240 let total_g: f64 = f64::from(iter_surrounding.clone().map(|item| u16::from(item[1])).reduce(|prev_total, current| prev_total+current).unwrap());
2241 let total_b: f64 = f64::from(iter_surrounding.clone().map(|item| u16::from(item[2])).reduce(|prev_total, current| prev_total+current).unwrap());
2242 let total_a: f64 = f64::from(iter_surrounding.clone().map(|item| u16::from(item[3])).reduce(|prev_total, current| prev_total+current).unwrap());
2243 let average_r: u8 = (total_r/(&surrounding_pixels).len() as f64).round() as u8;
2244 let average_g: u8 = (total_g/(&surrounding_pixels).len() as f64).round() as u8;
2245 let average_b: u8 = (total_b/(&surrounding_pixels).len() as f64).round() as u8;
2246 let average_a: u8 = (total_a/(&surrounding_pixels).len() as f64).round() as u8;
2247 [average_r, average_g, average_b, average_a]
2248 };
2249 return self.surround_filter(radius, get_mean_pixel);
2250 }
2251 pub fn draw_line(&mut self, fill: [u8; 4], p1: [u16; 2], p2: [u16; 2]) -> Result<(), ErrorKind> {
2254 if p1[0] == p2[0] {
2255 for ay in 0..(p2[1] as i16 - p1[1] as i16 + 1).abs() as u16 {
2257 if p1[1] < p2[1] {
2259 self.change_color_of_pixel(p1[0], p1[1]+ay, fill)?;
2260 } else {
2261 self.change_color_of_pixel(p2[0], p2[1]+ay, fill)?;
2262 }
2263 }
2264 } else if p1[1] == p2[1] {
2265 for ax in 0..(p2[0] as i16 - p1[0] as i16 + 1).abs() as u16 {
2267 if p1[0] < p2[0] {
2269 self.change_color_of_pixel(p1[0]+ax, p1[1], fill)?;
2270 } else {
2271 self.change_color_of_pixel(p2[0]+ax, p2[1], fill)?;
2272 }
2273 }
2274 } else {
2275 let vertical_diff: u16 = ((p2[1] as i16 - p1[1] as i16).abs() + 1) as u16;
2276 let horizontal_diff: u16 = ((p2[0] as i16 - p1[0] as i16).abs() + 1) as u16;
2277 let leftmost_p;
2279 let rightmost_p;
2280 if p1[0] < p2[0] {
2281 leftmost_p = p1;
2282 rightmost_p = p2;
2283 } else {
2284 leftmost_p = p2;
2285 rightmost_p = p1;
2286 }
2287 let highest_p;
2288 let lowest_p;
2289 if p1[1] < p2[1] {
2290 highest_p = p1;
2291 lowest_p = p2;
2292 } else {
2293 highest_p = p2;
2294 lowest_p = p1;
2295 }
2296 if vertical_diff >= 2 {
2298 let middle_segment_length: u16;
2299 let two_ends_combined_length;
2300 if horizontal_diff >= vertical_diff {
2301 middle_segment_length = f64::from((horizontal_diff)/(vertical_diff)).floor() as u16;
2303 two_ends_combined_length = horizontal_diff - (middle_segment_length*(vertical_diff-2));
2305 } else {
2306 middle_segment_length = f64::from((vertical_diff)/(horizontal_diff)).floor() as u16;
2309 two_ends_combined_length = vertical_diff - (middle_segment_length*(horizontal_diff-2));
2311 }
2312 if two_ends_combined_length == 1 {
2315 self.change_color_of_pixel(leftmost_p[0], leftmost_p[1], fill)?;
2319 for j in 0..(vertical_diff-2) {
2321 for ji in 0..middle_segment_length {
2322 if j == vertical_diff-3 && ji == middle_segment_length-1 {
2324 continue;
2325 }
2326 if highest_p == leftmost_p {
2327 self.change_color_of_pixel(leftmost_p[0]+ji+j*middle_segment_length, rightmost_p[1]+j, fill)?;
2328 } else {
2329 self.change_color_of_pixel(leftmost_p[0]+ji+j*middle_segment_length, rightmost_p[1]-j, fill)?;
2330 }
2331 }
2332 }
2333 self.change_color_of_pixel(rightmost_p[0], rightmost_p[1], fill)?;
2335 } else if horizontal_diff >= vertical_diff {
2336 let end_segment_length = two_ends_combined_length/2;
2337 for i in 0..end_segment_length {
2340 self.change_color_of_pixel(leftmost_p[0]+i, leftmost_p[1], fill)?;
2341 }
2342 for j in 0..(vertical_diff-2) {
2344 for ji in 0..middle_segment_length {
2345 if highest_p == leftmost_p {
2346 self.change_color_of_pixel(leftmost_p[0]+ji+j*middle_segment_length+end_segment_length, leftmost_p[1]+j+1, fill)?;
2347 } else {
2348 self.change_color_of_pixel(leftmost_p[0]+ji+j*middle_segment_length, rightmost_p[1]-j, fill)?;
2349 }
2350 }
2351 }
2352 for k in 0..end_segment_length {
2354 self.change_color_of_pixel(rightmost_p[0]-k, rightmost_p[1], fill)?;
2355 }
2356 } else if horizontal_diff < vertical_diff {
2357 let end_segment_length = two_ends_combined_length/2;
2358 for i in 0..end_segment_length {
2361 self.change_color_of_pixel(leftmost_p[0], leftmost_p[1]+i, fill)?;
2362 }
2363 for j in 0..(horizontal_diff-2) {
2365 for ji in 0..middle_segment_length {
2366 if highest_p == leftmost_p {
2367 self.change_color_of_pixel(leftmost_p[0]+j+1, leftmost_p[1]+ji+j*middle_segment_length+end_segment_length, fill)?;
2369 } else {
2370 self.change_color_of_pixel(leftmost_p[0]-j, rightmost_p[1]+ji+j*middle_segment_length, fill)?;
2372 }
2373 }
2374 }
2375 for k in 0..end_segment_length {
2377 self.change_color_of_pixel(lowest_p[0], lowest_p[1]-k, fill)?;
2378 }
2379 }
2380 } else {
2381 let first_segment: u16 = (f64::from(horizontal_diff/2)).floor() as u16;
2383 let second_segment: u16 = (f64::from(horizontal_diff/2)).ceil() as u16;
2384 for i in 0..first_segment {
2385 self.change_color_of_pixel(leftmost_p[0]+i, leftmost_p[1], fill)?;
2386 }
2387 for j in 0..second_segment {
2388 self.change_color_of_pixel(rightmost_p[0]-j, rightmost_p[1], fill)?;
2389 }
2390 }
2391 }
2392 return Ok(());
2393 }
2394 pub fn draw_rectangle(&mut self, fill: Option<[u8; 4]>, stroke: Option<[u8; 4]>, p1: [u16; 2], p2: [u16; 2]) -> Result<(), ErrorKind> {
2397 if stroke.is_some() {
2398 let unwrapped_stroke = stroke.unwrap();
2399 self.draw_line(unwrapped_stroke, p1, [p2[0], p1[1]])?;
2401 self.draw_line(unwrapped_stroke, [p1[0], p2[1]], [p2[0], p2[1]])?;
2403 self.draw_line(unwrapped_stroke, p1, [p1[0], p2[1]])?;
2405 self.draw_line(unwrapped_stroke, [p2[0], p1[1]], [p2[0], p2[1]])?;
2407 }
2408 if fill.is_some() {
2410 let dib_header = self.get_dib_header();
2411 let dib_header = match dib_header {
2412 Ok(returned_dib_header) => returned_dib_header,
2413 Err(e) => return Err(e),
2414 };
2415 let header = self.get_header();
2416 let unwrapped_fill = fill.unwrap();
2417 let p1_mod = [p1[0]+1, p1[1]+1];
2418 let p2_mod = [p2[0]-1, p2[1]-1];
2419 for y in 0..(p2_mod[1]-p1_mod[1]+1) {
2420 for x in 0..(p2_mod[0]-p1_mod[0]+1) {
2421 self.change_color_of_pixel_efficient(p1_mod[0]+x, p1_mod[1]+y, unwrapped_fill, &dib_header, &header)?;
2422 }
2423 }
2424 }
2425 return Ok(());
2426 }
2427 pub fn draw_ellipse(&mut self, center: [u16; 2], xlength: u16, ylength: u16, stroke: [u8; 4], fill: Option<[u8; 4]>, guess: bool) -> Result<(), ErrorKind> {
2432 let mut enclosure_all: Vec<[u16; 2]> = Vec::new();
2434 let xlength_2: f64 = i32::pow(xlength.into(), 2) as f64;
2439 let ylength_2: f64 = i32::pow(ylength.into(), 2) as f64;
2441 let mut prev_y = 0;
2442 for il in 1..xlength+1 {
2443 let c_x = il;
2444 let c_x_2: f64 = i32::pow(c_x.into(), 2) as f64;
2445 let y = (((1 as f64-c_x_2/xlength_2)*ylength_2) as f64).sqrt().round() as u16;
2446 self.change_color_of_pixel(center[0]-c_x, center[1]+y, stroke)?;
2447 self.change_color_of_pixel(center[0]-c_x, center[1]-y, stroke)?;
2448 enclosure_all.extend([[center[0]-c_x, center[1]+y], [center[0]-c_x, center[1]-y]]);
2449 let diff = (prev_y as i16-y as i16).abs() as u16;
2450 if diff > 1 && il != 1 && guess {
2451 for d in 1..diff+1 {
2452 self.change_color_of_pixel(center[0]-c_x+1, center[1]+y+d, stroke)?;
2453 self.change_color_of_pixel(center[0]-c_x+1, center[1]-y-d, stroke)?;
2454 enclosure_all.extend([[center[0]-c_x+1, center[1]+y+d], [center[0]-c_x+1, center[1]-y-d]]);
2455 }
2456 }
2457 prev_y = y;
2458 }
2459 for ir in 1..xlength+1 {
2460 let c_x = ir;
2461 let c_x_2: f64 = i32::pow(c_x.into(), 2) as f64;
2462 let y = (((1.0-c_x_2/xlength_2)*ylength_2) as f64).sqrt().round() as u16;
2463 self.change_color_of_pixel(center[0]+c_x, center[1]+y, stroke)?;
2464 self.change_color_of_pixel(center[0]+c_x, center[1]-y, stroke)?;
2465 enclosure_all.extend([[center[0]+c_x, center[1]+y], [center[0]+c_x, center[1]-y]]);
2466 let diff = (prev_y as i16-y as i16).abs() as u16;
2467 if diff > 1 && ir != 1 && guess {
2468 for d in 1..diff+1 {
2469 self.change_color_of_pixel(center[0]+c_x-1, center[1]+y+d, stroke)?;
2470 self.change_color_of_pixel(center[0]+c_x-1, center[1]-y-d, stroke)?;
2471 enclosure_all.extend([[center[0]+c_x-1, center[1]+y+d], [center[0]+c_x-1, center[1]-y-d]]);
2472 }
2473 }
2474 prev_y = y;
2475 }
2476 self.change_color_of_pixel(center[0], center[1]+ylength, stroke)?;
2477 self.change_color_of_pixel(center[0], center[1]-ylength, stroke)?;
2478 enclosure_all.extend([[center[0], center[1]+ylength], [center[0], center[1]-ylength]]);
2479 if fill.is_some() {
2480 let mut enclosure: Vec<[u16; 2]> = Vec::new();
2482 for coord in enclosure_all {
2483 if !enclosure.contains(&coord) {
2484 if coord[0] != 0 {
2485 if enclosure.contains(&[coord[0]-1, coord[1]]) {
2486 continue;
2487 }
2488 }
2489 if enclosure.contains(&[coord[0]+1, coord[1]]) {
2490 continue;
2491 }
2492 enclosure.push(coord);
2493 }
2494 }
2495 let unwrapped_fill = fill.unwrap();
2496 for y1 in 0..ylength*2+1 {
2498 for x1 in 0..xlength*2+1 {
2499 let point1: [i32; 2] = [i32::from(center[0])+i32::from(x1)-i32::from(xlength), i32::from(center[1])+i32::from(y1)-i32::from(ylength)];
2500 if point1[0] < 0 || point1[1] < 0 {
2501 continue;
2502 }
2503 let point1: [u16; 2] = [point1[0] as u16, point1[1] as u16];
2504 let point_inside = BMP::point_in_enclosure(point1, &enclosure);
2505 if point_inside {
2506 self.change_color_of_pixel(point1[0], point1[1], unwrapped_fill)?;
2507 }
2508 }
2509 }
2510 }
2511 return Ok(());
2512 }
2513 pub fn fill_bucket(&mut self, fill: [u8; 4], x: usize, y: usize) -> Result<Vec<[u16; 2]>, ErrorKind> {
2515 let dib_header = self.get_dib_header();
2519 let dib_header = match dib_header {
2520 Ok(returned_dib_header) => returned_dib_header,
2521 Err(e) => return Err(e),
2522 };
2523 let pixel_data = self.get_pixel_data();
2524 let pixel_data = match pixel_data {
2525 Ok(returned_pixel_data) => returned_pixel_data,
2526 Err(e) => return Err(e),
2527 };
2528 let replace_color = self.get_color_of_px(x, y);
2529 let replace_color: [u8; 4] = match replace_color {
2530 Ok(returned_replace_color) => returned_replace_color,
2531 Err(e) => return Err(e),
2532 };
2533 let mut visited: Vec<[u16; 2]> = Vec::new();
2534 let mut queue: Vec<[u16; 2]> = Vec::new();
2535 queue.push([x as u16, y as u16]);
2537 while queue.len() > 0 {
2538 let x2: u16 = queue[0][0];
2541 let y2: u16 = queue[0][1];
2542 if y2+1 < dib_header.height as u16 {
2548 if !visited.contains(&[x2, y2+1]) && !queue.contains(&[x2, y2+1]) {
2549 let down_color = self.get_color_of_px_efficient(x2 as usize, (y2+1) as usize, &dib_header, &pixel_data)?;
2550 if down_color == replace_color {
2551 queue.push([x2, y2+1]);
2552 }
2553 }
2554 }
2555 if y2 != 0 {
2556 if !visited.contains(&[x2, y2-1]) && !queue.contains(&[x2, y2-1]) {
2557 let up_color = self.get_color_of_px_efficient(x2 as usize, (y2-1) as usize, &dib_header, &pixel_data)?;
2559 if up_color == replace_color {
2560 queue.push([x2, y2-1]);
2561 }
2562 }
2563 }
2564 if x2 != 0 {
2565 if !visited.contains(&[x2-1, y2]) && !queue.contains(&[x2-1, y2]) {
2566 let left_color = self.get_color_of_px_efficient((x2-1) as usize, y2 as usize, &dib_header, &pixel_data)?;
2567 if left_color == replace_color {
2568 queue.push([x2-1, y2]);
2569 }
2570 }
2571 }
2572 if x2+1 < dib_header.width as u16 {
2573 if !visited.contains(&[x2+1, y2]) && !queue.contains(&[x2+1, y2]) {
2574 let right_color = self.get_color_of_px_efficient((x2+1) as usize, y2 as usize, &dib_header, &pixel_data)?;
2575 if right_color == replace_color {
2576 queue.push([x2+1, y2]);
2577 }
2578 }
2579 }
2580 visited.push(queue[0]);
2582 queue.remove(0);
2583 }
2584 let header = self.get_header();
2586 for px in &visited {
2587 self.change_color_of_pixel_efficient(px[0], px[1], fill, &dib_header, &header)?;
2588 }
2589 return Ok(visited);
2591 }
2592 pub fn save_to_new(self, file_path: &str) -> Result<(), ErrorKind> {
2595 let mut new_file = fs::File::create(&std::path::Path::new(file_path)).unwrap();
2596 let write_op = new_file.write_all(&self.contents);
2597 match write_op {
2598 Ok(_file) => return Ok(()),
2599 Err(_e) => return Err(ErrorKind::FailedToWrite),
2600 };
2601 }
2602}
2603
2604#[test]
2609fn non_existent_file() {
2610 assert!(BMP::new_from_file("doesnotexist.bmp") == Err(ErrorKind::NotFound));
2611}
2612
2613#[test]
2614fn out_of_bounds_access() {
2615 let mut b = BMP::new(150, 150, None);
2616 assert!(b.get_color_of_pixel(0, 150) == Err(ErrorKind::OutOfBounds));
2617 assert!(b.get_color_of_pixel(150, 0).is_err());
2618 assert!(b.get_color_of_pixel(150, 150).is_err());
2619 assert!(b.get_color_of_pixel(149, 149).is_ok());
2620 assert!(b.change_color_of_pixel(149, 149, [128, 128, 128, 255]).is_ok());
2621 assert!(b.change_color_of_pixel(150, 150, [128, 128, 128, 255]).is_err());
2622}