From eced3a7c13ee5ab03a20e77fd108cea989eb9e1a Mon Sep 17 00:00:00 2001 From: jaby Date: Sun, 22 Dec 2024 21:10:38 +0100 Subject: [PATCH] Generic header encoding interface --- src/Tools/psxfileconv/src/images/mod.rs | 19 ++++++++-------- .../psxfileconv/src/images/reduced_tim/mod.rs | 6 +++-- .../src/images/reduced_tim/types.rs | 22 ++++++++++++++----- src/Tools/psxfileconv/src/images/types.rs | 20 ++++++++++------- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/Tools/psxfileconv/src/images/mod.rs b/src/Tools/psxfileconv/src/images/mod.rs index e9b0aadf..378bd4cd 100644 --- a/src/Tools/psxfileconv/src/images/mod.rs +++ b/src/Tools/psxfileconv/src/images/mod.rs @@ -8,11 +8,10 @@ pub mod types; use args::{ColorType, ClutAlignment}; use color_clut::{IndexedImage, OutputType}; use color_full16::{RgbaImage, RgbImage}; -use types::{Color as PSXColor, PSXImageConverter}; +use types::{Color as PSXColor, HeaderEncoder, PSXImageConverter}; use image::{DynamicImage, io::Reader as ImageReader}; use std::io::{Cursor, Write}; use tool_helper::{Error, Input}; -use reduced_tim::types::Header; fn modify_palette(mut image: IndexedImage, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> IndexedImage { if semi_transparent { @@ -37,7 +36,7 @@ fn modify_palette(mut image: IndexedImage, clut_align: ClutAlignment, semi_trans image } -fn encode(image: T, color_depth: ColorType, clut_align: ClutAlignment, output: &mut dyn Write) -> Result<(), Error> { +fn encode(header_conv: &dyn HeaderEncoder, image: T, color_depth: ColorType, clut_align: ClutAlignment, output: &mut dyn Write) -> Result<(), Error> { let (width, height) = { fn return_error(clut_type: u32, div: u32, width: u16, height: u16) -> Result<(u16, u16), Error> { return Err(Error::from_callback(|| {format!("CLUT {} images require a width divideable by {} (found width: {}/{}={}, height: {})", clut_type, div, width, div, (width as f32/div as f32), height)})); @@ -94,9 +93,9 @@ fn encode(image: T, color_depth: ColorType, clut_align: Cl } }; - let header = Header::encode(width, height, pal_width, pal_height).ok_or(Error::from_callback(|| {format!("Image size (width: {}, height: {}) needs to be even", width, height)}))?; + let header_raw = header_conv.encode(width, height, pal_width, pal_height)?; - tool_helper::raw::write_raw(output, &header)?; + output.write(&header_raw)?; if let Some(palette) = palette { let mut color_count = pal_width*pal_height; for color in palette { @@ -117,12 +116,12 @@ fn encode(image: T, color_depth: ColorType, clut_align: Cl Ok(()) } -fn convert_full16(input: Input, output: &mut dyn Write) -> Result<(), Error> { +fn convert_full16(header_conv: &dyn HeaderEncoder, input: Input, output: &mut dyn Write) -> Result<(), Error> { match ImageReader::new(Cursor::new(tool_helper::input_to_vec(input)?)).with_guessed_format()?.decode() { Ok(image) => { match image { - DynamicImage::ImageRgb8(image) => encode(RgbImage::new(image), ColorType::Full16, ClutAlignment::None, output), - DynamicImage::ImageRgba8(image) => encode(RgbaImage::new(image), ColorType::Full16, ClutAlignment::None, output), + DynamicImage::ImageRgb8(image) => encode(header_conv, RgbImage::new(image), ColorType::Full16, ClutAlignment::None, output), + DynamicImage::ImageRgba8(image) => encode(header_conv, RgbaImage::new(image), ColorType::Full16, ClutAlignment::None, output), _ => Err(Error::from_str("Only RGB and RGBA images are supported for 16bit encoding")) } @@ -131,7 +130,7 @@ fn convert_full16(input: Input, output: &mut dyn Write) -> Result<(), Error> { } } -fn convert_palette_based(input: Input, output: &mut dyn Write, color_type: ColorType, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> Result<(), Error> { +fn convert_palette_based(header_conv: &dyn HeaderEncoder, input: Input, output: &mut dyn Write, color_type: ColorType, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> Result<(), Error> { match png::Decoder::new(input).read_info() { Ok(reader) => { let output_type = { @@ -142,7 +141,7 @@ fn convert_palette_based(input: Input, output: &mut dyn Write, color_type: Color } }; - encode(modify_palette(IndexedImage::new(reader, output_type)?, clut_align, semi_transparent, transparent_palette), color_type, clut_align, output) + encode(header_conv, modify_palette(IndexedImage::new(reader, output_type)?, clut_align, semi_transparent, transparent_palette), color_type, clut_align, output) }, Err(error) => Err(Error::from_error(error)) } diff --git a/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs b/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs index 446579f1..6dc4c4b4 100644 --- a/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs +++ b/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs @@ -2,13 +2,15 @@ pub mod types; use super::args::ColorType; use std::io::Write; +use types::Header; use tool_helper::{Error, Input}; pub type Arguments = super::args::Arguments; pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { + let header_conv = Header::default(); match args.color_depth { - ColorType::Full16 => super::convert_full16(input, output), - _ => super::convert_palette_based(input, output, args.color_depth, args.clut_align, args.semi_transparent, args.transparent_palette), + ColorType::Full16 => super::convert_full16(&header_conv, input, output), + _ => super::convert_palette_based(&header_conv, input, output, args.color_depth, args.clut_align, args.semi_transparent, args.transparent_palette), } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/reduced_tim/types.rs b/src/Tools/psxfileconv/src/images/reduced_tim/types.rs index 17b355c2..bd783ae0 100644 --- a/src/Tools/psxfileconv/src/images/reduced_tim/types.rs +++ b/src/Tools/psxfileconv/src/images/reduced_tim/types.rs @@ -1,5 +1,5 @@ -use super::super::types::set_member_value; -use tool_helper::{bits::BitRange, raw::RawConversion}; +use super::super::types::{HeaderEncoder, set_member_value}; +use tool_helper::{bits::BitRange, raw::RawConversion, Error}; #[repr(packed(1))] #[allow(dead_code)] @@ -14,9 +14,9 @@ impl Header { const CLUT_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(17, 22); const CLUT_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(23, 31); - pub fn encode(tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Option
{ + pub fn from(tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Result { if tex_width & 1 == 1 || tex_height & 1 == 1 { - None + Err(Error::from_text(format!("Image size (width: {}, height: {}) needs to be even", tex_width, tex_height))) } else { @@ -26,11 +26,23 @@ impl Header { clut_width, 4, u32), clut_height, 0, u32); - Some(Header{value}) + Ok(Header{value}) } } } +impl Default for Header { + fn default() -> Self { + Header{value: 0} + } +} + +impl HeaderEncoder for Header { + fn encode(&self, tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Result, Error> { + Ok(Header::from(tex_width, tex_height, clut_width, clut_height)?.convert_to_raw().to_vec()) + } +} + impl RawConversion<4> for Header { fn convert_to_raw(&self) -> [u8; 4] { self.value.to_le_bytes() diff --git a/src/Tools/psxfileconv/src/images/types.rs b/src/Tools/psxfileconv/src/images/types.rs index dc3135eb..b4ec0d72 100644 --- a/src/Tools/psxfileconv/src/images/types.rs +++ b/src/Tools/psxfileconv/src/images/types.rs @@ -1,11 +1,5 @@ use tool_helper::{*, bits::BitRange, raw::RawConversion}; -#[repr(packed(1))] -#[allow(dead_code)] -pub struct Color { - value: u16 -} - macro_rules! set_member_value { ($dst:expr, $color:ident, $shift:expr, $bits:ident) => { paste::item! { @@ -14,8 +8,6 @@ macro_rules! set_member_value { }; } -pub(crate) use set_member_value; - macro_rules! make_member_getter_setter { ($color:ident, $shift:expr, $bits:ident) => { paste::item! { @@ -30,6 +22,14 @@ macro_rules! make_member_getter_setter { }; } +pub(crate) use set_member_value; + +#[repr(packed(1))] +#[allow(dead_code)] +pub struct Color { + value: u16 +} + #[allow(dead_code)] impl Color { const COLOR_SHIFT: u16 = 3; @@ -120,6 +120,10 @@ impl RawConversion<2> for Color { } } +pub trait HeaderEncoder { + fn encode(&self, tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Result, Error>; +} + pub trait PSXImageConverter: std::iter::Iterator { fn width(&self) -> u16; fn height(&self) -> u16;