1use alloc::vec::Vec;
4
5use crate::error::{err, ValidationError};
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 retained_baseline_bytes: usize,
132}
133
134#[doc(hidden)]
139pub struct PreparedRegionDecoder<'image, 'context, 'a> {
140 image: &'image Image<'a>,
141 decoder_context: &'context mut DecoderContext<'a>,
142 tiles: j2c::ParsedTiles<'a>,
143 retained_image_bytes: usize,
144 retained_session_bytes: usize,
145}
146
147#[derive(Clone, Copy)]
148pub(crate) struct ImageSource<'a> {
149 encoded_input: &'a [u8],
150 codestream: &'a [u8],
151}
152
153impl<'a> ImageSource<'a> {
154 pub(crate) const fn new(encoded_input: &'a [u8], codestream: &'a [u8]) -> Self {
155 Self {
156 encoded_input,
157 codestream,
158 }
159 }
160}
161
162pub(crate) struct ImageProperties {
163 boxes: ImageBoxes,
164 settings: DecodeSettings,
165 color_space: ColorSpace,
166 has_alpha: bool,
167 used_lenient_metadata_recovery: bool,
168}
169
170impl ImageProperties {
171 pub(crate) const fn new(
172 boxes: ImageBoxes,
173 settings: DecodeSettings,
174 color_space: ColorSpace,
175 has_alpha: bool,
176 used_lenient_metadata_recovery: bool,
177 ) -> Self {
178 Self {
179 boxes,
180 settings,
181 color_space,
182 has_alpha,
183 used_lenient_metadata_recovery,
184 }
185 }
186}
187
188impl<'a> Image<'a> {
189 #[doc(hidden)]
195 pub fn prepare_region_decoder_with_context<'image, 'context>(
196 &'image self,
197 decoder_context: &'context mut DecoderContext<'a>,
198 ) -> Result<PreparedRegionDecoder<'image, 'context, 'a>> {
199 let retained_image_bytes = self.retained_planning_bytes()?;
200 let tiles = j2c::prepare_region_tiles(
201 self.codestream,
202 &self.header,
203 retained_image_bytes,
204 decoder_context,
205 )?;
206 let retained_session_bytes = retained_image_bytes
207 .checked_add(tiles.metadata_owner_bytes())
208 .ok_or(ValidationError::ImageTooLarge)?;
209 Ok(PreparedRegionDecoder {
210 image: self,
211 decoder_context,
212 tiles,
213 retained_image_bytes,
214 retained_session_bytes,
215 })
216 }
217
218 pub(crate) fn from_parsed_parts(
219 source: ImageSource<'a>,
220 header: Header<'a>,
221 properties: ImageProperties,
222 ) -> Result<Self> {
223 Self::from_parsed_parts_with_retained_baseline(source, header, properties, 0)
224 }
225
226 pub(crate) fn from_parsed_parts_with_retained_baseline(
227 source: ImageSource<'a>,
228 header: Header<'a>,
229 properties: ImageProperties,
230 retained_baseline_bytes: usize,
231 ) -> Result<Self> {
232 let ImageProperties {
233 boxes,
234 settings,
235 color_space,
236 has_alpha,
237 used_lenient_metadata_recovery,
238 } = properties;
239 let metadata_bytes = retained_metadata_bytes(&header, &boxes, &color_space)?;
240 allocation::combine_retained_bytes(retained_baseline_bytes, metadata_bytes)?;
241 Ok(Self {
242 encoded_input: source.encoded_input,
243 codestream: source.codestream,
244 header,
245 boxes,
246 settings,
247 used_lenient_metadata_recovery,
248 has_alpha,
249 color_space,
250 retained_baseline_bytes,
251 })
252 }
253
254 pub(crate) fn retained_metadata_bytes(&self) -> Result<usize> {
255 retained_metadata_bytes(&self.header, &self.boxes, &self.color_space)
256 }
257
258 pub(crate) fn retained_planning_bytes(&self) -> Result<usize> {
259 allocation::combine_retained_bytes(
260 self.retained_baseline_bytes,
261 self.retained_metadata_bytes()?,
262 )
263 }
264
265 #[doc(hidden)]
272 pub fn retained_allocation_bytes(&self) -> Result<usize> {
273 self.retained_metadata_bytes()
274 }
275
276 #[doc(hidden)]
278 #[must_use]
279 pub const fn used_lenient_metadata_recovery(&self) -> bool {
280 self.used_lenient_metadata_recovery
281 }
282
283 pub fn new(data: &'a [u8], settings: &DecodeSettings) -> Result<Self> {
289 if data.starts_with(JP2_MAGIC) {
290 jp2::parse(data, *settings, None)
291 } else if data.starts_with(CODESTREAM_MAGIC) {
292 j2c::parse(data, settings, None)
293 } else {
294 err!(FormatError::InvalidSignature)
295 }
296 }
297
298 #[doc(hidden)]
309 pub fn new_with_reduction(
310 data: &'a [u8],
311 settings: &DecodeSettings,
312 reduction_levels: u8,
313 ) -> Result<Self> {
314 if settings.target_resolution.is_some() {
315 return err!(DecodingError::UnsupportedFeature(
316 "exact reduction cannot be combined with a target-resolution hint",
317 ));
318 }
319 if data.starts_with(JP2_MAGIC) {
320 jp2::parse(data, *settings, Some(reduction_levels))
321 } else if data.starts_with(CODESTREAM_MAGIC) {
322 j2c::parse(data, settings, Some(reduction_levels))
323 } else {
324 err!(FormatError::InvalidSignature)
325 }
326 }
327
328 #[doc(hidden)]
339 pub fn new_with_retained_baseline(
340 data: &'a [u8],
341 settings: &DecodeSettings,
342 retained_baseline_bytes: usize,
343 ) -> Result<Self> {
344 if retained_baseline_bytes == 0 {
345 return Self::new(data, settings);
346 }
347 if data.starts_with(JP2_MAGIC) {
348 jp2::parse_with_retained_baseline(data, *settings, retained_baseline_bytes, None)
349 } else if data.starts_with(CODESTREAM_MAGIC) {
350 j2c::parse_with_retained_baseline(data, settings, retained_baseline_bytes, None)
351 } else {
352 err!(FormatError::InvalidSignature)
353 }
354 }
355
356 #[must_use]
358 pub fn has_alpha(&self) -> bool {
359 self.has_alpha
360 }
361
362 #[must_use]
364 pub fn color_space(&self) -> &ColorSpace {
365 &self.color_space
366 }
367
368 #[doc(hidden)]
370 #[must_use]
371 pub fn primary_icc_profile(&self) -> Option<&[u8]> {
372 match self
373 .boxes
374 .primary_color_specification()
375 .map(|specification| &specification.color_space)
376 {
377 Some(jp2::colr::ColorSpace::Icc(profile)) => Some(profile),
378 _ => None,
379 }
380 }
381
382 #[must_use]
384 pub fn width(&self) -> u32 {
385 self.header.size_data.image_width()
386 }
387
388 #[must_use]
390 pub fn height(&self) -> u32 {
391 self.header.size_data.image_height()
392 }
393
394 #[must_use]
397 pub fn original_bit_depth(&self) -> u8 {
398 self.header.component_infos[0].size_info.precision
400 }
401
402 #[doc(hidden)]
404 #[must_use]
405 pub fn supports_direct_device_plane_reuse(&self) -> bool {
406 if self.settings.resolve_palette_indices && self.boxes.palette.is_some() {
407 return false;
408 }
409 if self.boxes.channel_definition.is_some() {
410 return false;
411 }
412 !matches!(
413 self.boxes
414 .primary_color_specification()
415 .map(|spec| &spec.color_space),
416 Some(jp2::colr::ColorSpace::Enumerated(
417 EnumeratedColorspace::Sycc | EnumeratedColorspace::CieLab(_)
418 ))
419 )
420 }
421
422 #[doc(hidden)]
424 #[must_use]
425 pub fn tile_count(&self) -> u32 {
426 self.header.size_data.num_tiles()
427 }
428
429 pub fn decode(&self) -> Result<Vec<u8>> {
436 let bitmap = self.decode_with_context(&mut DecoderContext::default())?;
437 Ok(bitmap.data)
438 }
439
440 pub fn decode_with_context(&self, decoder_context: &mut DecoderContext<'a>) -> Result<Bitmap> {
447 (|| {
448 let retained_image_bytes = self.retained_metadata_bytes()?;
449 let mut decoded_image =
450 self.decode_image(decoder_context, None, None, true, retained_image_bytes)?;
451 let component_owner_capacity = decoded_image.decoded_components.capacity();
452 let buffer_size = checked_decode_byte_len3(
453 self.width() as usize,
454 self.height() as usize,
455 decoded_image.decoded_components.len(),
456 )?;
457 let mut budget = NativeOutputBudget::for_decoded_channels(
458 retained_image_bytes,
459 decoded_image.decoded_components,
460 component_owner_capacity,
461 )?;
462 budget.include_elements::<u8>(buffer_size)?;
463 budget.include_color_space_clone(&self.color_space)?;
464
465 let color_space = try_clone_color_space(&self.color_space)?;
466 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
467 let mut data = Vec::new();
468 try_resize_decode_elements(&mut data, buffer_size, 0_u8)?;
469 budget.include_capacity_overage::<u8>(buffer_size, data.capacity())?;
470 validate_interleaved_output_buffer(&decoded_image, &data)?;
471 interleave_and_convert(&mut decoded_image, &mut data)?;
472 let bitmap = Bitmap {
473 color_space,
474 data,
475 has_alpha: self.has_alpha,
476 width: self.width(),
477 height: self.height(),
478 original_bit_depth: self.original_bit_depth(),
479 };
480 NativeOutputBudget::validate_bitmap_pack(
481 retained_image_bytes,
482 decoded_image.decoded_components,
483 component_owner_capacity,
484 &bitmap,
485 )?;
486 Ok(bitmap)
487 })()
488 }
489
490 pub fn decode_components_with_context<'ctx>(
497 &self,
498 decoder_context: &'ctx mut DecoderContext<'a>,
499 ) -> Result<DecodedComponents<'ctx>> {
500 self.decode_borrowed_component_planes(decoder_context, None, None, false)
501 }
502
503 pub fn decode_native_components(&self) -> Result<DecodedNativeComponents> {
513 let mut decoder_context = DecoderContext::default();
514 self.decode_native_components_with_context(&mut decoder_context)
515 }
516
517 #[doc(hidden)]
528 pub fn decode_native_components_with_retained_capacity(
529 &self,
530 retained_capacity: usize,
531 ) -> Result<DecodedNativeComponents> {
532 let retained_baseline_bytes =
533 allocation::combine_retained_bytes(retained_capacity, self.retained_metadata_bytes()?)?;
534 let mut decoder_context = DecoderContext::default();
535 self.decode_native_components_with_context_and_retained_baseline(
536 &mut decoder_context,
537 retained_baseline_bytes,
538 )
539 }
540
541 pub fn decode_native_components_with_context(
548 &self,
549 decoder_context: &mut DecoderContext<'a>,
550 ) -> Result<DecodedNativeComponents> {
551 let retained_baseline_bytes = self.retained_metadata_bytes()?;
552 self.decode_native_components_with_context_and_retained_baseline(
553 decoder_context,
554 retained_baseline_bytes,
555 )
556 }
557
558 fn decode_native_components_with_context_and_retained_baseline(
559 &self,
560 decoder_context: &mut DecoderContext<'a>,
561 retained_baseline_bytes: usize,
562 ) -> Result<DecodedNativeComponents> {
563 let decoded_image =
564 self.decode_image(decoder_context, None, None, true, retained_baseline_bytes)?;
565 let DecodedImage {
566 decoded_components,
567 boxes: _,
568 } = decoded_image;
569 let component_owner_capacity = decoded_components.capacity();
570 self.pack_native_component_planes(
571 decoded_components,
572 component_owner_capacity,
573 (self.width(), self.height()),
574 retained_baseline_bytes,
575 )
576 }
577
578 #[doc(hidden)]
580 pub fn decode_components_with_ht_decoder<'ctx>(
581 &self,
582 decoder_context: &'ctx mut DecoderContext<'a>,
583 ht_decoder: &mut dyn HtCodeBlockDecoder,
584 ) -> Result<DecodedComponents<'ctx>> {
585 self.decode_borrowed_component_planes(decoder_context, None, Some(ht_decoder), false)
586 }
587
588 pub fn decode_region_components_with_context<'ctx>(
595 &self,
596 roi: (u32, u32, u32, u32),
597 decoder_context: &'ctx mut DecoderContext<'a>,
598 ) -> Result<DecodedComponents<'ctx>> {
599 self.decode_borrowed_component_planes(decoder_context, Some(roi), None, false)
600 }
601
602 pub fn decode_native_region_components_with_context(
609 &self,
610 roi: (u32, u32, u32, u32),
611 decoder_context: &mut DecoderContext<'a>,
612 ) -> Result<DecodedNativeComponents> {
613 validate_roi((self.width(), self.height()), roi)?;
614 if self.requires_exact_integer_decode() {
615 return self.decode_native_region_components_via_full_decode(roi, decoder_context);
616 }
617 let (_x, _y, width, height) = roi;
618 let retained_image_bytes = self.retained_metadata_bytes()?;
619 let decoded_image =
620 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
621 let DecodedImage {
622 decoded_components,
623 boxes: _,
624 } = decoded_image;
625 let component_owner_capacity = decoded_components.capacity();
626 self.pack_native_component_planes(
627 decoded_components,
628 component_owner_capacity,
629 (width, height),
630 retained_image_bytes,
631 )
632 }
633
634 #[doc(hidden)]
637 pub fn decode_region_components_with_ht_decoder<'ctx>(
638 &self,
639 decoder_context: &'ctx mut DecoderContext<'a>,
640 roi: (u32, u32, u32, u32),
641 ht_decoder: &mut dyn HtCodeBlockDecoder,
642 ) -> Result<DecodedComponents<'ctx>> {
643 self.decode_borrowed_component_planes(decoder_context, Some(roi), Some(ht_decoder), false)
644 }
645
646 pub fn decode_region(&self, roi: (u32, u32, u32, u32)) -> Result<Bitmap> {
652 self.decode_region_with_context(roi, &mut DecoderContext::default())
653 }
654
655 pub fn decode_region_with_context(
662 &self,
663 roi: (u32, u32, u32, u32),
664 decoder_context: &mut DecoderContext<'a>,
665 ) -> Result<Bitmap> {
666 validate_roi((self.width(), self.height()), roi)?;
667 (|| {
668 let retained_image_bytes = self.retained_metadata_bytes()?;
669 let mut decoded_image =
670 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
671 let component_owner_capacity = decoded_image.decoded_components.capacity();
672 let (_x, _y, width, height) = roi;
673 let data_len = checked_decode_byte_len3(
674 width as usize,
675 height as usize,
676 decoded_image.decoded_components.len(),
677 )?;
678 let mut budget = NativeOutputBudget::for_decoded_channels(
679 retained_image_bytes,
680 decoded_image.decoded_components,
681 component_owner_capacity,
682 )?;
683 budget.include_elements::<u8>(data_len)?;
684 budget.include_color_space_clone(&self.color_space)?;
685
686 let color_space = try_clone_color_space(&self.color_space)?;
687 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
688 let mut data = Vec::new();
689 try_resize_decode_elements(&mut data, data_len, 0_u8)?;
690 budget.include_capacity_overage::<u8>(data_len, data.capacity())?;
691 interleave_and_convert_region(
692 &mut decoded_image,
693 width as usize,
694 (0, 0, width, height),
695 &mut data,
696 )?;
697 let bitmap = Bitmap {
698 color_space,
699 data,
700 has_alpha: self.has_alpha,
701 width,
702 height,
703 original_bit_depth: self.original_bit_depth(),
704 };
705 NativeOutputBudget::validate_bitmap_pack(
706 retained_image_bytes,
707 decoded_image.decoded_components,
708 component_owner_capacity,
709 &bitmap,
710 )?;
711 Ok(bitmap)
712 })()
713 }
714
715 pub fn decode_into(
729 &self,
730 buf: &mut [u8],
731 decoder_context: &mut DecoderContext<'a>,
732 ) -> Result<()> {
733 let mut decoded_image = self.decode_image(
734 decoder_context,
735 None,
736 None,
737 true,
738 self.retained_metadata_bytes()?,
739 )?;
740 validate_interleaved_output_buffer(&decoded_image, buf)?;
741 interleave_and_convert(&mut decoded_image, buf)?;
742
743 Ok(())
744 }
745
746 fn decode_image<'ctx>(
747 &self,
748 decoder_context: &'ctx mut DecoderContext<'a>,
749 output_region: Option<(u32, u32, u32, u32)>,
750 ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
751 round_irreversible_output: bool,
752 retained_baseline_bytes: usize,
753 ) -> Result<DecodedImage<'ctx, '_>> {
754 let mut ht_decoder = ht_decoder;
755 decoder_context.set_output_region(output_region);
756 decoder_context.set_round_irreversible_output(round_irreversible_output);
757 let decode_result = j2c::decode(
758 self.codestream,
759 &self.header,
760 retained_baseline_bytes,
761 decoder_context,
762 &mut ht_decoder,
763 );
764 decoder_context.set_output_region(None);
765 decoder_context.set_round_irreversible_output(false);
766 decode_result?;
767 self.finish_decoded_image(decoder_context, retained_baseline_bytes)
768 }
769
770 fn finish_decoded_image<'ctx>(
771 &self,
772 decoder_context: &'ctx mut DecoderContext<'a>,
773 retained_baseline_bytes: usize,
774 ) -> Result<DecodedImage<'ctx, '_>> {
775 let settings = &self.settings;
776 let mut decoded_image = DecodedImage {
777 decoded_components: &mut decoder_context.tile_decode_context.channel_data,
778 boxes: &self.boxes,
779 };
780
781 if settings.resolve_palette_indices {
782 let components = core::mem::take(decoded_image.decoded_components);
783 *decoded_image.decoded_components =
784 resolve_palette_indices(components, decoded_image.boxes, retained_baseline_bytes)?;
785 }
786
787 if let Some(cdef) = decoded_image
788 .boxes
789 .primary_color_specification()
790 .and(decoded_image.boxes.channel_definition.as_ref())
791 {
792 validate_and_reorder_channels(
793 cdef,
794 decoded_image.decoded_components,
795 retained_baseline_bytes,
796 )?;
797 }
798
799 let bit_depth = decoded_image
800 .decoded_components
801 .first()
802 .ok_or(DecodingError::CodeBlockDecodeFailure)?
803 .bit_depth;
804 convert_color_space(&mut decoded_image, bit_depth)?;
805 Ok(decoded_image)
806 }
807}
808
809impl PreparedRegionDecoder<'_, '_, '_> {
810 pub fn decode_region_components(
816 &mut self,
817 roi: (u32, u32, u32, u32),
818 ) -> Result<DecodedComponents<'_>> {
819 self.decode_region_component_planes(roi, false)
820 }
821
822 #[doc(hidden)]
830 pub fn decode_region_components_for_integer_output(
831 &mut self,
832 roi: (u32, u32, u32, u32),
833 ) -> Result<DecodedComponents<'_>> {
834 self.decode_region_component_planes(roi, true)
835 }
836
837 fn decode_region_component_planes(
838 &mut self,
839 roi: (u32, u32, u32, u32),
840 round_irreversible_output: bool,
841 ) -> Result<DecodedComponents<'_>> {
842 validate_roi((self.image.width(), self.image.height()), roi)?;
843 self.image.validate_component_plane_precision()?;
844 self.decoder_context.set_output_region(Some(roi));
845 self.decoder_context
846 .set_round_irreversible_output(round_irreversible_output);
847 let decode_result = j2c::decode_preparsed(
848 &self.image.header,
849 self.retained_image_bytes,
850 &self.tiles,
851 self.decoder_context,
852 );
853 self.decoder_context.set_output_region(None);
854 self.decoder_context.set_round_irreversible_output(false);
855 decode_result?;
856 let (_x, _y, width, height) = roi;
857 let decoded_image = self
858 .image
859 .finish_decoded_image(self.decoder_context, self.retained_session_bytes)?;
860 let DecodedImage {
861 decoded_components,
862 boxes: _,
863 } = decoded_image;
864 self.image
865 .try_borrow_component_planes_with_retained_baseline(
866 decoded_components.as_slice(),
867 decoded_components.capacity(),
868 (width, height),
869 self.retained_session_bytes,
870 )
871 }
872}