use fast_image_resize as fr;
pub use fimg::*;
mod holder;
pub use holder::ImageHolder;
pub trait ImageUtils {
/// Tint this image with the color
fn tint(&mut self, color: (u8, u8, u8)) -> &mut Self;
/// rotate (squares only)
/// # Safety
///
/// UB if image is not square
unsafe fn rotate(&mut self, times: u8) -> &mut Self;
/// shadow
fn shadow(&mut self) -> &mut Self;
/// scale a image
fn scale(self, to: u32) -> Image<Vec<u8>, 4>;
}
impl ImageUtils for Image<&mut [u8], 4> {
unsafe fn rotate(&mut self, times: u8) -> &mut Self {
match times {
2 => self.rot_180(),
1 => unsafe { self.rot_90() },
3 => unsafe { self.rot_270() },
_ => {}
}
self
}
fn tint(&mut self, (r, g, b): (u8, u8, u8)) -> &mut Self {
let [tr, tg, tb] = [r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0];
for [r, g, b, _] in self.buffer.array_chunks_mut::<4>() {
*r = (*r as f32 * tr) as u8;
*g = (*g as f32 * tg) as u8;
*b = (*b as f32 * tb) as u8;
}
self
}
// this function is very cold but im removing image so might as well use fir
fn scale(self, to: u32) -> Image<Vec<u8>, 4> {
let from =
fr::Image::from_slice_u8(self.width, self.height, self.buffer, fr::PixelType::U8x4)
.unwrap();
let to = to.try_into().unwrap();
let mut dst = fr::Image::new(to, to, fr::PixelType::U8x4);
fr::Resizer::new(fr::ResizeAlg::Nearest)
.resize(&from.view(), &mut dst.view_mut())
.unwrap();
Image::new(to, to, dst.into_vec())
}
fn shadow(&mut self) -> &mut Self {
let mut shadow: Image<Vec<u8>, 4> =
Image::new(self.width, self.height, self.buffer.to_vec());
for [r, g, b, a] in shadow.buffer.array_chunks_mut() {
if *a < 128 {
*r /= 10;
*g /= 10;
*b /= 10;
}
}
blurslice::gaussian_blur_bytes::<4>(
&mut shadow.buffer,
self.width() as usize,
self.height() as usize,
9.0,
)
.unwrap();
for ([r, g, b, a], &[from_r, from_g, from_b, from_a]) in self
.buffer
.array_chunks_mut()
.zip(shadow.buffer.array_chunks())
{
if *a == 0 {
(*r, *g, *b, *a) = (from_r, from_g, from_b, from_a);
}
}
self
}
}
pub fn blend(bg: &mut [u8; 4], fg: [u8; 4]) {
if fg[3] == 0 {
return;
}
if fg[3] == 255 {
*bg = fg;
return;
}
let bg_a = bg[3] as f32 / 255.0;
let fg_a = fg[3] as f32 / 255.0;
let a = bg_a + fg_a - bg_a * fg_a;
if a == 0.0 {
return;
};
*bg = [
(255.0
* ((((fg[0] as f32 / 255.0) * fg_a) + ((bg[0] as f32 / 255.0) * bg_a) * (1.0 - fg_a))
/ a)) as u8,
(255.0
* ((((fg[1] as f32 / 255.0) * fg_a) + ((bg[1] as f32 / 255.0) * bg_a) * (1.0 - fg_a))
/ a)) as u8,
(255.0
* ((((fg[2] as f32 / 255.0) * fg_a) + ((bg[2] as f32 / 255.0) * bg_a) * (1.0 - fg_a))
/ a)) as u8,
(255.0 * a) as u8,
]
}