1use crate::{
7 bit_reader::BitReader,
8 error::Error,
9 headers::{bit_depth::*, color_encoding::*, encodings::*, extra_channels::*, size::*},
10 image::Rect,
11};
12use jxl_macros::UnconditionalCoder;
13use num_derive::FromPrimitive;
14
15#[derive(Debug, Default, Clone)]
16pub struct Signature;
17
18impl Signature {
19 #[allow(dead_code)]
20 pub fn new() -> Signature {
21 Signature {}
22 }
23}
24
25impl crate::headers::encodings::UnconditionalCoder<()> for Signature {
26 type Nonserialized = Empty;
27 fn read_unconditional(_: &(), br: &mut BitReader, _: &Empty) -> Result<Signature, Error> {
28 let sig1 = br.read(8)? as u8;
29 let sig2 = br.read(8)? as u8;
30 if (sig1, sig2) != (0xff, 0x0a) {
31 Err(Error::InvalidSignature)
32 } else {
33 Ok(Signature {})
34 }
35 }
36}
37
38#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
39pub enum Orientation {
40 Identity = 1,
41 FlipHorizontal = 2,
42 Rotate180 = 3,
43 FlipVertical = 4,
44 Transpose = 5,
45 Rotate90Cw = 6,
46 AntiTranspose = 7,
47 Rotate90Ccw = 8,
48}
49
50impl Orientation {
51 pub fn is_transposing(&self) -> bool {
52 matches!(
53 self,
54 Orientation::Transpose
55 | Orientation::AntiTranspose
56 | Orientation::Rotate90Cw
57 | Orientation::Rotate90Ccw
58 )
59 }
60
61 pub fn map_size(&self, size: (usize, usize)) -> (usize, usize) {
62 if self.is_transposing() {
63 (size.1, size.0)
64 } else {
65 size
66 }
67 }
68
69 pub fn display_pixel(&self, (x, y): (usize, usize), size: (usize, usize)) -> (usize, usize) {
70 match self {
71 Orientation::Identity => (x, y),
72 Orientation::FlipHorizontal => (size.0 - 1 - x, y),
73 Orientation::Rotate180 => (size.0 - 1 - x, size.1 - 1 - y),
74 Orientation::FlipVertical => (x, size.1 - 1 - y),
75 Orientation::Transpose => (y, x),
76 Orientation::Rotate90Cw => (size.1 - 1 - y, x),
77 Orientation::AntiTranspose => (size.1 - 1 - y, size.0 - 1 - x),
78 Orientation::Rotate90Ccw => (y, size.0 - 1 - x),
79 }
80 }
81
82 pub fn display_row_step(&self) -> (isize, isize) {
88 match self {
89 Orientation::Identity | Orientation::FlipVertical => (1, 0),
90 Orientation::FlipHorizontal | Orientation::Rotate180 => (-1, 0),
91 Orientation::Transpose | Orientation::Rotate90Cw => (0, 1),
92 Orientation::AntiTranspose | Orientation::Rotate90Ccw => (0, -1),
93 }
94 }
95
96 pub fn display_rect(
97 &self,
98 Rect {
99 size: (sx, sy),
100 origin: (ox, oy),
101 }: Rect,
102 size: (usize, usize),
103 ) -> Rect {
104 match self {
105 Orientation::Identity => Rect {
106 origin: (ox, oy),
107 size: (sx, sy),
108 },
109 Orientation::FlipHorizontal => Rect {
110 origin: (size.0 - sx - ox, oy),
111 size: (sx, sy),
112 },
113 Orientation::Rotate180 => Rect {
114 origin: (size.0 - sx - ox, size.1 - sy - oy),
115 size: (sx, sy),
116 },
117 Orientation::FlipVertical => Rect {
118 origin: (ox, size.1 - sy - oy),
119 size: (sx, sy),
120 },
121 Orientation::Transpose => Rect {
122 origin: (oy, ox),
123 size: (sy, sx),
124 },
125 Orientation::Rotate90Cw => Rect {
126 origin: (size.1 - sy - oy, ox),
127 size: (sy, sx),
128 },
129 Orientation::AntiTranspose => Rect {
130 origin: (size.1 - sy - oy, size.0 - sx - ox),
131 size: (sy, sx),
132 },
133 Orientation::Rotate90Ccw => Rect {
134 origin: (oy, size.0 - sx - ox),
135 size: (sy, sx),
136 },
137 }
138 }
139}
140
141#[derive(UnconditionalCoder, Debug, Clone)]
142pub struct Animation {
143 #[coder(u2S(100, 1000, Bits(10) + 1, Bits(30) + 1))]
144 pub tps_numerator: u32,
145 #[coder(u2S(1, 1001, Bits(8) + 1, Bits(10) + 1))]
146 pub tps_denominator: u32,
147 #[coder(u2S(0, Bits(3), Bits(16), Bits(32)))]
148 pub num_loops: u32,
149 pub have_timecodes: bool,
150}
151
152#[derive(UnconditionalCoder, Debug, Clone)]
153#[validate]
154pub struct ToneMapping {
155 #[all_default]
156 #[allow(dead_code)] pub all_default: bool,
158 #[default(255.0)]
159 pub intensity_target: f32,
160 #[default(0.0)]
161 pub min_nits: f32,
162 #[default(false)]
163 pub relative_to_max_display: bool,
164 #[default(0.0)]
165 pub linear_below: f32,
166}
167
168impl ToneMapping {
169 #[cfg(test)]
170 pub fn empty() -> ToneMapping {
171 ToneMapping {
172 all_default: false,
173 intensity_target: 0f32,
174 min_nits: 0f32,
175 relative_to_max_display: false,
176 linear_below: 0f32,
177 }
178 }
179 pub fn check(&self, _: &Empty) -> Result<(), Error> {
180 if self.intensity_target <= 0.0 {
181 Err(Error::InvalidIntensityTarget(self.intensity_target))
182 } else if self.min_nits < 0.0 || self.min_nits > self.intensity_target {
183 Err(Error::InvalidMinNits(self.min_nits))
184 } else if self.linear_below < 0.0
185 || (self.relative_to_max_display && self.linear_below > 1.0)
186 {
187 Err(Error::InvalidLinearBelow(
188 self.relative_to_max_display,
189 self.linear_below,
190 ))
191 } else {
192 Ok(())
193 }
194 }
195}
196
197#[allow(dead_code)]
198#[derive(UnconditionalCoder, Debug, Clone)]
199#[validate]
200pub struct ImageMetadata {
201 #[all_default]
202 all_default: bool,
203 #[default(false)]
204 extra_fields: bool,
205 #[condition(extra_fields)]
206 #[default(Orientation::Identity)]
207 #[coder(Bits(3) + 1)]
208 pub orientation: Orientation,
209 #[condition(extra_fields)]
210 #[default(false)]
211 have_intrinsic_size: bool, #[condition(have_intrinsic_size)]
213 pub intrinsic_size: Option<Size>,
214 #[condition(extra_fields)]
215 #[default(false)]
216 have_preview: bool,
217 #[condition(have_preview)]
218 pub preview: Option<Preview>,
219 #[condition(extra_fields)]
220 #[default(false)]
221 have_animation: bool,
222 #[condition(have_animation)]
223 pub animation: Option<Animation>,
224 #[default(BitDepth::default(&field_nonserialized))]
225 pub bit_depth: BitDepth,
226 #[default(true)]
227 pub modular_16bit_sufficient: bool,
228 #[size_coder(implicit(u2S(0, 1, Bits(4) + 2, Bits(12) + 1)))]
229 pub extra_channel_info: Vec<ExtraChannelInfo>,
230 #[default(true)]
231 pub xyb_encoded: bool,
232 #[default(ColorEncoding::default(&field_nonserialized))]
233 pub color_encoding: ColorEncoding,
234 #[condition(extra_fields)]
235 #[default(ToneMapping::default(&field_nonserialized))]
236 pub tone_mapping: ToneMapping,
237 extensions: Option<Extensions>,
238}
239
240impl ImageMetadata {
241 fn check(&self, _: &Empty) -> Result<(), Error> {
242 if self.extra_channel_info.len() > 256 {
243 return Err(Error::TooManyExtraChannels(self.extra_channel_info.len()));
244 }
245 Ok(())
246 }
247}