use crate::{color, Color, Error, Point, Result, Size};
pub trait Bitmap: Clone {
fn new(size: Size<i32>, color: Color) -> Self;
fn size(&self) -> Size<i32>;
fn width(&self) -> i32;
fn height(&self) -> i32;
fn pixel(&self, point: Point<i32>) -> Color;
fn set_pixel(&mut self, point: Point<i32>, color: Color);
fn bytes(&self) -> &[u8];
fn from_parts(size: Size<i32>, bytes: &[u8]) -> Self;
fn set_from(&mut self, other: &Self);
fn png_bytes(&self) -> Result<Vec<u8>> {
let img = image::RgbaImage::from_raw(
self.width() as u32,
self.height() as u32,
self.bytes().to_owned(),
)
.ok_or(Error::FailedImageFromRaw)?;
let vec = Vec::<u8>::new();
let mut vec = std::io::Cursor::new(vec);
img.write_to(&mut vec, image::ImageOutputFormat::Png)?;
Ok(vec.into_inner())
}
fn try_from_file_bytes(bytes: Vec<u8>) -> Result<Self> {
let reader = image::io::Reader::new(std::io::Cursor::new(bytes)).with_guessed_format()?;
let img = reader.decode()?;
let img = img.into_rgba8();
let size: Size<i32> = (img.width() as i32, img.height() as i32).into();
let mut bitmap = Self::new(size, color::TRANSPARENT);
for (x, y, pixel) in img.enumerate_pixels() {
let color = Color::new(pixel.0[0], pixel.0[1], pixel.0[2], pixel.0[3]);
bitmap.set_pixel((x as i32, y as i32).into(), color);
}
Ok(bitmap)
}
}
#[cfg(feature = "test-utils")]
pub use test::TestImage;
#[cfg(feature = "test-utils")]
mod test {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize)]
pub struct TestImage {
size: Size<i32>,
pixels: Vec<Vec<Color>>, bytes: Vec<u8>,
}
impl TestImage {
fn update_bytes(&mut self) {
self.bytes = self
.pixels
.iter()
.map(|row| {
row.iter()
.map(|c| [c.r, c.g, c.b, c.a])
.flatten()
.collect::<Vec<_>>()
})
.flatten()
.collect();
}
}
impl Bitmap for TestImage {
fn new(size: Size<i32>, color: Color) -> Self {
let pixels = vec![vec![color; size.x as usize]; size.y as usize];
let mut img = Self {
size,
pixels,
bytes: Vec::new(),
};
img.update_bytes();
img
}
fn size(&self) -> Size<i32> {
self.size
}
fn width(&self) -> i32 {
self.size.x
}
fn height(&self) -> i32 {
self.size.y
}
fn pixel(&self, point: Point<i32>) -> Color {
self.pixels[point.y as usize][point.x as usize]
}
fn set_pixel(&mut self, point: Point<i32>, color: Color) {
self.pixels[point.y as usize][point.x as usize] = color;
self.update_bytes();
}
fn bytes(&self) -> &[u8] {
&self.bytes
}
fn from_parts(size: Size<i32>, bytes: &[u8]) -> Self {
todo!()
}
fn set_from(&mut self, other: &Self) {
self.pixels = other.pixels.clone();
if self.pixels.len() >= self.size.y as usize {
self.pixels = self.pixels[0..self.size.y as usize].to_vec();
} else {
while self.pixels.len() < self.size.y as usize {
self.pixels
.push(vec![color::TRANSPARENT; self.size.x as usize]);
}
}
if self.pixels[0].len() >= self.size.x as usize {
for row in self.pixels.iter_mut() {
*row = row[0..self.size.x as usize].to_vec();
}
} else {
for row in self.pixels.iter_mut() {
while row.len() < self.size.x as usize {
row.push(color::TRANSPARENT);
}
}
}
}
}
}