use std::fmt::{Formatter, LowerHex, UpperHex}; use std::path::{Component, Path, PathBuf}; use deltae::LabValue; use glam::Vec3; use image::{GenericImage, GenericImageView, Rgb, Rgba, RgbaImage, SubImage}; use lab::Lab; #[derive(Clone, Copy)] pub struct SpriteData<'a, T: GenericImage> { pub data: SubImage<&'a T>, #[allow(dead_code)] pub x: u32, #[allow(dead_code)] pub y: u32, pub tx: u32, pub ty: u32, #[allow(dead_code)] pub width: u32, #[allow(dead_code)] pub height: u32, } pub type OutputFormat = image::ImageBuffer<Rgba<u8>, Vec<u8>>; #[allow(type_alias_bounds)] pub type TypedOutputFormat<T: GenericImage> = image::ImageBuffer<T::Pixel, Vec<<T::Pixel as image::Pixel>::Subpixel>>; pub type RgbaOutputFormat = TypedOutputFormat<RgbaImage>; pub fn new_image(new_width: u32, new_height: u32) -> OutputFormat { let mut new_image = RgbaImage::new(new_width, new_height); let (new_image_x, new_image_y, new_image_width, new_image_height) = new_image.bounds(); for x in new_image_x..new_image_width { for y in new_image_y..new_image_height { new_image.put_pixel(x, y, Rgba::from([0, 0, 0, 0])); } } new_image } #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct BasicRgba { pub r: u8, pub g: u8, pub b: u8, pub a: u8, } impl BasicRgba { pub fn hue(&self) -> f32 { let red = self.r as f32 / u8::MAX as f32; let green = self.g as f32 / u8::MAX as f32; let blue = self.b as f32 / u8::MAX as f32; let minimum = red.min(green).min(blue); let maximum = red.max(green).max(blue); let mut hue = if red >= green && red >= blue { (green - blue) / (maximum - minimum) } else if green >= red && green >= blue { 2.0 + (blue - red) / (maximum - minimum) } else { 4.0 + (red - green) / (maximum - minimum) }; hue *= 60.0; while hue < 0.0 { hue += 360.0; } hue } pub fn transparent() -> Self { Self { r: 0, g: 0, b: 0, a: 0, } } } impl From<Rgba<u8>> for BasicRgba { fn from(other: Rgba<u8>) -> Self { Self { r: other.0[0], g: other.0[1], b: other.0[2], a: other.0[3], } } } impl From<&Rgba<u8>> for BasicRgba { fn from(other: &Rgba<u8>) -> Self { Self { r: other.0[0], g: other.0[1], b: other.0[2], a: other.0[3], } } } impl From<Rgb<u8>> for BasicRgba { fn from(other: Rgb<u8>) -> Self { Self { r: other.0[0], g: other.0[1], b: other.0[2], a: u8::MAX, } } } impl From<&Rgb<u8>> for BasicRgba { fn from(other: &Rgb<u8>) -> Self { Self { r: other.0[0], g: other.0[1], b: other.0[2], a: u8::MAX, } } } impl From<BasicRgba> for Rgba<u8> { fn from(other: BasicRgba) -> Self { Self::from([other.r, other.g, other.b, other.a]) } } impl From<&BasicRgba> for Rgba<u8> { fn from(other: &BasicRgba) -> Self { Self::from([other.r, other.g, other.b, other.a]) } } impl From<BasicRgba> for Rgb<u8> { fn from(other: BasicRgba) -> Self { Self::from([other.r, other.g, other.b]) } } impl From<&BasicRgba> for Rgb<u8> { fn from(other: &BasicRgba) -> Self { Self::from([other.r, other.g, other.b]) } } impl From<BasicRgba> for LabValue { fn from(other: BasicRgba) -> Self { let converted = lab::Lab::from_rgb(&[other.r, other.g, other.b]); LabValue { l: converted.l, a: converted.a, b: converted.b, } } } impl From<&BasicRgba> for LabValue { fn from(other: &BasicRgba) -> Self { let converted = lab::Lab::from_rgb(&[other.r, other.g, other.b]); LabValue { l: converted.l, a: converted.a, b: converted.b, } } } #[derive(Clone, Copy, Debug)] pub struct BasicLab { pub l: f32, pub a: f32, pub b: f32, } impl From<LabValue> for BasicLab { fn from(other: LabValue) -> Self { Self { l: other.l, a: other.a, b: other.b, } } } impl From<BasicLab> for LabValue { fn from(other: BasicLab) -> Self { Self { l: other.l, a: other.a, b: other.b, } } } impl From<BasicLab> for Lab { fn from(other: BasicLab) -> Self { Self { l: other.l, a: other.a, b: other.b, } } } impl From<BasicLab> for BasicRgba { fn from(other: BasicLab) -> Self { let lab: Lab = other.into(); let vals = lab.to_rgb(); Self { r: vals[0], g: vals[1], b: vals[2], a: u8::MAX, } } } impl From<BasicRgba> for Vec3 { fn from(other: BasicRgba) -> Self { Vec3::new(other.r as f32, other.g as f32, other.b as f32) } } impl From<BasicLab> for Vec3 { fn from(other: BasicLab) -> Self { Vec3::new(other.l, other.a, other.b) } } impl UpperHex for BasicRgba { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&format!( "{:02X}{:02X}{:02X}{:02X}", self.r, self.g, self.b, self.a )) } } impl LowerHex for BasicRgba { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&format!( "{:02x}{:02x}{:02x}{:02x}", self.r, self.g, self.b, self.a )) } } pub struct HexStringValue(String); pub trait HexString { fn as_hex_string(&self) -> HexStringValue; } impl HexString for Rgba<u8> { fn as_hex_string(&self) -> HexStringValue { HexStringValue(format!( "{:02X}{:02X}{:02X}{:02X}", self.0[0], self.0[1], self.0[2], self.0[3] )) } } impl<T: HexString + Clone> HexString for &T { fn as_hex_string(&self) -> HexStringValue { (*self).clone().as_hex_string() } } impl UpperHex for HexStringValue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0.to_uppercase()) } } impl LowerHex for HexStringValue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0.to_lowercase()) } } pub fn normalize_path<T: AsRef<Path>>(path: T) -> PathBuf { let path = path.as_ref(); let mut components = path.components().peekable(); let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { components.next(); PathBuf::from(c.as_os_str()) } else { PathBuf::new() }; for component in components { match component { Component::Prefix(..) => unreachable!(), Component::RootDir => { ret.push(component.as_os_str()); } Component::CurDir => {} Component::ParentDir => { ret.pop(); } Component::Normal(c) => { ret.push(c); } } } ret }