mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-19 15:22:53 -05:00
Cleaned up implementations
This commit is contained in:
parent
27eea7a38a
commit
e7f76a51c0
5 changed files with 158 additions and 93 deletions
|
@ -1,6 +1,9 @@
|
||||||
//! Shared types and traits between CZ# files
|
//! Shared types and traits between CZ# files
|
||||||
|
|
||||||
use std::io::{self, Cursor, Read};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
io::{self, Cursor, Read},
|
||||||
|
};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
use image::Rgba;
|
use image::Rgba;
|
||||||
|
@ -11,15 +14,21 @@ pub enum CzError {
|
||||||
#[error("Version in header does not match expected version")]
|
#[error("Version in header does not match expected version")]
|
||||||
VersionMismatch,
|
VersionMismatch,
|
||||||
|
|
||||||
#[error("Format of supplied file is incorrect; expected {} bytes, got {}", expected, got)]
|
#[error(
|
||||||
InvalidFormat{expected: usize, got: usize},
|
"Format of supplied file is incorrect; expected {} bytes, got {}",
|
||||||
|
expected,
|
||||||
|
got
|
||||||
|
)]
|
||||||
|
InvalidFormat { expected: usize, got: usize },
|
||||||
|
|
||||||
#[error("Failed to read input")]
|
#[error("Failed to read input")]
|
||||||
ReadError(#[from] io::Error),
|
ReadError(#[from] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CzHeader {
|
pub trait CzHeader {
|
||||||
fn new(bytes: &[u8]) -> Result<Self, CzError> where Self: Sized;
|
fn new(bytes: &mut Cursor<&[u8]>) -> Result<Self, CzError>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
fn version(&self) -> u8;
|
fn version(&self) -> u8;
|
||||||
|
|
||||||
|
@ -36,23 +45,26 @@ pub trait CzHeader {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct CommonHeader {
|
pub struct CommonHeader {
|
||||||
/// Format version from the magic bytes, (eg. CZ3, CZ4)
|
/// Format version from the magic bytes, (eg. CZ3, CZ4)
|
||||||
pub version: u8,
|
version: u8,
|
||||||
|
|
||||||
/// Length of the header in bytes
|
/// Length of the header in bytes
|
||||||
pub length: u32,
|
length: u32,
|
||||||
|
|
||||||
/// Width of the image in pixels
|
/// Width of the image in pixels
|
||||||
pub width: u16,
|
width: u16,
|
||||||
|
|
||||||
/// Height of the image in pixels
|
/// Height of the image in pixels
|
||||||
pub height: u16,
|
height: u16,
|
||||||
|
|
||||||
/// Bit depth in Bits Per Pixel (BPP)
|
/// Bit depth in Bits Per Pixel (BPP)
|
||||||
pub depth: u16,
|
depth: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommonHeader {
|
impl CzHeader for CommonHeader {
|
||||||
pub fn new(bytes: &mut Cursor<&[u8]>) -> Result<Self, io::Error> {
|
fn new(bytes: &mut Cursor<&[u8]>) -> Result<Self, CzError>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
let mut magic = [0u8; 4];
|
let mut magic = [0u8; 4];
|
||||||
bytes.read_exact(&mut magic)?;
|
bytes.read_exact(&mut magic)?;
|
||||||
|
|
||||||
|
@ -64,13 +76,35 @@ impl CommonHeader {
|
||||||
depth: bytes.read_u16::<LittleEndian>()?,
|
depth: bytes.read_u16::<LittleEndian>()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u8 {
|
||||||
|
self.version
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header_length(&self) -> usize {
|
||||||
|
self.length as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> u16 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> u16 {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
fn depth(&self) -> u16 {
|
||||||
|
self.depth
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CzImage {
|
pub trait CzImage {
|
||||||
type Header;
|
type Header;
|
||||||
|
|
||||||
/// Create a [CZImage] from bytes
|
/// Create a [CZImage] from bytes
|
||||||
fn decode(bytes: &[u8]) -> Result<Self, CzError> where Self: Sized;
|
fn decode(bytes: &[u8]) -> Result<Self, CzError>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
/// Save the image as a PNG
|
/// Save the image as a PNG
|
||||||
fn save_as_png(&self, name: &str);
|
fn save_as_png(&self, name: &str);
|
||||||
|
@ -82,7 +116,10 @@ pub trait CzImage {
|
||||||
fn into_bitmap(self) -> Vec<u8>;
|
fn into_bitmap(self) -> Vec<u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_colormap(input: &mut Cursor<&[u8]>, num_colors: usize) -> Result<Vec<Rgba<u8>>, CzError> {
|
pub fn parse_colormap(
|
||||||
|
input: &mut Cursor<&[u8]>,
|
||||||
|
num_colors: usize,
|
||||||
|
) -> Result<Vec<Rgba<u8>>, CzError> {
|
||||||
let mut colormap = Vec::with_capacity(num_colors);
|
let mut colormap = Vec::with_capacity(num_colors);
|
||||||
let mut rgba_buf = [0u8; 4];
|
let mut rgba_buf = [0u8; 4];
|
||||||
|
|
||||||
|
@ -94,11 +131,13 @@ pub fn parse_colormap(input: &mut Cursor<&[u8]>, num_colors: usize) -> Result<Ve
|
||||||
Ok(colormap)
|
Ok(colormap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ChunkInfo {
|
pub struct ChunkInfo {
|
||||||
pub size_compressed: usize,
|
pub size_compressed: usize,
|
||||||
pub size_raw: usize,
|
pub size_raw: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct CompressionInfo {
|
pub struct CompressionInfo {
|
||||||
pub chunk_count: usize,
|
pub chunk_count: usize,
|
||||||
pub total_size_compressed: usize,
|
pub total_size_compressed: usize,
|
||||||
|
@ -112,8 +151,8 @@ pub struct CompressionInfo {
|
||||||
/// Get info about the compression chunks
|
/// Get info about the compression chunks
|
||||||
pub fn parse_chunk_info(bytes: &mut Cursor<&[u8]>) -> Result<CompressionInfo, CzError> {
|
pub fn parse_chunk_info(bytes: &mut Cursor<&[u8]>) -> Result<CompressionInfo, CzError> {
|
||||||
let parts_count = bytes.read_u32::<LittleEndian>()?;
|
let parts_count = bytes.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
dbg!(parts_count);
|
dbg!(parts_count);
|
||||||
|
|
||||||
let mut part_sizes = vec![];
|
let mut part_sizes = vec![];
|
||||||
let mut total_size = 0;
|
let mut total_size = 0;
|
||||||
let mut total_size_raw = 0;
|
let mut total_size_raw = 0;
|
||||||
|
@ -131,6 +170,8 @@ pub fn parse_chunk_info(bytes: &mut Cursor<&[u8]>) -> Result<CompressionInfo, Cz
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbg!(&part_sizes);
|
||||||
|
|
||||||
Ok(CompressionInfo {
|
Ok(CompressionInfo {
|
||||||
chunk_count: parts_count as usize,
|
chunk_count: parts_count as usize,
|
||||||
total_size_compressed: total_size as usize,
|
total_size_compressed: total_size as usize,
|
||||||
|
@ -140,8 +181,11 @@ pub fn parse_chunk_info(bytes: &mut Cursor<&[u8]>) -> Result<CompressionInfo, Cz
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decompress an LZW compressed stream, like CZ1
|
||||||
pub fn decompress(input: &mut Cursor<&[u8]>, chunk_info: CompressionInfo) -> Result<Vec<u8>, CzError> {
|
pub fn decompress(
|
||||||
|
input: &mut Cursor<&[u8]>,
|
||||||
|
chunk_info: CompressionInfo,
|
||||||
|
) -> Result<Vec<u8>, CzError> {
|
||||||
let mut m_dst = 0;
|
let mut m_dst = 0;
|
||||||
let mut bitmap = vec![0; chunk_info.total_size_raw];
|
let mut bitmap = vec![0; chunk_info.total_size_raw];
|
||||||
for chunk in chunk_info.chunks {
|
for chunk in chunk_info.chunks {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use std::io::Cursor;
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
|
||||||
use crate::cz_common::{CommonHeader, CzError, CzHeader, CzImage};
|
use crate::cz_common::{CommonHeader, CzError, CzHeader, CzImage};
|
||||||
|
|
||||||
|
@ -8,22 +10,22 @@ pub struct Cz0Header {
|
||||||
common: CommonHeader,
|
common: CommonHeader,
|
||||||
|
|
||||||
/// Width of cropped image area
|
/// Width of cropped image area
|
||||||
crop_width: u16,
|
pub crop_width: u16,
|
||||||
|
|
||||||
/// Height of cropped image area
|
/// Height of cropped image area
|
||||||
crop_height: u16,
|
pub crop_height: u16,
|
||||||
|
|
||||||
/// Bounding box width
|
/// Bounding box width
|
||||||
bounds_width: u16,
|
pub bounds_width: u16,
|
||||||
|
|
||||||
/// Bounding box height
|
/// Bounding box height
|
||||||
bounds_height: u16,
|
pub bounds_height: u16,
|
||||||
|
|
||||||
/// Offset width
|
/// Offset width
|
||||||
offset_width: Option<u16>,
|
pub offset_width: Option<u16>,
|
||||||
|
|
||||||
/// Offset height
|
/// Offset height
|
||||||
offset_height: Option<u16>,
|
pub offset_height: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -33,29 +35,39 @@ pub struct Cz0Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CzHeader for Cz0Header {
|
impl CzHeader for Cz0Header {
|
||||||
fn new(bytes: &[u8]) -> Result<Self, CzError> {
|
fn new(bytes: &mut Cursor<&[u8]>) -> Result<Self, CzError>
|
||||||
let mut input = Cursor::new(bytes);
|
where
|
||||||
let common = CommonHeader::new(&mut input)?;
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let common = CommonHeader::new(bytes)?;
|
||||||
|
|
||||||
if common.version != 0 {
|
if common.version() != 0 {
|
||||||
return Err(CzError::VersionMismatch)
|
return Err(CzError::VersionMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _unknown = bytes.read_u48::<LittleEndian>()?;
|
||||||
|
|
||||||
|
let crop_width = bytes.read_u16::<LittleEndian>()?;
|
||||||
|
let crop_height = bytes.read_u16::<LittleEndian>()?;
|
||||||
|
|
||||||
|
let bounds_width = bytes.read_u16::<LittleEndian>()?;
|
||||||
|
let bounds_height = bytes.read_u16::<LittleEndian>()?;
|
||||||
|
|
||||||
let mut offset_width = None;
|
let mut offset_width = None;
|
||||||
let mut offset_height = None;
|
let mut offset_height = None;
|
||||||
if common.length > 28 {
|
if common.header_length() > 28 {
|
||||||
offset_width = Some(u16::from_le_bytes(bytes[28..30].try_into().unwrap()));
|
offset_width = Some(bytes.read_u16::<LittleEndian>()?);
|
||||||
offset_height = Some(u16::from_le_bytes(bytes[30..32].try_into().unwrap()));
|
offset_height = Some(bytes.read_u16::<LittleEndian>()?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
common,
|
common,
|
||||||
|
|
||||||
crop_width: u16::from_le_bytes(bytes[20..22].try_into().unwrap()),
|
crop_width,
|
||||||
crop_height: u16::from_le_bytes(bytes[22..24].try_into().unwrap()),
|
crop_height,
|
||||||
|
|
||||||
bounds_width: u16::from_le_bytes(bytes[24..26].try_into().unwrap()),
|
bounds_width,
|
||||||
bounds_height: u16::from_le_bytes(bytes[26..28].try_into().unwrap()),
|
bounds_height,
|
||||||
|
|
||||||
offset_width,
|
offset_width,
|
||||||
offset_height,
|
offset_height,
|
||||||
|
@ -63,23 +75,23 @@ impl CzHeader for Cz0Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version(&self) -> u8 {
|
fn version(&self) -> u8 {
|
||||||
self.common.version
|
self.common.version()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_length(&self) -> usize {
|
fn header_length(&self) -> usize {
|
||||||
self.common.length as usize
|
self.common.header_length()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn width(&self) -> u16 {
|
fn width(&self) -> u16 {
|
||||||
self.common.width
|
self.common.width()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn height(&self) -> u16 {
|
fn height(&self) -> u16 {
|
||||||
self.common.height
|
self.common.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn depth(&self) -> u16 {
|
fn depth(&self) -> u16 {
|
||||||
self.common.depth
|
self.common.depth()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,26 +99,27 @@ impl CzImage for Cz0Image {
|
||||||
type Header = Cz0Header;
|
type Header = Cz0Header;
|
||||||
|
|
||||||
fn decode(bytes: &[u8]) -> Result<Self, CzError> {
|
fn decode(bytes: &[u8]) -> Result<Self, CzError> {
|
||||||
|
let mut input = Cursor::new(bytes);
|
||||||
|
|
||||||
// Get the header from the input
|
// Get the header from the input
|
||||||
let header = Cz0Header::new(bytes)?;
|
let header = Cz0Header::new(&mut input)?;
|
||||||
|
|
||||||
// Get the rest of the file, which is the bitmap
|
// Get the rest of the file, which is the bitmap
|
||||||
let bitmap = bytes[header.header_length()..].to_vec();
|
let mut bitmap = vec![];
|
||||||
|
input.read_to_end(&mut bitmap)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self { header, bitmap })
|
||||||
header,
|
|
||||||
bitmap
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_as_png(&self, name: &str) {
|
fn save_as_png(&self, name: &str) {
|
||||||
image::save_buffer(
|
image::save_buffer(
|
||||||
name,
|
name,
|
||||||
&self.bitmap,
|
&self.bitmap,
|
||||||
self.header.common.width as u32,
|
self.header.width() as u32,
|
||||||
self.header.common.height as u32,
|
self.header.height() as u32,
|
||||||
image::ExtendedColorType::Rgba8
|
image::ExtendedColorType::Rgba8,
|
||||||
).unwrap()
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header(&self) -> &Self::Header {
|
fn header(&self) -> &Self::Header {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::io::Cursor;
|
use crate::cz_common::{
|
||||||
|
decompress, parse_chunk_info, parse_colormap, CommonHeader, CzError, CzHeader, CzImage,
|
||||||
|
};
|
||||||
use image::{ImageFormat, Rgba};
|
use image::{ImageFormat, Rgba};
|
||||||
use crate::cz_common::{decompress, parse_chunk_info, parse_colormap, CommonHeader, CzError, CzImage};
|
use std::io::Cursor;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Cz1Image {
|
pub struct Cz1Image {
|
||||||
|
@ -20,17 +22,17 @@ impl CzImage for Cz1Image {
|
||||||
|
|
||||||
// The color palette, gotten for 8 and 4 BPP images
|
// The color palette, gotten for 8 and 4 BPP images
|
||||||
let mut palette = None;
|
let mut palette = None;
|
||||||
if header.depth == 8 || header.depth == 4 {
|
if header.depth() == 8 || header.depth() == 4 {
|
||||||
palette = Some(parse_colormap(&mut input, 1 << header.depth)?);
|
palette = Some(parse_colormap(&mut input, 1 << header.depth())?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let chunk_info = parse_chunk_info(&mut input)?;
|
let chunk_info = parse_chunk_info(&mut input)?;
|
||||||
|
|
||||||
if chunk_info.total_size_compressed as usize > bytes.len() {
|
if chunk_info.total_size_compressed as usize > bytes.len() {
|
||||||
return Err(CzError::InvalidFormat{
|
return Err(CzError::InvalidFormat {
|
||||||
expected: chunk_info.total_size_compressed,
|
expected: chunk_info.total_size_compressed,
|
||||||
got: bytes.len(),
|
got: bytes.len(),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bitmap = decompress(&mut input, chunk_info).unwrap();
|
let mut bitmap = decompress(&mut input, chunk_info).unwrap();
|
||||||
|
@ -51,10 +53,11 @@ impl CzImage for Cz1Image {
|
||||||
|
|
||||||
fn save_as_png(&self, name: &str) {
|
fn save_as_png(&self, name: &str) {
|
||||||
let img = image::RgbaImage::from_raw(
|
let img = image::RgbaImage::from_raw(
|
||||||
self.header.width as u32,
|
self.header.width() as u32,
|
||||||
self.header.height as u32,
|
self.header.height() as u32,
|
||||||
self.bitmap.clone()
|
self.bitmap.clone(),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
img.save_with_format(name, ImageFormat::Png).unwrap();
|
img.save_with_format(name, ImageFormat::Png).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
|
|
||||||
use crate::cz_common::{decompress, parse_chunk_info, CommonHeader, CzError, CzHeader, CzImage};
|
use crate::cz_common::{decompress, parse_chunk_info, CommonHeader, CzError, CzHeader, CzImage};
|
||||||
|
@ -29,29 +30,39 @@ pub struct Cz3Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CzHeader for Cz3Header {
|
impl CzHeader for Cz3Header {
|
||||||
fn new(bytes: &[u8]) -> Result<Self, CzError> where Self: Sized {
|
fn new(bytes: &mut Cursor<&[u8]>) -> Result<Self, CzError>
|
||||||
let mut input = Cursor::new(bytes);
|
where
|
||||||
let common = CommonHeader::new(&mut input)?;
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let common = CommonHeader::new(bytes)?;
|
||||||
|
|
||||||
if common.version != 3 {
|
if common.version() != 3 {
|
||||||
return Err(CzError::VersionMismatch)
|
return Err(CzError::VersionMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _unknown = bytes.read_u48::<LittleEndian>()?;
|
||||||
|
|
||||||
|
let crop_width = bytes.read_u16::<LittleEndian>()?;
|
||||||
|
let crop_height = bytes.read_u16::<LittleEndian>()?;
|
||||||
|
|
||||||
|
let bounds_width = bytes.read_u16::<LittleEndian>()?;
|
||||||
|
let bounds_height = bytes.read_u16::<LittleEndian>()?;
|
||||||
|
|
||||||
let mut offset_width = None;
|
let mut offset_width = None;
|
||||||
let mut offset_height = None;
|
let mut offset_height = None;
|
||||||
if common.length > 28 {
|
if common.header_length() > 28 {
|
||||||
offset_width = Some(u16::from_le_bytes(bytes[28..30].try_into().unwrap()));
|
offset_width = Some(bytes.read_u16::<LittleEndian>()?);
|
||||||
offset_height = Some(u16::from_le_bytes(bytes[30..32].try_into().unwrap()));
|
offset_height = Some(bytes.read_u16::<LittleEndian>()?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
common,
|
common,
|
||||||
|
|
||||||
crop_width: u16::from_le_bytes(bytes[20..22].try_into().unwrap()),
|
crop_width,
|
||||||
crop_height: u16::from_le_bytes(bytes[22..24].try_into().unwrap()),
|
crop_height,
|
||||||
|
|
||||||
bounds_width: u16::from_le_bytes(bytes[24..26].try_into().unwrap()),
|
bounds_width,
|
||||||
bounds_height: u16::from_le_bytes(bytes[26..28].try_into().unwrap()),
|
bounds_height,
|
||||||
|
|
||||||
offset_width,
|
offset_width,
|
||||||
offset_height,
|
offset_height,
|
||||||
|
@ -59,23 +70,23 @@ impl CzHeader for Cz3Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version(&self) -> u8 {
|
fn version(&self) -> u8 {
|
||||||
self.common.version
|
self.common.version()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_length(&self) -> usize {
|
fn header_length(&self) -> usize {
|
||||||
self.common.length as usize
|
self.common.header_length()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn width(&self) -> u16 {
|
fn width(&self) -> u16 {
|
||||||
self.common.width
|
self.common.width()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn height(&self) -> u16 {
|
fn height(&self) -> u16 {
|
||||||
self.common.height
|
self.common.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn depth(&self) -> u16 {
|
fn depth(&self) -> u16 {
|
||||||
self.common.depth
|
self.common.depth()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,15 +101,13 @@ impl CzImage for Cz3Image {
|
||||||
|
|
||||||
fn decode(bytes: &[u8]) -> Result<Self, CzError> {
|
fn decode(bytes: &[u8]) -> Result<Self, CzError> {
|
||||||
let mut input = Cursor::new(bytes);
|
let mut input = Cursor::new(bytes);
|
||||||
let header = Cz3Header::new(bytes)?;
|
let header = Cz3Header::new(&mut input)?;
|
||||||
input.set_position(header.header_length() as u64);
|
input.set_position(header.header_length() as u64);
|
||||||
|
|
||||||
let block_info = parse_chunk_info(&mut input)?;
|
let block_info = parse_chunk_info(&mut input)?;
|
||||||
|
|
||||||
let mut bitmap = decompress(&mut input, block_info)?;
|
let mut bitmap = decompress(&mut input, block_info)?;
|
||||||
|
|
||||||
dbg!(bitmap.len());
|
|
||||||
|
|
||||||
let stride = (header.width() * (header.depth() / 8)) as usize;
|
let stride = (header.width() * (header.depth() / 8)) as usize;
|
||||||
let third = ((header.height() + 2) / 3) as usize;
|
let third = ((header.height() + 2) / 3) as usize;
|
||||||
for y in 0..header.height() as usize {
|
for y in 0..header.height() as usize {
|
||||||
|
@ -110,20 +119,16 @@ impl CzImage for Cz3Image {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg!(bitmap.len());
|
Ok(Self { header, bitmap })
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
header,
|
|
||||||
bitmap
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_as_png(&self, name: &str) {
|
fn save_as_png(&self, name: &str) {
|
||||||
let img = image::RgbaImage::from_raw(
|
let img = image::RgbaImage::from_raw(
|
||||||
self.header.width() as u32,
|
self.header.width() as u32,
|
||||||
self.header.height() as u32,
|
self.header.height() as u32,
|
||||||
self.bitmap.clone()
|
self.bitmap.clone(),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
img.save_with_format(name, ImageFormat::Png).unwrap();
|
img.save_with_format(name, ImageFormat::Png).unwrap();
|
||||||
}
|
}
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -1,5 +1,5 @@
|
||||||
pub mod cz_common;
|
pub mod cz_common;
|
||||||
pub mod formats{
|
pub mod formats {
|
||||||
pub mod cz0;
|
pub mod cz0;
|
||||||
pub mod cz1;
|
pub mod cz1;
|
||||||
pub mod cz3;
|
pub mod cz3;
|
||||||
|
@ -11,9 +11,9 @@ use std::fs;
|
||||||
use crate::{cz_common::CzImage, formats::cz3::Cz3Image};
|
use crate::{cz_common::CzImage, formats::cz3::Cz3Image};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input = fs::read("../test_files/Old_TestFiles/129.CZ3").expect("Error, could not open image");
|
let input = fs::read("../test_files/BAD_BG_011_10.cz4").expect("Error, could not open image");
|
||||||
let cz3_file = Cz3Image::decode(&input).unwrap();
|
let img_file = Cz3Image::decode(&input).unwrap();
|
||||||
println!("{:#?}", cz3_file.header());
|
println!("{:#?}", img_file.header());
|
||||||
|
|
||||||
cz3_file.save_as_png("test.png")
|
img_file.save_as_png("test.png")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue