mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-07 13:28:47 +08:00
Add import support for Qlie tiled PNG image (.png)
This commit is contained in:
@@ -202,12 +202,14 @@ pub trait ScriptBuilder: std::fmt::Debug {
|
||||
/// Creates an image file from the given data.
|
||||
///
|
||||
/// * `data` - The image data to write.
|
||||
/// * `filename` - The path to the image file.
|
||||
/// * `writer` - A writer with seek capabilities to write the image data.
|
||||
/// * `options` - Additional configuration options.
|
||||
#[cfg(feature = "image")]
|
||||
fn create_image_file<'a>(
|
||||
&'a self,
|
||||
_data: ImageData,
|
||||
_filename: &str,
|
||||
_writer: Box<dyn WriteSeek + 'a>,
|
||||
_options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
@@ -221,16 +223,18 @@ pub trait ScriptBuilder: std::fmt::Debug {
|
||||
/// * `data` - The image data to write.
|
||||
/// * `filename` - The path to the output file.
|
||||
/// * `options` - Additional configuration options.
|
||||
/// * `image_filename` - The path to the image file.
|
||||
#[cfg(feature = "image")]
|
||||
fn create_image_file_filename(
|
||||
&self,
|
||||
data: ImageData,
|
||||
filename: &str,
|
||||
image_filename: &str,
|
||||
options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
let f = std::fs::File::create(filename)?;
|
||||
let f = std::io::BufWriter::new(f);
|
||||
self.create_image_file(data, Box::new(f), options)
|
||||
self.create_image_file(data, image_filename, Box::new(f), options)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,8 +521,14 @@ pub trait Script: std::fmt::Debug + std::any::Any {
|
||||
/// Imports an image into this script.
|
||||
///
|
||||
/// * `data` - The image data to import.
|
||||
/// * `filename` - The path of the image file.
|
||||
/// * `file` - A writer with seek capabilities to write the patched scripts.
|
||||
fn import_image<'a>(&'a self, _data: ImageData, _file: Box<dyn WriteSeek + 'a>) -> Result<()> {
|
||||
fn import_image<'a>(
|
||||
&'a self,
|
||||
_data: ImageData,
|
||||
_filename: &str,
|
||||
_file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
Err(anyhow::anyhow!(
|
||||
"This script type does not support to import image."
|
||||
))
|
||||
@@ -529,10 +539,16 @@ pub trait Script: std::fmt::Debug + std::any::Any {
|
||||
///
|
||||
/// * `data` - The image data to import.
|
||||
/// * `filename` - The path of the file to write the patched scripts.
|
||||
fn import_image_filename(&self, data: ImageData, filename: &str) -> Result<()> {
|
||||
/// * `image_filename` - The path of the image file.
|
||||
fn import_image_filename(
|
||||
&self,
|
||||
data: ImageData,
|
||||
image_filename: &str,
|
||||
filename: &str,
|
||||
) -> Result<()> {
|
||||
let f = std::fs::File::create(filename)?;
|
||||
let f = std::io::BufWriter::new(f);
|
||||
self.import_image(data, Box::new(f))
|
||||
self.import_image(data, image_filename, Box::new(f))
|
||||
}
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
|
||||
@@ -67,6 +67,7 @@ impl ScriptBuilder for BgiCBGBuilder {
|
||||
fn create_image_file<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
_filename: &str,
|
||||
mut writer: Box<dyn WriteSeek + 'a>,
|
||||
_options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
@@ -200,6 +201,7 @@ impl Script for BgiCBG {
|
||||
fn import_image<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
_filename: &str,
|
||||
mut file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
let encoder = CbgEncoder::new(data)?;
|
||||
|
||||
@@ -85,6 +85,7 @@ impl ScriptBuilder for BgiImageBuilder {
|
||||
fn create_image_file<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
_filename: &str,
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
@@ -257,7 +258,12 @@ impl Script for BgiImage {
|
||||
})
|
||||
}
|
||||
|
||||
fn import_image<'a>(&'a self, data: ImageData, file: Box<dyn WriteSeek + 'a>) -> Result<()> {
|
||||
fn import_image<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
_filename: &str,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
create_image(
|
||||
data,
|
||||
file,
|
||||
|
||||
@@ -144,6 +144,7 @@ impl ScriptBuilder for CrxImageBuilder {
|
||||
fn create_image_file<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
_filename: &str,
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
@@ -1156,6 +1157,7 @@ impl Script for CrxImage {
|
||||
fn import_image<'a>(
|
||||
&'a self,
|
||||
mut data: ImageData,
|
||||
_filename: &str,
|
||||
mut file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
let mut color_type = match data.color_type {
|
||||
|
||||
@@ -63,6 +63,7 @@ impl ScriptBuilder for TlgImageBuilder {
|
||||
fn create_image_file<'a>(
|
||||
&'a self,
|
||||
mut data: ImageData,
|
||||
_filename: &str,
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
_options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
@@ -142,6 +143,7 @@ impl Script for TlgImage {
|
||||
fn import_image<'a>(
|
||||
&'a self,
|
||||
mut data: ImageData,
|
||||
_filename: &str,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
if data.depth != 8 {
|
||||
|
||||
@@ -86,15 +86,34 @@ impl ScriptBuilder for DpngImageBuilder {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn can_create_image_file(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn create_image_file<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
filename: &str,
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
if options.qlie_dpng_use_raw_png {
|
||||
create_raw_png_image(filename, writer, None)
|
||||
} else {
|
||||
create_image(data, writer, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DpngImage {
|
||||
img: DpngFile,
|
||||
config: ExtraConfig,
|
||||
}
|
||||
|
||||
impl DpngImage {
|
||||
pub fn new<T: Read + Seek>(mut data: T, _config: &ExtraConfig) -> Result<Self> {
|
||||
pub fn new<T: Read + Seek>(mut data: T, config: &ExtraConfig) -> Result<Self> {
|
||||
let img = DpngFile::unpack(&mut data, false, Encoding::Utf8, &None)?;
|
||||
if img.header.magic != *b"DPNG" {
|
||||
anyhow::bail!("Not a valid DPNG image");
|
||||
@@ -102,7 +121,10 @@ impl DpngImage {
|
||||
if img.tiles.is_empty() {
|
||||
anyhow::bail!("DPNG image has no tiles");
|
||||
}
|
||||
Ok(DpngImage { img })
|
||||
Ok(DpngImage {
|
||||
img,
|
||||
config: config.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,4 +168,111 @@ impl Script for DpngImage {
|
||||
}
|
||||
Ok(base)
|
||||
}
|
||||
|
||||
fn import_image<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
filename: &str,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
if self.config.qlie_dpng_use_raw_png {
|
||||
let img = load_png(std::fs::File::open(filename)?)?;
|
||||
if img.width != self.img.header.image_width
|
||||
|| img.height != self.img.header.image_height
|
||||
{
|
||||
eprintln!(
|
||||
"Warning: Image dimensions do not match original DPNG image (expected {}x{}, got {}x{})",
|
||||
self.img.header.image_width,
|
||||
self.img.header.image_height,
|
||||
img.width,
|
||||
img.height
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
create_raw_png_image(filename, file, Some(img))?;
|
||||
} else {
|
||||
if data.width != self.img.header.image_width
|
||||
|| data.height != self.img.header.image_height
|
||||
{
|
||||
eprintln!(
|
||||
"Warning: Image dimensions do not match original DPNG image (expected {}x{}, got {}x{})",
|
||||
self.img.header.image_width,
|
||||
self.img.header.image_height,
|
||||
data.width,
|
||||
data.height
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
create_image(data, file, &self.config)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn create_raw_png_image<'a>(
|
||||
filename: &str,
|
||||
mut file: Box<dyn WriteSeek + 'a>,
|
||||
img: Option<ImageData>,
|
||||
) -> Result<()> {
|
||||
let img = match img {
|
||||
Some(img) => img,
|
||||
None => load_png(std::fs::File::open(filename)?)?,
|
||||
};
|
||||
let header = DpngHeader {
|
||||
magic: *b"DPNG",
|
||||
_unk1: 1,
|
||||
tile_count: 1,
|
||||
image_width: img.width,
|
||||
image_height: img.height,
|
||||
};
|
||||
let png_data = crate::utils::files::read_file(filename)?;
|
||||
let tile = Tile {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
size: png_data.len() as u32,
|
||||
_unk: 0,
|
||||
png_data,
|
||||
};
|
||||
let dpng = DpngFile {
|
||||
header,
|
||||
tiles: vec![tile],
|
||||
};
|
||||
dpng.pack(&mut file, false, Encoding::Utf8, &None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_image<'a>(
|
||||
image: ImageData,
|
||||
mut writer: Box<dyn WriteSeek + 'a>,
|
||||
config: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
let header = DpngHeader {
|
||||
magic: *b"DPNG",
|
||||
_unk1: 1,
|
||||
tile_count: 1,
|
||||
image_width: image.width,
|
||||
image_height: image.height,
|
||||
};
|
||||
let mut png_data = MemWriter::new();
|
||||
let width = image.width;
|
||||
let height = image.height;
|
||||
encode_img_writer(image, ImageOutputType::Png, &mut png_data, config)?;
|
||||
let png_data = png_data.into_inner();
|
||||
let tile = Tile {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width,
|
||||
height,
|
||||
size: png_data.len() as u32,
|
||||
_unk: 0,
|
||||
png_data,
|
||||
};
|
||||
let dpng = DpngFile {
|
||||
header,
|
||||
tiles: vec![tile],
|
||||
};
|
||||
dpng.pack(&mut writer, false, Encoding::Utf8, &None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ impl ScriptBuilder for PgdGeBuilder {
|
||||
fn create_image_file<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
_filename: &str,
|
||||
mut writer: Box<dyn WriteSeek + 'a>,
|
||||
options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
@@ -125,6 +126,7 @@ impl Script for PgdGe {
|
||||
fn import_image<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
_filename: &str,
|
||||
mut file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
let mut header = self.header.clone();
|
||||
|
||||
@@ -153,6 +153,7 @@ impl Script for Pgd3 {
|
||||
fn import_image<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
_filename: &str,
|
||||
mut file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
let mut header = PgdGeHeader {
|
||||
|
||||
Reference in New Issue
Block a user