mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-19 23:32:55 -05:00
Compare commits
No commits in common. "2f881ce2949e0874ae9d0937dadd2a280256d776" and "b36ea64d84acdc778132d895907422ce988f2b9b" have entirely different histories.
2f881ce294
...
b36ea64d84
6 changed files with 44 additions and 39 deletions
|
@ -9,11 +9,17 @@ Prototype Ltd.
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
png = ["dep:image"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder-lite = "0.1"
|
byteorder-lite = "0.1.0"
|
||||||
thiserror = "2.0"
|
thiserror = "1.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
|
||||||
|
|
|
@ -192,6 +192,35 @@ 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 {
|
||||||
|
|
|
@ -11,10 +11,9 @@ publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
colog = "1.3.0"
|
colog = "1.3.0"
|
||||||
cz = { path = "../cz/" }
|
cz = { path = "../cz/", features = ["png"] }
|
||||||
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"
|
||||||
|
|
|
@ -162,14 +162,7 @@ impl eframe::App for PakExplorer {
|
||||||
entry.as_bytes(),
|
entry.as_bytes(),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
image::save_buffer_with_format(
|
cz.save_as_png(&path).unwrap();
|
||||||
path,
|
|
||||||
cz.as_raw(),
|
|
||||||
cz.header().width() as u32,
|
|
||||||
cz.header().height() as u32,
|
|
||||||
image::ColorType::Rgba8,
|
|
||||||
image::ImageFormat::Png
|
|
||||||
).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ name = "czutil"
|
||||||
name = "pakutil"
|
name = "pakutil"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cz = { path = "../cz/" }
|
cz = { path = "../cz/", features = ["png"] }
|
||||||
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"] }
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use clap::{error::ErrorKind, Error, Parser, Subcommand};
|
use clap::{error::ErrorKind, Command, Error, Parser, Subcommand};
|
||||||
use image::ColorType;
|
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
@ -147,37 +146,16 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
image::save_buffer_with_format(
|
cz.save_as_png(&final_path).unwrap();
|
||||||
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 {
|
||||||
image::save_buffer_with_format(
|
cz.save_as_png(output).unwrap();
|
||||||
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());
|
||||||
image::save_buffer_with_format(
|
cz.save_as_png(&file_stem.with_extension("png")).unwrap();
|
||||||
file_stem.with_extension("png"),
|
|
||||||
cz.as_raw(),
|
|
||||||
cz.header().width() as u32,
|
|
||||||
cz.header().height() as u32,
|
|
||||||
ColorType::Rgba8,
|
|
||||||
image::ImageFormat::Png
|
|
||||||
).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue