Skip to main content

zenjxl_decoder/api/
data_types.rs

1// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6use crate::{headers::extra_channels::ExtraChannel, image::DataTypeTag};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum JxlColorType {
10    Grayscale,
11    GrayscaleAlpha,
12    Rgb,
13    Rgba,
14    Bgr,
15    Bgra,
16}
17
18impl JxlColorType {
19    pub fn has_alpha(&self) -> bool {
20        match self {
21            Self::Grayscale => false,
22            Self::GrayscaleAlpha => true,
23            Self::Rgb | Self::Bgr => false,
24            Self::Rgba | Self::Bgra => true,
25        }
26    }
27    pub fn samples_per_pixel(&self) -> usize {
28        match self {
29            Self::Grayscale => 1,
30            Self::GrayscaleAlpha => 2,
31            Self::Rgb | Self::Bgr => 3,
32            Self::Rgba | Self::Bgra => 4,
33        }
34    }
35    pub fn is_grayscale(&self) -> bool {
36        match self {
37            Self::Grayscale => true,
38            Self::GrayscaleAlpha => true,
39            Self::Rgb | Self::Bgr => false,
40            Self::Rgba | Self::Bgra => false,
41        }
42    }
43    pub fn add_alpha(&self) -> Self {
44        match self {
45            Self::Grayscale | Self::GrayscaleAlpha => Self::GrayscaleAlpha,
46            Self::Rgb | Self::Rgba => Self::Rgba,
47            Self::Bgr | Self::Bgra => Self::Bgra,
48        }
49    }
50}
51
52#[derive(Clone, Copy, Debug, PartialEq, Eq)]
53pub enum Endianness {
54    LittleEndian,
55    BigEndian,
56}
57
58impl Endianness {
59    pub fn native() -> Self {
60        #[cfg(target_endian = "little")]
61        {
62            Endianness::LittleEndian
63        }
64        #[cfg(target_endian = "big")]
65        {
66            Endianness::BigEndian
67        }
68    }
69}
70
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub enum JxlDataFormat {
73    U8 {
74        bit_depth: u8,
75    },
76    U16 {
77        endianness: Endianness,
78        bit_depth: u8,
79    },
80    F16 {
81        endianness: Endianness,
82    },
83    F32 {
84        endianness: Endianness,
85    },
86}
87
88impl JxlDataFormat {
89    pub fn bytes_per_sample(&self) -> usize {
90        match self {
91            Self::U8 { .. } => 1,
92            Self::U16 { .. } | Self::F16 { .. } => 2,
93            Self::F32 { .. } => 4,
94        }
95    }
96
97    pub fn f32() -> Self {
98        Self::F32 {
99            endianness: Endianness::native(),
100        }
101    }
102
103    pub(crate) fn data_type(&self) -> DataTypeTag {
104        match self {
105            JxlDataFormat::U8 { .. } => DataTypeTag::U8,
106            JxlDataFormat::U16 { .. } => DataTypeTag::U16,
107            JxlDataFormat::F16 { .. } => DataTypeTag::F16,
108            JxlDataFormat::F32 { .. } => DataTypeTag::F32,
109        }
110    }
111
112    /// Returns the byte representation of opaque alpha (1.0) for this format.
113    pub(crate) fn opaque_alpha_bytes(&self) -> Vec<u8> {
114        match self {
115            JxlDataFormat::U8 { bit_depth } => {
116                let val = (1u16 << bit_depth) - 1;
117                vec![val as u8]
118            }
119            JxlDataFormat::U16 {
120                endianness,
121                bit_depth,
122            } => {
123                let val = (1u32 << bit_depth) - 1;
124                let val = val as u16;
125                if *endianness == Endianness::LittleEndian {
126                    val.to_le_bytes().to_vec()
127                } else {
128                    val.to_be_bytes().to_vec()
129                }
130            }
131            JxlDataFormat::F16 { endianness } => {
132                // 1.0 in f16 is 0x3C00
133                let val: u16 = 0x3C00;
134                if *endianness == Endianness::LittleEndian {
135                    val.to_le_bytes().to_vec()
136                } else {
137                    val.to_be_bytes().to_vec()
138                }
139            }
140            JxlDataFormat::F32 { endianness } => {
141                let val: f32 = 1.0;
142                if *endianness == Endianness::LittleEndian {
143                    val.to_le_bytes().to_vec()
144                } else {
145                    val.to_be_bytes().to_vec()
146                }
147            }
148        }
149    }
150}
151
152#[derive(Clone, Debug, PartialEq, Eq)]
153pub struct JxlPixelFormat {
154    pub color_type: JxlColorType,
155    // None -> ignore
156    pub color_data_format: Option<JxlDataFormat>,
157    pub extra_channel_format: Vec<Option<JxlDataFormat>>,
158}
159
160impl JxlPixelFormat {
161    /// Creates an RGBA 8-bit pixel format.
162    pub fn rgba8(num_extra_channels: usize) -> Self {
163        Self {
164            color_type: JxlColorType::Rgba,
165            color_data_format: Some(JxlDataFormat::U8 { bit_depth: 8 }),
166            extra_channel_format: vec![
167                Some(JxlDataFormat::U8 { bit_depth: 8 });
168                num_extra_channels
169            ],
170        }
171    }
172
173    /// Creates an RGBA 16-bit pixel format.
174    pub fn rgba16(num_extra_channels: usize) -> Self {
175        Self {
176            color_type: JxlColorType::Rgba,
177            color_data_format: Some(JxlDataFormat::U16 {
178                endianness: Endianness::native(),
179                bit_depth: 16,
180            }),
181            extra_channel_format: vec![
182                Some(JxlDataFormat::U16 {
183                    endianness: Endianness::native(),
184                    bit_depth: 16,
185                });
186                num_extra_channels
187            ],
188        }
189    }
190
191    /// Creates an RGBA f16 pixel format.
192    pub fn rgba_f16(num_extra_channels: usize) -> Self {
193        Self {
194            color_type: JxlColorType::Rgba,
195            color_data_format: Some(JxlDataFormat::F16 {
196                endianness: Endianness::native(),
197            }),
198            extra_channel_format: vec![
199                Some(JxlDataFormat::F16 {
200                    endianness: Endianness::native(),
201                });
202                num_extra_channels
203            ],
204        }
205    }
206
207    /// Creates an RGBA f32 pixel format.
208    pub fn rgba_f32(num_extra_channels: usize) -> Self {
209        Self {
210            color_type: JxlColorType::Rgba,
211            color_data_format: Some(JxlDataFormat::F32 {
212                endianness: Endianness::native(),
213            }),
214            extra_channel_format: vec![
215                Some(JxlDataFormat::F32 {
216                    endianness: Endianness::native(),
217                });
218                num_extra_channels
219            ],
220        }
221    }
222}
223
224#[derive(Clone, Debug, PartialEq, Eq)]
225pub enum JxlBitDepth {
226    Int {
227        bits_per_sample: u32,
228    },
229    Float {
230        bits_per_sample: u32,
231        exponent_bits_per_sample: u32,
232    },
233}
234
235impl JxlBitDepth {
236    pub fn bits_per_sample(&self) -> u32 {
237        match self {
238            JxlBitDepth::Int { bits_per_sample: b } => *b,
239            JxlBitDepth::Float {
240                bits_per_sample: b, ..
241            } => *b,
242        }
243    }
244}
245
246#[derive(Clone, Debug, PartialEq, Eq)]
247pub struct JxlExtraChannel {
248    pub ec_type: ExtraChannel,
249    pub alpha_associated: bool,
250    /// Bits per sample for this extra channel.
251    pub bits_per_sample: u32,
252    /// Channel name (empty string if unnamed).
253    pub name: String,
254    /// Dimensional shift (0 = full resolution, 1 = half, etc.).
255    pub dim_shift: u32,
256}
257
258#[derive(Clone, Debug, PartialEq, Eq)]
259pub struct JxlAnimation {
260    pub tps_numerator: u32,
261    pub tps_denominator: u32,
262    pub num_loops: u32,
263    pub have_timecodes: bool,
264}
265
266#[derive(Clone, Debug)]
267pub struct JxlFrameHeader {
268    pub name: String,
269    pub duration: Option<f64>,
270    /// Frame size (width, height)
271    pub size: (usize, usize),
272}