Fixed CZ1/CZ3 compression

This commit is contained in:
G2-Games 2024-05-10 11:59:35 -05:00
parent 9da8d68683
commit 5b95687393
6 changed files with 122 additions and 14 deletions

View file

@ -58,7 +58,7 @@ impl TryFrom<u8> for CzVersion {
}
pub trait CzHeader {
fn new<T: Seek + ReadBytesExt + Read>(bytes: &mut T) -> Result<Self, CzError>
fn from_bytes<T: Seek + ReadBytesExt + Read>(bytes: &mut T) -> Result<Self, CzError>
where
Self: Sized;
@ -122,8 +122,29 @@ pub struct CommonHeader {
unknown: u8,
}
impl CommonHeader {
pub fn new(
version: CzVersion,
width: u16,
height: u16,
) -> Self {
Self {
version,
length: 15,
width,
height,
depth: 32,
unknown: 0
}
}
pub fn set_length(&mut self, length: u32) {
self.length = length
}
}
impl CzHeader for CommonHeader {
fn new<T: Seek + ReadBytesExt + Read>(bytes: &mut T) -> Result<Self, CzError>
fn from_bytes<T: Seek + ReadBytesExt + Read>(bytes: &mut T) -> Result<Self, CzError>
where
Self: Sized,
{
@ -243,7 +264,37 @@ pub struct ExtendedHeader {
}
impl ExtendedHeader {
pub fn new<T: Seek + ReadBytesExt + Read>(
pub fn new(
crop_width: u16,
crop_height: u16,
bounds_width: u16,
bounds_height: u16,
) -> Self {
ExtendedHeader {
unknown_1: [0u8; 5],
crop_width,
crop_height,
bounds_width,
bounds_height,
offset_width: None,
offset_height: None,
unknown_2: None
}
}
pub fn with_offset(
mut self,
offset_width: u16,
offset_height: u16
) -> Self {
self.offset_width = Some(offset_width);
self.offset_height = Some(offset_height);
self.unknown_2 = Some(0);
self
}
pub fn from_bytes<T: Seek + ReadBytesExt + Read>(
input: &mut T,
common_header: &CommonHeader
) -> Result<Self, CzError> {

View file

@ -334,7 +334,7 @@ pub fn compress(
let mut part_data;
let mut offset = 0;
let mut count = 0;
let mut count;
let mut last = Vec::new();
let mut output_buf: Vec<u8> = vec![];
@ -362,6 +362,13 @@ pub fn compress(
output_info.chunk_count += 1;
}
if output_info.chunk_count == 0 {
panic!("No chunks compressed!")
} else if output_info.chunk_count != 1 {
output_info.chunks[0].size_raw -= 1;
output_info.chunks[output_info.chunk_count - 1].size_raw += 1;
}
output_info.total_size_compressed = output_buf.len() / 2;
(output_buf, output_info)

View file

@ -33,15 +33,53 @@ impl DynamicCz {
Ok(())
}
pub fn from_raw(
version: CzVersion,
width: u16,
height: u16,
bitmap: Vec<u8>,
) -> Self {
let header_common = CommonHeader::new(
version,
width,
height
);
Self {
header_common,
header_extended: None,
palette: None,
bitmap,
}
}
pub fn with_header(mut self, header: CommonHeader) -> Self {
self.header_common = header;
self
}
pub fn with_extended_header(mut self, ext_header: ExtendedHeader) -> Self {
if ext_header.offset_width.is_none() {
self.header_common.set_length(28)
} else {
self.header_common.set_length(36)
}
self.header_extended = Some(ext_header);
self
}
}
impl DynamicCz {
pub fn decode<T: Seek + ReadBytesExt + Read>(input: &mut T) -> Result<Self, CzError> {
// Get the header common to all CZ images
let header_common = CommonHeader::new(input)?;
let header_common = CommonHeader::from_bytes(input)?;
let mut header_extended = None;
if header_common.length() > 15 && header_common.version() != CzVersion::CZ2 {
header_extended = Some(ExtendedHeader::new(input, &header_common)?);
header_extended = Some(ExtendedHeader::from_bytes(input, &header_common)?);
}
input.seek(SeekFrom::Start(header_common.length() as u64))?;

View file

@ -21,7 +21,7 @@ pub fn encode<T: WriteBytesExt + Write>(
output: &mut T,
bitmap: &[u8]
) -> Result<(), CzError> {
let (compressed_data, compressed_info) = compress(bitmap, 65277);
let (compressed_data, compressed_info) = compress(bitmap, 0xFEFD);
dbg!(&compressed_info);

View file

@ -24,7 +24,7 @@ pub fn encode<T: WriteBytesExt + Write, H: CzHeader>(
) -> Result<(), CzError> {
let bitmap = diff_line(header, bitmap);
let (compressed_data, compressed_info) = compress(&bitmap, 65277);
let (compressed_data, compressed_info) = compress(&bitmap, 0xFEFD);
compressed_info.write_into(output)?;

View file

@ -1,11 +1,23 @@
use cz::dynamic::DynamicCz;
use cz::{common::{CzVersion, ExtendedHeader}, dynamic::DynamicCz};
fn main() {
let img = DynamicCz::open("font72.cz1").unwrap();
let mio = image::open("mio_inverted.png").unwrap();
let mio = mio.to_rgba8();
img.save_as_cz("test.cz1").unwrap();
img.save_as_png("test1.png").unwrap();
let cz_mio =
DynamicCz::from_raw(
CzVersion::CZ3,
mio.width() as u16,
mio.height() as u16,
mio.into_raw()
)
.with_extended_header(
ExtendedHeader::new(1280, 960, 1280, 960)
);
let img2 = DynamicCz::open("test.cz1").unwrap();
img2.save_as_png("test2.png").unwrap();
cz_mio.save_as_cz("test1.cz3").unwrap();
let img = DynamicCz::open("test1.cz3").unwrap();
img.save_as_png("test.png").unwrap();
}