rustic_bitmap/
get.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
use crate::Bitmap;
use crate::Rgb;
use crate::Point;
use crate::constants::*;


/// A trait for accessing metadata and pixel-level data from a bitmap.
pub trait Get {
        /// Returns the byte offset where the pixel array starts in the image file.
	fn get_pixel_array_offset(&self) -> usize;

        /// Returns the height of the image in pixels.
	fn get_height(&self) -> u32;

        /// Returns the width of the image in pixels.
	fn get_width(&self) -> u32;

        /// Returns the number of bits per pixel (e.g., 24 for RGB, 32 for RGBA).
	fn get_bits_per_pixel(&self) -> u8;

        /// Returns the total size of the image file in bytes.
	fn get_file_size(&self) -> u32;

        /// Returns the size of the info header (40 bytes for BITMAPINFOHEADER).
	fn get_size_of_info_header(&self) -> u32;

        /// Returns the number of color planes (usually 1).
	fn get_planes(&self) -> u16;

        /// Returns the compression method used
        /// 0 = BI_RGB   no compression  
        /// 1 = BI_RLE8 8bit RLE encoding  
        /// 2 = BI_RLE4 4bit RLE encoding
	fn get_compression(&self) -> u32;

        /// Returns the compressed image size.
        /// It is valid to set this =0 if Compression = 0
	fn get_image_size(&self) -> u32;

        /// Returns the number of colors used in the bitmap (0 = default).
	fn get_colors_used(&self) -> u32;

	/// Returns the number of important colors (0 = all colors are important).
	fn get_important_colors(&self) -> u32;

        /// Returns the total size of padding bytes added to the image data.
	fn get_padding_size(&self) -> u32;

        /// Returns the number of padding bytes per scan line.
	fn get_padding_per_line(&self) -> u8;

        /// Returns the RGB value of the pixel at the specified point.
        ///
        /// # Arguments
        ///
        /// * `point` - A reference to a `Point` representing the x and y position.
        ///
        /// # Returns
        ///
        /// * `Ok(Rgb)` containing the pixel color at the specified point.
        /// * `Err(String)` if the point is out of bounds or invalid.
	fn get_pixel(&self, point: &Point) -> Result<Rgb, String>;
}

impl Get for Vec<u8> {
	fn get_pixel(&self, point: &Point) -> Result<Rgb, String> {
                // Ensure the point is within the bounds of the bitmap
                if !self.point_exists(point) {
			return Err(format!("Point ({}, {}) is out of bounds", point.x, point.y));
                }

                // Convert dimensions to usize for consistent indexing
                let width = self.get_width() as usize;
                let bytes_per_pixel = (self.get_bits_per_pixel() as usize) / 8;

                // Calculate the row width in bytes, including padding
                let row_width = width * bytes_per_pixel;
                let padding = (4 - (row_width % 4)) % 4; // Calculate padding to make row width a multiple of 4
                let padded_row_width = row_width + padding;

                // Calculate the base index for the pixel location
                let base_index = (point.y as usize * padded_row_width + point.x as usize * bytes_per_pixel) + self.get_pixel_array_offset() as usize;

                // Ensure the base index is within bounds before accessing the array
                if base_index + 2 < self.len() {
                        let blue = self[base_index];
                        let green = self[base_index + 1];
                        let red = self[base_index + 2];
			return Ok(Rgb {r: red, g: green, b: blue});
                } else {
                        return Err(format!("Point ({}, {}) is out of bounds", point.x, point.y));
                }
        }

	fn get_padding_per_line(&self) -> u8 {
                // Calculate the width of the scan line in bytes
                let mut padded_width: u32 = self.get_width() * (self.get_bits_per_pixel() as u32 / 8);
                // Compute the remainder when divided by 4
                let remainder = padded_width % 4;

                // If there's no remainder, it's already a multiple of 4
                if remainder != 0 {
                        // Add padding to make it a multiple of 4
                        padded_width += 4 - remainder;
                }
                // Return the padding (which is the difference between padded width and original width)
                (padded_width - (self.get_width() * (self.get_bits_per_pixel() as u32 / 8))) as u8
	}

	fn get_padding_size(&self) -> u32 {
		self.get_padding_per_line() as u32 * self.get_height()
	}

	fn get_pixel_array_offset(&self) -> usize {
		return self[HEADER_PIXEL_ARRAY_OFFSET] as usize; 
	}

	fn get_width(&self) -> u32 {
		let byte_slice = &self[HEADER_WIDTH_OFFSET..HEADER_WIDTH_OFFSET+4];
		u32::from_le_bytes([byte_slice[0], byte_slice[1], byte_slice[2], byte_slice[3]])
	}

	fn get_height(&self) -> u32 {
		let byte_slice = &self[HEADER_HEIGHT_OFFSET..HEADER_HEIGHT_OFFSET+4];
		u32::from_le_bytes([byte_slice[0], byte_slice[1], byte_slice[2], byte_slice[3]])
        }

	fn get_bits_per_pixel(&self) -> u8 {
		return self[HEADER_BITS_PER_PIXEL];
	}

	fn get_file_size(&self) -> u32 {
		let byte_slice = &self[HEADER_FILE_SIZE..HEADER_FILE_SIZE+4];
		u32::from_le_bytes([byte_slice[0], byte_slice[1], byte_slice[2], byte_slice[3]])
	}

	fn get_size_of_info_header(&self) -> u32 {
		let byte_slice = &self[INFOHEADER_SIZE_OFFSET..INFOHEADER_SIZE_OFFSET+4];
		u32::from_le_bytes([byte_slice[0], byte_slice[1], byte_slice[2], byte_slice[3]])
	}
	
	fn get_planes(&self) -> u16 {
		let byte_slice = &self[HEADER_PLANES_OFFSET..HEADER_PLANES_OFFSET+2];
		u16::from_le_bytes([byte_slice[0], byte_slice[1]])
	}

	fn get_compression(&self) -> u32 {
		let byte_slice = &self[HEADER_COMPRESSION_OFFSET..HEADER_COMPRESSION_OFFSET+4];
		u32::from_le_bytes([byte_slice[0], byte_slice[1], byte_slice[2], byte_slice[3]])
	}

	fn get_image_size(&self) -> u32 {
		let byte_slice = &self[HEADER_IMAGE_SIZE..HEADER_IMAGE_SIZE+4];
		u32::from_le_bytes([byte_slice[0], byte_slice[1], byte_slice[2], byte_slice[3]])
	}

	fn get_colors_used(&self) -> u32 {
		let byte_slice = &self[HEADER_COLORS_USED..HEADER_COLORS_USED+4];
		u32::from_le_bytes([byte_slice[0], byte_slice[1], byte_slice[2], byte_slice[3]])
	}

	fn get_important_colors(&self) -> u32 {
		let byte_slice = &self[HEADER_IMPORTANT_COLORS..HEADER_IMPORTANT_COLORS+4];
		u32::from_le_bytes([byte_slice[0], byte_slice[1], byte_slice[2], byte_slice[3]])
	}
}