1use byteorder::{LittleEndian, WriteBytesExt};
2
3const HEADER_LENGHT: u32 = 14;
4const INFO_LENGHT: u32 = 124;
5const COLOR_SIZE: u32 = 4;
6const RESERVED: u8 = 0;
7
8#[derive(Debug)]
9pub struct BitMap {
10 header: BitMapHeader,
11 info: BitMapInfo,
12 color_table: ColorTable,
13 array: Vec<u8>,
14}
15
16impl Default for BitMap {
17 fn default() -> Self {
18 Self::new(740, 480)
19 }
20}
21
22impl BitMap {
23 pub fn new(width: usize, height: usize) -> Self {
24 let mut b = BitMap {
25 header: BitMapHeader::new(),
26 info: BitMapInfo::new(),
27 color_table: ColorTable::new(),
28 array: vec![],
29 };
30
31 b.info.set_width(width as i32);
32 b.info.set_height(height as i32);
33
34 b
35 }
36
37 pub fn add_pixels(&mut self, pic: &[u8]) {
38 self.array.extend_from_slice(pic);
39 }
40
41 pub fn add_color<C>(&mut self, color: C) -> u8
42 where C: Into<Color>
43 {
44 let color = color.into();
45 self.color_table.add_color(color);
46
47 self.info.clr_used += 1;
48 (self.info.clr_used - 1) as u8
49 }
50
51 pub fn as_vec(&mut self) -> Vec<u8> {
52 let mut bitmap = vec![]; let pixels_data_offset = HEADER_LENGHT + INFO_LENGHT + self.color_table.get_size();
55 self.header.set_data_offset(pixels_data_offset);
56
57 let file_lenght = pixels_data_offset + self.array.len() as u32;
58 self.header.set_lenght(file_lenght);
59
60 bitmap.extend_from_slice(&self.header.to_vec());
61 bitmap.extend_from_slice(&self.info.to_vec());
62 bitmap.extend_from_slice(&self.color_table.to_vec());
63 bitmap.extend_from_slice(&self.array);
64 bitmap
65 }
66}
67
68#[derive(Debug)]
69struct BitMapHeader {
70 little_indian: u16,
71 file_length: u32,
72 reserved: u32,
73 f_off_bitsfield: u32,
74}
75
76impl BitMapHeader {
77 fn new() -> Self {
78 BitMapHeader {
79 little_indian: 0x4d42,
80 file_length: 0u32,
81 reserved: 0u32,
82 f_off_bitsfield: 0u32,
83 }
84 }
85
86 fn set_lenght(&mut self, length: u32) {
87 self.file_length = length;
88 }
89
90
91 fn set_data_offset(&mut self, offset: u32) {
92 self.f_off_bitsfield = offset;
93 }
94
95 fn to_vec(&self) -> Vec<u8> {
96 let mut header = vec![]; header.write_u16::<LittleEndian>(self.little_indian).unwrap();
98 header.write_u32::<LittleEndian>(self.file_length).unwrap();
99 header.write_u32::<LittleEndian>(self.reserved).unwrap();
100 header.write_u32::<LittleEndian>(self.f_off_bitsfield).unwrap();
101 header
102 }
103}
104
105#[derive(Debug)]
106struct BitMapInfo {
107 size: u32,
108 width: i32,
109 height: i32,
110 planes: u16,
111 bitcount: u16,
112 compression: u32,
113 sizeimage: u32,
114 xpels_per_meter: i32,
115 ypels_per_meter: i32,
116 clr_used: u32,
117 clr_important: u32,
118
119 red_mask: u32,
120 green_mask: u32,
121 blue_mask: u32,
122 alpha_mask: u32,
123 c_stype: u32,
124
125 c_iexyztriple: Vec<u8>,
126
127 gamma_red: u32,
128 gamma_green: u32,
129 gamma_blue: u32,
130
131 intent: u32,
132 profile_data: u32,
133 profile_size: u32,
134 reserved: u32,
135}
136
137impl BitMapInfo {
138 fn new() -> Self {
139 BitMapInfo {
140 size: 124u32,
141 width: 0i32,
142 height: 0i32,
143 planes: 1u16,
144 bitcount: 8u16,
145 compression: 0u32,
146 sizeimage: 0u32,
147 xpels_per_meter: 3780i32, ypels_per_meter: 3780i32, clr_used: 0u32,
150 clr_important: 0u32,
151
152 red_mask: 0u32,
153 green_mask: 0u32,
154 blue_mask: 0u32,
155 alpha_mask: 0u32,
156 c_stype: 0u32,
157
158 c_iexyztriple: vec![0u8; 36],
159 gamma_red: 0u32,
160 gamma_green: 0u32,
161 gamma_blue: 0u32,
162
163 intent: 4u32, profile_data: 0u32,
165 profile_size: 0u32,
166 reserved: 0u32,
167 }
168 }
169
170 fn to_vec(&self) -> Vec<u8> {
171 let mut bmp_info = vec![]; bmp_info.write_u32::<LittleEndian>(self.size).unwrap(); bmp_info.write_i32::<LittleEndian>(self.width).unwrap(); bmp_info.write_i32::<LittleEndian>(self.height).unwrap(); bmp_info.write_u16::<LittleEndian>(self.planes).unwrap(); bmp_info.write_u16::<LittleEndian>(self.bitcount).unwrap(); bmp_info.write_u32::<LittleEndian>(self.compression).unwrap(); bmp_info.write_u32::<LittleEndian>(self.sizeimage).unwrap(); bmp_info.write_i32::<LittleEndian>(self.xpels_per_meter).unwrap(); bmp_info.write_i32::<LittleEndian>(self.ypels_per_meter).unwrap(); bmp_info.write_u32::<LittleEndian>(self.clr_used).unwrap(); bmp_info.write_u32::<LittleEndian>(self.clr_important).unwrap(); bmp_info.write_u32::<LittleEndian>(self.red_mask).unwrap(); bmp_info.write_u32::<LittleEndian>(self.green_mask).unwrap(); bmp_info.write_u32::<LittleEndian>(self.blue_mask).unwrap(); bmp_info.write_u32::<LittleEndian>(self.alpha_mask).unwrap(); bmp_info.write_u32::<LittleEndian>(self.c_stype).unwrap(); bmp_info.extend_from_slice(&self.c_iexyztriple); bmp_info.write_u32::<LittleEndian>(self.gamma_red).unwrap(); bmp_info.write_u32::<LittleEndian>(self.gamma_green).unwrap(); bmp_info.write_u32::<LittleEndian>(self.gamma_blue).unwrap(); bmp_info.write_u32::<LittleEndian>(self.intent).unwrap(); bmp_info.write_u32::<LittleEndian>(self.profile_data).unwrap(); bmp_info.write_u32::<LittleEndian>(self.profile_size).unwrap(); bmp_info.write_u32::<LittleEndian>(self.reserved).unwrap(); bmp_info
202 }
203
204 fn set_width(&mut self, width: i32) {
205 self.width = width;
206 }
207
208 fn set_height(&mut self, height: i32) {
209 self.height = height;
210 }
211}
212
213#[derive(Debug)]
214struct ColorTable {
215 count: u32,
216 table: Vec<u8>,
217}
218
219impl ColorTable {
220 fn new() -> ColorTable {
221 ColorTable {
222 count: 0,
223 table: vec![],
224 }
225 }
226
227 fn add_color(&mut self, color: Color) {
228 self.count += 1;
229 self.table.append(&mut color.get_buffer());
230 }
231
232 fn get_size(&self) -> u32 {
233 256 * COLOR_SIZE
234 }
235
236 fn to_vec(&self) -> Vec<u8> {
237 let mut v: Vec<u8> = vec![];
238 v.extend_from_slice(&self.table);
239 for _ in self.count..256 {
240 v.write_u32::<LittleEndian>(0).unwrap();
241 }
242 v
243 }
244}
245
246#[derive(Debug)]
247pub struct Color {
248 pub r: u8,
249 pub g: u8,
250 pub b: u8,
251}
252
253impl Color {
254 fn get_buffer(&self) -> Vec<u8> {
255 vec![self.b, self.g, self.r, RESERVED]
256 }
257}
258
259impl<'a> From<&'a str> for Color {
261 fn from(string: &str) -> Color {
262 let s = &string.to_lowercase();
263 let r = u8::from_str_radix(&s[1..3], 16).unwrap();
264 let g = u8::from_str_radix(&s[3..5], 16).unwrap();
265 let b = u8::from_str_radix(&s[5..7], 16).unwrap();
266 Color { r: r, g: g, b: b }
267 }
268}