diff --git a/src/blue.png b/src/blue.png new file mode 100644 index 0000000..88f302d Binary files /dev/null and b/src/blue.png differ diff --git a/src/main.rs b/src/main.rs index 4543b8e..4f9f6a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,12 +5,12 @@ use std::io::Write; use std::fs; use std::fs::File; -#[derive(Copy, Clone)] struct HeaderCZ0 { magic: [u8; 3], // The magic bytes, can be CZ0, (CZ1, CZ2?) length: u8, res: (i16, i16), // The width in the header depth: u8, // Bit depth + mystery: Vec, crop: (i16, i16), // Crop dimensions bounds: (i16, i16), // Bounding box dimensions offset: (i16, i16), // Offset coordinates @@ -22,14 +22,14 @@ struct CZ0File { } // Converts 8 bit bytes to a 16 bit little endian word or -pub fn bytes_to_word(first:u8, second:u8) -> i16 { +fn bytes_to_word(first:u8, second:u8) -> i16 { let final_value = ((second as i16) << 8) | (first as i16); return final_value; } // Converts a 16 bit little endian word to 8 bit bytes -pub fn word_to_bytes(word:i16) -> [u8; 2] { +fn word_to_bytes(word:i16) -> [u8; 2] { let first: u8 = (word & 0xFF) as u8; // Extract the first byte let second: u8 = ((word >> 8) & 0xFF) as u8; // Extract the second byte @@ -38,43 +38,50 @@ pub fn word_to_bytes(word:i16) -> [u8; 2] { /// Extract all the header information from a CZ0 file fn extract_header_cz0(header_vec: &Vec) -> (HeaderCZ0, usize) { + println!(""); + // Get the magic bytes let magic: [u8; 3] = header_vec[0..3].try_into().unwrap(); - println!("Magic Bytes : {:?}", magic); + println!("Magic Bytes : {:?}", magic); // Get the length of the header let length = header_vec[4]; - println!("Header Length: {:?}", length); + println!("Header Length : {:?} bytes", length); // Convert the width and height to i16 values let width = bytes_to_word(header_vec[8], header_vec[9]); let height = bytes_to_word(header_vec[10], header_vec[11]); - println!("Resolution : {}x{}", width, height); + println!("Resolution : {}x{}", width, height); // Get the bit depth let depth = header_vec[12]; - println!("Bit Depth : {} bits", depth); + println!("Bit Depth : {} bits", depth); + + // Get the mystery bytes + let mystery = header_vec[13..20].to_vec(); + println!("Header Length : {:?} bytes", length); // Get the crop resolution let crop_width = bytes_to_word(header_vec[20], header_vec[21]); let crop_height = bytes_to_word(header_vec[22], header_vec[23]); - println!("Crop Coords : {}x{}", crop_width, crop_height); + println!("Crop Coords : {}x{}", crop_width, crop_height); // Get bounding box let bound_width = bytes_to_word(header_vec[24], header_vec[25]); let bound_height = bytes_to_word(header_vec[26], header_vec[27]); - println!("Bound Coords : {}x{}", bound_width, bound_height); + println!("Bound Coords : {}x{}", bound_width, bound_height); // Get offset coordinates let offset_x = bytes_to_word(header_vec[28], header_vec[29]); let offset_y = bytes_to_word(header_vec[30], header_vec[31]); - println!("Offset Coords: {}x{}", offset_x, offset_y); + println!("Offset Coords : {}x{}", offset_x, offset_y); let image_header = HeaderCZ0 { magic, length, res: (width, height), depth, + mystery, crop: (crop_width, crop_height), bounds: (bound_width, bound_height), offset: (offset_x, offset_y), @@ -91,7 +98,6 @@ fn decode_cz0(input_filename:&str) -> CZ0File { let mut input = fs::read(input_filename).unwrap(); println!("Decoding input..."); - // TODO Research the header more! let (header, header_length) = extract_header_cz0(&input); input.drain(..header_length); @@ -109,62 +115,66 @@ fn decode_cz0(input_filename:&str) -> CZ0File { /// header information from a previous CZ0 file in order to /// replace it fn encode_cz0(original_file:CZ0File, in_name:&str, out_name:&str) -> io::Result<()> { + println!("Reading input file..."); let input_image = open(in_name).unwrap().into_rgba8(); let (input_width, input_height) = input_image.dimensions(); let width_diff = input_width as i16 - original_file.header.res.0; let height_diff = input_height as i16 - original_file.header.res.1; - // Crop - let crop_width = input_width as i16; - let crop_height = input_height as i16; - // Offset let offset_x = original_file.header.offset.0 + width_diff; let offset_y = original_file.header.offset.1 + height_diff; + let mut length = 28; + if offset_y > 0 || offset_x > 0 { + length = 36; + } + // Construct the header let header = HeaderCZ0 { magic: [67, 90, 48], - length: 36, + length, res: (input_width as i16, input_height as i16), - depth: 32, - crop: (crop_width, crop_height), + depth: original_file.header.depth, + mystery: original_file.header.mystery, + crop: (input_width as i16, input_height as i16), bounds: (original_file.header.bounds.0, original_file.header.bounds.1), - offset: (offset_x, offset_y), + offset: (original_file.header.offset.0, original_file.header.offset.1), }; let bitmap = input_image.to_vec(); + + println!("Writing to output file..."); let mut file = File::create(out_name)?; - // Write magic and length - file.write_all(&header.magic)?; - file.write_all(&[0])?; - file.write_all(&[header.length])?; - file.write_all(&vec![0u8; 3])?; + // Assemble the header + let mut header_assembled = [ + &header.magic[..], + &[0], + &[header.length], + &vec![0u8; 3], - // Write width and height - file.write_all(&word_to_bytes(header.res.0))?; - file.write_all(&word_to_bytes(header.res.1))?; + &word_to_bytes(header.res.0), + &word_to_bytes(header.res.1), + &[header.depth], - // Write bit depth - file.write_all(&[header.depth])?; - file.write_all(&vec![0u8; 7])?; + &header.mystery, - // Write crop width and height - file.write_all(&word_to_bytes(header.crop.0))?; - file.write_all(&word_to_bytes(header.crop.1))?; + &word_to_bytes(header.crop.0), + &word_to_bytes(header.crop.1), - // Write bound width and height - file.write_all(&word_to_bytes(header.bounds.0))?; - file.write_all(&word_to_bytes(header.bounds.1))?; + &word_to_bytes(header.bounds.0), + &word_to_bytes(header.bounds.1), - // Write offset width and height - file.write_all(&word_to_bytes(header.offset.0))?; - file.write_all(&word_to_bytes(header.offset.1))?; + &word_to_bytes(header.offset.0), + &word_to_bytes(header.offset.1), + &vec![0u8; 4], + ].concat(); - // Write unknown padding bytes - file.write_all(&vec![0u8; 4])?; + header_assembled.drain(length as usize..); + + file.write_all(&header_assembled)?; // Write the actual image data file.write_all(&bitmap)?; @@ -175,7 +185,8 @@ fn encode_cz0(original_file:CZ0File, in_name:&str, out_name:&str) -> io::Result< fn main() -> io::Result<()> { let image = decode_cz0("775.cz0"); - /* Create and save a PNG of the image data + /* + // Create and save a PNG of the image data // This errors if the image data is too short let tmp = match RgbaImage::from_raw( image.header.res.0 as u32, @@ -198,8 +209,13 @@ fn main() -> io::Result<()> { } }*/ - encode_cz0(image, "melon_test.png", "test.cz0").unwrap(); - decode_cz0("test.cz0"); + + match encode_cz0(image, "melon_test.png", "test.cz0") { + Ok(file) => file, + Err(error) => panic!("Problem opening the file: {:?}", error), + }; + + decode_cz0("test.cz0"); // Running this function standalone simply prints information about the image's header return Ok(()); } diff --git a/src/melon_test.png b/src/melon_test.png new file mode 100644 index 0000000..424b282 Binary files /dev/null and b/src/melon_test.png differ