1use alloc::vec::Vec;
4
5use crate::error::err;
6use crate::j2c::{self, Header};
7use crate::jp2::colr::EnumeratedColorspace;
8use crate::jp2::{self, DecodedImage, ImageBoxes};
9use crate::{
10 checked_decode_byte_len3, convert_color_space, interleave_and_convert,
11 interleave_and_convert_region, resolve_palette_indices, try_resize_decode_elements,
12 validate_and_reorder_channels, validate_interleaved_output_buffer, validate_roi, Bitmap,
13 ColorSpace, DecodedComponents, DecodedNativeComponents, DecoderContext, DecodingError,
14 FormatError, HtCodeBlockDecoder, Result, CODESTREAM_MAGIC, JP2_MAGIC,
15};
16
17mod allocation;
18mod compare;
19#[cfg(test)]
20mod contract_tests;
21mod direct_api;
22mod native;
23mod output_api;
24use self::allocation::retained_metadata_bytes;
25pub(crate) use self::allocation::{retained_container_metadata_bytes, DecodeOwnerBudget};
26use self::native::{try_clone_color_space, NativeOutputBudget};
27
28#[derive(Debug, Copy, Clone)]
30pub struct DecodeSettings {
31 pub resolve_palette_indices: bool,
43 pub strict: bool,
49 pub target_resolution: Option<(u32, u32)>,
51}
52
53impl DecodeSettings {
54 #[must_use]
71 pub const fn lenient() -> Self {
72 Self {
73 resolve_palette_indices: true,
74 strict: false,
75 target_resolution: None,
76 }
77 }
78
79 #[must_use]
81 pub const fn strict() -> Self {
82 Self {
83 resolve_palette_indices: true,
84 strict: true,
85 target_resolution: None,
86 }
87 }
88
89 #[must_use]
92 pub const fn lenient_tolerance_enabled(&self) -> bool {
93 !self.strict
94 }
95}
96
97impl Default for DecodeSettings {
98 fn default() -> Self {
99 Self::strict()
100 }
101}
102
103pub struct Image<'a> {
105 pub(crate) encoded_input: &'a [u8],
108 pub(crate) codestream: &'a [u8],
110 pub(crate) header: Header<'a>,
112 pub(crate) boxes: ImageBoxes,
115 pub(crate) settings: DecodeSettings,
117 pub(crate) used_lenient_metadata_recovery: bool,
120 pub(crate) has_alpha: bool,
122 pub(crate) color_space: ColorSpace,
124}
125
126#[derive(Clone, Copy)]
127pub(crate) struct ImageSource<'a> {
128 encoded_input: &'a [u8],
129 codestream: &'a [u8],
130}
131
132impl<'a> ImageSource<'a> {
133 pub(crate) const fn new(encoded_input: &'a [u8], codestream: &'a [u8]) -> Self {
134 Self {
135 encoded_input,
136 codestream,
137 }
138 }
139}
140
141pub(crate) struct ImageProperties {
142 boxes: ImageBoxes,
143 settings: DecodeSettings,
144 color_space: ColorSpace,
145 has_alpha: bool,
146 used_lenient_metadata_recovery: bool,
147}
148
149impl ImageProperties {
150 pub(crate) const fn new(
151 boxes: ImageBoxes,
152 settings: DecodeSettings,
153 color_space: ColorSpace,
154 has_alpha: bool,
155 used_lenient_metadata_recovery: bool,
156 ) -> Self {
157 Self {
158 boxes,
159 settings,
160 color_space,
161 has_alpha,
162 used_lenient_metadata_recovery,
163 }
164 }
165}
166
167impl<'a> Image<'a> {
168 pub(crate) fn from_parsed_parts(
169 source: ImageSource<'a>,
170 header: Header<'a>,
171 properties: ImageProperties,
172 ) -> Result<Self> {
173 Self::from_parsed_parts_with_retained_baseline(source, header, properties, 0)
174 }
175
176 pub(crate) fn from_parsed_parts_with_retained_baseline(
177 source: ImageSource<'a>,
178 header: Header<'a>,
179 properties: ImageProperties,
180 retained_baseline_bytes: usize,
181 ) -> Result<Self> {
182 let ImageProperties {
183 boxes,
184 settings,
185 color_space,
186 has_alpha,
187 used_lenient_metadata_recovery,
188 } = properties;
189 let metadata_bytes = retained_metadata_bytes(&header, &boxes, &color_space)?;
190 allocation::combine_retained_bytes(retained_baseline_bytes, metadata_bytes)?;
191 Ok(Self {
192 encoded_input: source.encoded_input,
193 codestream: source.codestream,
194 header,
195 boxes,
196 settings,
197 used_lenient_metadata_recovery,
198 has_alpha,
199 color_space,
200 })
201 }
202
203 pub(crate) fn retained_metadata_bytes(&self) -> Result<usize> {
204 retained_metadata_bytes(&self.header, &self.boxes, &self.color_space)
205 }
206
207 #[doc(hidden)]
214 pub fn retained_allocation_bytes(&self) -> Result<usize> {
215 self.retained_metadata_bytes()
216 }
217
218 #[doc(hidden)]
220 #[must_use]
221 pub const fn used_lenient_metadata_recovery(&self) -> bool {
222 self.used_lenient_metadata_recovery
223 }
224
225 pub fn new(data: &'a [u8], settings: &DecodeSettings) -> Result<Self> {
231 if data.starts_with(JP2_MAGIC) {
232 jp2::parse(data, *settings, None)
233 } else if data.starts_with(CODESTREAM_MAGIC) {
234 j2c::parse(data, settings, None)
235 } else {
236 err!(FormatError::InvalidSignature)
237 }
238 }
239
240 #[doc(hidden)]
251 pub fn new_with_reduction(
252 data: &'a [u8],
253 settings: &DecodeSettings,
254 reduction_levels: u8,
255 ) -> Result<Self> {
256 if settings.target_resolution.is_some() {
257 return err!(DecodingError::UnsupportedFeature(
258 "exact reduction cannot be combined with a target-resolution hint",
259 ));
260 }
261 if data.starts_with(JP2_MAGIC) {
262 jp2::parse(data, *settings, Some(reduction_levels))
263 } else if data.starts_with(CODESTREAM_MAGIC) {
264 j2c::parse(data, settings, Some(reduction_levels))
265 } else {
266 err!(FormatError::InvalidSignature)
267 }
268 }
269
270 #[doc(hidden)]
280 pub fn new_with_retained_baseline(
281 data: &'a [u8],
282 settings: &DecodeSettings,
283 retained_baseline_bytes: usize,
284 ) -> Result<Self> {
285 if retained_baseline_bytes == 0 {
286 return Self::new(data, settings);
287 }
288 if data.starts_with(JP2_MAGIC) {
289 jp2::parse_with_retained_baseline(data, *settings, retained_baseline_bytes, None)
290 } else if data.starts_with(CODESTREAM_MAGIC) {
291 j2c::parse_with_retained_baseline(data, settings, retained_baseline_bytes, None)
292 } else {
293 err!(FormatError::InvalidSignature)
294 }
295 }
296
297 #[must_use]
299 pub fn has_alpha(&self) -> bool {
300 self.has_alpha
301 }
302
303 #[must_use]
305 pub fn color_space(&self) -> &ColorSpace {
306 &self.color_space
307 }
308
309 #[doc(hidden)]
311 #[must_use]
312 pub fn primary_icc_profile(&self) -> Option<&[u8]> {
313 match self
314 .boxes
315 .primary_color_specification()
316 .map(|specification| &specification.color_space)
317 {
318 Some(jp2::colr::ColorSpace::Icc(profile)) => Some(profile),
319 _ => None,
320 }
321 }
322
323 #[must_use]
325 pub fn width(&self) -> u32 {
326 self.header.size_data.image_width()
327 }
328
329 #[must_use]
331 pub fn height(&self) -> u32 {
332 self.header.size_data.image_height()
333 }
334
335 #[must_use]
338 pub fn original_bit_depth(&self) -> u8 {
339 self.header.component_infos[0].size_info.precision
341 }
342
343 #[doc(hidden)]
345 #[must_use]
346 pub fn supports_direct_device_plane_reuse(&self) -> bool {
347 if self.settings.resolve_palette_indices && self.boxes.palette.is_some() {
348 return false;
349 }
350 if self.boxes.channel_definition.is_some() {
351 return false;
352 }
353 !matches!(
354 self.boxes
355 .primary_color_specification()
356 .map(|spec| &spec.color_space),
357 Some(jp2::colr::ColorSpace::Enumerated(
358 EnumeratedColorspace::Sycc | EnumeratedColorspace::CieLab(_)
359 ))
360 )
361 }
362
363 pub fn decode(&self) -> Result<Vec<u8>> {
370 let bitmap = self.decode_with_context(&mut DecoderContext::default())?;
371 Ok(bitmap.data)
372 }
373
374 pub fn decode_with_context(&self, decoder_context: &mut DecoderContext<'a>) -> Result<Bitmap> {
381 (|| {
382 let retained_image_bytes = self.retained_metadata_bytes()?;
383 let mut decoded_image =
384 self.decode_image(decoder_context, None, None, retained_image_bytes)?;
385 let component_owner_capacity = decoded_image.decoded_components.capacity();
386 let buffer_size = checked_decode_byte_len3(
387 self.width() as usize,
388 self.height() as usize,
389 decoded_image.decoded_components.len(),
390 )?;
391 let mut budget = NativeOutputBudget::for_decoded_channels(
392 retained_image_bytes,
393 decoded_image.decoded_components,
394 component_owner_capacity,
395 )?;
396 budget.include_elements::<u8>(buffer_size)?;
397 budget.include_color_space_clone(&self.color_space)?;
398
399 let color_space = try_clone_color_space(&self.color_space)?;
400 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
401 let mut data = Vec::new();
402 try_resize_decode_elements(&mut data, buffer_size, 0_u8)?;
403 budget.include_capacity_overage::<u8>(buffer_size, data.capacity())?;
404 validate_interleaved_output_buffer(&decoded_image, &data)?;
405 interleave_and_convert(&mut decoded_image, &mut data)?;
406 let bitmap = Bitmap {
407 color_space,
408 data,
409 has_alpha: self.has_alpha,
410 width: self.width(),
411 height: self.height(),
412 original_bit_depth: self.original_bit_depth(),
413 };
414 NativeOutputBudget::validate_bitmap_pack(
415 retained_image_bytes,
416 decoded_image.decoded_components,
417 component_owner_capacity,
418 &bitmap,
419 )?;
420 Ok(bitmap)
421 })()
422 }
423
424 pub fn decode_components_with_context<'ctx>(
431 &self,
432 decoder_context: &'ctx mut DecoderContext<'a>,
433 ) -> Result<DecodedComponents<'ctx>> {
434 self.validate_component_plane_precision()?;
435 let decoded_image =
436 self.decode_image(decoder_context, None, None, self.retained_metadata_bytes()?)?;
437 let DecodedImage {
438 decoded_components,
439 boxes: _,
440 } = decoded_image;
441 self.try_borrow_component_planes(
442 decoded_components.as_slice(),
443 decoded_components.capacity(),
444 (self.width(), self.height()),
445 )
446 }
447
448 pub fn decode_native_components(&self) -> Result<DecodedNativeComponents> {
458 let mut decoder_context = DecoderContext::default();
459 self.decode_native_components_with_context(&mut decoder_context)
460 }
461
462 #[doc(hidden)]
473 pub fn decode_native_components_with_retained_capacity(
474 &self,
475 retained_capacity: usize,
476 ) -> Result<DecodedNativeComponents> {
477 let retained_baseline_bytes =
478 allocation::combine_retained_bytes(retained_capacity, self.retained_metadata_bytes()?)?;
479 let mut decoder_context = DecoderContext::default();
480 self.decode_native_components_with_context_and_retained_baseline(
481 &mut decoder_context,
482 retained_baseline_bytes,
483 )
484 }
485
486 pub fn decode_native_components_with_context(
493 &self,
494 decoder_context: &mut DecoderContext<'a>,
495 ) -> Result<DecodedNativeComponents> {
496 let retained_baseline_bytes = self.retained_metadata_bytes()?;
497 self.decode_native_components_with_context_and_retained_baseline(
498 decoder_context,
499 retained_baseline_bytes,
500 )
501 }
502
503 fn decode_native_components_with_context_and_retained_baseline(
504 &self,
505 decoder_context: &mut DecoderContext<'a>,
506 retained_baseline_bytes: usize,
507 ) -> Result<DecodedNativeComponents> {
508 let decoded_image =
509 self.decode_image(decoder_context, None, None, retained_baseline_bytes)?;
510 let DecodedImage {
511 decoded_components,
512 boxes: _,
513 } = decoded_image;
514 let component_owner_capacity = decoded_components.capacity();
515 self.pack_native_component_planes(
516 decoded_components,
517 component_owner_capacity,
518 (self.width(), self.height()),
519 retained_baseline_bytes,
520 )
521 }
522
523 #[doc(hidden)]
525 pub fn decode_components_with_ht_decoder<'ctx>(
526 &self,
527 decoder_context: &'ctx mut DecoderContext<'a>,
528 ht_decoder: &mut dyn HtCodeBlockDecoder,
529 ) -> Result<DecodedComponents<'ctx>> {
530 self.validate_component_plane_precision()?;
531 let decoded_image = self.decode_image(
532 decoder_context,
533 None,
534 Some(ht_decoder),
535 self.retained_metadata_bytes()?,
536 )?;
537 let DecodedImage {
538 decoded_components,
539 boxes: _,
540 } = decoded_image;
541 self.try_borrow_component_planes(
542 decoded_components.as_slice(),
543 decoded_components.capacity(),
544 (self.width(), self.height()),
545 )
546 }
547
548 pub fn decode_region_components_with_context<'ctx>(
555 &self,
556 roi: (u32, u32, u32, u32),
557 decoder_context: &'ctx mut DecoderContext<'a>,
558 ) -> Result<DecodedComponents<'ctx>> {
559 validate_roi((self.width(), self.height()), roi)?;
560 self.validate_component_plane_precision()?;
561 let (_x, _y, width, height) = roi;
562 let decoded_image = self.decode_image(
563 decoder_context,
564 Some(roi),
565 None,
566 self.retained_metadata_bytes()?,
567 )?;
568 let DecodedImage {
569 decoded_components,
570 boxes: _,
571 } = decoded_image;
572 self.try_borrow_component_planes(
573 decoded_components.as_slice(),
574 decoded_components.capacity(),
575 (width, height),
576 )
577 }
578
579 pub fn decode_native_region_components_with_context(
586 &self,
587 roi: (u32, u32, u32, u32),
588 decoder_context: &mut DecoderContext<'a>,
589 ) -> Result<DecodedNativeComponents> {
590 validate_roi((self.width(), self.height()), roi)?;
591 if self.requires_exact_integer_decode() {
592 return self.decode_native_region_components_via_full_decode(roi, decoder_context);
593 }
594 let (_x, _y, width, height) = roi;
595 let retained_image_bytes = self.retained_metadata_bytes()?;
596 let decoded_image =
597 self.decode_image(decoder_context, Some(roi), None, retained_image_bytes)?;
598 let DecodedImage {
599 decoded_components,
600 boxes: _,
601 } = decoded_image;
602 let component_owner_capacity = decoded_components.capacity();
603 self.pack_native_component_planes(
604 decoded_components,
605 component_owner_capacity,
606 (width, height),
607 retained_image_bytes,
608 )
609 }
610
611 #[doc(hidden)]
614 pub fn decode_region_components_with_ht_decoder<'ctx>(
615 &self,
616 decoder_context: &'ctx mut DecoderContext<'a>,
617 roi: (u32, u32, u32, u32),
618 ht_decoder: &mut dyn HtCodeBlockDecoder,
619 ) -> Result<DecodedComponents<'ctx>> {
620 validate_roi((self.width(), self.height()), roi)?;
621 self.validate_component_plane_precision()?;
622 let (_x, _y, width, height) = roi;
623 let decoded_image = self.decode_image(
624 decoder_context,
625 Some(roi),
626 Some(ht_decoder),
627 self.retained_metadata_bytes()?,
628 )?;
629 let DecodedImage {
630 decoded_components,
631 boxes: _,
632 } = decoded_image;
633 self.try_borrow_component_planes(
634 decoded_components.as_slice(),
635 decoded_components.capacity(),
636 (width, height),
637 )
638 }
639
640 pub fn decode_region(&self, roi: (u32, u32, u32, u32)) -> Result<Bitmap> {
646 self.decode_region_with_context(roi, &mut DecoderContext::default())
647 }
648
649 pub fn decode_region_with_context(
656 &self,
657 roi: (u32, u32, u32, u32),
658 decoder_context: &mut DecoderContext<'a>,
659 ) -> Result<Bitmap> {
660 validate_roi((self.width(), self.height()), roi)?;
661 (|| {
662 let retained_image_bytes = self.retained_metadata_bytes()?;
663 let mut decoded_image =
664 self.decode_image(decoder_context, Some(roi), None, retained_image_bytes)?;
665 let component_owner_capacity = decoded_image.decoded_components.capacity();
666 let (_x, _y, width, height) = roi;
667 let data_len = checked_decode_byte_len3(
668 width as usize,
669 height as usize,
670 decoded_image.decoded_components.len(),
671 )?;
672 let mut budget = NativeOutputBudget::for_decoded_channels(
673 retained_image_bytes,
674 decoded_image.decoded_components,
675 component_owner_capacity,
676 )?;
677 budget.include_elements::<u8>(data_len)?;
678 budget.include_color_space_clone(&self.color_space)?;
679
680 let color_space = try_clone_color_space(&self.color_space)?;
681 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
682 let mut data = Vec::new();
683 try_resize_decode_elements(&mut data, data_len, 0_u8)?;
684 budget.include_capacity_overage::<u8>(data_len, data.capacity())?;
685 interleave_and_convert_region(
686 &mut decoded_image,
687 width as usize,
688 (0, 0, width, height),
689 &mut data,
690 );
691 let bitmap = Bitmap {
692 color_space,
693 data,
694 has_alpha: self.has_alpha,
695 width,
696 height,
697 original_bit_depth: self.original_bit_depth(),
698 };
699 NativeOutputBudget::validate_bitmap_pack(
700 retained_image_bytes,
701 decoded_image.decoded_components,
702 component_owner_capacity,
703 &bitmap,
704 )?;
705 Ok(bitmap)
706 })()
707 }
708
709 pub fn decode_into(
723 &self,
724 buf: &mut [u8],
725 decoder_context: &mut DecoderContext<'a>,
726 ) -> Result<()> {
727 let mut decoded_image =
728 self.decode_image(decoder_context, None, None, self.retained_metadata_bytes()?)?;
729 validate_interleaved_output_buffer(&decoded_image, buf)?;
730 interleave_and_convert(&mut decoded_image, buf)?;
731
732 Ok(())
733 }
734
735 fn decode_image<'ctx>(
736 &self,
737 decoder_context: &'ctx mut DecoderContext<'a>,
738 output_region: Option<(u32, u32, u32, u32)>,
739 ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
740 retained_baseline_bytes: usize,
741 ) -> Result<DecodedImage<'ctx, '_>> {
742 let settings = &self.settings;
743 let mut ht_decoder = ht_decoder;
744 decoder_context.set_output_region(output_region);
745 let decode_result = j2c::decode(
746 self.codestream,
747 &self.header,
748 retained_baseline_bytes,
749 decoder_context,
750 &mut ht_decoder,
751 );
752 decoder_context.set_output_region(None);
753 decode_result?;
754 let mut decoded_image = DecodedImage {
755 decoded_components: &mut decoder_context.tile_decode_context.channel_data,
756 boxes: &self.boxes,
757 };
758
759 if settings.resolve_palette_indices {
760 let components = core::mem::take(decoded_image.decoded_components);
761 *decoded_image.decoded_components =
762 resolve_palette_indices(components, decoded_image.boxes, retained_baseline_bytes)?;
763 }
764
765 if let Some(cdef) = &decoded_image.boxes.channel_definition {
766 validate_and_reorder_channels(
767 cdef,
768 decoded_image.decoded_components,
769 retained_baseline_bytes,
770 )?;
771 }
772
773 let bit_depth = decoded_image
774 .decoded_components
775 .first()
776 .ok_or(DecodingError::CodeBlockDecodeFailure)?
777 .bit_depth;
778 convert_color_space(&mut decoded_image, bit_depth)?;
779 Ok(decoded_image)
780 }
781}