1//! Bitmap header
2//!
3//! Information gleaned from [wikipedia](https://en.wikipedia.org/wiki/BMP_file_format) and
4//! [this website](http://paulbourke.net/dataformats/bmp/)
5
6use embedded_graphics::prelude::*;
7
8use crate::{
9 color_table::ColorTable,
10 parser::{le_u16, le_u32, take, take_slice},
11 ParseError,
12};
13
14mod dib_header;
15
16use dib_header::DibHeader;
17
18/// Bits per pixel.
19#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
20#[non_exhaustive]
21pub enum Bpp {
22 /// 1 bit per pixel.
23 Bits1,
24 /// 4 bit per pixel.
25 Bits4,
26 /// 8 bits per pixel.
27 Bits8,
28 /// 16 bits per pixel.
29 Bits16,
30 /// 24 bits per pixel.
31 Bits24,
32 /// 32 bits per pixel.
33 Bits32,
34}
35
36impl Bpp {
37 const fn new(value: u16) -> Result<Self, ParseError> {
38 Ok(match value {
39 1 => Self::Bits1,
40 4 => Self::Bits4,
41 8 => Self::Bits8,
42 16 => Self::Bits16,
43 24 => Self::Bits24,
44 32 => Self::Bits32,
45 _ => return Err(ParseError::UnsupportedBpp(value)),
46 })
47 }
48
49 fn parse(input: &[u8]) -> Result<(&[u8], Self), ParseError> {
50 le_u16(input).and_then(|(input, value)| Ok((input, Self::new(value)?)))
51 }
52
53 /// Returns the number of bits.
54 pub const fn bits(self) -> u16 {
55 match self {
56 Self::Bits1 => 1,
57 Self::Bits4 => 4,
58 Self::Bits8 => 8,
59 Self::Bits16 => 16,
60 Self::Bits24 => 24,
61 Self::Bits32 => 32,
62 }
63 }
64}
65
66/// Image row order.
67#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
68#[non_exhaustive]
69pub enum RowOrder {
70 /// Bottom-up (standard)
71 BottomUp,
72 /// Top-down
73 TopDown,
74}
75
76impl Default for RowOrder {
77 fn default() -> Self {
78 Self::BottomUp
79 }
80}
81
82/// BMP header information.
83///
84/// The header can be accessed by using [`RawBmp::header`](crate::RawBmp::header).
85#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
86pub struct Header {
87 /// Total file size in bytes.
88 pub file_size: u32,
89
90 /// Byte offset from beginning of file at which pixel data begins.
91 pub image_data_start: usize,
92
93 /// Image size in pixels.
94 pub image_size: Size,
95
96 /// Number of bits per pixel.
97 pub bpp: Bpp,
98
99 /// Length in bytes of the image data.
100 pub image_data_len: u32,
101
102 /// Bit masks for the color channels.
103 pub channel_masks: Option<ChannelMasks>,
104
105 /// Row order of the image data within the file
106 pub row_order: RowOrder,
107}
108
109impl Header {
110 pub(crate) fn parse(
111 input: &[u8],
112 ) -> Result<(&[u8], (Header, Option<ColorTable<'_>>)), ParseError> {
113 // File header
114 let (input, magic) = take::<2>(input)?;
115 if &magic != b"BM" {
116 return Err(ParseError::InvalidFileSignature(magic));
117 }
118
119 let (input, file_size) = le_u32(input)?;
120 let (input, _reserved_1) = le_u16(input)?;
121 let (input, _reserved_2) = le_u16(input)?;
122 let (input, image_data_start) = le_u32(input)?;
123
124 // DIB header
125 let (input, dib_header) = DibHeader::parse(input)?;
126
127 let (input, color_table) = if dib_header.color_table_num_entries > 0 {
128 // Each color table entry is 4 bytes long
129 let (input, table) =
130 take_slice(input, dib_header.color_table_num_entries as usize * 4)?;
131 (input, Some(ColorTable::new(table)))
132 } else {
133 (input, None)
134 };
135
136 Ok((
137 input,
138 (
139 Header {
140 file_size,
141 image_data_start: image_data_start as usize,
142 image_size: dib_header.image_size,
143 image_data_len: dib_header.image_data_len,
144 bpp: dib_header.bpp,
145 channel_masks: dib_header.channel_masks,
146 row_order: dib_header.row_order,
147 },
148 color_table,
149 ),
150 ))
151 }
152
153 /// Returns the row length in bytes.
154 ///
155 /// Each row in a BMP file is a multiple of 4 bytes long.
156 pub(crate) fn bytes_per_row(&self) -> usize {
157 let bits_per_row = self.image_size.width as usize * usize::from(self.bpp.bits());
158
159 (bits_per_row + 31) / 32 * (32 / 8)
160 }
161}
162
163/// Bit masks for the color channels.
164#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
165pub struct ChannelMasks {
166 /// Red channel mask.
167 pub red: u32,
168 /// Green channel mask.
169 pub green: u32,
170 /// Blue channel mask.
171 pub blue: u32,
172 /// Alpha channel mask.
173 pub alpha: u32,
174}
175
176impl ChannelMasks {
177 /// Rgb555 color masks.
178 pub const RGB555: Self = Self {
179 red: 0b11111_00000_00000,
180 green: 0b00000_11111_00000,
181 blue: 0b00000_00000_11111,
182 alpha: 0,
183 };
184
185 /// Rgb565 color masks.
186 pub const RGB565: Self = Self {
187 red: 0b11111_000000_00000,
188 green: 0b00000_111111_00000,
189 blue: 0b00000_000000_11111,
190 alpha: 0,
191 };
192
193 /// Rgb888 color masks.
194 pub const RGB888: Self = Self {
195 red: 0xFF0000,
196 green: 0x00FF00,
197 blue: 0x0000FF,
198 alpha: 0,
199 };
200}
201
202#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
203pub enum CompressionMethod {
204 Rgb,
205 Bitfields,
206}
207
208impl CompressionMethod {
209 const fn new(value: u32) -> Result<Self, ParseError> {
210 Ok(match value {
211 0 => Self::Rgb,
212 3 => Self::Bitfields,
213 _ => return Err(ParseError::UnsupportedCompressionMethod(value)),
214 })
215 }
216
217 fn parse(input: &[u8]) -> Result<(&[u8], Self), ParseError> {
218 le_u32(input).and_then(|(input: &[u8], value: u32)| Ok((input, Self::new(value)?)))
219 }
220}
221