1use alloc::vec::Vec;
6
7use super::ColorSpace;
8use crate::error::bail;
9use crate::{checked_decode_sample_count, DecodingError, Result};
10
11pub struct NativeComponentPlane {
13 pub(crate) data: Vec<u8>,
14 pub(crate) dimensions: (u32, u32),
15 pub(crate) bit_depth: u8,
16 pub(crate) signed: bool,
17 pub(crate) sampling: (u8, u8),
18 pub(crate) bytes_per_sample: u8,
19}
20
21#[doc(hidden)]
23pub struct NativeComponentPlaneParts {
24 pub data: Vec<u8>,
26 pub dimensions: (u32, u32),
28 pub bit_depth: u8,
30 pub signed: bool,
32 pub sampling: (u8, u8),
34 pub bytes_per_sample: u8,
36}
37
38impl NativeComponentPlane {
39 #[must_use]
41 pub fn data(&self) -> &[u8] {
42 &self.data
43 }
44
45 crate::__j2k_component_plane_metadata_accessors!();
46
47 #[must_use]
49 pub fn bytes_per_sample(&self) -> u8 {
50 self.bytes_per_sample
51 }
52
53 #[doc(hidden)]
55 #[must_use]
56 pub fn allocated_bytes(&self) -> usize {
57 self.data.capacity()
58 }
59
60 #[doc(hidden)]
62 #[must_use]
63 pub fn into_parts(self) -> NativeComponentPlaneParts {
64 NativeComponentPlaneParts {
65 data: self.data,
66 dimensions: self.dimensions,
67 bit_depth: self.bit_depth,
68 signed: self.signed,
69 sampling: self.sampling,
70 bytes_per_sample: self.bytes_per_sample,
71 }
72 }
73}
74
75pub struct DecodedNativeComponents {
77 pub(crate) dimensions: (u32, u32),
78 pub(crate) color_space: ColorSpace,
79 pub(crate) has_alpha: bool,
80 pub(crate) planes: Vec<NativeComponentPlane>,
81}
82
83#[doc(hidden)]
85pub struct DecodedNativeComponentsParts {
86 pub dimensions: (u32, u32),
88 pub color_space: ColorSpace,
90 pub has_alpha: bool,
92 pub planes: Vec<NativeComponentPlane>,
94}
95
96impl DecodedNativeComponents {
97 #[must_use]
99 pub fn dimensions(&self) -> (u32, u32) {
100 self.dimensions
101 }
102
103 #[must_use]
105 pub fn color_space(&self) -> &ColorSpace {
106 &self.color_space
107 }
108
109 #[must_use]
111 pub fn has_alpha(&self) -> bool {
112 self.has_alpha
113 }
114
115 #[must_use]
117 pub fn planes(&self) -> &[NativeComponentPlane] {
118 &self.planes
119 }
120
121 #[doc(hidden)]
123 #[must_use]
124 pub fn allocated_bytes(&self) -> Option<usize> {
125 let mut bytes = self
126 .planes
127 .capacity()
128 .checked_mul(core::mem::size_of::<NativeComponentPlane>())?;
129 for plane in &self.planes {
130 bytes = bytes.checked_add(plane.allocated_bytes())?;
131 }
132 if let ColorSpace::Icc { profile, .. } = &self.color_space {
133 bytes = bytes.checked_add(profile.capacity())?;
134 }
135 Some(bytes)
136 }
137
138 #[doc(hidden)]
140 #[must_use]
141 pub fn into_parts(self) -> DecodedNativeComponentsParts {
142 DecodedNativeComponentsParts {
143 dimensions: self.dimensions,
144 color_space: self.color_space,
145 has_alpha: self.has_alpha,
146 planes: self.planes,
147 }
148 }
149}
150
151pub struct ComponentPlane<'a> {
153 pub(crate) samples: &'a [f32],
154 pub(crate) dimensions: (u32, u32),
155 pub(crate) bit_depth: u8,
156 pub(crate) signed: bool,
157 pub(crate) sampling: (u8, u8),
158}
159
160#[doc(hidden)]
162pub struct ComponentPlaneParts<'a> {
163 pub samples: &'a [f32],
165 pub dimensions: (u32, u32),
167 pub bit_depth: u8,
169 pub signed: bool,
171 pub sampling: (u8, u8),
173}
174
175impl<'a> ComponentPlane<'a> {
176 #[must_use]
178 pub fn samples(&self) -> &'a [f32] {
179 self.samples
180 }
181
182 crate::__j2k_component_plane_metadata_accessors!();
183
184 #[doc(hidden)]
186 #[must_use]
187 pub fn into_parts(self) -> ComponentPlaneParts<'a> {
188 ComponentPlaneParts {
189 samples: self.samples,
190 dimensions: self.dimensions,
191 bit_depth: self.bit_depth,
192 signed: self.signed,
193 sampling: self.sampling,
194 }
195 }
196}
197
198pub struct DecodedComponents<'a> {
200 pub(crate) dimensions: (u32, u32),
201 pub(crate) color_space: ColorSpace,
202 pub(crate) has_alpha: bool,
203 pub(crate) planes: Vec<ComponentPlane<'a>>,
204 pub(crate) live_bytes: usize,
205}
206
207#[doc(hidden)]
209pub struct DecodedComponentsParts<'a> {
210 pub dimensions: (u32, u32),
212 pub color_space: ColorSpace,
214 pub has_alpha: bool,
216 pub planes: Vec<ComponentPlane<'a>>,
218}
219
220impl<'a> DecodedComponents<'a> {
221 #[must_use]
223 pub fn dimensions(&self) -> (u32, u32) {
224 self.dimensions
225 }
226
227 #[must_use]
229 pub fn color_space(&self) -> &ColorSpace {
230 &self.color_space
231 }
232
233 #[must_use]
235 pub fn has_alpha(&self) -> bool {
236 self.has_alpha
237 }
238
239 #[must_use]
241 pub fn planes(&self) -> &[ComponentPlane<'a>] {
242 &self.planes
243 }
244
245 #[doc(hidden)]
247 #[must_use]
248 pub fn live_bytes(&self) -> usize {
249 self.live_bytes
250 }
251
252 #[doc(hidden)]
254 #[must_use]
255 pub fn into_parts(self) -> DecodedComponentsParts<'a> {
256 DecodedComponentsParts {
257 dimensions: self.dimensions,
258 color_space: self.color_space,
259 has_alpha: self.has_alpha,
260 planes: self.planes,
261 }
262 }
263}
264
265pub(crate) fn native_component_plane_dimensions(
266 reference_dimensions: (u32, u32),
267 sampling: (u8, u8),
268 sample_count: usize,
269) -> Result<(u32, u32)> {
270 let reference_sample_count =
271 checked_decode_sample_count(reference_dimensions.0, reference_dimensions.1)?;
272 if sample_count == reference_sample_count {
273 return Ok(reference_dimensions);
274 }
275
276 let (x_rsiz, y_rsiz) = sampling;
277 if x_rsiz == 0 || y_rsiz == 0 {
278 bail!(DecodingError::CodeBlockDecodeFailure);
279 }
280 let sampled_dimensions = (
281 reference_dimensions.0.div_ceil(u32::from(x_rsiz)),
282 reference_dimensions.1.div_ceil(u32::from(y_rsiz)),
283 );
284 let sampled_sample_count =
285 checked_decode_sample_count(sampled_dimensions.0, sampled_dimensions.1)?;
286 if sample_count == sampled_sample_count {
287 return Ok(sampled_dimensions);
288 }
289
290 bail!(DecodingError::CodeBlockDecodeFailure)
291}
292
293#[cfg(test)]
294mod tests {
295 use alloc::vec::Vec;
296 use core::mem::size_of;
297
298 use super::*;
299
300 #[test]
301 fn native_component_handoff_preserves_owned_capacities() {
302 let mut data = Vec::with_capacity(9);
303 data.push(3);
304 let mut planes = Vec::with_capacity(4);
305 planes.push(NativeComponentPlane {
306 data,
307 dimensions: (1, 1),
308 bit_depth: 8,
309 signed: false,
310 sampling: (1, 1),
311 bytes_per_sample: 1,
312 });
313 let mut profile = Vec::with_capacity(7);
314 profile.push(1);
315 let decoded = DecodedNativeComponents {
316 dimensions: (1, 1),
317 color_space: ColorSpace::Icc {
318 profile,
319 num_channels: 1,
320 },
321 has_alpha: false,
322 planes,
323 };
324 let expected = decoded.planes.capacity() * size_of::<NativeComponentPlane>()
325 + decoded.planes[0].data.capacity()
326 + match &decoded.color_space {
327 ColorSpace::Icc { profile, .. } => profile.capacity(),
328 _ => 0,
329 };
330 let plane_owner_capacity = decoded.planes.capacity();
331 let data_capacity = decoded.planes[0].data.capacity();
332 let profile_capacity = match &decoded.color_space {
333 ColorSpace::Icc { profile, .. } => profile.capacity(),
334 _ => 0,
335 };
336 assert_eq!(decoded.allocated_bytes(), Some(expected));
337
338 let DecodedNativeComponentsParts {
339 color_space,
340 planes,
341 ..
342 } = decoded.into_parts();
343 assert_eq!(planes.capacity(), plane_owner_capacity);
344 assert_eq!(planes[0].allocated_bytes(), data_capacity);
345 assert!(matches!(
346 color_space,
347 ColorSpace::Icc { profile, .. } if profile.capacity() == profile_capacity
348 ));
349 }
350
351 #[test]
352 fn borrowed_component_handoff_preserves_metadata_capacities() {
353 let samples = [2.0_f32];
354 let mut planes = Vec::with_capacity(3);
355 planes.push(ComponentPlane {
356 samples: &samples,
357 dimensions: (1, 1),
358 bit_depth: 8,
359 signed: false,
360 sampling: (1, 1),
361 });
362 let mut profile = Vec::with_capacity(5);
363 profile.push(1);
364 let decoded = DecodedComponents {
365 dimensions: (1, 1),
366 color_space: ColorSpace::Icc {
367 profile,
368 num_channels: 1,
369 },
370 has_alpha: false,
371 planes,
372 live_bytes: 123,
373 };
374 let plane_owner_capacity = decoded.planes.capacity();
375 let profile_capacity = match &decoded.color_space {
376 ColorSpace::Icc { profile, .. } => profile.capacity(),
377 _ => 0,
378 };
379
380 assert_eq!(decoded.live_bytes(), 123);
381 let DecodedComponentsParts {
382 color_space,
383 planes,
384 ..
385 } = decoded.into_parts();
386 assert_eq!(planes.capacity(), plane_owner_capacity);
387 assert!(core::ptr::eq(
388 planes[0].samples().as_ptr(),
389 samples.as_ptr()
390 ));
391 assert!(matches!(
392 color_space,
393 ColorSpace::Icc { profile, .. } if profile.capacity() == profile_capacity
394 ));
395 }
396}