bmp_rust/
bmp.rs

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;
8//use std::io::ErrorKind;
9
10//support packed dibs, dibs that have no empty gaps
11
12/*
13Documentation - important links
14https://docs.microsoft.com/en-us/windows/win32/gdi/bitmap-header-types
15https://en.wikipedia.org/wiki/BMP_file_format#File_structure
16http://fileformats.archiveteam.org/wiki/BMP
17*/
18
19const HEADER_OFFSET: usize = 14;
20
21//Errors
22#[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
63//Color
64pub enum RGBAChannel {
65  Red,
66  Green,
67  Blue,
68  Alpha,
69}
70
71//BMP Diff
72#[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/// Returned by the `BMP::diff()` method.
80#[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//File header
115/// The BMP file header, see the [microsoft docs](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapfileheader) for more information on the fields.
116#[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    //vector.len() should be 14
134    for i in 0..bytes_vec.len() {
135      bytes_array[i] = bytes_vec[i];
136    }
137    //DEPRECATED
138    //return std::array::IntoIter::new(bytes_array);
139    return IntoIterator::into_iter(bytes_array);
140  }
141}
142
143/*
144DIB Headers
145struct BITMAPCOREHEADER {
146  size: u16,
147  width: u32,
148  height: u32,
149  planes: u16,
150  bitcount: u16,
151}
152if biCompression is BI_ALPHABITFIELDS or BI_BITFIELDS 
153struct BITMAPINFOHEADER {
154  size: u16,
155  width: u32,
156  biHeight can be negative
157  height: i32,
158  planes: u16,
159  bitcount: u16,
160  compression: String,
161  sizeimage: u32,
162  XPelsPerMeter: u32,
163  YPelsPerMeter: u32,
164  ClrUsed: u32,
165  ClrImportant: u32,
166}
167struct BITMAPV4HEADER {
168  size: u16,
169  width: u32,
170  bV4Height can be negative
171  height: i32,
172  planes: u16,
173  bitcount: u16,
174  compression: String,
175  sizeimage: u32,
176  XPelsPerMeter: u32,
177  YPelsPerMeter: u32,
178  ClrUsed: u32,
179  ClrImportant: u32,
180  RedMask: u32,
181  GreenMask: u32,
182  BlueMask: u32,
183  AlphaMask: u32,
184  CSType: String,
185  rgb
186  Endpoints: [[i32; 3]; 3],
187  GammaRed: u32,
188  GammaGreen: u32,
189  GammaBlue: u32,
190}
191struct BITMAPV5HEADER {
192  size: u16,
193  width: u32,
194  height: i32,
195  planes: u16,
196  bitcount: u16,
197  compression: String,
198  sizeimage: u32,
199  XPelsPerMeter: u32,
200  YPelsPerMeter: u32,
201  ClrUsed: u32,
202  ClrImportant: u32,
203  RedMask: u32,
204  GreenMask: u32,
205  BlueMask: u32,
206  AlphaMask: u32,
207  CSType: String,
208  Endpoints: [[i32; 3]; 3],
209  GammaRed: u32,
210  GammaGreen: u32,
211  GammaBlue: u32,
212  Intent: String,
213  ProfileData: u16,
214  ProfileSize: u16,
215  Reserved: Vec<u8>,
216}
217
218enum DIBHEADER {
219  BITMAPCOREHEADER(BITMAPCOREHEADER),
220  BITMAPINFOHEADER(BITMAPINFOHEADER),
221  BITMAPV4HEADER(BITMAPV4HEADER),
222  BITMAPV5HEADER(BITMAPV5HEADER),
223}
224*/
225
226//DIB header
227/// The BMP DIB header, which has multiple versions.
228/// The officially documented versions (BITMAPCOREHEADER, BITMAPINFOHEADER, BITMAPV4HEADER, BITMAPV5HEADER) can be found [here](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmap-structures), 
229/// but there are also some undocumented versions [see wikipedia](https://en.wikipedia.org/wiki/BMP_file_format#DIB_header_(bitmap_information_header)).
230/// 
231/// Find out what version header is being used by accessing the `size` property of the DIB header (returns length of DIB header in bytes), 
232/// since different versions of the DIB headers are all different lengths.
233/// 
234/// Depending on what DIB header version is being used (BITMAPV5HEADER is the most modern and common), fields that are `Option`s may or may not exist.
235/// 
236#[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
265//for non 124 byte dib headers, cut off excess bytes
266impl IntoIterator for DIBHEADER {
267  //DIBHEADER example: line 504ish
268  type Item = u8;
269  type IntoIter = std::array::IntoIter<u8, 124>;
270
271  fn into_iter(self) -> Self::IntoIter {
272    //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();
273    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      //create endpoints list
291      for i in 0..3 {
292        for ii in 0..3 {
293          //4 bytes
294          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      //println!("{:?}", endpoints_l);
301      //wip
302      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      //Reserved
306      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      //Intent
312      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    //vector.len() should be 124
324    for i in 0..bytes_vec.len() {
325      bytes_array[i] = bytes_vec[i];
326    }
327    //DEPRECATED
328    //return std::array::IntoIter::new(bytes_array);
329    return IntoIterator::into_iter(bytes_array);
330  }
331}
332  
333//rgbtriple and rgbquad
334/// Color table used in some versions of the format. Can be either an array of RGB (`RGBTRIPLE`) or RGBA (`RGBQUAD`) colors.
335pub enum ColorTable {
336  RGBTRIPLE(Vec<[u8; 3]>),
337  RGBQUAD(Vec<[u8; 4]>),
338}
339
340//extra bit masks, these are unofficial names
341#[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
362/// Represents loaded BMP file, the `contents` is a vector of the file bytes.
363/// 
364/// Also contains many useful utility functions.
365/// 
366pub struct BMP {
367  pub contents: Vec<u8>,
368  from_file: bool,
369  //bitmap_file_header: BITMAPFILEHEADER,
370  //dib_header: DIBHEADER,
371}
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  //have a file header, generate (40 bytes? 108 bytes? 124 bytes?) dib header, load in [0, 0, 0, 0] for pixels in pixel data in bgra
389  pub fn new(height: i32, width: u32, default_color: Option<[u8; 4]>) -> BMP {
390    let mut contents = Vec::new();
391    //file header
392    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    //turns into bytes, and adds it
402    contents.extend(file_header);
403    //use v5: 124 bytes
404    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      //96 dpi
413      XPelsPerMeter: Some(3780),
414      YPelsPerMeter: Some(3780),
415      //no color table, so ClrUsed and ClrImportant are 0
416      ClrUsed: Some(0),
417      ClrImportant: Some(0),
418      //ARGB?
419      RedMask: Some(16711680),
420      GreenMask: Some(65280),
421      BlueMask: Some(255),
422      AlphaMask: Some(4278190080),
423      //"BGRs" why? I don't know and I will not question
424      CSType: Some("BGRs".to_string()),
425      //I don't know what these numbers mean :)
426      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    //pixels, turn it into the bytes
437    //no rounding is needed, because each row is rounded up to a multiple of u32, which all our pixels are
438    for _pixel_num in 0..(width*height as u32) {
439      //white by default
440      if default_color.is_some() {
441        //change rgb to bgr
442        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    //println!("{:?}", contents);
451    return BMP { contents: contents, from_file: false };
452  }
453  /// Load BMP from file.
454  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  //utilities
459  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  /// Converts bytes to kilobytes (1024 bytes per kilobyte).
478  pub fn num_bytes_to_kilobytes(bytes: u32) -> u32 {
479    //1024 bytes per kilobyte
480    bytes/1024
481  }
482  fn vec_to_4u8_array(vector: Vec<u8>) -> [u8; 4] {
483    let mut array: [u8; 4] = [0u8; 4];
484    //vector.len() should be 4
485    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    //vector.len() should be 2
493    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    //vector.len() should be 1
501    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  //coordinate utilities
529  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    //x2 = x cos - y sin
534    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    //y2 = y cos + x sin
536    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  /// Check if a point is in an enclosure of points, using the even-odd rule.
540  pub fn point_in_enclosure(point: [u16; 2], enclosure: &Vec<[u16; 2]>) -> bool {
541    //implement even odd rule
542    //return false if point is on the border
543    if enclosure.contains(&point) {
544      return false;
545    }
546    //see how many points in enclosure have same y as our point, casting a ray to the right (arbitrary, could be to the left)
547    let same_y_count_right = enclosure.into_iter().filter(|item| {
548      item[1] == point[1] && item[0] > point[0]
549    }).count();
550    //if even, false, if odd, true
551    return same_y_count_right % 2 == 1;
552  }
553  //color related utilities
554  fn alpha_to_percentage(alpha: u8) -> f64 {
555    //.into() turns the u8 into f64 (expected return type)
556    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  /*
562  fn rgb_to_color(rgb: [u8; 3]) -> String {
563    //changes rgb to readable color. (takes rgba) eg: black
564    //finds closest color and returns
565    //colors.keys()
566    //([0, 49, 83], "prussian blue")
567    let colors: HashMap<[u8; 3], String> = HashMap::from([
568      ([255, 255, 255], "white".to_string()),
569      ([0, 0, 0], "black".to_string()),
570      ([255, 0, 0], "red".to_string()),
571      ([0, 255, 0], "green".to_string()),
572      ([0, 0, 255], "blue".to_string()),
573      ([255, 128, 0], "orange".to_string()),
574      ([128, 64, 0], "brown".to_string()),
575      ([0, 128, 0], "dark green".to_string()),
576      ([255, 255, 0], "yellow".to_string()),
577      ([128, 128, 128], "gray".to_string()),
578      ([255, 192, 203], "pink".to_string()),
579      ([128, 0, 128], "purple".to_string()),
580      ([0, 128, 255], "azure".to_string()),
581      ([183, 65, 14], "rust".to_string()),
582      ([0, 128, 128], "teal".to_string()),
583      ([192, 192, 192], "silver".to_string()),
584      ([0, 255, 191], "aquamarine".to_string()),
585      ([128, 0, 0], "maroon".to_string())
586    ]);
587    if colors.contains_key(&rgb) {
588      return colors.get(&rgb).unwrap().to_string();
589    } else {
590      //by default lets say its white
591      let mut closest: [u8; 3] = [255, 255, 255];
592      for c in colors.keys() {
593        let r_diff = (c[0] as i8-rgb[0] as i8).abs() as u16;
594        let g_diff = (c[1] as i8-rgb[1] as i8).abs() as u16;
595        let b_diff = (c[2] as i8-rgb[2] as i8).abs() as u16;
596        let total_diff: u16 = r_diff+g_diff+b_diff;
597        let r2_diff = (closest[0] as i8-rgb[0] as i8).abs() as u16;
598        let g2_diff = (closest[1] as i8-rgb[1] as i8).abs() as u16;
599        let b2_diff = (closest[2] as i8-rgb[2] as i8).abs() as u16;
600        let total_diff2: u16 = r2_diff+g2_diff+b2_diff;
601        if total_diff > total_diff2 {
602          closest = *c;
603        }
604      }
605      return "Similar to ".to_string()+colors.get(&closest).unwrap();
606    }
607  }
608  */
609  /// Converts RGBA to hexadecimal string.
610  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    //each u8 is two hex chars
614    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  /// Converts hexadecimal string to RGBA.
622  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  /// Convert HSL (hue, saturation, lightness) to RGB.
638  pub fn hsl_to_rgb(hsl: [f64; 3]) -> Result<[u8; 3], ErrorKind> {
639    //https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB
640    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    //chroma = (1 - |2 * light - 1|) * sat
651    let chroma: f64 = (1.0 - (2.0 * lig - 1.0).abs()) * sat;
652    //h' = h / 60 deg
653    let hprime: f64 = hue / 60.0;
654    //x = chroma * (1 - |h' % 2 - 1|)
655    let x: f64 = chroma * (1.0 - (hprime % 2.0 - 1.0).abs());
656    let color1: [f64; 3];
657    if hprime < 1.0 {
658      //(c, x, 0)
659      color1 = [chroma, x, 0.0];
660    } else if hprime < 2.0 {
661      //(x, c, 0)
662      color1 = [x, chroma, 0.0];
663    } else if hprime < 3.0 {
664      //(0, c, x)
665      color1 = [0.0, chroma, x];
666    } else if hprime < 4.0 {
667      //(0, x, c)
668      color1 = [0.0, x, chroma];
669    } else if hprime < 5.0 {
670      //(x, 0, c)
671      color1 = [x, 0.0, chroma];
672    } else {
673      //same as `else if hprime < 6.0`
674      //(c, 0, x)
675      color1 = [chroma, 0.0, x];
676    }
677    //[136.0, 0.95, 0.38]
678    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    //convert the a from range 0-255 to range 0-1 (alpha_to_percentage)
684    let a1 = BMP::alpha_to_percentage(color1[3]);
685    let a2 = BMP::alpha_to_percentage(color2[3]);
686    //alpha equation: a0 = a1 + a2(1-a1)
687    let a0 = a1+a2*(1.0 - a1);
688    //c0 = (c1a1 + c2a2(1 - a1)) / a0
689    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    //alpha channel ignored
696    //0.2126R + 0.7152G + 0.0722B
697    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  //file header related
701  fn get_header_bytes(&self) -> &[u8; 14] {
702    //turn slice into array
703    self.contents[..14].try_into().unwrap()
704  }
705  /// Gets the file header. The file header contains the size of the file and offset in bytes to pixel array.
706  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  /// Get the offset in bytes to pixel array from the file header.
717  pub fn get_offset(&self) -> u32 {
718    self.get_header().bfOffBits
719  }
720  /// Get file size, either from the file header or by actually checking the length in bytes of the file
721  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  //diff util
729  /// Returns the difference between two loaded BMP files. Works even if the two files are different height and width.
730  pub fn diff(bmp1: &BMP, bmp2: &BMP) -> Result<ImageDiff, ErrorKind> {
731    //compare two bmps, should work even if the two bmps are different sizes
732    //find the largest height and width of the two bmps
733    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      //will trigger not only if bmp2 has more height, but also if both are same height
758      //but if both are same height, doesn't matter which we pick
759      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    //find the different pixels
768    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  //is from file
799  /// See if BMP was originally loaded from file or not
800  pub fn is_from_file(&self) -> bool {
801    self.from_file
802  }
803  //dib header related
804  /// Get the DIB header for the BMP file. There are several different versions of the DIB header, documented [here](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmap-header-types).
805  /// 
806  /// The BITMAPV5HEADER is the most recent and most common version, and the documentation for that can be found [here](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapv5header).
807  /// 
808  pub fn get_dib_header(&self) -> Result<DIBHEADER, ErrorKind> {
809    //this will not work because there may be other data besides the DIB header
810    //let dib_size: i32 = self.get_offset()-14;
811    //instead we will read the first 4 bytes after the header, which *should* specify the DIB header size, so we can figure out what kind of header it is
812    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        //"BITMAPCOREHEADER"
817        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        //"BITMAPINFOHEADER"
846        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        //"BITMAPV4HEADER"
875        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          //rgb
893          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        //"BITMAPV5HEADER"
905        //dword 4 bytes
906        //long 4 bytes
907        //CIEXYZTRIPLE 36 bytes
908        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          //rgb
926          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          //Some(BMP::bytes_to_string(&self.contents[HEADER_OFFSET+108..HEADER_OFFSET+112]))
932          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        //"unsupported"
939        return Err(ErrorKind::Unsupported);
940      },
941    }
942    return Ok(dib_header);
943  }
944  //extra bit masks
945  fn get_extra_bit_masks(&self) -> Result<EXTRA_BIT_MASKS, ErrorKind> {
946    //should be mutable instead of redefined, maybe
947    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        //see previous comment, should be mutable instead of redefined, maybe
955        //offset should be 14+40
956        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  //color table
979  //in between pixel array and everything else, I guess?
980  //update: use the dib header's 'size' attribute - the actual size
981  //return some kind of vector/array
982  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    //match (?) and extract header, get size
989    //14 is the file header size
990    let mut offset: u32 = 14;
991    //where the actual pixel data starts, so the color table must end sometime before
992    let end: u32;
993    //either rgbtriple or masks or 
994    let data_type: &str;
995    //12, 40, 108, 124
996    match dib_header.size {
997      /*DIBHEADER::BITMAPCOREHEADER(b) | DIBHEADER::BITMAPINFOHEADER(b) | DIBHEADER::BITMAPV4HEADER(b) | DIBHEADER::BITMAPV5HEADER(b) => {
998        size = b.size;
999      }*/
1000      12 => {
1001        //https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapcoreinfo
1002        offset += dib_header.size;
1003        end = self.get_header().bfOffBits;
1004        //RGBTRIPLE, 3 bytes
1005        data_type = "rgbtriple";
1006      },
1007      40 | 108 | 124 => {
1008        //16 bit array instead of rgbquad is possible, but should not be used if file is "stored in a file or transferred to another application" https://www.digicamsoft.com/bmp/bmp.html
1009        offset += dib_header.size;
1010        end = self.get_header().bfOffBits;
1011        //https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfo
1012        //if compression is BI_RGB, using RGBQUAD 
1013        //size of array is biClrUsed
1014        let compression = dib_header.compression.unwrap();
1015        if compression == "BI_BITFIELDS" && (dib_header.bitcount == 16 || dib_header.bitcount == 32) {
1016          //extra bit masks, not color table. return error, or maybe extra bit masks? hmm
1017          return Err(ErrorKind::UseExtraBitMasks);
1018        } else if compression == "BI_RGB" && dib_header.bitcount >= 16 {
1019          //no color table
1020          //color table used for optimizing color palette or something instead, idk
1021          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      //3 bytes
1034      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 /*if "rgbquad" == data_type*/ {
1040      let mut color_table_vec: Vec::<[u8; 4]> = Vec::new();
1041      //4 bytes
1042      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  //pixel array
1051  /// Get the pixel array.
1052  /// Returned as a `VecDeque<Vec<Vec<u8>>`.
1053  /// The `VecDeque` stores rows of pixels. The outer `Vec` contains one row of pixels, and the inner `Vec` represents the actual pixel color.
1054  pub fn get_pixel_data(&self) -> Result<VecDeque<Vec<Vec<u8>>>, ErrorKind> {
1055    //figure out if top down or bottom up
1056    //let it panic if it is an error
1057    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    //figure out row size and image height
1063    //figure out pixel format
1064    //figure out is padded
1065    //monochrome is 1 bit per pixel. lets not support that for now
1066    //Vec<[[u8; dib_header.bitcount/4]; dib_header.width]>
1067    //then change to array (must change to vector first since array size cannot be dynamic)
1068    let mut rows: VecDeque<Vec<Vec<u8>>> = VecDeque::new();
1069    let header = self.get_header();
1070    if dib_header.height < 0 {
1071      //top down (starts from top left)
1072      //add rows as normal, to the back of vector
1073      //header.bfOffBits
1074      //https://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage
1075      let row_length = f64::from(dib_header.bitcount*dib_header.width as u16/32).ceil() as u32 * 4;
1076      //this may not work if there is profile data or other stuff after image?
1077      let rows_num = (self.contents.len() as u32-header.bfOffBits)/row_length;
1078      for row_num in 0..rows_num {
1079        //let row: Vec<[u8; dib_header.bitcount/4]> = Vec::new();
1080        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            //we need to do bitwise operators if the pixels are smaller than 1 byte size (1 bit, 2 bit, 4 bit)
1087            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      //self.contents[]
1104    } else if dib_header.height > 0 {
1105      //bottom up (starts from lower left)
1106      //add rows to front of vector
1107      //let start: u32 = header.bfOffBits+row_num*row_length+pixel*((dib_header.bitcount/8) as u32);
1108      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            //we need to do bitwise operators if the pixels are smaller than 1 byte size (1 bit, 2 bit, 4 bit)
1118            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  //location here is told
1138  //ICC color profile
1139  fn get_color_profile(&self) -> Result<Vec<u8>, ErrorKind> {
1140    //https://en.wikipedia.org/wiki/Color_management
1141    //CIEXYZTRIPLE ?
1142    //https://www.color.org/ICC_Minor_Revision_for_Web.pdf
1143    //seems pretty complex, and niche. We'll check if it exists, if so, return raw bytes data, otherwise return error
1144    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          //dib_header.ProfileData.unwrap()..dib_header.ProfileData.unwrap()+dib_header.ProfileSize.unwrap()
1155        } else {
1156          return Err(ErrorKind::DoesNotExist);
1157        }
1158      },
1159      _ => return Err(ErrorKind::DoesNotExist),
1160    }
1161    //Intent: String,
1162    //ProfileData: u16,
1163    //ProfileSize: u16,
1164    //CSType: String
1165  }
1166  //interpret color data
1167  //returns an array rgba (4 u8)
1168  /// Given x and y coordinates (`(0, 0)` is the upper left corner of the image), get the RGB/RGBA color at that location.
1169  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    //need to check if error
1179    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    //TODO: incorporate masks
1187    //if more than 12 bytes dib header, there are masks
1188    //RedMask, GreenMask, BlueMask, AlphaMask
1189    //if BI_BITFIELDS and 16 or 24 bits
1190    //also for smaller dib header (info), check to see if there are extra bit masks
1191    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        //check masks
1195        //due to complexity we dont actually use the masks, we convert them into integer, and then compare size. Bigger it is, the more the one is to the left
1196        let rgba: [u8; 4];
1197        //these should be from extra bit masks!
1198        let red_mask: u32 = dib_header.RedMask.unwrap();
1199        //let green_mask: u32 = dib_header.GreenMask.unwrap();
1200        let blue_mask: u32 = dib_header.BlueMask.unwrap();
1201        if red_mask < blue_mask {
1202          //assume rgb
1203          rgba = [BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), 255];
1204        } else {
1205          //assume brg
1206          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        //compression is "BI_RGB"
1211        //5 for each r,g,b (15 bits + 1 per pixel)
1212        //currently placeholder
1213        return Ok([0, 0, 0, 255]);
1214      }
1215    } else if dib_header.bitcount == 24 {
1216      //if 24 bit, no need to look at color table because it is rgb.
1217      //there is no alpha value, so it is 100 (nontransparent/opaque)
1218      //order is BGR not RGB
1219      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      //32 means rgba
1223      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        //check masks
1226        //due to complexity we dont actually use the masks, we convert them into integer, and then compare size. Bigger it is, the more the one is to the left
1227        //placeholder
1228        //determine if alpha is in front or back. determine is rgb or brg
1229        let rgba: [u8; 4];
1230        let red_mask: u32 = dib_header.RedMask.unwrap();
1231        //let green_mask: u32 = dib_header.GreenMask.unwrap();
1232        let blue_mask: u32 = dib_header.BlueMask.unwrap();
1233        let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1234        if alpha_mask < red_mask {
1235          //alpha is in front
1236          if red_mask < blue_mask {
1237            //argb
1238            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            //abgr
1241            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          //alpha is in back
1245          if red_mask < blue_mask {
1246            //rgba
1247            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            //bgra
1250            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      //otherwise look at color table for corresponding color. The bit (s) in the pixel data are indexes. We look up the index in the color table to find the color
1260      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      //1, 2, 4 (half byte), 8 (1 bytes), 16 (2 bytes)
1266      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          //the array is fixed size [u8; 3] we want to turn it into [u8; 4] with the 4th being 255
1277          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  /// More efficient version of `get_color_of_pixel` that accepts the DIB header and pixel array as references to prevent unnecessary and slow copying of data.
1292  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    //TODO: incorporate masks
1299    //if more than 12 bytes dib header, there are masks
1300    //RedMask, GreenMask, BlueMask, AlphaMask
1301    //if BI_BITFIELDS and 16 or 24 bits
1302    //also for smaller dib header (info), check to see if there are extra bit masks
1303    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        //check masks
1307        //due to complexity we dont actually use the masks, we convert them into integer, and then compare size. Bigger it is, the more the one is to the left
1308        let rgba: [u8; 4];
1309        //these should be from extra bit masks!
1310        let red_mask: u32 = dib_header.RedMask.unwrap();
1311        //let green_mask: u32 = dib_header.GreenMask.unwrap();
1312        let blue_mask: u32 = dib_header.BlueMask.unwrap();
1313        if red_mask < blue_mask {
1314          //assume rgb
1315          rgba = [BMP::byte_to_int(pixel[0]), BMP::byte_to_int(pixel[1]), BMP::byte_to_int(pixel[2]), 255];
1316        } else {
1317          //assume brg
1318          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        //compression is "BI_RGB"
1323        //5 for each r,g,b (15 bits + 1 per pixel)
1324        //currently placeholder
1325        return Ok([0, 0, 0, 255]);
1326      }
1327    } else if dib_header.bitcount == 24 {
1328      //if 24 bit, no need to look at color table because it is rgb.
1329      //there is no alpha value, so it is 100 (nontransparent/opaque)
1330      //order is BGR not RGB
1331      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      //32 means rgba
1335      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        //check masks
1338        //due to complexity we dont actually use the masks, we convert them into integer, and then compare size. Bigger it is, the more the one is to the left
1339        //placeholder
1340        //determine if alpha is in front or back. determine is rgb or brg
1341        let rgba: [u8; 4];
1342        let red_mask: u32 = dib_header.RedMask.unwrap();
1343        //let green_mask: u32 = dib_header.GreenMask.unwrap();
1344        let blue_mask: u32 = dib_header.BlueMask.unwrap();
1345        let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1346        if alpha_mask < red_mask {
1347          //alpha is in front
1348          if red_mask < blue_mask {
1349            //argb
1350            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            //abgr
1353            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          //alpha is in back
1357          if red_mask < blue_mask {
1358            //rgba
1359            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            //bgra
1362            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      //otherwise look at color table for corresponding color. The bit (s) in the pixel data are indexes. We look up the index in the color table to find the color
1372      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      //1, 2, 4 (half byte), 8 (1 bytes), 16 (2 bytes)
1378      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          //the array is fixed size [u8; 3] we want to turn it into [u8; 4] with the 4th being 255
1389          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  //rgba, bgra, etc
1404  /// See what color format the pixels are stored in.
1405  /// Will return one of the following: rgb, bgr, rgba, bgra, argb, abgr, color table.
1406  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        //check masks
1412        //due to complexity we dont actually use the masks, we convert them into integer, and then compare size. Bigger it is, the more the one is to the left
1413        //these should be from extra bit masks!
1414        let red_mask: u32 = dib_header.RedMask.unwrap();
1415        //let green_mask: u32 = dib_header.GreenMask.unwrap();
1416        let blue_mask: u32 = dib_header.BlueMask.unwrap();
1417        if red_mask < blue_mask {
1418          //assume rgb
1419          return "rgb".to_string();
1420        } else {
1421          //assume brg
1422          return "brg".to_string();
1423        }
1424      } else {
1425        //compression is "BI_RGB"
1426        //5 for each r,g,b (15 bits + 1 per pixel)
1427        //currently placeholder
1428        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      //32 means rgba
1434      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 green_mask: u32 = dib_header.GreenMask.unwrap();
1438        let blue_mask: u32 = dib_header.BlueMask.unwrap();
1439        let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1440        if alpha_mask < red_mask {
1441          //alpha is in front
1442          if red_mask < blue_mask {
1443            //argb
1444            return "argb".to_string();
1445          } else {
1446            //abgr
1447            return "abgr".to_string();
1448          }
1449        } else {
1450          //alpha is in back
1451          if red_mask < blue_mask {
1452            //rgba
1453            return "rgba".to_string();
1454          } else {
1455            //bgra
1456            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  //edit color pixels, only supports 24 and 32 bit
1467  /// Given x and y coordinates (`(0, 0)` is the upper left corner of the image), change the RGB/RGBA color at that location.
1468  /// 
1469  /// Note: Currently only supports files where pixel color is stored as 24 or 32 bits, which should be most BMP files.
1470  /// 
1471  pub fn change_color_of_pixel(&mut self, x: u16, mut y: u16, new_color: [u8; 4]) -> Result<(), ErrorKind> {
1472    //NEW_COLOR IS FLIPPED! See get color from pixel and get the correct order like in get_color_of_px
1473    //todo: top down or bottom down?
1474    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    //bits per pixel
1484    let bitcount = dib_header.bitcount;
1485    //only 24 and 32 bit
1486    if bitcount != 24 && bitcount != 32 {
1487      //return error
1488      return Err(ErrorKind::Unsupported);
1489    }
1490    //depending on if top down or bottom up, adjust  y
1491    if dib_header.height > 0 {
1492      //bottom up
1493      y = dib_header.height as u16 - y - 1;
1494    }
1495    //calculate row width (bytes)
1496    let row_length = (f64::from((bitcount/8) as u16*dib_header.width as u16/4).ceil() as u32 * 4) as u16;
1497    //amount of rows in front = y
1498    //add offset bits: header.bfOffBits (actually bytes)
1499    let start = u32::from(y)*u32::from(row_length)+header.bfOffBits+(bitcount/8) as u32*u32::from(x);
1500    //get indexes to change
1501    //self.contents
1502    //change the contents
1503    if bitcount == 24 {
1504      //order is BGR not RGB
1505      //3 bytes
1506      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 green_mask: u32 = dib_header.RedMask.unwrap();
1512      let blue_mask: u32 = dib_header.BlueMask.unwrap();
1513      let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1514      //4 bytes
1515      if alpha_mask < red_mask {
1516        //alpha in front
1517        if red_mask < blue_mask {
1518          //argb
1519          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          //abgr
1525          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        //alpha in back
1532        if red_mask < blue_mask {
1533          //rgba
1534          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          //bgra
1540          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  /// More efficient version of `change_color_of_pixel` that accepts the DIB header and file header as references to prevent unnecessary and slow copying of data.
1550  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    //bits per pixel
1555    let bitcount = dib_header.bitcount;
1556    //only 24 and 32 bit
1557    if bitcount != 24 && bitcount != 32 {
1558      //return error
1559      return Err(ErrorKind::Unsupported);
1560    }
1561    //depending on if top down or bottom up, adjust  y
1562    if dib_header.height > 0 {
1563      //bottom up
1564      y = dib_header.height as u16 - y - 1;
1565    }
1566    //calculate row width (bytes)
1567    let row_length = (f64::from((bitcount/8) as u16*dib_header.width as u16/4).ceil() as u32 * 4) as u16;
1568    //amount of rows in front = y
1569    //add offset bits: header.bfOffBits (actually bytes)
1570    let start = u32::from(y)*u32::from(row_length)+header.bfOffBits+(bitcount/8) as u32*x as u32;
1571    //get indexes to change
1572    //self.contents
1573    //change the contents
1574    if bitcount == 24 {
1575      //order is BGR not RGB
1576      //3 bytes
1577      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 green_mask: u32 = dib_header.RedMask.unwrap();
1583      let blue_mask: u32 = dib_header.BlueMask.unwrap();
1584      let alpha_mask: u32 = dib_header.AlphaMask.unwrap();
1585      //4 bytes
1586      if alpha_mask < red_mask {
1587        //alpha in front
1588        if red_mask < blue_mask {
1589          //argb
1590          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          //abgr
1596          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        //alpha in back
1603        if red_mask < blue_mask {
1604          //rgba
1605          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          //bgra
1611          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  /// Batch change color of pixels. Pass in a vector of coordinates, and a new color.
1621  /// Useful if wanting to changing many pixels to the same color.
1622  pub fn change_color_of_pixels(&mut self, pixels: Vec<[u16; 2]>, new_color: [u8; 4]) -> Result<(), ErrorKind> {
1623    //same as change_color_of_pixel but more efficient
1624    //see comments in that function for explanations
1625    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            //argb
1654            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            //abgr
1660            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            //rgba
1668            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            //bgra
1674            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  //image editing functions
1685  /// Draw another loaded BMP file on the current BMP file, with upper left corner of the drawn on file at the given x and y coordinates.
1686  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    //get height and width
1694    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  /// Change opacity of the whole image.
1717  pub fn change_opacity(&mut self, opacity: u8) -> Result<(), ErrorKind> {
1718    //todo: option to not change opacity if the alpha channel is 0, and color is 255, 255, 255 or 0, 0, 0
1719    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    //change every pixel
1732    for y in 0..height {
1733      for x in 0..width {
1734        //get pixel color
1735        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        //change pixel color
1742        self.change_color_of_pixel(x, y, new_fill)?;
1743      }
1744    }
1745    return Ok(());
1746  }
1747  /// Invert the colors of the image.
1748  pub fn invert(&mut self, invert_alpha: Option<bool>) -> Result<(), ErrorKind> {
1749    //invert colors of image
1750    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    //change every pixel
1764    for y in 0..height {
1765      for x in 0..width {
1766        //get pixel color
1767        //although we are actively changing the pixel data, because we query the color before it is changed, we can use the old one for efficiency
1768        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        //change pixel color
1781        self.change_color_of_pixel_efficient(x, y, new_fill, &dib_header, &header)?;
1782      }
1783    }
1784    return Ok(());
1785  }
1786  //translate, rotate
1787  /// Translate the image in the horizontal and/or vertical directions.
1788  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    //copy self, to get original colors, iterate through and put new colors
1795    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    //empty self
1804    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  /// Rotate the image. If no center coordinate provided, defaults to `(0, 0)` (top left corner of image). 
1819  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    //change deg ro radians
1827    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        //check to make sure coords are in bounds
1846        if y2 < 0 || y2 >= i32::from(height) || x2 < 0 || x2 >= i32::from(width) {
1847          continue;
1848        }
1849        //round, then color? make sure there are no gaps
1850        let color = og_bmp.get_color_of_px_efficient(column as usize, row as usize, &dib_header, &og_pixel_data).unwrap();
1851        //also color floor/ceil?
1852        self.change_color_of_pixel(x2 as u16, y2 as u16, color)?;
1853      }
1854      //fill in holes
1855    }
1856    return Ok(());
1857  }
1858  //blurs
1859  pub fn separable_blur(&mut self, radius: u8, gen_distribution: impl Fn(u8, u8) -> u16, horizontal: Option<bool>, vertical: Option<bool>) -> Result<(), ErrorKind> {
1860    //a separable blur can be separated into two passes, horizontal and vertical, instead of applying the whole square, meaning much more efficient
1861    //gen_distribution is a closure that, based on radius and 1d distance from center, spits out a weighting
1862    //all the weightings will be added up, and the color of that pixel will be multiplied by weighting/all weightings,
1863    //and added together with all other pixels in row/column, and be the new pixel color
1864    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    //change every pixel
1883    //vertical blur
1884    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      //calculate weights
1891      let mut weights: Vec<u16> = Vec::new();
1892      for l in 0..radius {
1893        //calculate weights to the left
1894        weights.push(gen_distribution(radius, radius-l));
1895      }
1896      weights.push(gen_distribution(radius, 0));
1897      for r in 0..radius {
1898        //calculate weights to the right
1899        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          //check if out of bounds, calculate horizontal weights
1909          for hl_b in 1..radius+1 {
1910            if x < u16::from(hl_b) {
1911              //out of bounds
1912              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              //out of bounds
1918              total_weight_h -= weights[(radius+hr_b) as usize];
1919            }
1920          }
1921          //get pixel values, multiply and add them together
1922          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              //not out of bounds
1929              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              //not out of bounds
1944              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          //round values
1952          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          //write to pixel
1954          self.change_color_of_pixel(x, y, new_color).unwrap();
1955        }
1956      }
1957    }
1958    //repeat for vertical blur
1959    //regenerate pixel data since it has changed
1960    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      //calculate weights
1967      let mut weights: Vec<u16> = Vec::new();
1968      for l in 0..radius {
1969        //calculate weights to the left
1970        weights.push(gen_distribution(radius, radius-l));
1971      }
1972      weights.push(gen_distribution(radius, 0));
1973      for r in 0..radius {
1974        //calculate weights to the right
1975        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          //check if out of bounds, calculate horizontal weights
1985          for vu_b in 1..radius+1 {
1986            if y < u16::from(vu_b) {
1987              //out of bounds
1988              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              //out of bounds
1994              total_weight_v -= weights[(radius+vd_b) as usize];
1995            }
1996          }
1997          //get pixel values, multiply and add them together
1998          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              //not out of bounds
2005              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          //
2013          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              //not out of bounds
2021              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          //round values
2029          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          //write to pixel
2031          self.change_color_of_pixel(x, y, new_color).unwrap();
2032        }
2033      }
2034    }
2035    return Ok(());
2036  }
2037  /// Apply box blur with given radius.
2038  /// The larger the radius, the more it will blur, since the radius determines how many neighbouring pixels will be considered.
2039  /// 
2040  /// A box blur essentially averages the color value of every pixel with the neighbours' color values.
2041  /// 
2042  /// Since a box blur is a separable filter, unlike the mean filter, but has the same effect, it is recommended to use `box_blur` instead of `mean_filter`.
2043  /// 
2044  pub fn box_blur(&mut self, radius: u8) -> Result<(), ErrorKind> {
2045    //in box blur the kernel is just the same for all pixels
2046    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  /// Apply gaussian blur with given radius.
2052  /// The larger the radius, the more it will blur, since the radius determines how many neighbouring pixels will be considered.
2053  /// 
2054  /// Learn more about gaussian blurs [here](https://en.wikipedia.org/wiki/Gaussian_blur).
2055  /// 
2056  pub fn gaussian_blur(&mut self, radius: u8) -> Result<(), ErrorKind> {
2057    //cheat and use pascal's triangle for distribution
2058    let gen_gaussian_distribution = |radius: u8, distance: u8| -> u16 {
2059      //https://en.wikipedia.org/wiki/Pascal%27s_triangle#Calculating_a_row_or_diagonal_by_itself
2060      if distance == radius {
2061        //endpoints are always 1
2062        return 1u16;
2063      }
2064      //add one for the center point, subtract one since rows start at 0
2065      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  //filters
2079  /// Turn the image into grayscale
2080  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    //change every pixel
2095    for y in 0..height {
2096      for x in 0..width {
2097        //get pixel color
2098        //although we are actively changing the pixel data, because we query the color before it is changed, we can use the old one for efficiency
2099        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        //change pixel color, preserving alpha channel
2105        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    //just an alias function with 'grey' instead of 'gray'
2112    self.grayscale()
2113  }
2114  /// Only considers the value of a specific channel (red, green, alpha) when turning the image grayscale.
2115  pub fn channel_grayscale(&mut self, channel: RGBAChannel) -> Result<(), ErrorKind> {
2116    //use r, g, b, or a channel to turn into gray scale image
2117    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    //change every pixel
2131    for y in 0..height {
2132      for x in 0..width {
2133        //get pixel color
2134        //although we are actively changing the pixel data, because we query the color before it is changed, we can use the old one for efficiency
2135        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        //change pixel color, preserving alpha channel
2152        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    //non separable filter that requires the surrounding pixels
2159    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        //get surrounding colors and own color
2179        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          //to the left of the center x
2188          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          //the same column as the center x
2196          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          //to the right of the center x
2199          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  /// A median filter changes the color a value of a pixel to the median color value of all of the pixel's neighbours.
2213  /// The larger the radius, the more neighbouring pixels will be considered.
2214  /// 
2215  /// Median filters are great at filtering out noise.
2216  /// 
2217  pub fn median_filter(&mut self, radius: u8) -> Result<(), ErrorKind> {
2218    //good for filtering out noise
2219    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      //vector[vector.len()/2] will return the middle element in the vector, the length of the vector is odd
2230      //length of vector/2 will be a decimal, but rounded down
2231      [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  /// A less efficient version of the `box_blur`, use that instead.
2236  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  //shape, line making functions
2252  /// Draw a line specifying color fill, start point and end point.
2253  pub fn draw_line(&mut self, fill: [u8; 4], p1: [u16; 2], p2: [u16; 2]) -> Result<(), ErrorKind> {
2254    if p1[0] == p2[0] {
2255      //x matches x, straight vertical line
2256      for ay in 0..(p2[1] as i16 - p1[1] as i16 + 1).abs() as u16 {
2257        //if p1 is below p2
2258        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      //y matches y, straight horizontal line
2266      for ax in 0..(p2[0] as i16 - p1[0] as i16 + 1).abs() as u16 {
2267        //if p1 is to the left of p2
2268        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      //get left most point
2278      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 equal or more than 2, there will be middle segments
2297      if vertical_diff >= 2 {
2298        let middle_segment_length: u16;
2299        let two_ends_combined_length;
2300        if horizontal_diff >= vertical_diff {
2301          // middle segments = floor horizontal/vertical
2302          middle_segment_length = f64::from((horizontal_diff)/(vertical_diff)).floor() as u16;
2303          // two ends = horizontal - (middle segments * (vertical-2))
2304          two_ends_combined_length = horizontal_diff - (middle_segment_length*(vertical_diff-2));
2305        } else {
2306          //else vertical_diff > horizontal_diff
2307          // middle segments = floor vertical/horizontal
2308          middle_segment_length = f64::from((vertical_diff)/(horizontal_diff)).floor() as u16;
2309          // two ends = vertical - (middle segments * (horizontal-2))
2310          two_ends_combined_length = vertical_diff - (middle_segment_length*(horizontal_diff-2));
2311        }
2312        // each end should be two ends / 2
2313        // if two ends = 1, make first end 1 and subtract 1 from last segment and give to last end
2314        if two_ends_combined_length == 1 {
2315          //let end_segment_length = two_ends_combined_length/2;
2316          //first segment
2317          //leftmost_p
2318          self.change_color_of_pixel(leftmost_p[0], leftmost_p[1], fill)?;
2319          //middle segments
2320          for j in 0..(vertical_diff-2) {
2321            for ji in 0..middle_segment_length {
2322              //if last pixel of last segment
2323              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          //last segment
2334          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          //first segment
2338          //leftmost_p
2339          for i in 0..end_segment_length {
2340            self.change_color_of_pixel(leftmost_p[0]+i, leftmost_p[1], fill)?;
2341          }
2342          //middle segments
2343          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          //last segment
2353          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          //first segment
2359          //leftmost_p
2360          for i in 0..end_segment_length {
2361            self.change_color_of_pixel(leftmost_p[0], leftmost_p[1]+i, fill)?;
2362          }
2363          //middle segments
2364          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]+ji+j*middle_segment_length+end_segment_length, leftmost_p[1]+j+1, fill);
2368                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]+ji+j*middle_segment_length, rightmost_p[1]-j, fill);
2371                self.change_color_of_pixel(leftmost_p[0]-j, rightmost_p[1]+ji+j*middle_segment_length, fill)?;
2372              }
2373            }
2374          }
2375          //last segment
2376          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        //if vertical diff is 1, divide in half. if decimal, floor and ceil, those are the two segments. else, two segments are equal length
2382        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  //p1 is top left, p2 is top right
2395  /// Draw rectangle, specifying fill color and/or stroke color, and upper left and lower right corners.
2396  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      //top left to top right
2400      self.draw_line(unwrapped_stroke, p1, [p2[0], p1[1]])?;
2401      //bottom left to bottom right
2402      self.draw_line(unwrapped_stroke, [p1[0], p2[1]], [p2[0], p2[1]])?;
2403      //top left to bottom left
2404      self.draw_line(unwrapped_stroke, p1, [p1[0], p2[1]])?;
2405      //top right to bottom right
2406      self.draw_line(unwrapped_stroke, [p2[0], p1[1]], [p2[0], p2[1]])?;
2407    }
2408    //todo: rewrite to not use bucket
2409    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  /// Draw an ellipse specifying the center coordinates, horizontal radius, vertical radius, stroke color and optionally fill color.
2428  /// 
2429  /// If `guess` is `true`, the function will guess missing parts of the ellipse, so there are no gaps in the ellipse outline.
2430  /// 
2431  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    //todo: add bounds checking when changing the pixels
2433    let mut enclosure_all: Vec<[u16; 2]> = Vec::new();
2434    //x^2/a^2 + y^2/b^2 = 1
2435    //y = sqroot((1 - x^2 / a^2) * b^2)
2436    //plug in values from x-xlength to x+xlength and find y value, fill inside
2437    //aka a^2
2438    let xlength_2: f64 = i32::pow(xlength.into(), 2) as f64;
2439    //aka b^2
2440    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      //remove duplicates
2481      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      //self.fill_bucket(unwrapped_fill, center[0] as usize, center[1] as usize)?;
2497      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  /// Equivalent to the bucket fill tool in many image editors. Specify the starting coordinates and the new fill color.
2514  pub fn fill_bucket(&mut self, fill: [u8; 4], x: usize, y: usize) -> Result<Vec<[u16; 2]>, ErrorKind> {
2515    //todo: have parameter allowing fill if the color only deviates a certain small percentage
2516    //fill same color connected to the (x,y) with new paint
2517    //check up, down, left, right. If same color as initial square, add to queue. Iterate through queue, after iterating add to visit and repeat
2518    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    //let mut i = 0;
2536    queue.push([x as u16, y as u16]);
2537    while queue.len() > 0 {
2538      //i += 1;
2539      //println!("{} {}", i, queue.len());
2540      let x2: u16 = queue[0][0];
2541      let y2: u16 = queue[0][1];
2542      //turn current coords into fill color
2543      //self.change_color_of_pixel(x2, y2, fill);
2544      //check is surrounding (up, down, left, right) are same color
2545      //check to make sure these coords exist. (get height, width)
2546      //remember, indexes start at 0
2547      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          //does not go all the way to up color
2558          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      //end
2581      visited.push(queue[0]);
2582      queue.remove(0);
2583    }
2584    //loop through visited
2585    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    //&self.save_to_new("src/images/e2.bmp");
2590    return Ok(visited);
2591  }
2592  //save image functions
2593  /// Save the image to a new file.
2594  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//https://docs.microsoft.com/en-us/windows/win32/wcs/basic-color-management-concepts
2605
2606/*RGB to written color hash table*/
2607
2608#[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}