use std::ops::{Index, IndexMut};
use super::bit_depth::BitDepth;
use super::image::BitMap;
use super::info_header::InfoHeader;
use super::rgba::Rgba;
pub struct PixelData {
pixels: Vec<Rgba>,
padding: u32,
width: u32,
height: u32,
bit_depth: BitDepth,
}
impl PixelData {
pub fn from_bitmap(bitmap: &BitMap, bit_depth: BitDepth) -> PixelData {
PixelData {
pixels: bitmap.get_pixels().clone(),
padding: PixelData::get_row_padding_size(bitmap.get_width(), bit_depth),
width: bitmap.get_width(),
height: bitmap.get_height(),
bit_depth,
}
}
pub fn from_slice(bit_stream: &[u8], info: &InfoHeader, bit_depth: BitDepth) -> PixelData {
let mut pixels: Vec<Rgba> = Vec::new();
let padding = PixelData::get_row_padding_size(info.get_width(), bit_depth);
let step = bit_depth.get_step_counter() as usize;
let mut counter = 0;
for _ in 0..info.get_height() {
for _ in 0..info.get_width() {
let i = counter;
let pixel = match bit_depth {
BitDepth::AllColors => {
Rgba::bgr(bit_stream[i], bit_stream[i + 1], bit_stream[i + 2])
}
BitDepth::AllColorsAndShades => Rgba::bgra(
bit_stream[i],
bit_stream[i + 1],
bit_stream[i + 2],
bit_stream[i + 3],
),
_ => Rgba::black(),
};
pixels.push(pixel);
counter += step;
}
counter += padding as usize;
}
PixelData {
pixels,
padding,
width: info.get_width(),
height: info.get_height(),
bit_depth,
}
}
pub fn as_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
let mut counter = self.width;
for p in &self.pixels {
bytes.push(p.get_blue());
bytes.push(p.get_green());
bytes.push(p.get_red());
if self.bit_depth == BitDepth::AllColorsAndShades {
bytes.push(p.get_alpha())
}
counter = counter - 1;
if counter == 0 {
while bytes.len() % 4 != 0 {
bytes.push(0);
}
counter = self.width;
}
}
bytes
}
pub fn len(&self) -> usize {
self.pixels.len()
}
pub fn get_bytes_size(&self) -> u32 {
let used_bits = self.pixels.len() as u32 * self.bit_depth.get_step_counter();
let padding = self.padding * self.height;
used_bits + padding
}
pub fn as_rgba(&self) -> Vec<Rgba> {
self.pixels.clone()
}
fn get_row_padding_size(width: u32, bit_depth: BitDepth) -> u32 {
match bit_depth {
BitDepth::AllColors => match (width * 3) % 4 {
1 => 3,
2 => 2,
3 => 1,
_ => 0,
},
_ => 0,
}
}
}
impl Index<usize> for PixelData {
type Output = Rgba;
fn index<'a>(&'a self, i: usize) -> &'a Rgba {
&self.pixels[i]
}
}
impl IndexMut<usize> for PixelData {
fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut Rgba {
&mut self.pixels[i]
}
}
#[cfg(debug_assertions)]
impl std::fmt::Display for PixelData {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
for p in 0..self.pixels.len() {
write!(f, "{}: {}\n", p, self.pixels[p]).unwrap();
}
write!(f, "")
}
}
#[cfg(test)]
mod test {
use super::BitDepth;
use super::BitMap;
use super::PixelData;
use super::Rgba;
#[test]
fn get_length_of_pixel_data_from_bitmap() {
let b = BitMap::new(10, 10);
let data = PixelData::from_bitmap(&b, BitDepth::AllColors);
assert_eq!(data.len(), 100);
}
#[test]
fn get_size_of_bytes_in_pixel_data() {
let b = BitMap::new(10, 10);
let data = PixelData::from_bitmap(&b, BitDepth::AllColors);
assert_eq!(data.get_bytes_size(), 320);
let b = BitMap::new(546, 879);
let data = PixelData::from_bitmap(&b, BitDepth::AllColors);
assert_eq!(data.get_bytes_size(), 1441560);
}
#[test]
fn get_pixel_data_as_rgb() {
let b = BitMap::new(10, 10);
let data = PixelData::from_bitmap(&b, BitDepth::AllColors);
let colors = data.as_rgba();
for c in &colors {
assert!(c == &Rgba::white());
}
}
#[test]
#[should_panic]
fn get_data_from_outside_of_pixel_data_range() {
let b = BitMap::new(10, 10);
let data = PixelData::from_bitmap(&b, BitDepth::AllColors);
data[100];
}
}