diff --git a/Cargo.toml b/Cargo.toml index 5ee55af..19b2309 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -clap = "4.2.4" -image = { version = "0.24.6", features = ["webp", "webp-encoder"] } -png = "0.17.8" -sdl2 = { version = "0.35.2", features = ["gfx"] } -sdl2-sys = "0.35.2" +image = "0.25" +thiserror = "1.0.59" diff --git a/src/cz_common.rs b/src/cz_common.rs index 670c65f..9ba0a3b 100644 --- a/src/cz_common.rs +++ b/src/cz_common.rs @@ -1,11 +1,19 @@ //! Shared types and traits between CZ# files +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum CzError { + #[error("Version in header does not match expected version")] + VersionMismatch +} + pub trait CzHeader { - fn new(bytes: &[u8]) -> Self; + fn new(bytes: &[u8]) -> Result where Self: Sized; fn version(&self) -> u8; - fn header_length(&self) -> u16; + fn header_length(&self) -> usize; fn width(&self) -> u16; @@ -46,9 +54,17 @@ impl CommonHeader { } pub trait CzImage { - /// Create a [CZImage] from bytes - fn decode(bytes: &[u8]) -> Self; + type Header; - /// Get the underlying bitmap for an image + /// Create a [CZImage] from bytes + fn decode(bytes: &[u8]) -> Result where Self: Sized; + + /// Save the image as a PNG + fn save_as_png(&self, name: &str); + + /// Get the header for metadata + fn header(&self) -> &Self::Header; + + /// Get the raw underlying bitmap for an image fn raw_bitmap(&self) -> &Vec; } diff --git a/src/formats/cz0.rs b/src/formats/cz0.rs index e8673c5..0922bdb 100644 --- a/src/formats/cz0.rs +++ b/src/formats/cz0.rs @@ -1,53 +1,106 @@ -use crate::cz_common::{CommonHeader, CzHeader, CzImage}; +use crate::cz_common::{CommonHeader, CzError, CzHeader, CzImage}; -struct Cz0Header { +#[derive(Debug)] +pub struct Cz0Header { /// Common CZ# header - common_header: CommonHeader, + common: CommonHeader, - /// Dimensions of cropped image area - crop: (u16, u16), + /// Width of cropped image area + crop_width: u16, - /// Bounding box dimensions - bounds: (u16, u16), + /// Height of cropped image area + crop_height: u16, - // Offset coordinates - offset: (u16, u16), + /// Bounding box width + bounds_width: u16, + + /// Bounding box height + bounds_height: u16, + + /// Offset width + offset_width: u16, + + /// Offset height + offset_height: u16, } -struct Cz0Image { +#[derive(Debug)] +pub struct Cz0Image { header: Cz0Header, bitmap: Vec, } impl CzHeader for Cz0Header { - fn new(bytes: &[u8]) -> Self { - todo!() + fn new(bytes: &[u8]) -> Result { + let common = CommonHeader::new(bytes); + + if common.version != 0 { + return Err(CzError::VersionMismatch) + } + + Ok(Self { + common, + + crop_width: u16::from_le_bytes(bytes[20..22].try_into().unwrap()), + crop_height: u16::from_le_bytes(bytes[22..24].try_into().unwrap()), + + bounds_width: u16::from_le_bytes(bytes[24..26].try_into().unwrap()), + bounds_height: u16::from_le_bytes(bytes[26..28].try_into().unwrap()), + + offset_width: u16::from_le_bytes(bytes[28..30].try_into().unwrap()), + offset_height: u16::from_le_bytes(bytes[30..32].try_into().unwrap()), + }) } fn version(&self) -> u8 { - todo!() + self.common.version } - fn header_length(&self) -> u16 { - todo!() + fn header_length(&self) -> usize { + self.common.length as usize } fn width(&self) -> u16 { - todo!() + self.common.width } fn height(&self) -> u16 { - todo!() + self.common.height } fn depth(&self) -> u8 { - todo!() + self.common.depth } } impl CzImage for Cz0Image { - fn decode(bytes: &[u8]) -> Self { - let header = CZH + type Header = Cz0Header; + + fn decode(bytes: &[u8]) -> Result { + // Get the header from the input + let header = Cz0Header::new(bytes)?; + + // Get the rest of the file, which is the bitmap + let bitmap = bytes[header.header_length() as usize..].to_vec(); + + Ok(Self { + header, + bitmap + }) + } + + fn save_as_png(&self, name: &str) { + image::save_buffer( + name, + &self.bitmap, + self.header.common.width as u32, + self.header.common.height as u32, + image::ExtendedColorType::Rgba8 + ).unwrap() + } + + fn header(&self) -> &Self::Header { + &self.header } fn raw_bitmap(&self) -> &Vec { diff --git a/src/main.rs b/src/main.rs index a5e3982..e0bf4b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,10 +5,13 @@ pub mod formats{ // Generic tools use std::fs; -use crate::cz_common::CommonHeader; + +use crate::{cz_common::CzImage, formats::cz0::Cz0Image}; fn main() { - let input = fs::read("../test_files/x5a3bvy.cz1").expect("Error, could not open image"); - let header = CommonHeader::new(&input); - println!("{:?}", header); + let input = fs::read("../test_files/Old_TestFiles/LOGO0.CZ0").expect("Error, could not open image"); + let cz0_file = Cz0Image::decode(&input).unwrap(); + println!("{:#?}", cz0_file.header()); + + cz0_file.save_as_png("test.png") } diff --git a/src/test.png b/src/test.png new file mode 100644 index 0000000..524aa5e Binary files /dev/null and b/src/test.png differ