diff --git a/cz/Cargo.toml b/cz/Cargo.toml index 0089a7d..6eeab66 100644 --- a/cz/Cargo.toml +++ b/cz/Cargo.toml @@ -11,4 +11,4 @@ A encoder/decoder for CZ# image files used in byteorder = "1.5.0" thiserror = "1.0.59" png = "0.17.13" -image = "0.25.1" +image = { version = "0.25.1", default-features = false } diff --git a/cz/src/binio.rs b/cz/src/binio.rs index 5bf99e6..9a21db9 100644 --- a/cz/src/binio.rs +++ b/cz/src/binio.rs @@ -18,10 +18,10 @@ impl BitIO { } pub fn bit_offset(&self) -> usize { - self.byte_offset + self.bit_offset } - pub fn to_vec(self) -> Vec { + pub fn into_vec(self) -> Vec { self.data } @@ -38,7 +38,7 @@ impl BitIO { let mut result = 0; for i in 0..bit_len { let bit_value = - ((self.data[self.byte_offset] as usize >> self.bit_offset as usize) & 1) as u64; + ((self.data[self.byte_offset] as usize >> self.bit_offset) & 1) as u64; self.bit_offset += 1; if self.bit_offset == 8 { @@ -49,7 +49,7 @@ impl BitIO { result |= bit_value << i; } - return result; + result } pub fn read(&mut self, byte_len: usize) -> u64 { diff --git a/cz/src/common.rs b/cz/src/common.rs index 2ce3fbc..540d130 100644 --- a/cz/src/common.rs +++ b/cz/src/common.rs @@ -101,7 +101,7 @@ impl CzHeader for CommonHeader { } fn common(&self) -> &CommonHeader { - &self + self } fn version(&self) -> u8 { @@ -184,7 +184,7 @@ pub fn parse_colormap( Ok(colormap) } -pub fn apply_palette(input: &mut Vec, palette: &[[u8; 4]]) -> Vec { +pub fn apply_palette(input: &mut &[u8], palette: &[[u8; 4]]) -> Vec { let mut output_map = Vec::new(); for byte in input.iter() { diff --git a/cz/src/compression.rs b/cz/src/compression.rs index 151c7f5..9291e55 100644 --- a/cz/src/compression.rs +++ b/cz/src/compression.rs @@ -1,4 +1,5 @@ use byteorder::{LittleEndian, ReadBytesExt}; +use image::RgbaImage; use std::{ collections::BTreeMap, io::{Read, Seek, Write}, @@ -160,11 +161,11 @@ pub fn decompress_lzw2(input_data: &[u8], size: usize) -> Vec { //println!("{}", element); - result.write(&entry).unwrap(); + result.write_all(&entry).unwrap(); w.push(entry[0]); dictionary.insert(dictionary_count, w.clone()); dictionary_count += 1; - w = entry.clone(); + w.clone_from(&entry); } result } @@ -234,7 +235,7 @@ pub fn line_diff(header: &T, data: &[u8]) -> Vec { } } - prev_line = curr_line.clone(); + prev_line.clone_from(&curr_line); if pixel_byte_count == 4 { output_buf[i..i + line_byte_count].copy_from_slice(&curr_line); } else if pixel_byte_count == 3 { @@ -242,7 +243,7 @@ pub fn line_diff(header: &T, data: &[u8]) -> Vec { let loc = ((y * width) as usize + x) * 4; output_buf[loc..loc + 4].copy_from_slice(&[ - curr_line[x + 0], + curr_line[x], curr_line[x + 1], curr_line[x + 2], 0xFF @@ -256,16 +257,11 @@ pub fn line_diff(header: &T, data: &[u8]) -> Vec { output_buf } -pub fn line_diff_cz4(header: &T, data: &[u8]) -> Vec { - let width = header.width() as u32; - let height = header.height() as u32; +pub fn line_diff_cz4(picture: &mut RgbaImage, pixel_byte_count: usize, data: &[u8]) { + let width = picture.width(); + let height = picture.height(); let block_height = (f32::ceil(height as f32 / 3.0) as u16) as u32; - //let pixel_byte_count = (header.depth() >> 3) as usize; - let pixel_byte_count = 3; - - let mut output_buf = data.to_vec(); - let mut curr_line; let mut prev_line = vec![0u8; width as usize * pixel_byte_count]; @@ -280,30 +276,26 @@ pub fn line_diff_cz4(header: &T, data: &[u8]) -> Vec { } for x in 0..width as usize { - let loc = ((y * width) as usize + x) * 4; - if pixel_byte_count == 1 { - output_buf[loc + 4] = curr_line[x]; + picture.get_pixel_mut(x as u32, y).0[3] = curr_line[x]; } else if pixel_byte_count == 4 { - output_buf[loc..loc + 4].copy_from_slice(&[ - curr_line[x * pixel_byte_count + 0], + picture.get_pixel_mut(x as u32, y).0 = [ + curr_line[x * pixel_byte_count], curr_line[x * pixel_byte_count + 1], curr_line[x * pixel_byte_count + 2], curr_line[x * pixel_byte_count + 3], - ]); + ]; } else if pixel_byte_count == 3 { - output_buf[loc..loc + 4].copy_from_slice(&[ - curr_line[x * pixel_byte_count + 0], + picture.get_pixel_mut(x as u32, y).0 = [ + curr_line[x * pixel_byte_count], curr_line[x * pixel_byte_count + 1], curr_line[x * pixel_byte_count + 2], 0xFF, - ]); + ]; } } - prev_line = curr_line.clone(); + prev_line.clone_from(&curr_line); i += width as usize * pixel_byte_count; } - - output_buf } diff --git a/cz/src/dynamic.rs b/cz/src/dynamic.rs index 917fca5..42cd705 100644 --- a/cz/src/dynamic.rs +++ b/cz/src/dynamic.rs @@ -1,4 +1,4 @@ -use std::io::{Read, Seek}; +use std::{io::{Read, Seek}, path::{Path, PathBuf}}; use byteorder::ReadBytesExt; use crate::{ @@ -20,12 +20,18 @@ pub enum DynamicCz { } impl DynamicCz { - pub fn save_as_png(&self, name: &str) -> Result<(), png::EncodingError> { - let file = std::fs::File::create(name).unwrap(); - let ref mut w = std::io::BufWriter::new(file); + pub fn open>(path: &P) -> Result { + let mut img_file = std::fs::File::open(path)?; + + Self::decode(&mut img_file) + } + + pub fn save_as_png>(&self, path: &P) -> Result<(), png::EncodingError> { + let file = std::fs::File::create(path).unwrap(); + let writer = std::io::BufWriter::new(file); let mut encoder = png::Encoder::new( - w, + writer, self.header().width() as u32, self.header().height() as u32, ); @@ -33,7 +39,7 @@ impl DynamicCz { encoder.set_depth(png::BitDepth::Eight); let mut writer = encoder.write_header()?; - writer.write_image_data(&self.bitmap())?; + writer.write_image_data(self.bitmap())?; // Save Ok(()) } @@ -70,11 +76,11 @@ impl CzImage for DynamicCz { fn header(&self) -> &Self::Header { match self { - DynamicCz::CZ0(img) => &img.header().common(), - DynamicCz::CZ1(img) => &img.header().common(), - DynamicCz::CZ2(img) => &img.header().common(), - DynamicCz::CZ3(img) => &img.header().common(), - DynamicCz::CZ4(img) => &img.header().common(), + DynamicCz::CZ0(img) => img.header().common(), + DynamicCz::CZ1(img) => img.header().common(), + DynamicCz::CZ2(img) => img.header().common(), + DynamicCz::CZ3(img) => img.header().common(), + DynamicCz::CZ4(img) => img.header().common(), } } diff --git a/cz/src/formats/cz1.rs b/cz/src/formats/cz1.rs index d003c05..6364bb5 100644 --- a/cz/src/formats/cz1.rs +++ b/cz/src/formats/cz1.rs @@ -51,7 +51,7 @@ impl CzImage for Cz1Image { bitmap.clone_into(raw); } - bitmap = apply_palette(&mut bitmap, pal); + bitmap = apply_palette(&mut bitmap.as_slice(), pal); } let image = Self { diff --git a/cz/src/formats/cz2.rs b/cz/src/formats/cz2.rs index eb9683c..cbf2742 100644 --- a/cz/src/formats/cz2.rs +++ b/cz/src/formats/cz2.rs @@ -102,7 +102,7 @@ impl CzImage for Cz2Image { // Apply the palette if it exists if let Some(pal) = &palette { - bitmap = apply_palette(&mut bitmap, pal); + bitmap = apply_palette(&mut bitmap.as_slice(), pal); } let image = Self { diff --git a/cz/src/formats/cz4.rs b/cz/src/formats/cz4.rs index c4d273a..f05c773 100644 --- a/cz/src/formats/cz4.rs +++ b/cz/src/formats/cz4.rs @@ -76,15 +76,22 @@ impl CzImage for Cz4Image { let block_info = parse_chunk_info(bytes)?; bytes.seek(SeekFrom::Start(block_info.length as u64))?; - let pcount = header.width() as usize * header.height() as usize; - let bitmap = decompress(bytes, &block_info)?; - let data2 = bitmap[pcount * 3..].to_vec(); + let pcount = (header.width() as usize * header.height() as usize) * 3; + let data = decompress(bytes, &block_info)?; + let data2 = data[pcount..].to_vec(); - let bitmap = line_diff_cz4(&header, &bitmap); + let mut picture = image::RgbaImage::new(header.width() as u32, header.height() as u32); - let bitmap = line_diff_cz4(&header, &bitmap); + let pixel_byte_count = 3; + line_diff_cz4(&mut picture, pixel_byte_count, &data); - Ok(Self { header, bitmap }) + let pixel_byte_count = 1; + line_diff_cz4(&mut picture, pixel_byte_count, &data2); + + Ok(Self { + header, + bitmap: picture.into_raw() + }) } fn header(&self) -> &Self::Header { @@ -107,7 +114,12 @@ impl CzImage for Cz4Image { todo!() } +<<<<<<< HEAD fn set_bitmap(&mut self, bitmap: &[u8], width: u16, height: u16) { todo!() +======= + fn set_bitmap(&mut self, bitmap: &[u8], header: &Self::Header) { + self.bitmap = bitmap.to_vec(); +>>>>>>> 613e38c6b560990c77e994f2359fc4c30ff112a4 } } diff --git a/utils/src/main.rs b/utils/src/main.rs index 6adeacd..1d9c382 100644 --- a/utils/src/main.rs +++ b/utils/src/main.rs @@ -1,9 +1,35 @@ -use cz::{dynamic::DynamicCz, Cz0Image, CzImage}; -use std::fs; +use std::{fs::DirBuilder, time::{Duration, Instant}}; + +use cz::dynamic::DynamicCz; +use walkdir::WalkDir; fn main() { - let mut file = fs::File::open("TEXTBOX.CZ3").unwrap(); - let img = DynamicCz::decode(&mut file).unwrap(); + let _ = DirBuilder::new().create("test"); - img.save_as_png("test.png").unwrap(); + let mut total_time = Duration::default(); + let mut num_images = 0; + for entry in WalkDir::new("../../test_files/loopers/") { + let entry = entry.unwrap(); + if entry.path().is_dir() { + continue; + } + + let timer = Instant::now(); + let img = match DynamicCz::open(entry.path()) { + Ok(img) => img, + Err(err) => { + println!("{}: {}", entry.path().file_name().unwrap().to_string_lossy(), err); + continue; + }, + }; + let elapsed = timer.elapsed(); + total_time += elapsed; + num_images += 1; + + img.save_as_png( + &format!("test/{}.png", entry.path().file_name().unwrap().to_string_lossy()) + ).unwrap(); + } + + dbg!(total_time / num_images); }