Skip to content

Commit

Permalink
add support for converting from image::DynamicImage to smdh::IconData
Browse files Browse the repository at this point in the history
  • Loading branch information
Maccraft123 committed Nov 26, 2023
1 parent ce81c61 commit f4b458f
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 3 deletions.
1 change: 1 addition & 0 deletions cytryna/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
55 changes: 52 additions & 3 deletions cytryna/src/smdh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -451,6 +451,31 @@ pub struct Rgb565Pixel {
r: B5,
}

impl Rgb565Pixel {
/// Copies an image::Pixel<Subpixel = u8> into Rgb565Pixel
/// It is not implemented as a From trait impl as that makes a compiler error
fn from_image_pixel_subpixel_u8<T>(pixel: T) -> Self
where
T: image::Pixel<Subpixel = u8>,
{
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<T>(pixel: T) -> Self
where
T: image::Pixel<Subpixel = f32>,
{
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] = [
Expand Down Expand Up @@ -521,7 +546,7 @@ impl<const SIZE: usize> TryFrom<&bmp::Image> for IconData<SIZE> {
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,
});
Expand All @@ -538,6 +563,30 @@ impl<const SIZE: usize> TryFrom<&bmp::Image> for IconData<SIZE> {
}
}

impl<const SIZE: usize> TryFrom<&image::DynamicImage> for IconData<SIZE> {
type Error = SmdhError;

fn try_from(src: &image::DynamicImage) -> Result<Self, Self::Error> {
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> {
Expand Down

0 comments on commit f4b458f

Please sign in to comment.