Load indexed png
This commit is contained in:
parent
6fa574c921
commit
4f0103e8fa
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
png = "0.17.16"
|
||||||
rfd = "0.15.2"
|
rfd = "0.15.2"
|
||||||
slint = "1.9.2"
|
slint = "1.9.2"
|
||||||
tiny-skia = "0.11.4"
|
tiny-skia = "0.11.4"
|
||||||
|
|
|
@ -40,6 +40,6 @@ impl UnaddedTIM {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty() -> UnaddedTIM {
|
fn empty() -> UnaddedTIM {
|
||||||
UnaddedTIM{info: TIMInfo{}, image: Image::default()}
|
UnaddedTIM{info: TIMInfo::default(), image: Image::default()}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
use tool_helper::Error;
|
||||||
|
|
||||||
pub struct TIMInfo {}
|
pub struct TIMInfo {
|
||||||
|
image_data: SharedPixelBuffer<Rgba8Pixel>,
|
||||||
|
palette: Option<Vec<Rgba8Pixel>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl std::default::Default for TIMInfo {
|
impl std::default::Default for TIMInfo {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
TIMInfo{}
|
TIMInfo{image_data: SharedPixelBuffer::new(1, 1), palette: None}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_image(path: PathBuf) -> Result<(slint::Image, TIMInfo), Error> {
|
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{}))
|
fn make_color(iter: &mut dyn std::iter::Iterator<Item = &u8>) -> Option<Rgba8Pixel> {
|
||||||
|
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"))
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -47,8 +47,8 @@ fn setup_file_tab(gui_elements_ref: Rc<RefCell<GUIElements>>, logic_ref: Rc<RefC
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = FileDialog::new()
|
let file = FileDialog::new()
|
||||||
.add_filter("Images (.png; .bmp; .jpeg)", &["png", "bmp", "jpeg"])
|
.add_filter("PNG image (.png)", &["png"])
|
||||||
.set_title("Select image file")
|
.set_title("PNG image file")
|
||||||
.pick_file();
|
.pick_file();
|
||||||
|
|
||||||
if let Some(file) = file {
|
if let Some(file) = file {
|
||||||
|
@ -59,7 +59,7 @@ fn setup_file_tab(gui_elements_ref: Rc<RefCell<GUIElements>>, logic_ref: Rc<RefC
|
||||||
let file_tab = &gui_elements.file_tab;
|
let file_tab = &gui_elements.file_tab;
|
||||||
let file_name = if let Some(name) = file.file_name() {Some(name.to_string_lossy().to_string())} else {None};
|
let file_name = if let Some(name) = file.file_name() {Some(name.to_string_lossy().to_string())} else {None};
|
||||||
|
|
||||||
let (image, info) = match load_image(file) {
|
let (image, info) = match load_image(&file) {
|
||||||
Ok((image, info)) => (image, info),
|
Ok((image, info)) => (image, info),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
file_tab.clear_load();
|
file_tab.clear_load();
|
||||||
|
|
Loading…
Reference in New Issue