1use clap::ValueEnum;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
7#[serde(untagged, rename_all = "camelCase")]
8pub enum Encoding {
10 Auto,
12 Utf8,
14 Cp932,
16 Gb2312,
18 Utf16LE,
20 #[cfg(windows)]
22 CodePage(u32),
23}
24
25impl Default for Encoding {
26 fn default() -> Self {
27 Encoding::Utf8
28 }
29}
30
31impl Encoding {
32 pub fn is_jis(&self) -> bool {
34 match self {
35 Self::Cp932 => true,
36 #[cfg(windows)]
37 Self::CodePage(code_page) => *code_page == 932,
38 _ => false,
39 }
40 }
41
42 pub fn is_utf16le(&self) -> bool {
44 match self {
45 Self::Utf16LE => true,
46 #[cfg(windows)]
47 Self::CodePage(code_page) => *code_page == 1200,
48 _ => false,
49 }
50 }
51
52 pub fn is_utf8(&self) -> bool {
54 match self {
55 Self::Utf8 => true,
56 #[cfg(windows)]
57 Self::CodePage(code_page) => *code_page == 65001,
58 _ => false,
59 }
60 }
61
62 pub fn charset(&self) -> Option<&'static str> {
64 match self {
65 Self::Auto => None,
66 Self::Utf8 => Some("UTF-8"),
67 Self::Cp932 => Some("shift_jis"),
68 Self::Gb2312 => Some("gbk"),
69 Self::Utf16LE => Some("utf-16le"),
70 #[cfg(windows)]
71 Self::CodePage(code_page) => match *code_page {
72 932 => Some("shift_jis"),
73 65001 => Some("utf-8"),
74 1200 => Some("utf-16le"),
75 936 => Some("gbk"),
76 _ => None,
77 },
78 }
79 }
80}
81
82#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
83pub enum TextEncoding {
85 Default,
87 Auto,
89 Utf8,
91 #[value(alias("jis"))]
92 Cp932,
94 #[value(alias("gbk"))]
95 Gb2312,
97}
98
99#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
100pub enum OutputScriptType {
102 M3t,
104 M3ta,
106 M3tTxt,
108 Json,
110 Yaml,
112 Pot,
114 Po,
116 Custom,
118}
119
120impl OutputScriptType {
121 pub fn is_custom(&self) -> bool {
123 matches!(self, OutputScriptType::Custom)
124 }
125
126 pub fn is_m3t(&self) -> bool {
128 matches!(
129 self,
130 OutputScriptType::M3t | OutputScriptType::M3ta | OutputScriptType::M3tTxt
131 )
132 }
133}
134
135impl AsRef<str> for OutputScriptType {
136 fn as_ref(&self) -> &str {
138 match self {
139 OutputScriptType::M3t => "m3t",
140 OutputScriptType::M3ta => "m3ta",
141 OutputScriptType::M3tTxt => "txt",
142 OutputScriptType::Json => "json",
143 OutputScriptType::Yaml => "yaml",
144 OutputScriptType::Pot => "pot",
145 OutputScriptType::Po => "po",
146 OutputScriptType::Custom => "",
147 }
148 }
149}
150
151#[cfg(feature = "circus")]
152#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
153pub enum CircusMesType {
155 Ffexa,
157 Ffexs,
159 Ef,
161 Dcos,
163 Ktlep,
165 Dcws,
167 Dcsv,
169 Dcpc,
171 Dcmems,
173 Dcdx,
175 Dcas,
177 Dcbs,
179 Dc2fl,
181 Dc2bs,
183 Dc2dm,
185 Dc2fy,
187 Dc2cckko,
189 Dc2ccotm,
191 Dc2sc,
193 Dc2ty,
195 Dc2pc,
197 Dc3rx,
199 Dc3pp,
201 Dc3wy,
203 Dc3dd,
205 Dc4,
207 Dc4ph,
209 Ds,
211 Dsif,
213 Tmpl,
215 Nightshade,
217}
218
219#[cfg(feature = "circus")]
220impl AsRef<str> for CircusMesType {
221 fn as_ref(&self) -> &str {
223 match self {
224 CircusMesType::Ffexa => "ffexa",
225 CircusMesType::Ffexs => "ffexs",
226 CircusMesType::Ef => "ef",
227 CircusMesType::Dcos => "dcos",
228 CircusMesType::Ktlep => "ktlep",
229 CircusMesType::Dcws => "dcws",
230 CircusMesType::Dcsv => "dcsv",
231 CircusMesType::Dcpc => "dcpc",
232 CircusMesType::Dcmems => "dcmems",
233 CircusMesType::Dcdx => "dcdx",
234 CircusMesType::Dcas => "dcas",
235 CircusMesType::Dcbs => "dcbs",
236 CircusMesType::Dc2fl => "dc2fl",
237 CircusMesType::Dc2bs => "dc2bs",
238 CircusMesType::Dc2dm => "dc2dm",
239 CircusMesType::Dc2fy => "dc2fy",
240 CircusMesType::Dc2cckko => "dc2cckko",
241 CircusMesType::Dc2ccotm => "dc2ccotm",
242 CircusMesType::Dc2sc => "dc2sc",
243 CircusMesType::Dc2ty => "dc2ty",
244 CircusMesType::Dc2pc => "dc2pc",
245 CircusMesType::Dc3rx => "dc3rx",
246 CircusMesType::Dc3pp => "dc3pp",
247 CircusMesType::Dc3wy => "dc3wy",
248 CircusMesType::Dc3dd => "dc3dd",
249 CircusMesType::Dc4 => "dc4",
250 CircusMesType::Dc4ph => "dc4ph",
251 CircusMesType::Ds => "ds",
252 CircusMesType::Dsif => "dsif",
253 CircusMesType::Tmpl => "tmpl",
254 CircusMesType::Nightshade => "nightshade",
255 }
256 }
257}
258
259#[derive(Debug, Clone, msg_tool_macro::Default)]
261pub struct ExtraConfig {
262 #[cfg(feature = "circus")]
263 pub circus_mes_type: Option<CircusMesType>,
265 #[cfg(feature = "escude-arc")]
266 pub escude_fake_compress: bool,
268 #[cfg(feature = "escude")]
269 pub escude_enum_scr: Option<String>,
271 #[cfg(feature = "bgi")]
272 pub bgi_import_duplicate: bool,
275 #[cfg(feature = "bgi")]
276 pub bgi_disable_append: bool,
279 #[cfg(feature = "image")]
280 pub image_type: Option<ImageOutputType>,
282 #[cfg(all(feature = "bgi-arc", feature = "bgi-img"))]
283 pub bgi_is_sysgrp_arc: Option<bool>,
285 #[cfg(feature = "bgi-img")]
286 pub bgi_img_scramble: Option<bool>,
289 #[cfg(feature = "cat-system-arc")]
290 pub cat_system_int_encrypt_password: Option<String>,
292 #[cfg(feature = "cat-system-img")]
293 pub cat_system_image_canvas: bool,
295 #[cfg(feature = "kirikiri")]
296 pub kirikiri_language_index: Option<usize>,
298 #[cfg(feature = "kirikiri")]
299 pub kirikiri_export_chat: bool,
302 #[cfg(feature = "kirikiri")]
303 pub kirikiri_chat_key: Option<Vec<String>>,
306 #[cfg(feature = "kirikiri")]
307 pub kirikiri_chat_json:
310 Option<std::sync::Arc<HashMap<String, HashMap<String, (String, usize)>>>>,
311 #[cfg(feature = "kirikiri")]
312 pub kirikiri_languages: Option<std::sync::Arc<Vec<String>>>,
314 #[cfg(feature = "kirikiri")]
315 pub kirikiri_remove_empty_lines: bool,
317 #[cfg(feature = "kirikiri")]
318 pub kirikiri_name_commands: std::sync::Arc<std::collections::HashSet<String>>,
320 #[cfg(feature = "kirikiri")]
321 pub kirikiri_message_commands: std::sync::Arc<std::collections::HashSet<String>>,
323 #[cfg(feature = "bgi-arc")]
324 pub bgi_compress_file: bool,
326 #[cfg(feature = "bgi-arc")]
327 #[default(3)]
328 pub bgi_compress_min_len: usize,
330 #[cfg(feature = "emote-img")]
331 pub emote_pimg_overlay: Option<bool>,
333 #[cfg(feature = "artemis-arc")]
334 pub artemis_arc_disable_xor: bool,
336 #[cfg(feature = "artemis")]
337 pub artemis_indent: Option<usize>,
340 #[cfg(feature = "artemis")]
341 pub artemis_no_indent: bool,
343 #[cfg(feature = "artemis")]
344 #[default(100)]
345 pub artemis_max_line_width: usize,
347 #[cfg(feature = "artemis")]
348 pub artemis_ast_lang: Option<String>,
351 #[cfg(feature = "cat-system")]
352 pub cat_system_cstl_lang: Option<String>,
355 #[cfg(feature = "flate2")]
356 #[default(6)]
357 pub zlib_compression_level: u32,
359 #[cfg(feature = "image")]
360 pub png_compression_level: PngCompressionLevel,
362 #[cfg(feature = "circus-img")]
363 pub circus_crx_keep_original_bpp: bool,
365 #[cfg(feature = "circus-img")]
366 pub circus_crx_zstd: bool,
368 #[cfg(feature = "zstd")]
369 #[default(3)]
370 pub zstd_compression_level: i32,
372 #[cfg(feature = "circus-img")]
373 pub circus_crx_mode: crate::scripts::circus::image::crx::CircusCrxMode,
375 #[cfg(feature = "ex-hibit")]
376 pub ex_hibit_rld_xor_key: Option<u32>,
379 #[cfg(feature = "ex-hibit")]
380 pub ex_hibit_rld_def_xor_key: Option<u32>,
382 #[cfg(feature = "ex-hibit")]
383 pub ex_hibit_rld_keys: Option<Box<[u32; 0x100]>>,
385 #[cfg(feature = "ex-hibit")]
386 pub ex_hibit_rld_def_keys: Option<Box<[u32; 0x100]>>,
388 #[cfg(feature = "mozjpeg")]
389 #[default(80)]
390 pub jpeg_quality: u8,
392 #[cfg(feature = "webp")]
393 pub webp_lossless: bool,
395 #[cfg(feature = "webp")]
396 #[default(80)]
397 pub webp_quality: u8,
399 #[cfg(feature = "circus-img")]
400 pub circus_crx_canvas: bool,
402 pub custom_yaml: bool,
404 #[cfg(feature = "entis-gls")]
405 pub entis_gls_srcxml_lang: Option<String>,
408 #[cfg(feature = "will-plus")]
409 pub will_plus_ws2_no_disasm: bool,
413 #[cfg(feature = "artemis-panmimisoft")]
414 pub artemis_panmimisoft_txt_blacklist_names: std::sync::Arc<std::collections::HashSet<String>>,
417 #[cfg(feature = "artemis-panmimisoft")]
418 pub artemis_panmimisoft_txt_lang: Option<String>,
421 #[cfg(feature = "lossless-audio")]
422 pub lossless_audio_fmt: LosslessAudioFormat,
424 #[cfg(feature = "audio-flac")]
425 #[default(5)]
426 pub flac_compression_level: u32,
428 #[cfg(feature = "artemis")]
429 #[default(true)]
430 pub artemis_asb_format_lua: bool,
432 #[cfg(feature = "kirikiri")]
433 pub kirikiri_title: bool,
435 #[cfg(feature = "favorite")]
436 #[default(true)]
437 pub favorite_hcb_filter_ascii: bool,
439 #[cfg(feature = "bgi-img")]
440 #[default(get_default_threads())]
441 pub bgi_img_workers: usize,
444 #[cfg(feature = "image-jxl")]
445 #[default(true)]
446 pub jxl_lossless: bool,
448 #[cfg(feature = "image-jxl")]
449 #[default(1.0)]
450 pub jxl_distance: f32,
453 #[cfg(feature = "image-jxl")]
454 #[default(1)]
455 pub jxl_workers: usize,
458 #[cfg(feature = "emote-img")]
459 #[default(true)]
460 pub psb_process_tlg: bool,
462 #[cfg(feature = "softpal-img")]
463 #[default(true)]
464 pub pgd_fake_compress: bool,
467 #[cfg(feature = "softpal")]
468 pub softpal_add_message_index: bool,
470 #[cfg(feature = "kirikiri")]
471 #[default(true)]
472 pub kirikiri_chat_multilang: bool,
475 #[cfg(feature = "kirikiri-arc")]
476 #[default(true)]
477 pub xp3_simple_crypt: bool,
479 #[cfg(feature = "kirikiri-arc")]
480 #[default(true)]
481 pub xp3_mdf_decompress: bool,
483 #[cfg(feature = "kirikiri-arc")]
484 pub xp3_segmenter: crate::scripts::kirikiri::archive::xp3::SegmenterConfig,
486 #[cfg(feature = "kirikiri-arc")]
487 #[default(true)]
488 pub xp3_compress_files: bool,
490 #[cfg(feature = "kirikiri-arc")]
491 #[default(true)]
492 pub xp3_compress_index: bool,
494 #[cfg(feature = "kirikiri-arc")]
495 #[default(num_cpus::get())]
496 pub xp3_compress_workers: usize,
498 #[cfg(feature = "kirikiri-arc")]
499 pub xp3_zstd: bool,
501 #[cfg(feature = "kirikiri-arc")]
502 #[default(1)]
503 pub xp3_pack_workers: usize,
506 #[cfg(feature = "kirikiri-arc")]
507 pub xp3_no_adler: bool,
510 #[cfg(feature = "kirikiri")]
511 pub kirikiri_language_insert: bool,
513 #[cfg(feature = "musica-arc")]
514 pub musica_game_title: Option<String>,
516 #[cfg(feature = "musica-arc")]
517 pub musica_xor_key: Option<u8>,
519 #[cfg(feature = "musica-arc")]
520 pub musica_compress: bool,
522 #[cfg(feature = "bgi")]
523 pub bgi_add_space: bool,
526}
527
528#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
529pub enum ScriptType {
531 #[cfg(feature = "artemis")]
532 Artemis,
534 #[cfg(feature = "artemis")]
535 ArtemisAsb,
537 #[cfg(feature = "artemis")]
538 ArtemisTxt,
540 #[cfg(feature = "artemis-panmimisoft")]
541 ArtemisPanmimisoftTxt,
543 #[cfg(feature = "artemis-arc")]
544 #[value(alias("pfs"))]
545 ArtemisArc,
547 #[cfg(feature = "artemis-arc")]
548 #[value(alias("pf2"))]
549 ArtemisPf2,
551 #[cfg(feature = "bgi")]
552 #[value(alias("ethornell"))]
553 BGI,
555 #[cfg(feature = "bgi")]
556 #[value(alias("ethornell-bsi"))]
557 BGIBsi,
559 #[cfg(feature = "bgi")]
560 #[value(alias("ethornell-bp"))]
561 BGIBp,
563 #[cfg(feature = "bgi-arc")]
564 #[value(alias = "ethornell-arc-v1")]
565 BGIArcV1,
567 #[cfg(feature = "bgi-arc")]
568 #[value(alias = "ethornell-arc-v2", alias = "bgi-arc", alias = "ethornell-arc")]
569 BGIArcV2,
571 #[cfg(feature = "bgi-arc")]
572 #[value(alias("ethornell-dsc"))]
573 BGIDsc,
575 #[cfg(feature = "bgi-audio")]
576 #[value(alias("ethornell-audio"))]
577 BGIAudio,
579 #[cfg(feature = "bgi-img")]
580 #[value(alias("ethornell-img"))]
581 BGIImg,
583 #[cfg(feature = "bgi-img")]
584 #[value(alias("ethornell-cbg"))]
585 BGICbg,
587 #[cfg(feature = "cat-system")]
588 CatSystem,
590 #[cfg(feature = "cat-system")]
591 CatSystemCstl,
593 #[cfg(feature = "cat-system-arc")]
594 CatSystemInt,
596 #[cfg(feature = "cat-system-img")]
597 CatSystemHg3,
599 #[cfg(feature = "circus")]
600 Circus,
602 #[cfg(feature = "circus-arc")]
603 CircusCrm,
605 #[cfg(feature = "circus-arc")]
606 CircusDat,
608 #[cfg(feature = "circus-arc")]
609 CircusPck,
611 #[cfg(feature = "circus-audio")]
612 CircusPcm,
614 #[cfg(feature = "circus-img")]
615 CircusCrx,
617 #[cfg(feature = "circus-img")]
618 CircusCrxd,
620 #[cfg(feature = "emote-img")]
621 #[value(alias("psb"))]
622 EmotePsb,
624 #[cfg(feature = "emote-img")]
625 #[value(alias("pimg"))]
626 EmotePimg,
628 #[cfg(feature = "emote-img")]
629 #[value(alias("dref"))]
630 EmoteDref,
632 #[cfg(feature = "entis-gls")]
633 EntisGls,
635 #[cfg(feature = "escude-arc")]
636 EscudeArc,
638 #[cfg(feature = "escude")]
639 Escude,
641 #[cfg(feature = "escude")]
642 EscudeList,
644 #[cfg(feature = "ex-hibit")]
645 ExHibit,
647 #[cfg(feature = "ex-hibit-arc")]
648 ExHibitGrp,
650 #[cfg(feature = "favorite")]
651 Favorite,
653 #[cfg(feature = "hexen-haus")]
654 HexenHaus,
656 #[cfg(feature = "hexen-haus-arc")]
657 HexenHausArcc,
659 #[cfg(feature = "hexen-haus-arc")]
660 HexenHausOdio,
662 #[cfg(feature = "hexen-haus-arc")]
663 HexenHausWag,
665 #[cfg(feature = "hexen-haus-img")]
666 HexenHausPng,
668 #[cfg(feature = "kirikiri")]
669 #[value(alias("kr-scn"))]
670 KirikiriScn,
672 #[cfg(feature = "kirikiri")]
673 #[value(alias("kr-simple-crypt"))]
674 KirikiriSimpleCrypt,
676 #[cfg(feature = "kirikiri")]
677 #[value(alias = "kr", alias = "kr-ks", alias = "kirikiri-ks")]
678 Kirikiri,
680 #[cfg(feature = "kirikiri-arc")]
681 #[value(alias = "kr-xp3", alias = "xp3")]
682 KirikiriXp3,
684 #[cfg(feature = "kirikiri-img")]
685 #[value(alias("kr-tlg"))]
686 KirikiriTlg,
688 #[cfg(feature = "kirikiri")]
689 #[value(alias("kr-mdf"))]
690 KirikiriMdf,
692 #[cfg(feature = "kirikiri")]
693 #[value(alias("kr-tjs2"))]
694 KirikiriTjs2,
696 #[cfg(feature = "kirikiri")]
697 #[value(alias("kr-tjs-ns0"))]
698 KirikiriTjsNs0,
700 #[cfg(feature = "musica")]
701 Musica,
703 #[cfg(feature = "musica-arc")]
704 MusicaPaz,
706 #[cfg(feature = "silky")]
707 Silky,
709 #[cfg(feature = "silky")]
710 SilkyMap,
712 #[cfg(feature = "softpal")]
713 Softpal,
715 #[cfg(feature = "softpal-arc")]
716 SoftpalPac,
718 #[cfg(feature = "softpal-arc")]
719 SoftpalPacAmuse,
721 #[cfg(feature = "softpal-img")]
722 #[value(alias = "pgd-ge", alias = "pgd")]
723 SoftpalPgdGe,
725 #[cfg(feature = "softpal-img")]
726 #[value(alias = "softpal-pgd2", alias = "pgd3", alias = "pgd2")]
727 SoftpalPgd3,
729 #[cfg(feature = "will-plus")]
730 #[value(alias("adv-hd-ws2"))]
731 WillPlusWs2,
733 #[cfg(feature = "will-plus-img")]
734 #[value(alias("adv-hd-wip"))]
735 WillPlusWip,
737 #[cfg(feature = "yaneurao-itufuru")]
738 #[value(alias("itufuru"))]
739 YaneuraoItufuru,
741 #[cfg(feature = "yaneurao-itufuru")]
742 #[value(alias("itufuru-arc"))]
743 YaneuraoItufuruArc,
745}
746
747#[derive(Clone, Debug, Serialize, Deserialize)]
748pub struct Message {
750 #[serde(skip_serializing_if = "Option::is_none")]
751 pub name: Option<String>,
753 pub message: String,
755}
756
757impl Message {
758 pub fn new(message: String, name: Option<String>) -> Self {
760 Message { message, name }
761 }
762}
763
764pub enum ScriptResult {
766 Ok,
768 Ignored,
771 Uncount,
774}
775
776#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
777pub enum FormatType {
779 Fixed,
781 None,
783}
784
785#[derive(Clone)]
786pub enum FormatOptions {
788 Fixed {
790 length: usize,
792 keep_original: bool,
794 break_words: bool,
796 insert_fullwidth_space_at_line_start: bool,
798 break_with_sentence: bool,
800 #[cfg(feature = "jieba")]
801 break_chinese_words: bool,
803 #[cfg(feature = "jieba")]
804 jieba_dict: Option<String>,
806 },
807 None,
809}
810
811#[derive(Debug, Serialize, Deserialize)]
812pub struct NameTableCell {
814 #[serde(rename = "JP_Name")]
815 pub jp_name: String,
817 #[serde(rename = "CN_Name")]
818 pub cn_name: String,
820 #[serde(rename = "Count")]
821 pub count: usize,
823}
824
825#[derive(Debug, Serialize, Deserialize)]
826pub struct ReplacementTable {
828 #[serde(flatten)]
829 pub map: HashMap<String, String>,
831}
832
833#[cfg(feature = "image")]
834#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
835pub enum ImageColorType {
837 Grayscale,
839 Rgb,
841 Rgba,
843 Bgr,
845 Bgra,
847}
848
849#[cfg(feature = "image")]
850impl ImageColorType {
851 pub fn bpp(&self, depth: u8) -> u16 {
853 match self {
854 ImageColorType::Grayscale => depth as u16,
855 ImageColorType::Rgb => depth as u16 * 3,
856 ImageColorType::Rgba => depth as u16 * 4,
857 ImageColorType::Bgr => depth as u16 * 3,
858 ImageColorType::Bgra => depth as u16 * 4,
859 }
860 }
861}
862
863#[cfg(feature = "image")]
864#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
865pub enum ImageOutputType {
867 Png,
869 #[cfg(feature = "image-jpg")]
870 Jpg,
872 #[cfg(feature = "image-webp")]
873 Webp,
875 #[cfg(feature = "image-jxl")]
876 Jxl,
878}
879
880#[cfg(feature = "image")]
881impl TryFrom<&str> for ImageOutputType {
882 type Error = anyhow::Error;
883
884 fn try_from(value: &str) -> Result<Self, Self::Error> {
887 match value.to_ascii_lowercase().as_str() {
888 "png" => Ok(ImageOutputType::Png),
889 #[cfg(feature = "image-jpg")]
890 "jpg" => Ok(ImageOutputType::Jpg),
891 #[cfg(feature = "image-jpg")]
892 "jpeg" => Ok(ImageOutputType::Jpg),
893 #[cfg(feature = "image-webp")]
894 "webp" => Ok(ImageOutputType::Webp),
895 #[cfg(feature = "image-jxl")]
896 "jxl" => Ok(ImageOutputType::Jxl),
897 _ => Err(anyhow::anyhow!("Unsupported image output type: {}", value)),
898 }
899 }
900}
901
902#[cfg(feature = "image")]
903impl TryFrom<&std::path::Path> for ImageOutputType {
904 type Error = anyhow::Error;
905
906 fn try_from(value: &std::path::Path) -> Result<Self, Self::Error> {
907 if let Some(ext) = value.extension() {
908 Self::try_from(ext.to_string_lossy().as_ref())
909 } else {
910 Err(anyhow::anyhow!("No extension found in path"))
911 }
912 }
913}
914
915#[cfg(feature = "image")]
916impl AsRef<str> for ImageOutputType {
917 fn as_ref(&self) -> &str {
919 match self {
920 ImageOutputType::Png => "png",
921 #[cfg(feature = "image-jpg")]
922 ImageOutputType::Jpg => "jpg",
923 #[cfg(feature = "image-webp")]
924 ImageOutputType::Webp => "webp",
925 #[cfg(feature = "image-jxl")]
926 ImageOutputType::Jxl => "jxl",
927 }
928 }
929}
930
931#[cfg(feature = "image")]
932#[derive(Clone, Debug)]
933pub struct ImageData {
935 pub width: u32,
937 pub height: u32,
939 pub color_type: ImageColorType,
941 pub depth: u8,
943 pub data: Vec<u8>,
945}
946
947#[cfg(feature = "image")]
948#[derive(Clone, Debug)]
949pub struct ImageDataWithName {
951 pub name: String,
953 pub data: ImageData,
955}
956
957#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
958pub enum BomType {
960 None,
962 Utf8,
964 Utf16LE,
966 Utf16BE,
968}
969
970impl BomType {
971 pub fn as_bytes(&self) -> &'static [u8] {
973 match self {
974 BomType::None => &[],
975 BomType::Utf8 => b"\xEF\xBB\xBF",
976 BomType::Utf16LE => b"\xFF\xFE",
977 BomType::Utf16BE => b"\xFE\xFF",
978 }
979 }
980}
981
982#[cfg(feature = "image")]
983#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
984pub enum PngCompressionLevel {
986 #[value(alias = "n")]
987 NoCompression,
989 #[value(alias = "d")]
990 Default,
992 Fastest,
998 #[value(alias = "f")]
999 Fast,
1001 #[value(alias = "b")]
1002 Best,
1004 #[value(alias = "h")]
1005 High,
1007}
1008
1009#[cfg(feature = "image")]
1010impl Default for PngCompressionLevel {
1011 fn default() -> Self {
1012 PngCompressionLevel::Default
1013 }
1014}
1015
1016#[cfg(feature = "image")]
1017impl PngCompressionLevel {
1018 pub fn to_compression(&self) -> png::Compression {
1020 match self {
1021 PngCompressionLevel::NoCompression => png::Compression::NoCompression,
1022 PngCompressionLevel::Fastest => png::Compression::Fastest,
1023 PngCompressionLevel::Default => png::Compression::Balanced,
1024 PngCompressionLevel::Fast => png::Compression::Fast,
1025 PngCompressionLevel::Best => png::Compression::High,
1026 PngCompressionLevel::High => png::Compression::High,
1027 }
1028 }
1029}
1030
1031#[cfg(feature = "lossless-audio")]
1032#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
1033pub enum LosslessAudioFormat {
1035 Wav,
1037 #[cfg(feature = "audio-flac")]
1038 Flac,
1040}
1041
1042#[cfg(feature = "lossless-audio")]
1043impl Default for LosslessAudioFormat {
1044 fn default() -> Self {
1045 LosslessAudioFormat::Wav
1046 }
1047}
1048
1049#[cfg(feature = "lossless-audio")]
1050impl TryFrom<&str> for LosslessAudioFormat {
1051 type Error = anyhow::Error;
1052 fn try_from(value: &str) -> Result<Self, Self::Error> {
1055 match value.to_ascii_lowercase().as_str() {
1056 "wav" => Ok(LosslessAudioFormat::Wav),
1057 #[cfg(feature = "audio-flac")]
1058 "flac" => Ok(LosslessAudioFormat::Flac),
1059 _ => Err(anyhow::anyhow!(
1060 "Unsupported lossless audio format: {}",
1061 value
1062 )),
1063 }
1064 }
1065}
1066
1067#[cfg(feature = "lossless-audio")]
1068impl TryFrom<&std::path::Path> for LosslessAudioFormat {
1069 type Error = anyhow::Error;
1070
1071 fn try_from(value: &std::path::Path) -> Result<Self, Self::Error> {
1072 if let Some(ext) = value.extension() {
1073 Self::try_from(ext.to_string_lossy().as_ref())
1074 } else {
1075 Err(anyhow::anyhow!("No extension found in path"))
1076 }
1077 }
1078}
1079
1080#[cfg(feature = "lossless-audio")]
1081impl AsRef<str> for LosslessAudioFormat {
1082 fn as_ref(&self) -> &str {
1084 match self {
1085 LosslessAudioFormat::Wav => "wav",
1086 #[cfg(feature = "audio-flac")]
1087 LosslessAudioFormat::Flac => "flac",
1088 }
1089 }
1090}
1091
1092#[allow(unused)]
1093pub(crate) fn get_default_threads() -> usize {
1094 num_cpus::get().max(2) / 2
1095}