Compare commits

..

2 commits

6 changed files with 39 additions and 44 deletions

View file

@ -9,17 +9,11 @@ Prototype Ltd.
license = "MIT" license = "MIT"
authors.workspace = true authors.workspace = true
[features]
png = ["dep:image"]
[dependencies] [dependencies]
byteorder-lite = "0.1.0" byteorder-lite = "0.1"
thiserror = "1.0" thiserror = "2.0"
imagequant = "4.3" imagequant = "4.3"
rgb = "0.8" rgb = "0.8"
# Only active on PNG feature
image = { version = "0.25", optional = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -192,35 +192,6 @@ impl DynamicCz {
Ok(()) Ok(())
} }
/// Save the CZ# image as a lossless PNG file.
///
/// Internally, the [`DynamicCz`] struct operates on 32-bit RGBA values,
/// which is the highest encountered in CZ# files, therefore saving them
/// as a PNG of the same or better quality is lossless.
#[cfg(feature = "png")]
pub fn save_as_png<P: ?Sized + AsRef<std::path::Path>>(
&self,
path: &P,
) -> Result<(), image::error::EncodingError> {
let size = (self.header_common.width() as u32 * self.header_common.height() as u32) * 4;
let mut buf = vec![0; size as usize];
buf[..self.bitmap.len()].copy_from_slice(&self.bitmap);
let image = image::RgbaImage::from_raw(
self.header_common.width() as u32,
self.header_common.height() as u32,
buf.clone(),
)
.unwrap();
image
.save_with_format(path, image::ImageFormat::Png)
.unwrap();
Ok(())
}
/// Create a CZ# image from RGBA bytes. The bytes *must* be RGBA, as that /// Create a CZ# image from RGBA bytes. The bytes *must* be RGBA, as that
/// is the only format that is used internally. /// is the only format that is used internally.
pub fn from_raw(version: CzVersion, width: u16, height: u16, bitmap: Vec<u8>) -> Self { pub fn from_raw(version: CzVersion, width: u16, height: u16, bitmap: Vec<u8>) -> Self {

View file

@ -11,9 +11,10 @@ publish = false
[dependencies] [dependencies]
colog = "1.3.0" colog = "1.3.0"
cz = { path = "../cz/", features = ["png"] } cz = { path = "../cz/" }
eframe = { version = "0.28.1", default-features = false, features = ["wayland", "x11", "accesskit", "default_fonts", "wgpu"] } eframe = { version = "0.28.1", default-features = false, features = ["wayland", "x11", "accesskit", "default_fonts", "wgpu"] }
egui_extras = "0.28.1" egui_extras = "0.28.1"
image = { version = "0.25.5", default-features = false, features = ["png"] }
log = "0.4.22" log = "0.4.22"
luca_pak = { path = "../luca_pak/" } luca_pak = { path = "../luca_pak/" }
rfd = "0.14.1" rfd = "0.14.1"

View file

@ -162,7 +162,14 @@ impl eframe::App for PakExplorer {
entry.as_bytes(), entry.as_bytes(),
)) ))
.unwrap(); .unwrap();
cz.save_as_png(&path).unwrap(); image::save_buffer_with_format(
path,
cz.as_raw(),
cz.header().width() as u32,
cz.header().height() as u32,
image::ColorType::Rgba8,
image::ImageFormat::Png
).unwrap();
} }
} }

View file

@ -13,7 +13,7 @@ name = "czutil"
name = "pakutil" name = "pakutil"
[dependencies] [dependencies]
cz = { path = "../cz/", features = ["png"] } cz = { path = "../cz/" }
luca_pak = { path = "../luca_pak/" } luca_pak = { path = "../luca_pak/" }
image = { version = "0.25", default-features = false, features = ["png"] } image = { version = "0.25", default-features = false, features = ["png"] }

View file

@ -1,4 +1,5 @@
use clap::{error::ErrorKind, Command, Error, Parser, Subcommand}; use clap::{error::ErrorKind, Error, Parser, Subcommand};
use image::ColorType;
use std::{ use std::{
fs, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -146,16 +147,37 @@ fn main() {
} }
}; };
cz.save_as_png(&final_path).unwrap(); image::save_buffer_with_format(
final_path,
cz.as_raw(),
cz.header().width() as u32,
cz.header().height() as u32,
ColorType::Rgba8,
image::ImageFormat::Png
).unwrap();
} }
} else { } else {
let cz = cz::open(input).unwrap(); let cz = cz::open(input).unwrap();
if let Some(output) = output { if let Some(output) = output {
cz.save_as_png(output).unwrap(); image::save_buffer_with_format(
output,
cz.as_raw(),
cz.header().width() as u32,
cz.header().height() as u32,
ColorType::Rgba8,
image::ImageFormat::Png
).unwrap();
} else { } else {
let file_stem = PathBuf::from(input.file_name().unwrap()); let file_stem = PathBuf::from(input.file_name().unwrap());
cz.save_as_png(&file_stem.with_extension("png")).unwrap(); image::save_buffer_with_format(
file_stem.with_extension("png"),
cz.as_raw(),
cz.header().width() as u32,
cz.header().height() as u32,
ColorType::Rgba8,
image::ImageFormat::Png
).unwrap();
} }
} }
} }