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
198#[doc(hidden)]
208pub trait ComponentRowSink {
209 fn write_rows(&mut self, x: u32, y: u32, planes: &[ComponentPlane<'_>]);
211}
212
213pub struct DecodedComponents<'a> {
215 pub(crate) dimensions: (u32, u32),
216 pub(crate) color_space: ColorSpace,
217 pub(crate) has_alpha: bool,
218 pub(crate) planes: Vec<ComponentPlane<'a>>,
219 pub(crate) live_bytes: usize,
220}
221
222#[doc(hidden)]
224pub struct DecodedComponentsParts<'a> {
225 pub dimensions: (u32, u32),
227 pub color_space: ColorSpace,
229 pub has_alpha: bool,
231 pub planes: Vec<ComponentPlane<'a>>,
233}
234
235impl<'a> DecodedComponents<'a> {
236 #[must_use]
238 pub fn dimensions(&self) -> (u32, u32) {
239 self.dimensions
240 }
241
242 #[must_use]
244 pub fn color_space(&self) -> &ColorSpace {
245 &self.color_space
246 }
247
248 #[must_use]
250 pub fn has_alpha(&self) -> bool {
251 self.has_alpha
252 }
253
254 #[must_use]
256 pub fn planes(&self) -> &[ComponentPlane<'a>] {
257 &self.planes
258 }
259
260 #[doc(hidden)]
262 #[must_use]
263 pub fn live_bytes(&self) -> usize {
264 self.live_bytes
265 }
266
267 #[doc(hidden)]
269 #[must_use]
270 pub fn into_parts(self) -> DecodedComponentsParts<'a> {
271 DecodedComponentsParts {
272 dimensions: self.dimensions,
273 color_space: self.color_space,
274 has_alpha: self.has_alpha,
275 planes: self.planes,
276 }
277 }
278}
279
280pub(crate) fn native_component_plane_dimensions(
281 reference_dimensions: (u32, u32),
282 sampling: (u8, u8),
283 sample_count: usize,
284) -> Result<(u32, u32)> {
285 let reference_sample_count =
286 checked_decode_sample_count(reference_dimensions.0, reference_dimensions.1)?;
287 if sample_count == reference_sample_count {
288 return Ok(reference_dimensions);
289 }
290
291 let (x_rsiz, y_rsiz) = sampling;
292 if x_rsiz == 0 || y_rsiz == 0 {
293 bail!(DecodingError::CodeBlockDecodeFailure);
294 }
295 let sampled_dimensions = (
296 reference_dimensions.0.div_ceil(u32::from(x_rsiz)),
297 reference_dimensions.1.div_ceil(u32::from(y_rsiz)),
298 );
299 let sampled_sample_count =
300 checked_decode_sample_count(sampled_dimensions.0, sampled_dimensions.1)?;
301 if sample_count == sampled_sample_count {
302 return Ok(sampled_dimensions);
303 }
304
305 bail!(DecodingError::CodeBlockDecodeFailure)
306}
307
308#[cfg(test)]
309mod tests {
310 use alloc::vec::Vec;
311 use core::mem::size_of;
312
313 use super::*;
314
315 #[test]
316 fn native_component_handoff_preserves_owned_capacities() {
317 let mut data = Vec::with_capacity(9);
318 data.push(3);
319 let mut planes = Vec::with_capacity(4);
320 planes.push(NativeComponentPlane {
321 data,
322 dimensions: (1, 1),
323 bit_depth: 8,
324 signed: false,
325 sampling: (1, 1),
326 bytes_per_sample: 1,
327 });
328 let mut profile = Vec::with_capacity(7);
329 profile.push(1);
330 let decoded = DecodedNativeComponents {
331 dimensions: (1, 1),
332 color_space: ColorSpace::Icc {
333 profile,
334 num_channels: 1,
335 },
336 has_alpha: false,
337 planes,
338 };
339 let expected = decoded.planes.capacity() * size_of::<NativeComponentPlane>()
340 + decoded.planes[0].data.capacity()
341 + match &decoded.color_space {
342 ColorSpace::Icc { profile, .. } => profile.capacity(),
343 _ => 0,
344 };
345 let plane_owner_capacity = decoded.planes.capacity();
346 let data_capacity = decoded.planes[0].data.capacity();
347 let profile_capacity = match &decoded.color_space {
348 ColorSpace::Icc { profile, .. } => profile.capacity(),
349 _ => 0,
350 };
351 assert_eq!(decoded.allocated_bytes(), Some(expected));
352
353 let DecodedNativeComponentsParts {
354 color_space,
355 planes,
356 ..
357 } = decoded.into_parts();
358 assert_eq!(planes.capacity(), plane_owner_capacity);
359 assert_eq!(planes[0].allocated_bytes(), data_capacity);
360 assert!(matches!(
361 color_space,
362 ColorSpace::Icc { profile, .. } if profile.capacity() == profile_capacity
363 ));
364 }
365
366 #[test]
367 fn borrowed_component_handoff_preserves_metadata_capacities() {
368 let samples = [2.0_f32];
369 let mut planes = Vec::with_capacity(3);
370 planes.push(ComponentPlane {
371 samples: &samples,
372 dimensions: (1, 1),
373 bit_depth: 8,
374 signed: false,
375 sampling: (1, 1),
376 });
377 let mut profile = Vec::with_capacity(5);
378 profile.push(1);
379 let decoded = DecodedComponents {
380 dimensions: (1, 1),
381 color_space: ColorSpace::Icc {
382 profile,
383 num_channels: 1,
384 },
385 has_alpha: false,
386 planes,
387 live_bytes: 123,
388 };
389 let plane_owner_capacity = decoded.planes.capacity();
390 let profile_capacity = match &decoded.color_space {
391 ColorSpace::Icc { profile, .. } => profile.capacity(),
392 _ => 0,
393 };
394
395 assert_eq!(decoded.live_bytes(), 123);
396 let DecodedComponentsParts {
397 color_space,
398 planes,
399 ..
400 } = decoded.into_parts();
401 assert_eq!(planes.capacity(), plane_owner_capacity);
402 assert!(core::ptr::eq(
403 planes[0].samples().as_ptr(),
404 samples.as_ptr()
405 ));
406 assert!(matches!(
407 color_space,
408 ColorSpace::Icc { profile, .. } if profile.capacity() == profile_capacity
409 ));
410 }
411}