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