From b1c9fd93c9605c41d93c71d0a8c31eb1d73acfc9 Mon Sep 17 00:00:00 2001 From: Jaby Date: Thu, 12 Oct 2023 11:06:11 +0200 Subject: [PATCH] Do not accept images that have wrong sizes --- .../src/images/reduced_tim/mod.rs | 318 ++++++++++-------- 1 file changed, 171 insertions(+), 147 deletions(-) diff --git a/src/Tools/jaby_engine_fconv/src/images/reduced_tim/mod.rs b/src/Tools/jaby_engine_fconv/src/images/reduced_tim/mod.rs index d6745e6c..bcba4409 100644 --- a/src/Tools/jaby_engine_fconv/src/images/reduced_tim/mod.rs +++ b/src/Tools/jaby_engine_fconv/src/images/reduced_tim/mod.rs @@ -1,148 +1,172 @@ -use clap::{Args, ValueEnum}; -use image::{DynamicImage, io::Reader as ImageReader}; -use color_clut::IndexedImage; -use color_full16::{RgbaImage, RgbImage}; -use std::io::{Cursor, Write}; -use tool_helper::{Error, Input}; -use types::{Header, Color as PSXColor, PSXImageConverter}; - -mod types; -mod color_clut; -mod color_full16; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -pub enum ColorType{ - Clut4, - Clut8, - Full16, -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -pub enum ClutAlignment { - None, - Linear, - Block -} - -#[derive(Args)] -pub struct Arguments { - #[clap(value_enum, value_parser)] - color_depth: ColorType, - - #[clap(value_enum, value_parser, default_value_t=ClutAlignment::None)] - clut_align: ClutAlignment, - - #[clap(long="semi-trans", default_value_t=false)] - semi_transparent: bool, - #[clap(long="color-trans", default_value_t=false)] - transparent_palette: bool -} - -fn modify_palette(mut image: IndexedImage, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> IndexedImage { - if semi_transparent { - for color in image.palette.iter_mut() { - *color = PSXColor::semi_transparent(color.get_red(), color.get_green(), color.get_blue()); - } - } - - if transparent_palette { - if clut_align == ClutAlignment::Block { - for color in image.palette.iter_mut().step_by(16) { - *color = PSXColor::transparent(); - } - } - - else { - if let Some(first_color) = image.palette.get_mut(0) { - *first_color = PSXColor::transparent(); - } - } - } - image -} - -fn encode(image: T, color_depth: ColorType, clut_align: ClutAlignment, output: &mut dyn Write) -> Result<(), Error> { - let width = { - let width = image.width(); - match color_depth { - ColorType::Clut4 => width/4, - ColorType::Clut8 => width/2, - ColorType::Full16 => width - } - }; - let height = image.height(); - let palette = image.get_palette(); - let (pal_width, pal_height) = { - if let Some(palette) = &palette { - match clut_align { - ClutAlignment::None | - ClutAlignment::Linear => (palette.len() as u16, 1u16), - ClutAlignment::Block => (16u16, (palette.len()/16) as u16), - } - } - - else { - (0u16, 0u16) - } - }; - - 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)}))?; - - tool_helper::raw::write_raw(output, &header)?; - if let Some(palette) = palette { - let mut color_count = pal_width*pal_height; - for color in palette { - tool_helper::raw::write_raw(output, color)?; - color_count -= 1; - } - - while color_count > 0 { - tool_helper::raw::write_raw(output, &PSXColor::black())?; - color_count -= 1; - } - } - - for color in image { - tool_helper::raw::write_raw(output, &color)?; - } - - Ok(()) -} - -fn convert_full16(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), - - _ => Err(Error::from_str("Only RGB and RGBA images are supported for 16bit encoding")) - } - }, - Err(error) => Err(Error::from_error(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> { - match png::Decoder::new(input).read_info() { - Ok(reader) => { - let output_type = { - match color_type { - ColorType::Clut4 => color_clut::OutputType::FourBit, - ColorType::Clut8 => color_clut::OutputType::EightBit, - _ => return Err(Error::from_str("ColorType not supported")) - } - }; - - encode(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)) - } -} - -pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { - match args.color_depth { - ColorType::Full16 => convert_full16(input, output), - _ => convert_palette_based(input, output, args.color_depth, args.clut_align, args.semi_transparent, args.transparent_palette), - } +use clap::{Args, ValueEnum}; +use image::{DynamicImage, io::Reader as ImageReader}; +use color_clut::IndexedImage; +use color_full16::{RgbaImage, RgbImage}; +use std::io::{Cursor, Write}; +use tool_helper::{Error, Input}; +use types::{Header, Color as PSXColor, PSXImageConverter}; + +mod types; +mod color_clut; +mod color_full16; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub enum ColorType{ + Clut4, + Clut8, + Full16, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub enum ClutAlignment { + None, + Linear, + Block +} + +#[derive(Args)] +pub struct Arguments { + #[clap(value_enum, value_parser)] + color_depth: ColorType, + + #[clap(value_enum, value_parser, default_value_t=ClutAlignment::None)] + clut_align: ClutAlignment, + + #[clap(long="semi-trans", default_value_t=false)] + semi_transparent: bool, + #[clap(long="color-trans", default_value_t=false)] + transparent_palette: bool +} + +fn modify_palette(mut image: IndexedImage, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> IndexedImage { + if semi_transparent { + for color in image.palette.iter_mut() { + *color = PSXColor::semi_transparent(color.get_red(), color.get_green(), color.get_blue()); + } + } + + if transparent_palette { + if clut_align == ClutAlignment::Block { + for color in image.palette.iter_mut().step_by(16) { + *color = PSXColor::transparent(); + } + } + + else { + if let Some(first_color) = image.palette.get_mut(0) { + *first_color = PSXColor::transparent(); + } + } + } + image +} + +fn encode(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, div, (height as f32/div as f32))})); + } + + let width = image.width(); + let height = image.height(); + match color_depth { + ColorType::Clut4 => { + if width & 3 == 0 { + Ok((width/4, height)) + } + + else { + return_error(4, 4, width, height) + } + }, + ColorType::Clut8 => { + if width & 1 == 0 { + Ok((width/2, height)) + } + + else { + return_error(8, 2, width, height) + } + }, + ColorType::Full16 => { + Ok((width, height)) + } + } + }?; + let palette = image.get_palette(); + let (pal_width, pal_height) = { + if let Some(palette) = &palette { + match clut_align { + ClutAlignment::None | + ClutAlignment::Linear => (palette.len() as u16, 1u16), + ClutAlignment::Block => (16u16, (palette.len()/16) as u16), + } + } + + else { + (0u16, 0u16) + } + }; + + 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)}))?; + + tool_helper::raw::write_raw(output, &header)?; + if let Some(palette) = palette { + let mut color_count = pal_width*pal_height; + for color in palette { + tool_helper::raw::write_raw(output, color)?; + color_count -= 1; + } + + while color_count > 0 { + tool_helper::raw::write_raw(output, &PSXColor::black())?; + color_count -= 1; + } + } + + for color in image { + tool_helper::raw::write_raw(output, &color)?; + } + + Ok(()) +} + +fn convert_full16(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), + + _ => Err(Error::from_str("Only RGB and RGBA images are supported for 16bit encoding")) + } + }, + Err(error) => Err(Error::from_error(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> { + match png::Decoder::new(input).read_info() { + Ok(reader) => { + let output_type = { + match color_type { + ColorType::Clut4 => color_clut::OutputType::FourBit, + ColorType::Clut8 => color_clut::OutputType::EightBit, + _ => return Err(Error::from_str("ColorType not supported")) + } + }; + + encode(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)) + } +} + +pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { + match args.color_depth { + ColorType::Full16 => convert_full16(input, output), + _ => convert_palette_based(input, output, args.color_depth, args.clut_align, args.semi_transparent, args.transparent_palette), + } } \ No newline at end of file