use std::io::{self, Read, Seek, SeekFrom};
use byteorder::{LittleEndian, ReadBytesExt};
use crate::color::Pixels;
use crate::helpers::read_bytes;
use crate::{ColorDepth, Header};
pub enum Cel {
RawCel {
width: u16,
height: u16,
pixels: Pixels,
},
LinkedCel {
frame_position: u16,
},
CompressedImage {
width: u16,
height: u16,
zlib_compressed_data: Vec<u8>,
},
}
pub struct CelChunk {
pub layer_index: u16,
pub x_position: i16,
pub y_position: i16,
pub opacity_level: u8,
pub cel: Cel,
}
impl CelChunk {
pub fn from_read<R>(read: &mut R, chunk_size: u32, header: &Header) -> io::Result<Self>
where
R: Read + Seek,
{
let chunk_start = read.seek(SeekFrom::Current(0))?;
let layer_index = read.read_u16::<LittleEndian>()?;
let x_position = read.read_i16::<LittleEndian>()?;
let y_position = read.read_i16::<LittleEndian>()?;
let opacity_level = read.read_u8()?;
let cel_type = read.read_u16::<LittleEndian>()?;
let cel = match cel_type {
0 => {
let width = read.read_u16::<LittleEndian>()?;
let height = read.read_u16::<LittleEndian>()?;
let pixels_size =
chunk_start + chunk_size as u64 - read.seek(SeekFrom::Current(0))?;
let pixels = match header.color_depth {
ColorDepth::Indexed => Pixels::indexed_from_read(read, pixels_size as usize)?,
ColorDepth::Grayscale => {
Pixels::grayscale_from_read(read, pixels_size as usize)?
}
ColorDepth::RGBA => Pixels::rgba_from_read(read, pixels_size as usize)?,
};
Cel::RawCel {
width,
height,
pixels,
}
}
1 => Cel::LinkedCel {
frame_position: read.read_u16::<LittleEndian>()?,
},
2 => {
let width = read.read_u16::<LittleEndian>()?;
let height = read.read_u16::<LittleEndian>()?;
let data_size =
chunk_start + chunk_size as u64 - read.seek(SeekFrom::Current(0))?;
let zlib_compressed_data = read_bytes(read, data_size as usize)?;
Cel::CompressedImage {
width,
height,
zlib_compressed_data,
}
}
_ => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Invalid Cel Type {}", cel_type),
));
}
};
Ok(Self {
layer_index,
x_position,
y_position,
opacity_level,
cel,
})
}
}