msg_tool\scripts\kirikiri\image/
tlg.rs

1//! Kirikiri TLG Image File (.tlg)
2use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::img::*;
6use anyhow::Result;
7use libtlg_rs::*;
8use std::io::{Read, Seek};
9
10#[derive(Debug)]
11/// Kirikiri TLG Script Builder
12pub struct TlgImageBuilder {}
13
14impl TlgImageBuilder {
15    /// Creates a new instance of `TlgImageBuilder`
16    pub const fn new() -> Self {
17        TlgImageBuilder {}
18    }
19}
20
21impl ScriptBuilder for TlgImageBuilder {
22    fn default_encoding(&self) -> Encoding {
23        Encoding::Cp932
24    }
25
26    fn build_script(
27        &self,
28        data: Vec<u8>,
29        _filename: &str,
30        _encoding: Encoding,
31        _archive_encoding: Encoding,
32        config: &ExtraConfig,
33        _archive: Option<&Box<dyn Script>>,
34    ) -> Result<Box<dyn Script>> {
35        Ok(Box::new(TlgImage::new(MemReader::new(data), config)?))
36    }
37
38    fn extensions(&self) -> &'static [&'static str] {
39        &["tlg", "tlg5", "tlg6"]
40    }
41
42    fn script_type(&self) -> &'static ScriptType {
43        &ScriptType::KirikiriTlg
44    }
45
46    fn is_image(&self) -> bool {
47        true
48    }
49
50    fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
51        if buf_len >= 11 {
52            if is_valid_tlg(buf) {
53                return Some(255);
54            }
55        }
56        None
57    }
58
59    fn can_create_image_file(&self) -> bool {
60        true
61    }
62
63    fn create_image_file<'a>(
64        &'a self,
65        mut data: ImageData,
66        _filename: &str,
67        writer: Box<dyn WriteSeek + 'a>,
68        _options: &ExtraConfig,
69    ) -> Result<()> {
70        if data.depth != 8 {
71            return Err(anyhow::anyhow!("Unsupported image depth: {}", data.depth));
72        }
73        let color_type = match data.color_type {
74            ImageColorType::Bgr => TlgColorType::Bgr24,
75            ImageColorType::Bgra => TlgColorType::Bgra32,
76            ImageColorType::Grayscale => TlgColorType::Grayscale8,
77            ImageColorType::Rgb => {
78                convert_rgb_to_bgr(&mut data)?;
79                TlgColorType::Bgr24
80            }
81            ImageColorType::Rgba => {
82                convert_rgba_to_bgra(&mut data)?;
83                TlgColorType::Bgra32
84            }
85        };
86        let tlg = Tlg {
87            width: data.width,
88            height: data.height,
89            color: color_type,
90            data: data.data,
91            tags: Default::default(),
92            version: 5, // Currently only version 5 is supported
93        };
94        save_tlg(&tlg, writer)?;
95        Ok(())
96    }
97}
98
99#[derive(Debug)]
100/// Kirikiri TLG Script
101pub struct TlgImage {
102    data: Tlg,
103}
104
105impl TlgImage {
106    /// Create a new TLG script
107    ///
108    /// * `data` - The reader containing the TLG script data
109    /// * `config` - Extra configuration options
110    pub fn new<T: Read + Seek>(data: T, _config: &ExtraConfig) -> Result<Self> {
111        let tlg = load_tlg(data)?;
112        Ok(TlgImage { data: tlg })
113    }
114}
115
116impl Script for TlgImage {
117    fn default_output_script_type(&self) -> OutputScriptType {
118        OutputScriptType::Json
119    }
120
121    fn default_format_type(&self) -> FormatOptions {
122        FormatOptions::None
123    }
124
125    fn is_image(&self) -> bool {
126        true
127    }
128
129    fn export_image(&self) -> Result<ImageData> {
130        Ok(ImageData {
131            width: self.data.width,
132            height: self.data.height,
133            color_type: match self.data.color {
134                TlgColorType::Bgr24 => ImageColorType::Bgr,
135                TlgColorType::Bgra32 => ImageColorType::Bgra,
136                TlgColorType::Grayscale8 => ImageColorType::Grayscale,
137            },
138            depth: 8,
139            data: self.data.data.clone(),
140        })
141    }
142
143    fn import_image<'a>(
144        &'a self,
145        mut data: ImageData,
146        _filename: &str,
147        file: Box<dyn WriteSeek + 'a>,
148    ) -> Result<()> {
149        if data.depth != 8 {
150            return Err(anyhow::anyhow!("Unsupported image depth: {}", data.depth));
151        }
152        let color_type = match data.color_type {
153            ImageColorType::Bgr => TlgColorType::Bgr24,
154            ImageColorType::Bgra => TlgColorType::Bgra32,
155            ImageColorType::Grayscale => TlgColorType::Grayscale8,
156            ImageColorType::Rgb => {
157                convert_rgb_to_bgr(&mut data)?;
158                TlgColorType::Bgr24
159            }
160            ImageColorType::Rgba => {
161                convert_rgba_to_bgra(&mut data)?;
162                TlgColorType::Bgra32
163            }
164        };
165        let tlg = Tlg {
166            width: data.width,
167            height: data.height,
168            color: color_type,
169            data: data.data,
170            tags: self.data.tags.clone(),
171            version: 5, // Currently only version 5 is supported
172        };
173        save_tlg(&tlg, file)?;
174        Ok(())
175    }
176}