1use 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 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 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 pub color_data_format: Option<JxlDataFormat>,
157 pub extra_channel_format: Vec<Option<JxlDataFormat>>,
158}
159
160impl JxlPixelFormat {
161 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 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 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 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 pub bits_per_sample: u32,
252 pub name: String,
254 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 pub size: (usize, usize),
272}