simple_chart/
bitmap.rs

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![]; // V5
53
54        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![]; // V5
97        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, // 96 dpi
148            ypels_per_meter: 3780i32, // 96 dpi
149            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, // Picture
164            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![]; // V5
172        bmp_info.write_u32::<LittleEndian>(self.size).unwrap(); // size
173        bmp_info.write_i32::<LittleEndian>(self.width).unwrap(); // width
174        bmp_info.write_i32::<LittleEndian>(self.height).unwrap(); // height
175        bmp_info.write_u16::<LittleEndian>(self.planes).unwrap(); // planes
176        bmp_info.write_u16::<LittleEndian>(self.bitcount).unwrap(); // bitcount 32
177        bmp_info.write_u32::<LittleEndian>(self.compression).unwrap(); // compression 0 - BI_RGB
178        bmp_info.write_u32::<LittleEndian>(self.sizeimage).unwrap(); // sizeimage
179        bmp_info.write_i32::<LittleEndian>(self.xpels_per_meter).unwrap(); // XpelsPerMeter
180        bmp_info.write_i32::<LittleEndian>(self.ypels_per_meter).unwrap(); // YpelsPerMeter
181        bmp_info.write_u32::<LittleEndian>(self.clr_used).unwrap(); // ClrUsed
182        bmp_info.write_u32::<LittleEndian>(self.clr_important).unwrap(); // ClrImportant
183
184        bmp_info.write_u32::<LittleEndian>(self.red_mask).unwrap(); // RedMask
185        bmp_info.write_u32::<LittleEndian>(self.green_mask).unwrap(); // GreenMask
186        bmp_info.write_u32::<LittleEndian>(self.blue_mask).unwrap(); // BlueMask
187        bmp_info.write_u32::<LittleEndian>(self.alpha_mask).unwrap(); // AlphaMask
188        bmp_info.write_u32::<LittleEndian>(self.c_stype).unwrap(); // CSType
189
190        bmp_info.extend_from_slice(&self.c_iexyztriple);                  // CIEXYZTRIPLE
191
192        bmp_info.write_u32::<LittleEndian>(self.gamma_red).unwrap(); // GammaRed
193        bmp_info.write_u32::<LittleEndian>(self.gamma_green).unwrap(); // GammaGreen
194        bmp_info.write_u32::<LittleEndian>(self.gamma_blue).unwrap(); // GammaBlue
195
196        bmp_info.write_u32::<LittleEndian>(self.intent).unwrap(); // Intent
197        bmp_info.write_u32::<LittleEndian>(self.profile_data).unwrap(); // ProfileData
198        bmp_info.write_u32::<LittleEndian>(self.profile_size).unwrap(); // ProfileSize
199        bmp_info.write_u32::<LittleEndian>(self.reserved).unwrap(); // Reserved
200
201        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
259// #ffaabb
260impl<'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}