use crate::pixels::{ColorTrait, Colors, Pixel};
use crate::utility::{clamp, overlap_colors, to_grey_lumiosity};
use image::{GenericImageView, ImageFormat, RgbaImage};
use std::cmp::{max, min};
use std::path::Path;
#[derive(Clone, Debug)]
pub struct Canvas {
pub pixels: Vec<Pixel>,
pub height: u32,
pub width: u32,
}
#[derive(Debug)]
pub enum ImageError {
Decoding(String),
Encoding(String),
Parameter(String),
Limits(String),
Unsupported(String),
IoError(String),
}
fn map_error(error: &image::ImageError) -> ImageError {
match error {
image::ImageError::Decoding(e) => {
return ImageError::Decoding(e.to_string());
}
image::ImageError::Encoding(e) => {
return ImageError::Encoding(e.to_string());
}
image::ImageError::Parameter(e) => {
return ImageError::Parameter(e.to_string());
}
image::ImageError::Limits(e) => {
return ImageError::Limits(e.to_string());
}
image::ImageError::Unsupported(e) => {
return ImageError::Unsupported(e.to_string());
}
image::ImageError::IoError(e) => {
return ImageError::IoError(e.to_string());
}
}
}
impl Canvas {
pub fn new(w: u32, h: u32) -> Canvas {
let w = max(w, 1);
let h = max(h, 1);
let ps = vec![Colors::WHITE; (w * h) as usize];
Canvas {
pixels: ps,
height: h,
width: w,
}
}
pub fn save(&self, filename: &Path) -> Result<(), ImageError> {
let img = RgbaImage::from_vec(
self.width,
self.height,
self.pixels
.iter()
.flat_map(|x| vec![x.r, x.g, x.b, x.a])
.collect(),
);
match img {
Some(image) => {
let res = image.save_with_format(filename, ImageFormat::Png);
match res {
Ok(_) => {
return Ok(());
}
Err(e) => {
return Err(map_error(&e));
}
}
}
None => {
return Ok(());
}
}
}
pub fn load(filename: &Path) -> Result<Canvas, ImageError> {
let img = image::open(filename);
match img {
Ok(image) => {
let (width, height) = image.dimensions();
let mut vec = vec![Colors::WHITE; (width * height) as usize];
for (x, y, pixel) in image.pixels() {
vec[(width * y + x) as usize] = Pixel {
r: pixel[0],
g: pixel[1],
b: pixel[2],
a: pixel[3],
}
}
return Ok(Canvas {
pixels: vec,
height,
width,
});
}
Err(e) => {
return Err(map_error(&e));
}
}
}
pub fn get_subimage(&self, x: u32, y: u32, width: u32, height: u32) -> Canvas {
let w = min(width, width - x);
let h = min(height, height - y);
let mut c = Canvas::new(width, height);
for i in 0..w {
for j in 0..h {
c.set_pixel(i, j, &self.get_pixel(x + i, y + j));
}
}
c
}
pub fn set_subimage_mut(&mut self, x: u32, y: u32, c: &Canvas) {
let w = min(c.width, self.width);
let h = min(c.height, self.height);
for i in 0..w {
for j in 0..h {
self.set_pixel(i, j, &c.get_pixel(x + i, y + j));
}
}
}
pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
let x = clamp(0, self.width - 1, x);
let y = clamp(0, self.height - 1, y);
let pixel = self.pixels[(self.width * y + x) as usize].clone();
pixel
}
pub fn set_pixel(&mut self, x: u32, y: u32, pixel: &Pixel) {
self.pixels[(self.width * y + x) as usize] = pixel.clone();
}
pub fn to_grey(&self) -> Canvas {
let pixels = self.pixels.iter().map(|x| to_grey_lumiosity(x)).collect();
Canvas {
pixels,
height: self.height,
width: self.width,
}
}
pub fn draw_square_mut(&mut self, x: u32, y: u32, w: u32, h: u32, color: &Pixel) {
for i in x..(x + w) {
for j in y..(y + h) {
let current_color = &self.get_pixel(i, j);
if current_color.distance(&Colors::WHITE) > 3.0 {
let new_color = overlap_colors(¤t_color, &color);
self.set_pixel(i, j, &new_color);
} else {
self.set_pixel(i, j, &color);
}
}
}
}
}