From f4b458f00629e5b2ffcca3e9755a7c2d8027f244 Mon Sep 17 00:00:00 2001 From: Maccraft123 Date: Sun, 26 Nov 2023 14:38:39 +0100 Subject: [PATCH] add support for converting from image::DynamicImage to smdh::IconData --- cytryna/Cargo.toml | 1 + cytryna/src/smdh.rs | 55 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/cytryna/Cargo.toml b/cytryna/Cargo.toml index 0a00ed1..cafada4 100644 --- a/cytryna/Cargo.toml +++ b/cytryna/Cargo.toml @@ -14,6 +14,7 @@ ctr = { version = "0.9.2", features = ["std"] } derivative = "2.2.0" hex = "0.4.3" hex-literal = "0.4.1" +image = { version = "0.24.7", default-features = false } memoffset = "0.9.0" modular-bitfield = "0.11.2" sha2 = "0.10.8" diff --git a/cytryna/src/smdh.rs b/cytryna/src/smdh.rs index c5e0ab4..622510c 100644 --- a/cytryna/src/smdh.rs +++ b/cytryna/src/smdh.rs @@ -24,8 +24,8 @@ pub enum SmdhError { MissingIcon, #[error("SizedCString error: {0}")] StringErr(#[from] SizedCStringError), - #[error("Invalid BMP image size, got: {got}, expected: {expected}")] - InvalidBmpSize { got: u32, expected: u32 }, + #[error("Invalid image size, got: {got}, expected: {expected}")] + InvalidImageSize { got: u32, expected: u32 }, #[error("Only square images can be SMDH icons")] OnlySquaresAllowed, } @@ -451,6 +451,31 @@ pub struct Rgb565Pixel { r: B5, } +impl Rgb565Pixel { + /// Copies an image::Pixel into Rgb565Pixel + /// It is not implemented as a From trait impl as that makes a compiler error + fn from_image_pixel_subpixel_u8(pixel: T) -> Self + where + T: image::Pixel, + { + let rgb = pixel.to_rgb(); + Self::new() + .with_r(rgb.0[0] << 3) + .with_g(rgb.0[1] << 4) + .with_b(rgb.0[2] << 3) + } + /*fn from_image_pixel_subpixel_f32(pixel: T) -> Self + where + T: image::Pixel, + { + let rgb = pixel.to_rgb(); + Self::new() + .with_r((rgb.0[0] * 31.0) as u8) // scale from 0.0-1.0 to 0-31 + .with_g((rgb.0[1] * 63.0) as u8) // scale from 0.0-1.0 to 0-63 + .with_b((rgb.0[2] * 31.0) as u8) // scale from 0.0-1.0 to 0-31 + }*/ +} + /// SMDH icon tile order /// shamelessly stolen from smdhtool const TILE_ORDER: [u8; 64] = [ @@ -521,7 +546,7 @@ impl TryFrom<&bmp::Image> for IconData { return Err(SmdhError::OnlySquaresAllowed); } if src.get_width() * src.get_width() != SIZE as u32 { - return Err(SmdhError::InvalidBmpSize { + return Err(SmdhError::InvalidImageSize { got: src.get_width() * src.get_width(), expected: SIZE as u32, }); @@ -538,6 +563,30 @@ impl TryFrom<&bmp::Image> for IconData { } } +impl TryFrom<&image::DynamicImage> for IconData { + type Error = SmdhError; + + fn try_from(src: &image::DynamicImage) -> Result { + if src.width() != src.height() { + return Err(SmdhError::OnlySquaresAllowed); + } + if src.width() * src.width() != SIZE as u32 { + return Err(SmdhError::InvalidImageSize { + got: src.width() * src.width(), + expected: SIZE as u32, + }); + } + + let data: [Rgb565Pixel; SIZE] = [0u16; SIZE].map(|v| v.into()); + let src = src.to_rgb8(); + let mut this = Self { data }; + for (x, y, rgb) in this.pixel_iter_mut() { + *rgb = Rgb565Pixel::from_image_pixel_subpixel_u8(src.get_pixel(x as u32, y as u32).to_owned()); + } + Ok(this) + } +} + /// An iterator over x and y coordinates and a mutable refernce to Rgb565Pixel in that coordinates #[derive(Debug)] pub struct PixelIteratorMut<'a, const SIZE: usize> {