use super::bit_depth::BitDepth;
use super::file_header::FileHeader;
use super::util;
use super::image::BitMap;
pub struct InfoHeader {
size: u32,
width: u32,
height: u32,
planes: u16,
bit_depth: u16,
compression: u32,
size_image: u32,
x_pixels_per_meter: u32,
y_pixels_per_meter: u32,
colors_used: u32,
colors_important: u32,
}
impl InfoHeader {
pub fn from_slice_range() -> std::ops::Range<usize> {
let prefix = FileHeader::estimated_byte_size();
prefix..(prefix + InfoHeader::estimated_byte_size())
}
pub fn estimated_byte_size() -> usize {
40
}
}
impl InfoHeader {
pub fn from(bitmap: &BitMap, bit_depth: BitDepth) -> InfoHeader {
let colors_used = match bit_depth {
BitDepth::Color2Bit | BitDepth::Color16Bit | BitDepth::Color256Bit => {
bitmap.get_all_unique_colors().len()
}
_ => 0,
} as u32;
InfoHeader {
size: 40,
width: bitmap.get_width(),
height: bitmap.get_height(),
bit_depth: bit_depth as u16,
planes: 1,
compression: 0,
size_image: 0,
x_pixels_per_meter: 0,
y_pixels_per_meter: 0,
colors_used,
colors_important: 0,
}
}
pub fn from_slice(bit_stream: &[u8]) -> Result<InfoHeader, &'static str> {
let mut i: usize = 0;
if bit_stream.len() < 40 {
return Err("Error reading info header, not enough data found!");
}
Ok(InfoHeader {
size: util::byte_slice_to_u32(bit_stream, &mut i),
width: util::byte_slice_to_u32(bit_stream, &mut i),
height: util::byte_slice_to_u32(bit_stream, &mut i),
planes: util::byte_slice_to_u16(bit_stream, &mut i),
bit_depth: util::byte_slice_to_u16(bit_stream, &mut i),
compression: util::byte_slice_to_u32(bit_stream, &mut i),
size_image: util::byte_slice_to_u32(bit_stream, &mut i),
x_pixels_per_meter: util::byte_slice_to_u32(bit_stream, &mut i),
y_pixels_per_meter: util::byte_slice_to_u32(bit_stream, &mut i),
colors_used: util::byte_slice_to_u32(bit_stream, &mut i),
colors_important: util::byte_slice_to_u32(bit_stream, &mut i),
})
}
pub fn as_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&self.size.to_le_bytes());
bytes.extend_from_slice(&self.width.to_le_bytes());
bytes.extend_from_slice(&self.height.to_le_bytes());
bytes.extend_from_slice(&self.planes.to_le_bytes());
bytes.extend_from_slice(&self.bit_depth.to_le_bytes());
bytes.extend_from_slice(&self.compression.to_le_bytes());
bytes.extend_from_slice(&self.size_image.to_le_bytes());
bytes.extend_from_slice(&self.x_pixels_per_meter.to_le_bytes());
bytes.extend_from_slice(&self.y_pixels_per_meter.to_le_bytes());
bytes.extend_from_slice(&self.colors_used.to_le_bytes());
bytes.extend_from_slice(&self.colors_important.to_le_bytes());
bytes
}
pub fn get_byte_size(&self) -> u32 {
self.size
}
pub fn get_bit_depth(&self) -> Option<BitDepth> {
match self.bit_depth {
1 => Some(BitDepth::Color2Bit),
4 => Some(BitDepth::Color16Bit),
8 => Some(BitDepth::Color256Bit),
24 => Some(BitDepth::AllColors),
32 => Some(BitDepth::AllColorsAndShades),
_ => None,
}
}
pub fn get_width(&self) -> u32 {
self.width
}
pub fn get_height(&self) -> u32 {
self.height
}
pub fn get_colors_used(&self) -> u32 {
self.colors_used
}
}
#[cfg(debug_assertions)]
impl std::fmt::Display for InfoHeader {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"
Header Size: {}, Width: {}, Height: {}, Bit Count: {}
Planes: {}, compression: {}, image size: {}
x pxls per meter: {}, y pxls per meter: {}
colors_used: {} colors_important: {}",
self.size,
self.width,
self.height,
self.bit_depth,
self.planes,
self.compression,
self.size_image,
self.x_pixels_per_meter,
self.y_pixels_per_meter,
self.colors_used,
self.colors_important
)
}
}
#[cfg(test)]
mod test {
use super::BitDepth;
use super::BitMap;
use super::InfoHeader;
#[test]
fn get_correct_bit_depth() {
let b = BitMap::new(10, 10);
assert_eq!(
InfoHeader::from(&b, BitDepth::Color2Bit)
.get_bit_depth()
.unwrap(),
BitDepth::Color2Bit
);
assert_eq!(
InfoHeader::from(&b, BitDepth::Color16Bit)
.get_bit_depth()
.unwrap(),
BitDepth::Color16Bit
);
assert_eq!(
InfoHeader::from(&b, BitDepth::Color256Bit)
.get_bit_depth()
.unwrap(),
BitDepth::Color256Bit
);
assert_eq!(
InfoHeader::from(&b, BitDepth::AllColors)
.get_bit_depth()
.unwrap(),
BitDepth::AllColors
);
assert_eq!(
InfoHeader::from(&b, BitDepth::AllColorsAndShades)
.get_bit_depth()
.unwrap(),
BitDepth::AllColorsAndShades
);
}
#[test]
fn get_info_size_in_bytes_after_bitmap_conversion() {
let b = BitMap::new(10, 10);
let data = InfoHeader::from(&b, BitDepth::AllColors);
assert_eq!(data.get_byte_size(), 40);
}
#[test]
fn get_width_and_height_after_bitmap_conversion() {
let b = BitMap::new(10, 10);
let data = InfoHeader::from(&b, BitDepth::AllColors);
assert_eq!(data.get_width(), 10);
assert_eq!(data.get_height(), 10);
}
#[test]
fn get_colors_used_after_bitmap_conversion_24_bit() {
let b = BitMap::new(10, 10);
let data = InfoHeader::from(&b, BitDepth::AllColors);
assert_eq!(data.get_colors_used(), 0);
}
}