mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-06 12:58:45 +08:00
Add support for HexenHaus PNG Image File (.png)
This commit is contained in:
@@ -5,7 +5,7 @@ edition = "2024"
|
||||
repository = "https://github.com/lifegpc/msg-tool"
|
||||
description = "A command-line tool for exporting, importing, packing, and unpacking script files."
|
||||
license = "GPL-3.0-or-later"
|
||||
exclude = [".github", "*.py"]
|
||||
exclude = [".github", "*.py", "AGENTS.md"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
@@ -53,7 +53,7 @@ zstd = { version = "0.13", optional = true }
|
||||
default = ["all-fmt", "image-jpg", "image-jxl", "image-webp", "audio-flac", "jieba"]
|
||||
all-fmt = ["all-script", "all-img", "all-arc", "all-audio"]
|
||||
all-script = ["artemis", "artemis-panmimisoft", "bgi", "cat-system", "circus", "entis-gls", "escude", "ex-hibit", "favorite", "hexen-haus", "kirikiri", "silky", "softpal", "will-plus", "yaneurao", "yaneurao-itufuru"]
|
||||
all-img = ["bgi-img", "cat-system-img", "circus-img", "emote-img", "kirikiri-img", "softpal-img"]
|
||||
all-img = ["bgi-img", "cat-system-img", "circus-img", "emote-img", "hexen-haus-img", "kirikiri-img", "softpal-img"]
|
||||
all-arc = ["artemis-arc", "bgi-arc", "cat-system-arc", "circus-arc", "escude-arc", "ex-hibit-arc", "hexen-haus-arc", "softpal-arc"]
|
||||
all-audio = ["bgi-audio", "circus-audio"]
|
||||
artemis = ["stylua", "utils-escape"]
|
||||
@@ -79,6 +79,7 @@ ex-hibit-arc = ["ex-hibit"]
|
||||
favorite = []
|
||||
hexen-haus = ["memchr", "utils-str"]
|
||||
hexen-haus-arc = ["hexen-haus"]
|
||||
hexen-haus-img = ["hexen-haus", "image"]
|
||||
kirikiri = ["emote-psb", "fancy-regex", "flate2", "json", "lz4", "utils-escape"]
|
||||
kirikiri-img = ["kirikiri", "image", "libtlg-rs"]
|
||||
silky = []
|
||||
|
||||
@@ -171,6 +171,10 @@ msg-tool create -t <script-type> <input> <output>
|
||||
|---|---|---|---|---|---|
|
||||
| `hexen-haus-arcc` | `hexen-haus-arc` | HexenHaus Arcc Archive File (.arc) | ✔️ | ❌ | |
|
||||
| `hexen-haus-wag` | `hexen-haus-arc` | HexenHaus Wag Archive File (.wag) | ✔️ | ❌ | |
|
||||
|
||||
| Image Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Create | Remarks |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| `hexen-haus-png` | `hexen-haus-img` | HexenHaus PNG Image File (.png) | ✔️ | ❌ | ❌ | ❌ | ❌ | |
|
||||
### Kirikiri
|
||||
| Script Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Custom Export | Custom Import | Create | Remarks |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|
|
||||
|
||||
@@ -7,5 +7,9 @@ fn detect_script_type(_filename: &str, buf: &[u8]) -> Option<ScriptType> {
|
||||
if buf.len() >= 4 && buf.starts_with(b"NORI") {
|
||||
return Some(ScriptType::HexenHaus);
|
||||
}
|
||||
#[cfg(feature = "hexen-haus-img")]
|
||||
if buf.len() >= 4 && buf.starts_with(b"IMGD") {
|
||||
return Some(ScriptType::HexenHausPng);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
1
src/scripts/hexen_haus/img/mod.rs
Normal file
1
src/scripts/hexen_haus/img/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod png;
|
||||
120
src/scripts/hexen_haus/img/png.rs
Normal file
120
src/scripts/hexen_haus/img/png.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
//! HexenHaus PNG Image
|
||||
use crate::ext::io::*;
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::img::*;
|
||||
use anyhow::Result;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
|
||||
#[derive(Debug)]
|
||||
/// HexenHaus PNG Image Builder
|
||||
pub struct PngImageBuilder {}
|
||||
|
||||
impl PngImageBuilder {
|
||||
/// Creates a new instance of `PngImageBuilder`
|
||||
pub fn new() -> Self {
|
||||
PngImageBuilder {}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScriptBuilder for PngImageBuilder {
|
||||
fn default_encoding(&self) -> Encoding {
|
||||
Encoding::Cp932
|
||||
}
|
||||
|
||||
fn build_script(
|
||||
&self,
|
||||
data: Vec<u8>,
|
||||
_filename: &str,
|
||||
_encoding: Encoding,
|
||||
_archive_encoding: Encoding,
|
||||
config: &ExtraConfig,
|
||||
_archive: Option<&Box<dyn Script>>,
|
||||
) -> Result<Box<dyn Script>> {
|
||||
Ok(Box::new(PngImage::new(MemReader::new(data), config)?))
|
||||
}
|
||||
|
||||
fn extensions(&self) -> &'static [&'static str] {
|
||||
&["png"]
|
||||
}
|
||||
|
||||
fn script_type(&self) -> &'static ScriptType {
|
||||
&ScriptType::HexenHausPng
|
||||
}
|
||||
|
||||
fn is_image(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
|
||||
if buf_len >= 4 && buf.starts_with(b"IMGD") {
|
||||
return Some(10);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Extra information for PNG image
|
||||
pub struct ExtraInfo {
|
||||
/// x offset
|
||||
pub offset_x: u32,
|
||||
/// y offset
|
||||
pub offset_y: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PngImage {
|
||||
reader: MemReader,
|
||||
extra: Option<ExtraInfo>,
|
||||
}
|
||||
|
||||
impl PngImage {
|
||||
/// Creates a new instance of `PngImage`
|
||||
pub fn new(mut reader: MemReader, _config: &ExtraConfig) -> Result<Self> {
|
||||
let mut header = [0; 4];
|
||||
reader.read_exact(&mut header)?;
|
||||
if &header != b"IMGD" {
|
||||
return Err(anyhow::anyhow!("Not a valid HexenHaus PNG image"));
|
||||
}
|
||||
reader.seek(SeekFrom::End(-14))?;
|
||||
let cnt = reader.read_exact_vec(12)?;
|
||||
let extra = if cnt.starts_with(b"CNTR") {
|
||||
let mut cnt_reader = MemReaderRef::new(&cnt[4..]);
|
||||
let offset_x = cnt_reader.read_u32()?;
|
||||
let offset_y = cnt_reader.read_u32()?;
|
||||
Some(ExtraInfo { offset_x, offset_y })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(PngImage { reader, extra })
|
||||
}
|
||||
}
|
||||
|
||||
impl Script for PngImage {
|
||||
fn default_output_script_type(&self) -> OutputScriptType {
|
||||
OutputScriptType::Json
|
||||
}
|
||||
|
||||
fn default_format_type(&self) -> FormatOptions {
|
||||
FormatOptions::None
|
||||
}
|
||||
|
||||
fn is_image(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn export_image(&self) -> Result<ImageData> {
|
||||
let mut reader = self.reader.to_ref();
|
||||
reader.pos = 0;
|
||||
let reader = StreamRegion::with_start_pos(reader, 0x10)?;
|
||||
let img = load_png(reader)?;
|
||||
Ok(img)
|
||||
}
|
||||
|
||||
fn extra_info<'a>(&'a self) -> Option<Box<dyn AnyDebug + 'a>> {
|
||||
self.extra
|
||||
.as_ref()
|
||||
.map(|e| Box::new(e) as Box<dyn AnyDebug>)
|
||||
}
|
||||
}
|
||||
@@ -2,3 +2,5 @@
|
||||
#[cfg(feature = "hexen-haus-arc")]
|
||||
pub mod archive;
|
||||
pub mod bin;
|
||||
#[cfg(feature = "hexen-haus-img")]
|
||||
pub mod img;
|
||||
|
||||
@@ -146,6 +146,8 @@ lazy_static::lazy_static! {
|
||||
Box::new(artemis::archive::pf2::ArtemisPf2Builder::new()),
|
||||
#[cfg(feature = "hexen-haus-arc")]
|
||||
Box::new(hexen_haus::archive::wag::HexenHausWagArchiveBuilder::new()),
|
||||
#[cfg(feature = "hexen-haus-img")]
|
||||
Box::new(hexen_haus::img::png::PngImageBuilder::new()),
|
||||
];
|
||||
/// A list of all script extensions.
|
||||
pub static ref ALL_EXTS: Vec<String> =
|
||||
|
||||
@@ -605,6 +605,9 @@ pub enum ScriptType {
|
||||
#[cfg(feature = "hexen-haus-arc")]
|
||||
/// HexenHaus WAG archive
|
||||
HexenHausWag,
|
||||
#[cfg(feature = "hexen-haus-img")]
|
||||
/// HexenHaus PNG image
|
||||
HexenHausPng,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
#[value(alias("kr-scn"))]
|
||||
/// Kirikiri SCN script
|
||||
|
||||
Reference in New Issue
Block a user