use crate::image_data::ImageData;
use crate::{Error, Result};
#[derive(Default)]
pub struct Image {
image: ImageData,
}
impl Image {
pub(crate) fn as_mut_image(&mut self) -> &mut ImageData {
&mut self.image
}
pub fn from_gray(data: &[u8], width: u32, height: u32) -> Result<Self> {
if (data.len() as u64) != (width as u64) * (height as u64) {
return Err(Error::Invalid);
}
let mut image = Self::default();
image.image.width = width;
image.image.height = height;
image.image.data.extend_from_slice(data);
Ok(image)
}
pub fn width(&self) -> u32 {
self.image.width
}
pub fn height(&self) -> u32 {
self.image.height
}
pub fn data(&self) -> &[u8] {
&self.image.data
}
pub fn crop(&self, x: u32, y: u32, width: u32, height: u32) -> Option<Self> {
self.image
.crop(x, y, width, height)
.map(|image| Image { image })
}
pub fn upscale(&self, scale: u32) -> Option<Self> {
self.image.upscale(scale).map(|image| Image { image })
}
}
#[cfg(feature = "image")]
impl Image {
pub fn from_dynamic(img: &::image::DynamicImage) -> Result<Self> {
let gray = to_luma_over_white(img);
Self::from_gray(gray.as_raw(), gray.width(), gray.height())
}
}
#[cfg(feature = "image")]
fn to_luma_over_white(img: &::image::DynamicImage) -> ::image::GrayImage {
use ::image::{DynamicImage, Rgb, RgbImage};
if !img.color().has_alpha() {
return img.to_luma8();
}
let rgba = img.to_rgba8();
let mut rgb = RgbImage::new(rgba.width(), rgba.height());
for (dst, src) in rgb.pixels_mut().zip(rgba.pixels()) {
let [r, g, b, a] = src.0;
let over_white =
|c: u8| ((c as u32 * a as u32 + 255 * (255 - a as u32) + 127) / 255).min(255) as u8;
*dst = Rgb([over_white(r), over_white(g), over_white(b)]);
}
DynamicImage::ImageRgb8(rgb).to_luma8()
}