Convert IndexedImages

This commit is contained in:
jaby 2022-09-27 20:52:44 +02:00
parent 530fd10662
commit 92760cfce1
5 changed files with 138 additions and 24 deletions

View File

@ -1,16 +1,21 @@
use tool_helper::Error;
use super::types::Color;
use super::types::{Color, PSXImageConverter};
pub enum OutputType {
TwoIndex,
FourBit,
EightBit,
}
enum IndexPerByte {
OneIndex,
TwoIndices,
}
pub struct IndexedImage {
palette: Vec<Color>,
data: Vec<u8>,
bit_depth: png::BitDepth,
output_type: OutputType,
raw_data: std::vec::IntoIter<u8>,
index_byte: IndexPerByte,
next_func: fn(&mut Self) -> Option<Color>,
width: u16,
height: u16,
}
@ -24,19 +29,27 @@ impl IndexedImage {
Ok(info) => {
let width = info.width as u16;
let height = info.height as u16;
let bit_depth = info.bit_depth;
let index_byte = {
match info.bit_depth {
png::BitDepth::Four => IndexPerByte::TwoIndices,
png::BitDepth::Eight => IndexPerByte::OneIndex,
_ => {
return Err(Error::from_str("Only 4 and 8bit color depth are supported").with_action(action_name));
}
}
};
if info.color_type != png::ColorType::Indexed {
return Err(Error::from_str("PNG file must be indexed").with_action(action_name));
}
if bit_depth != png::BitDepth::Four && bit_depth != png::BitDepth::Eight {
Err(Error::from_str("Only 4 and 8bit color depth are supported").with_action(action_name))
}
else {
Ok(IndexedImage{palette: Self::make_palette(), data: buffer, bit_depth, output_type, width, height})
Ok(IndexedImage{palette: Self::make_palette(reader.info()), raw_data: buffer.into_iter(), index_byte, next_func: {
match output_type {
OutputType::FourBit => Self::next_four_bit,
OutputType::EightBit => Self::next_eight_bit,
}
}, width, height})
}
}
@ -46,7 +59,83 @@ impl IndexedImage {
}
}
fn make_palette() -> Vec<Color> {
Vec::new()
fn make_palette(png_info: &png::Info) -> Vec<Color> {
fn make_color(iter: &mut dyn std::iter::Iterator<Item = &u8>) -> Option<Color> {
let r = iter.next()?;
let g = iter.next()?;
let b = iter.next()?;
Some(Color::non_transparent(*r, *g, *b))
}
let mut new_palette = Vec::new();
if let Some(palette) = &png_info.palette {
let mut iter = palette.iter();
while let Some(color) = make_color(&mut iter) {
new_palette.push(color);
}
}
new_palette
}
fn split_into_two_indices(index: u8) -> (u8, u8) {
(index >> 4, index & 0xF)
}
fn next_four_bit(&mut self) -> Option<Color> {
let (pixel0, pixel1, pixel2, pixel3) = {
match self.index_byte {
IndexPerByte::OneIndex => {
(self.raw_data.next()?, self.raw_data.next()?, self.raw_data.next()?, self.raw_data.next()?)
}
IndexPerByte::TwoIndices => {
let (pixel0, pixel1) = Self::split_into_two_indices(self.raw_data.next()?);
let (pixel2, pixel3) = Self::split_into_two_indices(self.raw_data.next()?);
(pixel0, pixel1, pixel2, pixel3)
},
}
};
Some(Color::new_4bit_entry(pixel0, pixel1, pixel2, pixel3))
}
fn next_eight_bit(&mut self) -> Option<Color> {
let (pixel0, pixel1) = {
match self.index_byte {
IndexPerByte::OneIndex => {
(self.raw_data.next()?, self.raw_data.next()?)
},
IndexPerByte::TwoIndices => {
Self::split_into_two_indices(self.raw_data.next()?)
}
}
};
Some(Color::new_8bit_entry(pixel0, pixel1))
}
}
impl PSXImageConverter for IndexedImage {
fn width(&self) -> u16 {
self.width
}
fn height(&self) -> u16 {
self.height
}
fn get_palette(&self) -> Option<&Vec<Color>> {
Some(&self.palette)
}
}
impl std::iter::Iterator for IndexedImage {
type Item = Color;
fn next(&mut self) -> Option<Self::Item> {
(self.next_func)(self)
}
}

View File

@ -25,7 +25,7 @@ impl PSXImageConverter for RgbImage {
self.height
}
fn get_palette(&self) -> Option<Vec<Color>> {
fn get_palette(&self) -> Option<&Vec<Color>> {
None
}
}
@ -67,7 +67,7 @@ impl PSXImageConverter for RgbaImage {
self.height
}
fn get_palette(&self) -> Option<Vec<Color>> {
fn get_palette(&self) -> Option<&Vec<Color>> {
None
}
}

View File

@ -77,19 +77,17 @@ fn convert_full16(input: Input, output: Output) -> Result<(), Error> {
}
}
fn convert_palette_based(input: Input, _: Output, color_type: ColorType) -> Result<(), Error> {
fn convert_palette_based(input: Input, output: Output, color_type: ColorType) -> Result<(), Error> {
match png::Decoder::new(input).read_info() {
Ok(reader) => {
let output_type = {
match color_type {
ColorType::Clut4 => color_clut::OutputType::TwoIndex,
ColorType::Clut8 => color_clut::OutputType::OneIndex,
ColorType::Clut4 => color_clut::OutputType::FourBit,
ColorType::Clut8 => color_clut::OutputType::EightBit,
_ => return Err(Error::from_str("ColorType not supported"))
}
};
let _image = IndexedImage::new(reader, output_type)?;
Err(Error::from_str("Under construction"))
encode(IndexedImage::new(reader, output_type)?, ClutAlignment::None, output)
},
Err(error) => Err(Error::from_error(error))
}

View File

@ -40,7 +40,15 @@ impl Color {
const STP_BIT_RANGE: BitRange = BitRange::from_to(15, 15);
const RED_BIT_RANGE: BitRange = BitRange::from_to(0, 4);
const GREEN_BIT_RANGE: BitRange = BitRange::from_to(5, 9);
const BLUE_BIT_RANGE: BitRange = BitRange::from_to(10, 14);
const BLUE_BIT_RANGE: BitRange = BitRange::from_to(10, 14);
const PIXEL3_4_BIT_RANGE: BitRange = BitRange::from_to(12, 15);
const PIXEL2_4_BIT_RANGE: BitRange = BitRange::from_to(8, 11);
const PIXEL1_4_BIT_RANGE: BitRange = BitRange::from_to(4, 7);
const PIXEL0_4_BIT_RANGE: BitRange = BitRange::from_to(0, 3);
const PIXEL1_8_BIT_RANGE: BitRange = BitRange::from_to(8, 15);
const PIXEL0_8_BIT_RANGE: BitRange = BitRange::from_to(0, 7);
pub const fn transparent() -> Color {
Color::new(0, 0, 0, 0)
@ -76,6 +84,24 @@ impl Color {
Color::new(1, 0, 0, 0)
}
pub const fn new_4bit_entry(pixel0_4: u8, pixel1_4: u8, pixel2_4: u8, pixel3_4: u8) -> Color {
let value = set_member_value!(set_member_value!(set_member_value!(set_member_value!(0,
pixel0_4, 0, u16),
pixel1_4, 0, u16),
pixel2_4, 0, u16),
pixel3_4, 0, u16);
Color{value}
}
pub const fn new_8bit_entry(pixel0_8: u8, pixel1_8: u8) -> Color {
let value = set_member_value!(set_member_value!(0,
pixel0_8, 0, u16),
pixel1_8, 0, u16);
Color{value}
}
const fn new(stp: u8, red: u8, green: u8, blue: u8) -> Color {
let value = set_member_value!(set_member_value!(set_member_value!(set_member_value!(0,
stp, 0, u16),
@ -120,5 +146,5 @@ pub trait PSXImageConverter: std::iter::Iterator<Item = Color> {
fn width(&self) -> u16;
fn height(&self) -> u16;
fn get_palette(&self) -> Option<Vec<Color>>;
fn get_palette(&self) -> Option<&Vec<Color>>;
}

View File

@ -31,5 +31,6 @@ macro_rules! create_bit_functions {
};
}
create_bit_functions!(u8);
create_bit_functions!(u16);
create_bit_functions!(u32);