jxl_oxide_cli/commands/
decode.rs

1use std::path::PathBuf;
2
3use clap::Parser;
4use jxl_oxide::{CropInfo, EnumColourEncoding};
5
6#[derive(Debug, Parser)]
7#[non_exhaustive]
8pub struct DecodeArgs {
9    /// Output file
10    #[arg(short, long)]
11    pub output: Option<PathBuf>,
12    /// Output ICC file
13    #[arg(long)]
14    pub icc_output: Option<PathBuf>,
15    /// Input file
16    pub input: PathBuf,
17    /// (unstable) Region to render, in format of 'width height left top'
18    #[arg(long, value_parser = parse_crop_info)]
19    pub crop: Option<CropInfo>,
20    /// (unstable) Approximate memory limit, in bytes
21    #[arg(long, default_value_t = 0)]
22    pub approx_memory_limit: usize,
23    /// Format to output
24    #[arg(value_enum, short = 'f', long)]
25    pub output_format: Option<OutputFormat>,
26    #[allow(clippy::doc_overindented_list_items, reason = "verbatim doc comment")]
27    /// (unstable) Target colorspace specification
28    ///
29    /// Specification string consists of (optional) preset and a sequence of parameters delimited by commas.
30    ///
31    /// Parameters have a syntax of `name=value`. Possible parameter names:
32    /// - type:   Color space type. Possible values:
33    ///           - rgb
34    ///           - gray
35    ///           - xyb
36    /// - gamut:  Color gamut. Invalid if type is Gray or XYB. Possible values:
37    ///           - srgb
38    ///           - p3
39    ///           - bt2100
40    /// - wp:     White point. Invalid if type is XYB. Possible values:
41    ///           - d65
42    ///           - d50
43    ///           - dci
44    ///           - e
45    /// - tf:     Transfer function. Invalid if type is XYB. Possible values:
46    ///           - srgb
47    ///           - bt709
48    ///           - dci
49    ///           - pq
50    ///           - hlg
51    ///           - linear
52    ///           - (gamma value)
53    /// - intent: Rendering intent. Possible values:
54    ///           - relative
55    ///           - perceptual
56    ///           - saturation
57    ///           - absolute
58    ///
59    /// Presets define a set of parameters commonly used together. Possible presets:
60    /// - srgb:       type=rgb,gamut=srgb,wp=d65,tf=srgb,intent=relative
61    /// - display_p3: type=rgb,gamut=p3,wp=d65,tf=srgb,intent=relative
62    /// - rec2020:    type=rgb,gamut=bt2100,wp=d65,tf=bt709,intent=relative
63    /// - rec2100:    type=rgb,gamut=bt2100,wp=d65,intent=relative
64    ///               Transfer function is not set for this preset; one should be provided, e.g. rec2100,tf=pq
65    #[arg(long, value_parser = super::parse_color_encoding, verbatim_doc_comment)]
66    pub target_colorspace: Option<EnumColourEncoding>,
67    /// (unstable) Path to target ICC profile
68    #[arg(long)]
69    pub target_icc: Option<PathBuf>,
70    /// Number of parallelism to use
71    #[cfg_attr(feature = "rayon", arg(short = 'j', long))]
72    #[cfg_attr(not(feature = "rayon"), arg(skip))]
73    pub num_threads: Option<usize>,
74    /// Number of repeated decoding, used for benchmarking
75    #[arg(long, value_parser = clap::value_parser!(u32).range(1..))]
76    pub num_reps: Option<u32>,
77    /// External color management system to use for ICC profiles.
78    ///
79    /// External CMS will handle ICC profiles jxl-oxide cannot handle.
80    #[arg(long)]
81    pub cms: Option<Cms>,
82    /// (unstable) Force 32-bit Modular buffers when decoding.
83    #[arg(long)]
84    pub force_wide_buffers: bool,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
88pub enum OutputFormat {
89    /// PNG, respects bit depth information.
90    Png,
91    /// PNG, always 8-bit.
92    Png8,
93    /// PNG, always 16-bit.
94    Png16,
95    /// JPEG bitstream reconstruction.
96    #[value(name = "jpeg", alias("jpg"))]
97    JpegReconstruct,
98    /// Numpy, used for conformance test.
99    Npy,
100}
101
102#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
103pub enum Cms {
104    /// Little CMS 2.
105    #[default]
106    Lcms2,
107    /// moxcms crate.
108    Moxcms,
109}
110
111fn parse_crop_info(s: &str) -> Result<CropInfo, std::num::ParseIntError> {
112    let s = s.trim();
113    let mut it = s.split_whitespace().map(|s| s.parse::<u32>());
114    let Some(w) = it.next().transpose()? else {
115        return Ok(CropInfo {
116            width: 0,
117            height: 0,
118            left: 0,
119            top: 0,
120        });
121    };
122    let Some(h) = it.next().transpose()? else {
123        return Ok(CropInfo {
124            width: w,
125            height: w,
126            left: 0,
127            top: 0,
128        });
129    };
130    let Some(x) = it.next().transpose()? else {
131        return Ok(CropInfo {
132            width: w,
133            height: h,
134            left: 0,
135            top: 0,
136        });
137    };
138    let Some(y) = it.next().transpose()? else {
139        return Ok(CropInfo {
140            width: w,
141            height: w,
142            left: h,
143            top: x,
144        });
145    };
146    Ok(CropInfo {
147        width: w,
148        height: h,
149        left: x,
150        top: y,
151    })
152}