use std::{
fmt::Debug,
hash::{Hash, Hasher},
ops::{Deref, DerefMut},
};
use crate::layout::Size;
use super::ImageId;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ImageData {
data: Vec<u8>,
width: u32,
height: u32,
filter: bool,
}
impl Default for ImageData {
fn default() -> Self {
Self::new(vec![255; 4], 1, 1)
}
}
impl ImageData {
pub fn new(data: Vec<u8>, width: u32, height: u32) -> Self {
assert_eq!(data.len() as u32, width * height * 4);
Self {
data,
width,
height,
filter: true,
}
}
#[cfg(feature = "image")]
pub fn try_load_data(data: Vec<u8>) -> image::ImageResult<Self> {
let data = image::load_from_memory(&data)?;
Ok(Self {
data: data.to_rgba8().into_raw(),
width: data.width(),
height: data.height(),
filter: true,
})
}
#[cfg(feature = "image")]
pub fn load_data(data: Vec<u8>) -> Self {
match Self::try_load_data(data) {
Ok(data) => data,
Err(err) => {
tracing::error!("Failed to load image data: {}", err);
Self::default()
}
}
}
#[cfg(feature = "image")]
pub fn try_load(path: impl AsRef<std::path::Path>) -> image::ImageResult<Self> {
let data = image::open(path)?;
Ok(Self {
data: data.to_rgba8().into_raw(),
width: data.width(),
height: data.height(),
filter: true,
})
}
#[cfg(feature = "image")]
pub fn load(path: impl AsRef<std::path::Path>) -> Self {
match Self::try_load(path.as_ref()) {
Ok(data) => data,
Err(err) => {
tracing::error!("Failed to load image: {}: {}", path.as_ref().display(), err);
Self::default()
}
}
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn size(&self) -> Size {
Size::new(self.width as f32, self.height as f32)
}
pub fn get_pixel(&self, x: u32, y: u32) -> [u8; 4] {
let i = (y * self.width + x) as usize * 4;
let r = self.data[i];
let g = self.data[i + 1];
let b = self.data[i + 2];
let a = self.data[i + 3];
[r, g, b, a]
}
pub fn set_pixel(&mut self, x: u32, y: u32, pixel: [u8; 4]) {
let i = (y * self.width + x) as usize * 4;
self.data[i] = pixel[0];
self.data[i + 1] = pixel[1];
self.data[i + 2] = pixel[2];
self.data[i + 3] = pixel[3];
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn data_mut(&mut self) -> &mut [u8] {
&mut self.data
}
pub fn filter(&self) -> bool {
self.filter
}
pub fn set_filter(&mut self, filter: bool) {
self.filter = filter;
}
pub fn compute_id(&self) -> ImageId {
let mut hasher = seahash::SeaHasher::new();
self.hash(&mut hasher);
ImageId {
hash: hasher.finish(),
}
}
}
impl Debug for ImageData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ImageData")
.field("width", &self.width)
.field("height", &self.height)
.field("filter", &self.filter)
.finish()
}
}
impl Deref for ImageData {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl DerefMut for ImageData {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}