From 53ebb9612f691be0b437af6be2e94ae896e0bdc7 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Wed, 2 Jul 2025 19:59:32 +0800 Subject: [PATCH] Add tlg decode support (v5 only) --- Cargo.lock | 10 ++++ Cargo.toml | 4 +- src/scripts/kirikiri/image/mod.rs | 1 + src/scripts/kirikiri/image/tlg.rs | 93 +++++++++++++++++++++++++++++++ src/scripts/kirikiri/mod.rs | 2 + src/scripts/mod.rs | 2 + src/types.rs | 4 ++ 7 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/scripts/kirikiri/image/mod.rs create mode 100644 src/scripts/kirikiri/image/tlg.rs diff --git a/Cargo.lock b/Cargo.lock index df8c5a3..f5c7a01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,6 +427,15 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "libtlg-rs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c989df59ab8323731b26e3592f0ce760c852f47a327e198c89d9d7601226e485" +dependencies = [ + "overf", +] + [[package]] name = "memchr" version = "2.7.4" @@ -457,6 +466,7 @@ dependencies = [ "flate2", "int-enum", "lazy_static", + "libtlg-rs", "msg_tool_macro", "overf", "png", diff --git a/Cargo.toml b/Cargo.toml index cd7a4f2..c5aaf66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ fancy-regex = { version = "0.14", optional = true } flate2 = { version = "1.1", optional = true } int-enum = { version = "1.2", optional = true } lazy_static = "1.5.0" +libtlg-rs = { version = "0.1", optional = true } msg_tool_macro = { path = "./msg_tool_macro" } overf = "0.1" png = { version = "0.17", optional = true } @@ -24,7 +25,7 @@ unicode-segmentation = "1.12" utf16string = "0.2" [features] -default = ["bgi", "bgi-arc", "bgi-img", "cat-system", "cat-system-arc", "cat-system-img", "circus", "escude", "escude-arc", "kirikiri", "yaneurao", "yaneurao-itufuru"] +default = ["bgi", "bgi-arc", "bgi-img", "cat-system", "cat-system-arc", "cat-system-img", "circus", "escude", "escude-arc", "kirikiri", "kirikiri-img", "yaneurao", "yaneurao-itufuru"] bgi = [] bgi-arc = ["bgi", "utils-bit-stream"] bgi-img = ["bgi", "image", "utils-bit-stream"] @@ -35,6 +36,7 @@ circus = [] escude = ["int-enum"] escude-arc = ["escude", "rand", "utils-bit-stream"] kirikiri = ["emote-psb", "fancy-regex", "flate2", "utils-escape"] +kirikiri-img = ["kirikiri", "image", "libtlg-rs"] yaneurao = [] yaneurao-itufuru = ["yaneurao"] # basic feature diff --git a/src/scripts/kirikiri/image/mod.rs b/src/scripts/kirikiri/image/mod.rs new file mode 100644 index 0000000..c0110a1 --- /dev/null +++ b/src/scripts/kirikiri/image/mod.rs @@ -0,0 +1 @@ +pub mod tlg; diff --git a/src/scripts/kirikiri/image/tlg.rs b/src/scripts/kirikiri/image/tlg.rs new file mode 100644 index 0000000..430812e --- /dev/null +++ b/src/scripts/kirikiri/image/tlg.rs @@ -0,0 +1,93 @@ +use crate::ext::io::*; +use crate::scripts::base::*; +use crate::types::*; +use anyhow::Result; +use libtlg_rs::*; +use std::io::{Read, Seek}; + +#[derive(Debug)] +pub struct TlgImageBuilder {} + +impl TlgImageBuilder { + pub const fn new() -> Self { + TlgImageBuilder {} + } +} + +impl ScriptBuilder for TlgImageBuilder { + fn default_encoding(&self) -> Encoding { + Encoding::Cp932 + } + + fn build_script( + &self, + data: Vec, + _filename: &str, + _encoding: Encoding, + _archive_encoding: Encoding, + config: &ExtraConfig, + ) -> Result> { + Ok(Box::new(TlgImage::new(MemReader::new(data), config)?)) + } + + fn extensions(&self) -> &'static [&'static str] { + &["tlg", "tlg5", "tlg6"] + } + + fn script_type(&self) -> &'static ScriptType { + &ScriptType::KirikiriTlg + } + + fn is_image(&self) -> bool { + true + } + + fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option { + if buf_len >= 11 { + if is_valid_tlg(buf) { + return Some(255); + } + } + None + } +} + +#[derive(Debug)] +pub struct TlgImage { + data: Tlg, +} + +impl TlgImage { + pub fn new(data: T, _config: &ExtraConfig) -> Result { + let tlg = load_tlg(data)?; + Ok(TlgImage { data: tlg }) + } +} + +impl Script for TlgImage { + 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 { + Ok(ImageData { + width: self.data.width, + height: self.data.height, + color_type: match self.data.color { + TlgColorType::Bgr24 => ImageColorType::Bgr, + TlgColorType::Bgra32 => ImageColorType::Bgra, + TlgColorType::Grayscale8 => ImageColorType::Grayscale, + }, + depth: 8, + data: self.data.data.clone(), + }) + } +} diff --git a/src/scripts/kirikiri/mod.rs b/src/scripts/kirikiri/mod.rs index d22ea74..ad40679 100644 --- a/src/scripts/kirikiri/mod.rs +++ b/src/scripts/kirikiri/mod.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "kirikiri-img")] +pub mod image; pub mod ks; pub mod scn; pub mod simple_crypt; diff --git a/src/scripts/mod.rs b/src/scripts/mod.rs index be47d6f..8e3a0b6 100644 --- a/src/scripts/mod.rs +++ b/src/scripts/mod.rs @@ -54,6 +54,8 @@ lazy_static::lazy_static! { Box::new(kirikiri::simple_crypt::SimpleCryptBuilder::new()), #[cfg(feature = "kirikiri")] Box::new(kirikiri::ks::KsBuilder::new()), + #[cfg(feature = "kirikiri-img")] + Box::new(kirikiri::image::tlg::TlgImageBuilder::new()), ]; pub static ref ALL_EXTS: Vec = BUILDER.iter().flat_map(|b| b.extensions()).map(|s| s.to_string()).collect(); diff --git a/src/types.rs b/src/types.rs index 86610d8..8e32145 100644 --- a/src/types.rs +++ b/src/types.rs @@ -286,6 +286,10 @@ pub enum ScriptType { #[value(alias = "kr", alias = "kr-ks", alias = "kirikiri-ks")] /// Kirikiri script Kirikiri, + #[cfg(feature = "kirikiri-img")] + #[value(alias("kr-tlg"))] + /// Kirikiri TLG image + KirikiriTlg, #[cfg(feature = "yaneurao-itufuru")] #[value(alias("itufuru"))] /// Yaneurao Itufuru script