use crate::{
term::get_terminal_size,
utils::{get_pos, RsilleErr},
Paint,
};
use image::{
imageops::FilterType::Lanczos3, io::Reader as ImageReader, DynamicImage, GenericImageView,
};
#[derive(Debug, Clone)]
pub struct Imgille {
img: DynamicImage,
color: bool,
thresholds: u8,
invert: bool,
}
impl Imgille {
pub fn new(path: &str) -> Result<Self, RsilleErr> {
let err = Err(RsilleErr::new(format!("can't open image: {}", path)));
let img = if let Ok(reader) = ImageReader::open(path) {
if let Ok(img) = reader.decode() {
img
} else {
return err;
}
} else {
return err;
};
Ok(Self {
img,
color: true,
thresholds: 128,
invert: false,
})
}
pub fn open(&mut self, path: &str) -> Result<(), RsilleErr> {
let img = ImageReader::open(path)
.map_err(RsilleErr::to_rsille_err)?
.decode()
.map_err(RsilleErr::to_rsille_err)?;
self.img = img;
Ok(())
}
pub fn color(&mut self, color: bool) {
self.color = color;
}
pub fn thresholds(&mut self, thresholds: u8) {
self.thresholds = thresholds;
}
pub fn invert(&mut self, invert: bool) {
self.invert = invert;
}
}
impl Paint for Imgille {
fn paint<T>(&self, canvas: &mut crate::Canvas, x: T, y: T) -> Result<(), RsilleErr>
where
T: Into<f64>,
{
let (x, y) = (x.into(), y.into());
let (rest_width, rest_height) = get_rest_size(x, y);
let (img_width, img_height) = (self.img.width(), self.img.height());
let img = if img_width > rest_width * 2 || img_height > rest_height * 4 {
let f = rest_height as f64 * 4.0 / img_height as f64;
let w = (img_width as f64 * f) as u32;
if rest_width * 2 < w {
let f = rest_width as f64 * 2.0 / img_width as f64;
let h = (img_height as f64 * f) as u32;
self.img.resize_exact(rest_width * 2, h, Lanczos3)
} else {
self.img.resize_exact(w, rest_height * 4, Lanczos3)
}
} else {
self.img.clone()
};
if !self.color {
let img = img.grayscale();
let img = img.as_luma8().unwrap();
let (iw, ih) = (img.width(), img.height());
for ny in 0..ih {
for nx in 0..iw {
let pixel = img.get_pixel(nx, ny);
let if_draw = if self.invert {
(pixel.0)[0] > self.thresholds
} else {
(pixel.0)[0] < self.thresholds
};
if if_draw {
canvas.set(x + nx as f64, y + (ih - ny) as f64);
}
}
}
} else {
let (iw, ih) = (img.width(), img.height());
for ny in 0..ih {
for nx in 0..iw {
use crate::color::Color;
let pixel = img.get_pixel(nx, ny);
canvas.set_colorful(
x + nx as f64,
y + (ih - ny) as f64,
Color::Rgb {
r: pixel[0],
g: pixel[1],
b: pixel[2],
},
);
}
}
};
Ok(())
}
}
fn get_rest_size<T>(x: T, y: T) -> (u32, u32)
where
T: Into<f64>,
{
let (tw, th) = get_terminal_size();
let (start_col, start_row) = get_pos(x, y);
let rest_width = if start_col > 0 {
tw as u32 - start_col as u32
} else {
tw as u32
};
let rest_height = if start_row > 0 {
th as u32 - start_row as u32
} else {
th as u32
};
(rest_width, rest_height)
}