mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-19 07:12:55 -05:00
Refactoring in progress
This commit is contained in:
parent
a44f90da18
commit
e1d270942f
5 changed files with 118 additions and 161 deletions
54
src/cz_common.rs
Normal file
54
src/cz_common.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
//! Shared types and traits between CZ# files
|
||||||
|
|
||||||
|
pub trait CzHeader {
|
||||||
|
fn new(bytes: &[u8]) -> Self;
|
||||||
|
|
||||||
|
fn version(&self) -> u8;
|
||||||
|
|
||||||
|
fn header_length(&self) -> u16;
|
||||||
|
|
||||||
|
fn width(&self) -> u16;
|
||||||
|
|
||||||
|
fn height(&self) -> u16;
|
||||||
|
|
||||||
|
fn depth(&self) -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The common first part of a header of a CZ# file
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct CommonHeader {
|
||||||
|
/// Format version from the magic bytes, (eg. CZ3, CZ4)
|
||||||
|
pub version: u8,
|
||||||
|
|
||||||
|
/// Length of the header in bytes
|
||||||
|
pub length: u8,
|
||||||
|
|
||||||
|
/// Width of the image in pixels
|
||||||
|
pub width: u16,
|
||||||
|
|
||||||
|
/// Height of the image in pixels
|
||||||
|
pub height: u16,
|
||||||
|
|
||||||
|
/// Bit depth in Bits Per Pixel (BPP)
|
||||||
|
pub depth: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommonHeader {
|
||||||
|
pub fn new(bytes: &[u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
version: bytes[2] - b'0',
|
||||||
|
length: bytes[4],
|
||||||
|
width: u16::from_le_bytes(bytes[8..10].try_into().unwrap()),
|
||||||
|
height: u16::from_le_bytes(bytes[10..12].try_into().unwrap()),
|
||||||
|
depth: bytes[12],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CzImage {
|
||||||
|
/// Create a [CZImage] from bytes
|
||||||
|
fn decode(bytes: &[u8]) -> Self;
|
||||||
|
|
||||||
|
/// Get the underlying bitmap for an image
|
||||||
|
fn raw_bitmap(&self) -> &Vec<u8>;
|
||||||
|
}
|
126
src/cz_utils.rs
126
src/cz_utils.rs
|
@ -1,126 +0,0 @@
|
||||||
use image::{ImageFormat, RgbaImage};
|
|
||||||
|
|
||||||
/// The header of a CZ# file
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct CZHeader {
|
|
||||||
version: u8, // The version from the magic bytes, (eg. CZ3, CZ4)
|
|
||||||
length: u8,
|
|
||||||
res: (u16, u16), // The width in the header
|
|
||||||
depth: u8, // Bit depth
|
|
||||||
crop: (u16, u16), // Crop dimensions
|
|
||||||
bounds: (u16, u16), // Bounding box dimensions
|
|
||||||
offset: (u16, u16), // Offset coordinates
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CZHeader {
|
|
||||||
pub fn new(bytes: &[u8]) -> Self {
|
|
||||||
CZHeader {
|
|
||||||
version: bytes[2] - b'0',
|
|
||||||
length: bytes[4],
|
|
||||||
res: (
|
|
||||||
u16::from_le_bytes(bytes[8..10].try_into().unwrap()),
|
|
||||||
u16::from_le_bytes(bytes[10..12].try_into().unwrap())
|
|
||||||
),
|
|
||||||
depth: bytes[12],
|
|
||||||
crop: (
|
|
||||||
u16::from_le_bytes(bytes[20..22].try_into().unwrap()),
|
|
||||||
u16::from_le_bytes(bytes[22..24].try_into().unwrap())
|
|
||||||
),
|
|
||||||
bounds: (
|
|
||||||
u16::from_le_bytes(bytes[24..26].try_into().unwrap()),
|
|
||||||
u16::from_le_bytes(bytes[26..28].try_into().unwrap())
|
|
||||||
),
|
|
||||||
offset: (
|
|
||||||
u16::from_le_bytes(bytes[28..30].try_into().unwrap()),
|
|
||||||
u16::from_le_bytes(bytes[30..32].try_into().unwrap())
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines a full file that has a header of type `CZHeader` and a vector bitmap as the body
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct CZFile {
|
|
||||||
header: CZHeader,
|
|
||||||
bitmap: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CZFile {
|
|
||||||
/// Create and save a PNG of the image data
|
|
||||||
/// This errors if the data end up too short
|
|
||||||
pub fn to_rgba8(&self) -> RgbaImage {
|
|
||||||
let process_bitmap = self.bitmap.clone();
|
|
||||||
|
|
||||||
RgbaImage::from_raw(
|
|
||||||
self.header.res.0 as u32,
|
|
||||||
self.header.res.1 as u32,
|
|
||||||
process_bitmap,
|
|
||||||
).expect("Error encoding the image")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_png(&self, out_name:&str) {
|
|
||||||
let image_data = self.to_rgba8();
|
|
||||||
|
|
||||||
match image_data.save_with_format(out_name, ImageFormat::Png) {
|
|
||||||
Ok(()) => {}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("ERROR SAVING IMAGE: {}", e);
|
|
||||||
eprintln!("You probably have an image with the CZ0 offset bug!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pretty-print information about a CZ image
|
|
||||||
pub fn info(&self) {
|
|
||||||
let mut image_size = self.bitmap.len() as f32 + self.header.length as f32;
|
|
||||||
image_size /= 1024.0;
|
|
||||||
|
|
||||||
println!("\n--IMAGE INFORMATION--");
|
|
||||||
println!("Image size : {:.2} KB", image_size);
|
|
||||||
println!("Version : {:?}", self.header.version);
|
|
||||||
println!("Header Length : {:?} bytes", self.header.length);
|
|
||||||
println!(
|
|
||||||
"Resolution : {}x{}",
|
|
||||||
self.header.res.0, self.header.res.1
|
|
||||||
);
|
|
||||||
println!("Bit Depth : {} bits", self.header.depth);
|
|
||||||
println!(
|
|
||||||
"Crop Coords : {}x{}",
|
|
||||||
self.header.crop.0, self.header.crop.1
|
|
||||||
);
|
|
||||||
println!(
|
|
||||||
"Bound Coords : {}x{}",
|
|
||||||
self.header.bounds.0, self.header.bounds.1
|
|
||||||
);
|
|
||||||
println!(
|
|
||||||
"Offset Coords : {}x{}",
|
|
||||||
self.header.offset.0, self.header.offset.1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Utilities for manipulating CZ0 images
|
|
||||||
pub mod cz0 {
|
|
||||||
use std::fs;
|
|
||||||
use crate::cz_utils::{CZFile, CZHeader};
|
|
||||||
|
|
||||||
/// Provided a bitstream, extract the header information and the rest of the metadata about a CZ0 file, returning a struct containing the header information and bitmap
|
|
||||||
pub fn decode_cz0(input_filename: &str) -> CZFile {
|
|
||||||
let mut input = fs::read(input_filename).expect("Error, could not open image");
|
|
||||||
|
|
||||||
// TODO Research the header more!
|
|
||||||
let header = CZHeader::new(&input);
|
|
||||||
|
|
||||||
// Chop off the header and keep only the bitmap after it
|
|
||||||
input.drain(..header.length as usize);
|
|
||||||
|
|
||||||
// Construct the output CZ0 image
|
|
||||||
let final_image = CZFile {
|
|
||||||
header,
|
|
||||||
bitmap: input,
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("Decoded {}", input_filename);
|
|
||||||
final_image
|
|
||||||
}
|
|
||||||
}
|
|
56
src/formats/cz0.rs
Normal file
56
src/formats/cz0.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
use crate::cz_common::{CommonHeader, CzHeader, CzImage};
|
||||||
|
|
||||||
|
struct Cz0Header {
|
||||||
|
/// Common CZ# header
|
||||||
|
common_header: CommonHeader,
|
||||||
|
|
||||||
|
/// Dimensions of cropped image area
|
||||||
|
crop: (u16, u16),
|
||||||
|
|
||||||
|
/// Bounding box dimensions
|
||||||
|
bounds: (u16, u16),
|
||||||
|
|
||||||
|
// Offset coordinates
|
||||||
|
offset: (u16, u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cz0Image {
|
||||||
|
header: Cz0Header,
|
||||||
|
bitmap: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CzHeader for Cz0Header {
|
||||||
|
fn new(bytes: &[u8]) -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u8 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header_length(&self) -> u16 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> u16 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> u16 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn depth(&self) -> u8 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CzImage for Cz0Image {
|
||||||
|
fn decode(bytes: &[u8]) -> Self {
|
||||||
|
let header = CZH
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raw_bitmap(&self) -> &Vec<u8> {
|
||||||
|
&self.bitmap
|
||||||
|
}
|
||||||
|
}
|
21
src/main.rs
21
src/main.rs
|
@ -1,19 +1,14 @@
|
||||||
// Create the modules
|
pub mod cz_common;
|
||||||
pub mod cz_utils;
|
pub mod formats{
|
||||||
pub mod utils;
|
pub mod cz0;
|
||||||
|
}
|
||||||
|
|
||||||
// Generic tools
|
// Generic tools
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use crate::cz_common::CommonHeader;
|
||||||
use crate::cz_utils::CZHeader;
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input = fs::read(
|
let input = fs::read("../test_files/x5a3bvy.cz1").expect("Error, could not open image");
|
||||||
"/home/g2/Documents/projects/lbee-utils/test_files/GOOD_extra_bg.cz3"
|
let header = CommonHeader::new(&input);
|
||||||
).expect("Error, could not open image");
|
println!("{:?}", header);
|
||||||
|
|
||||||
let header = CZHeader::new(&input);
|
|
||||||
|
|
||||||
dbg!(header);
|
|
||||||
}
|
}
|
||||||
|
|
22
src/utils.rs
22
src/utils.rs
|
@ -1,22 +0,0 @@
|
||||||
/// Converts 8 bit bytes to a 16 bit little endian word
|
|
||||||
pub fn bytes_to_word(first: u8, second: u8) -> u16 {
|
|
||||||
((second as u16) << 8) | (first as u16)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts a 16 bit little endian word to 8 bit bytes
|
|
||||||
pub fn word_to_bytes(word: u16) -> [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
|
|
||||||
|
|
||||||
[first, second]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_bytes<const S: usize>(iterator: &mut std::vec::IntoIter<u8>) -> [u8; S] {
|
|
||||||
let mut bytes = [0; S];
|
|
||||||
|
|
||||||
for byte in bytes.iter_mut().take(S) {
|
|
||||||
*byte = iterator.next().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes
|
|
||||||
}
|
|
Loading…
Reference in a new issue