From 4f0103e8fafd36c6450fcd30b1d8aab0fae9b034 Mon Sep 17 00:00:00 2001 From: Jaby Date: Sat, 15 Feb 2025 17:07:41 +0100 Subject: [PATCH] Load indexed png --- src/Tools/tim_tool/Cargo.toml | 1 + src/Tools/tim_tool/src/logic/mod.rs | 2 +- src/Tools/tim_tool/src/logic/tim.rs | 59 ++++++++++++++++++++++++++--- src/Tools/tim_tool/src/main.rs | 6 +-- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/Tools/tim_tool/Cargo.toml b/src/Tools/tim_tool/Cargo.toml index dd0b80c4..a5253132 100644 --- a/src/Tools/tim_tool/Cargo.toml +++ b/src/Tools/tim_tool/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" panic = "abort" [dependencies] +png = "0.17.16" rfd = "0.15.2" slint = "1.9.2" tiny-skia = "0.11.4" diff --git a/src/Tools/tim_tool/src/logic/mod.rs b/src/Tools/tim_tool/src/logic/mod.rs index d7acaf11..a6b0d99f 100644 --- a/src/Tools/tim_tool/src/logic/mod.rs +++ b/src/Tools/tim_tool/src/logic/mod.rs @@ -40,6 +40,6 @@ impl UnaddedTIM { } fn empty() -> UnaddedTIM { - UnaddedTIM{info: TIMInfo{}, image: Image::default()} + UnaddedTIM{info: TIMInfo::default(), image: Image::default()} } } \ No newline at end of file diff --git a/src/Tools/tim_tool/src/logic/tim.rs b/src/Tools/tim_tool/src/logic/tim.rs index e92945d5..5487e39e 100644 --- a/src/Tools/tim_tool/src/logic/tim.rs +++ b/src/Tools/tim_tool/src/logic/tim.rs @@ -1,14 +1,63 @@ -use std::path::PathBuf; +use std::{default, fmt::format, fs::File, path::PathBuf}; +use slint::{Rgba8Pixel, SharedPixelBuffer}; use tool_helper::Error; -pub struct TIMInfo {} +pub struct TIMInfo { + image_data: SharedPixelBuffer, + palette: Option>, +} impl std::default::Default for TIMInfo { fn default() -> Self { - TIMInfo{} + TIMInfo{image_data: SharedPixelBuffer::new(1, 1), palette: None} } } -pub fn load_image(path: PathBuf) -> Result<(slint::Image, TIMInfo), Error> { - Ok((slint::Image::load_from_path(&path).or_else(|_| {Err(Error::from_str("Failed loading image"))})?, TIMInfo{})) +pub fn load_image(path: &PathBuf) -> Result<(slint::Image, TIMInfo), Error> { + fn make_color(iter: &mut dyn std::iter::Iterator) -> Option { + Some(Rgba8Pixel::new( + *iter.next()?, *iter.next()?, *iter.next()?, + 0xFF)) + } + + let mut reader = png::Decoder::new(File::open(path)?).read_info().or_else(|error| {Err(Error::from_error(error))})?; + let info = reader.info().clone(); + + let mut buffer = vec![0; reader.output_buffer_size()]; + let frame_info = reader.next_frame(&mut buffer).or_else(|error| {Err(Error::from_error(error))})?; + let bit_depth = frame_info.bit_depth; + let mut image_data = SharedPixelBuffer::new(frame_info.width, frame_info.height); + + if info.color_type == png::ColorType::Indexed { + let palette = info.palette.ok_or(Error::from_str("Found indexed PNG without palette"))?; + let mut palette_colors = Vec::new(); + let mut iter = palette.iter(); + + while let Some(color) = make_color(&mut iter) { + palette_colors.push(color); + } + + let mut dst_pixels = image_data.make_mut_slice(); + for byte in buffer.into_iter() { + match bit_depth { + png::BitDepth::Four => { + dst_pixels[0] = palette_colors[(byte >> 4) as usize]; + dst_pixels[1] = palette_colors[(byte & 0xF) as usize]; + dst_pixels = &mut dst_pixels[2..]; + }, + png::BitDepth::Eight => { + dst_pixels[0] = palette_colors[byte as usize]; + dst_pixels = &mut dst_pixels[1..]; + }, + _ => {return Err(Error::from_str("Only 4 and 8bit color depth are supported"));} + } + } + + let image = slint::Image::from_rgba8_premultiplied(image_data.clone()); + Ok((image, TIMInfo{image_data, palette: Some(palette_colors)})) + } + + else { + Err(Error::not_implemented("Support for non indexed images")) + } } \ No newline at end of file diff --git a/src/Tools/tim_tool/src/main.rs b/src/Tools/tim_tool/src/main.rs index 60479f3b..aa2c5882 100644 --- a/src/Tools/tim_tool/src/main.rs +++ b/src/Tools/tim_tool/src/main.rs @@ -47,8 +47,8 @@ fn setup_file_tab(gui_elements_ref: Rc>, logic_ref: Rc>, logic_ref: Rc (image, info), Err(error) => { file_tab.clear_load();