mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-19 15:22:53 -05:00
Fixed CZ1/CZ3 compression
This commit is contained in:
parent
9da8d68683
commit
5b95687393
6 changed files with 122 additions and 14 deletions
|
@ -58,7 +58,7 @@ impl TryFrom<u8> for CzVersion {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CzHeader {
|
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
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
|
@ -122,8 +122,29 @@ pub struct CommonHeader {
|
||||||
unknown: u8,
|
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 {
|
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
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -243,7 +264,37 @@ pub struct ExtendedHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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,
|
input: &mut T,
|
||||||
common_header: &CommonHeader
|
common_header: &CommonHeader
|
||||||
) -> Result<Self, CzError> {
|
) -> Result<Self, CzError> {
|
||||||
|
|
|
@ -334,7 +334,7 @@ pub fn compress(
|
||||||
let mut part_data;
|
let mut part_data;
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let mut count = 0;
|
let mut count;
|
||||||
let mut last = Vec::new();
|
let mut last = Vec::new();
|
||||||
|
|
||||||
let mut output_buf: Vec<u8> = vec![];
|
let mut output_buf: Vec<u8> = vec![];
|
||||||
|
@ -362,6 +362,13 @@ pub fn compress(
|
||||||
output_info.chunk_count += 1;
|
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_info.total_size_compressed = output_buf.len() / 2;
|
||||||
|
|
||||||
(output_buf, output_info)
|
(output_buf, output_info)
|
||||||
|
|
|
@ -33,15 +33,53 @@ impl DynamicCz {
|
||||||
|
|
||||||
Ok(())
|
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 {
|
impl DynamicCz {
|
||||||
pub fn decode<T: Seek + ReadBytesExt + Read>(input: &mut T) -> Result<Self, CzError> {
|
pub fn decode<T: Seek + ReadBytesExt + Read>(input: &mut T) -> Result<Self, CzError> {
|
||||||
// Get the header common to all CZ images
|
// 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;
|
let mut header_extended = None;
|
||||||
if header_common.length() > 15 && header_common.version() != CzVersion::CZ2 {
|
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))?;
|
input.seek(SeekFrom::Start(header_common.length() as u64))?;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn encode<T: WriteBytesExt + Write>(
|
||||||
output: &mut T,
|
output: &mut T,
|
||||||
bitmap: &[u8]
|
bitmap: &[u8]
|
||||||
) -> Result<(), CzError> {
|
) -> Result<(), CzError> {
|
||||||
let (compressed_data, compressed_info) = compress(bitmap, 65277);
|
let (compressed_data, compressed_info) = compress(bitmap, 0xFEFD);
|
||||||
|
|
||||||
dbg!(&compressed_info);
|
dbg!(&compressed_info);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub fn encode<T: WriteBytesExt + Write, H: CzHeader>(
|
||||||
) -> Result<(), CzError> {
|
) -> Result<(), CzError> {
|
||||||
let bitmap = diff_line(header, bitmap);
|
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)?;
|
compressed_info.write_into(output)?;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,23 @@
|
||||||
use cz::dynamic::DynamicCz;
|
use cz::{common::{CzVersion, ExtendedHeader}, dynamic::DynamicCz};
|
||||||
|
|
||||||
fn main() {
|
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();
|
let cz_mio =
|
||||||
img.save_as_png("test1.png").unwrap();
|
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();
|
cz_mio.save_as_cz("test1.cz3").unwrap();
|
||||||
img2.save_as_png("test2.png").unwrap();
|
|
||||||
|
let img = DynamicCz::open("test1.cz3").unwrap();
|
||||||
|
|
||||||
|
img.save_as_png("test.png").unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue