Convert IndexedImages
This commit is contained in:
parent
530fd10662
commit
92760cfce1
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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>>;
|
||||
}
|
|
@ -31,5 +31,6 @@ macro_rules! create_bit_functions {
|
|||
};
|
||||
}
|
||||
|
||||
create_bit_functions!(u8);
|
||||
create_bit_functions!(u16);
|
||||
create_bit_functions!(u32);
|
Loading…
Reference in New Issue