use byteorder::{LittleEndian, WriteBytesExt};
const HEADER_LENGHT: u32 = 14;
const INFO_LENGHT: u32 = 124;
const COLOR_SIZE: u32 = 4;
const RESERVED: u8 = 0;
#[derive(Debug)]
pub struct BitMap {
header: BitMapHeader,
info: BitMapInfo,
color_table: ColorTable,
array: Vec<u8>,
}
impl Default for BitMap {
fn default() -> Self {
Self::new(740, 480)
}
}
impl BitMap {
pub fn new(width: usize, height: usize) -> Self {
let mut b = BitMap {
header: BitMapHeader::new(),
info: BitMapInfo::new(),
color_table: ColorTable::new(),
array: vec![],
};
b.info.set_width(width as i32);
b.info.set_height(height as i32);
b
}
pub fn add_pixels(&mut self, pic: &[u8]) {
self.array.extend_from_slice(pic);
}
pub fn add_color<C>(&mut self, color: C) -> u8
where C: Into<Color>
{
let color = color.into();
self.color_table.add_color(color);
self.info.clr_used += 1;
(self.info.clr_used - 1) as u8
}
pub fn as_vec(&mut self) -> Vec<u8> {
let mut bitmap = vec![];
let pixels_data_offset = HEADER_LENGHT + INFO_LENGHT + self.color_table.get_size();
self.header.set_data_offset(pixels_data_offset);
let file_lenght = pixels_data_offset + self.array.len() as u32;
self.header.set_lenght(file_lenght);
bitmap.extend_from_slice(&self.header.to_vec());
bitmap.extend_from_slice(&self.info.to_vec());
bitmap.extend_from_slice(&self.color_table.to_vec());
bitmap.extend_from_slice(&self.array);
bitmap
}
}
#[derive(Debug)]
struct BitMapHeader {
little_indian: u16,
file_length: u32,
reserved: u32,
f_off_bitsfield: u32,
}
impl BitMapHeader {
fn new() -> Self {
BitMapHeader {
little_indian: 0x4d42,
file_length: 0u32,
reserved: 0u32,
f_off_bitsfield: 0u32,
}
}
fn set_lenght(&mut self, length: u32) {
self.file_length = length;
}
fn set_data_offset(&mut self, offset: u32) {
self.f_off_bitsfield = offset;
}
fn to_vec(&self) -> Vec<u8> {
let mut header = vec![]; header.write_u16::<LittleEndian>(self.little_indian).unwrap();
header.write_u32::<LittleEndian>(self.file_length).unwrap();
header.write_u32::<LittleEndian>(self.reserved).unwrap();
header.write_u32::<LittleEndian>(self.f_off_bitsfield).unwrap();
header
}
}
#[derive(Debug)]
struct BitMapInfo {
size: u32,
width: i32,
height: i32,
planes: u16,
bitcount: u16,
compression: u32,
sizeimage: u32,
xpels_per_meter: i32,
ypels_per_meter: i32,
clr_used: u32,
clr_important: u32,
red_mask: u32,
green_mask: u32,
blue_mask: u32,
alpha_mask: u32,
c_stype: u32,
c_iexyztriple: Vec<u8>,
gamma_red: u32,
gamma_green: u32,
gamma_blue: u32,
intent: u32,
profile_data: u32,
profile_size: u32,
reserved: u32,
}
impl BitMapInfo {
fn new() -> Self {
BitMapInfo {
size: 124u32,
width: 0i32,
height: 0i32,
planes: 1u16,
bitcount: 8u16,
compression: 0u32,
sizeimage: 0u32,
xpels_per_meter: 3780i32, ypels_per_meter: 3780i32, clr_used: 0u32,
clr_important: 0u32,
red_mask: 0u32,
green_mask: 0u32,
blue_mask: 0u32,
alpha_mask: 0u32,
c_stype: 0u32,
c_iexyztriple: vec![0u8; 36],
gamma_red: 0u32,
gamma_green: 0u32,
gamma_blue: 0u32,
intent: 4u32, profile_data: 0u32,
profile_size: 0u32,
reserved: 0u32,
}
}
fn to_vec(&self) -> Vec<u8> {
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
}
fn set_width(&mut self, width: i32) {
self.width = width;
}
fn set_height(&mut self, height: i32) {
self.height = height;
}
}
#[derive(Debug)]
struct ColorTable {
count: u32,
table: Vec<u8>,
}
impl ColorTable {
fn new() -> ColorTable {
ColorTable {
count: 0,
table: vec![],
}
}
fn add_color(&mut self, color: Color) {
self.count += 1;
self.table.append(&mut color.get_buffer());
}
fn get_size(&self) -> u32 {
256 * COLOR_SIZE
}
fn to_vec(&self) -> Vec<u8> {
let mut v: Vec<u8> = vec![];
v.extend_from_slice(&self.table);
for _ in self.count..256 {
v.write_u32::<LittleEndian>(0).unwrap();
}
v
}
}
#[derive(Debug)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl Color {
fn get_buffer(&self) -> Vec<u8> {
vec![self.b, self.g, self.r, RESERVED]
}
}
impl<'a> From<&'a str> for Color {
fn from(string: &str) -> Color {
let s = &string.to_lowercase();
let r = u8::from_str_radix(&s[1..3], 16).unwrap();
let g = u8::from_str_radix(&s[3..5], 16).unwrap();
let b = u8::from_str_radix(&s[5..7], 16).unwrap();
Color { r: r, g: g, b: b }
}
}