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}
125
126#[doc(hidden)]
131pub struct PreparedRegionDecoder<'image, 'context, 'a> {
132 image: &'image Image<'a>,
133 decoder_context: &'context mut DecoderContext<'a>,
134 tiles: j2c::ParsedTiles<'a>,
135 retained_image_bytes: usize,
136 retained_session_bytes: usize,
137}
138
139#[derive(Clone, Copy)]
140pub(crate) struct ImageSource<'a> {
141 encoded_input: &'a [u8],
142 codestream: &'a [u8],
143}
144
145impl<'a> ImageSource<'a> {
146 pub(crate) const fn new(encoded_input: &'a [u8], codestream: &'a [u8]) -> Self {
147 Self {
148 encoded_input,
149 codestream,
150 }
151 }
152}
153
154pub(crate) struct ImageProperties {
155 boxes: ImageBoxes,
156 settings: DecodeSettings,
157 color_space: ColorSpace,
158 has_alpha: bool,
159 used_lenient_metadata_recovery: bool,
160}
161
162impl ImageProperties {
163 pub(crate) const fn new(
164 boxes: ImageBoxes,
165 settings: DecodeSettings,
166 color_space: ColorSpace,
167 has_alpha: bool,
168 used_lenient_metadata_recovery: bool,
169 ) -> Self {
170 Self {
171 boxes,
172 settings,
173 color_space,
174 has_alpha,
175 used_lenient_metadata_recovery,
176 }
177 }
178}
179
180impl<'a> Image<'a> {
181 #[doc(hidden)]
187 pub fn prepare_region_decoder_with_context<'image, 'context>(
188 &'image self,
189 decoder_context: &'context mut DecoderContext<'a>,
190 ) -> Result<PreparedRegionDecoder<'image, 'context, 'a>> {
191 let retained_image_bytes = self.retained_metadata_bytes()?;
192 let tiles = j2c::prepare_region_tiles(
193 self.codestream,
194 &self.header,
195 retained_image_bytes,
196 decoder_context,
197 )?;
198 let retained_session_bytes = retained_image_bytes
199 .checked_add(tiles.metadata_owner_bytes())
200 .ok_or(ValidationError::ImageTooLarge)?;
201 Ok(PreparedRegionDecoder {
202 image: self,
203 decoder_context,
204 tiles,
205 retained_image_bytes,
206 retained_session_bytes,
207 })
208 }
209
210 pub(crate) fn from_parsed_parts(
211 source: ImageSource<'a>,
212 header: Header<'a>,
213 properties: ImageProperties,
214 ) -> Result<Self> {
215 Self::from_parsed_parts_with_retained_baseline(source, header, properties, 0)
216 }
217
218 pub(crate) fn from_parsed_parts_with_retained_baseline(
219 source: ImageSource<'a>,
220 header: Header<'a>,
221 properties: ImageProperties,
222 retained_baseline_bytes: usize,
223 ) -> Result<Self> {
224 let ImageProperties {
225 boxes,
226 settings,
227 color_space,
228 has_alpha,
229 used_lenient_metadata_recovery,
230 } = properties;
231 let metadata_bytes = retained_metadata_bytes(&header, &boxes, &color_space)?;
232 allocation::combine_retained_bytes(retained_baseline_bytes, metadata_bytes)?;
233 Ok(Self {
234 encoded_input: source.encoded_input,
235 codestream: source.codestream,
236 header,
237 boxes,
238 settings,
239 used_lenient_metadata_recovery,
240 has_alpha,
241 color_space,
242 })
243 }
244
245 pub(crate) fn retained_metadata_bytes(&self) -> Result<usize> {
246 retained_metadata_bytes(&self.header, &self.boxes, &self.color_space)
247 }
248
249 #[doc(hidden)]
256 pub fn retained_allocation_bytes(&self) -> Result<usize> {
257 self.retained_metadata_bytes()
258 }
259
260 #[doc(hidden)]
262 #[must_use]
263 pub const fn used_lenient_metadata_recovery(&self) -> bool {
264 self.used_lenient_metadata_recovery
265 }
266
267 pub fn new(data: &'a [u8], settings: &DecodeSettings) -> Result<Self> {
273 if data.starts_with(JP2_MAGIC) {
274 jp2::parse(data, *settings, None)
275 } else if data.starts_with(CODESTREAM_MAGIC) {
276 j2c::parse(data, settings, None)
277 } else {
278 err!(FormatError::InvalidSignature)
279 }
280 }
281
282 #[doc(hidden)]
293 pub fn new_with_reduction(
294 data: &'a [u8],
295 settings: &DecodeSettings,
296 reduction_levels: u8,
297 ) -> Result<Self> {
298 if settings.target_resolution.is_some() {
299 return err!(DecodingError::UnsupportedFeature(
300 "exact reduction cannot be combined with a target-resolution hint",
301 ));
302 }
303 if data.starts_with(JP2_MAGIC) {
304 jp2::parse(data, *settings, Some(reduction_levels))
305 } else if data.starts_with(CODESTREAM_MAGIC) {
306 j2c::parse(data, settings, Some(reduction_levels))
307 } else {
308 err!(FormatError::InvalidSignature)
309 }
310 }
311
312 #[doc(hidden)]
322 pub fn new_with_retained_baseline(
323 data: &'a [u8],
324 settings: &DecodeSettings,
325 retained_baseline_bytes: usize,
326 ) -> Result<Self> {
327 if retained_baseline_bytes == 0 {
328 return Self::new(data, settings);
329 }
330 if data.starts_with(JP2_MAGIC) {
331 jp2::parse_with_retained_baseline(data, *settings, retained_baseline_bytes, None)
332 } else if data.starts_with(CODESTREAM_MAGIC) {
333 j2c::parse_with_retained_baseline(data, settings, retained_baseline_bytes, None)
334 } else {
335 err!(FormatError::InvalidSignature)
336 }
337 }
338
339 #[must_use]
341 pub fn has_alpha(&self) -> bool {
342 self.has_alpha
343 }
344
345 #[must_use]
347 pub fn color_space(&self) -> &ColorSpace {
348 &self.color_space
349 }
350
351 #[doc(hidden)]
353 #[must_use]
354 pub fn primary_icc_profile(&self) -> Option<&[u8]> {
355 match self
356 .boxes
357 .primary_color_specification()
358 .map(|specification| &specification.color_space)
359 {
360 Some(jp2::colr::ColorSpace::Icc(profile)) => Some(profile),
361 _ => None,
362 }
363 }
364
365 #[must_use]
367 pub fn width(&self) -> u32 {
368 self.header.size_data.image_width()
369 }
370
371 #[must_use]
373 pub fn height(&self) -> u32 {
374 self.header.size_data.image_height()
375 }
376
377 #[must_use]
380 pub fn original_bit_depth(&self) -> u8 {
381 self.header.component_infos[0].size_info.precision
383 }
384
385 #[doc(hidden)]
387 #[must_use]
388 pub fn supports_direct_device_plane_reuse(&self) -> bool {
389 if self.settings.resolve_palette_indices && self.boxes.palette.is_some() {
390 return false;
391 }
392 if self.boxes.channel_definition.is_some() {
393 return false;
394 }
395 !matches!(
396 self.boxes
397 .primary_color_specification()
398 .map(|spec| &spec.color_space),
399 Some(jp2::colr::ColorSpace::Enumerated(
400 EnumeratedColorspace::Sycc | EnumeratedColorspace::CieLab(_)
401 ))
402 )
403 }
404
405 pub fn decode(&self) -> Result<Vec<u8>> {
412 let bitmap = self.decode_with_context(&mut DecoderContext::default())?;
413 Ok(bitmap.data)
414 }
415
416 pub fn decode_with_context(&self, decoder_context: &mut DecoderContext<'a>) -> Result<Bitmap> {
423 (|| {
424 let retained_image_bytes = self.retained_metadata_bytes()?;
425 let mut decoded_image =
426 self.decode_image(decoder_context, None, None, true, retained_image_bytes)?;
427 let component_owner_capacity = decoded_image.decoded_components.capacity();
428 let buffer_size = checked_decode_byte_len3(
429 self.width() as usize,
430 self.height() as usize,
431 decoded_image.decoded_components.len(),
432 )?;
433 let mut budget = NativeOutputBudget::for_decoded_channels(
434 retained_image_bytes,
435 decoded_image.decoded_components,
436 component_owner_capacity,
437 )?;
438 budget.include_elements::<u8>(buffer_size)?;
439 budget.include_color_space_clone(&self.color_space)?;
440
441 let color_space = try_clone_color_space(&self.color_space)?;
442 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
443 let mut data = Vec::new();
444 try_resize_decode_elements(&mut data, buffer_size, 0_u8)?;
445 budget.include_capacity_overage::<u8>(buffer_size, data.capacity())?;
446 validate_interleaved_output_buffer(&decoded_image, &data)?;
447 interleave_and_convert(&mut decoded_image, &mut data)?;
448 let bitmap = Bitmap {
449 color_space,
450 data,
451 has_alpha: self.has_alpha,
452 width: self.width(),
453 height: self.height(),
454 original_bit_depth: self.original_bit_depth(),
455 };
456 NativeOutputBudget::validate_bitmap_pack(
457 retained_image_bytes,
458 decoded_image.decoded_components,
459 component_owner_capacity,
460 &bitmap,
461 )?;
462 Ok(bitmap)
463 })()
464 }
465
466 pub fn decode_components_with_context<'ctx>(
473 &self,
474 decoder_context: &'ctx mut DecoderContext<'a>,
475 ) -> Result<DecodedComponents<'ctx>> {
476 self.validate_component_plane_precision()?;
477 let decoded_image = self.decode_image(
478 decoder_context,
479 None,
480 None,
481 false,
482 self.retained_metadata_bytes()?,
483 )?;
484 let DecodedImage {
485 decoded_components,
486 boxes: _,
487 } = decoded_image;
488 self.try_borrow_component_planes(
489 decoded_components.as_slice(),
490 decoded_components.capacity(),
491 (self.width(), self.height()),
492 )
493 }
494
495 pub fn decode_native_components(&self) -> Result<DecodedNativeComponents> {
505 let mut decoder_context = DecoderContext::default();
506 self.decode_native_components_with_context(&mut decoder_context)
507 }
508
509 #[doc(hidden)]
520 pub fn decode_native_components_with_retained_capacity(
521 &self,
522 retained_capacity: usize,
523 ) -> Result<DecodedNativeComponents> {
524 let retained_baseline_bytes =
525 allocation::combine_retained_bytes(retained_capacity, self.retained_metadata_bytes()?)?;
526 let mut decoder_context = DecoderContext::default();
527 self.decode_native_components_with_context_and_retained_baseline(
528 &mut decoder_context,
529 retained_baseline_bytes,
530 )
531 }
532
533 pub fn decode_native_components_with_context(
540 &self,
541 decoder_context: &mut DecoderContext<'a>,
542 ) -> Result<DecodedNativeComponents> {
543 let retained_baseline_bytes = self.retained_metadata_bytes()?;
544 self.decode_native_components_with_context_and_retained_baseline(
545 decoder_context,
546 retained_baseline_bytes,
547 )
548 }
549
550 fn decode_native_components_with_context_and_retained_baseline(
551 &self,
552 decoder_context: &mut DecoderContext<'a>,
553 retained_baseline_bytes: usize,
554 ) -> Result<DecodedNativeComponents> {
555 let decoded_image =
556 self.decode_image(decoder_context, None, None, true, retained_baseline_bytes)?;
557 let DecodedImage {
558 decoded_components,
559 boxes: _,
560 } = decoded_image;
561 let component_owner_capacity = decoded_components.capacity();
562 self.pack_native_component_planes(
563 decoded_components,
564 component_owner_capacity,
565 (self.width(), self.height()),
566 retained_baseline_bytes,
567 )
568 }
569
570 #[doc(hidden)]
572 pub fn decode_components_with_ht_decoder<'ctx>(
573 &self,
574 decoder_context: &'ctx mut DecoderContext<'a>,
575 ht_decoder: &mut dyn HtCodeBlockDecoder,
576 ) -> Result<DecodedComponents<'ctx>> {
577 self.validate_component_plane_precision()?;
578 let decoded_image = self.decode_image(
579 decoder_context,
580 None,
581 Some(ht_decoder),
582 false,
583 self.retained_metadata_bytes()?,
584 )?;
585 let DecodedImage {
586 decoded_components,
587 boxes: _,
588 } = decoded_image;
589 self.try_borrow_component_planes(
590 decoded_components.as_slice(),
591 decoded_components.capacity(),
592 (self.width(), self.height()),
593 )
594 }
595
596 pub fn decode_region_components_with_context<'ctx>(
603 &self,
604 roi: (u32, u32, u32, u32),
605 decoder_context: &'ctx mut DecoderContext<'a>,
606 ) -> Result<DecodedComponents<'ctx>> {
607 validate_roi((self.width(), self.height()), roi)?;
608 self.validate_component_plane_precision()?;
609 let (_x, _y, width, height) = roi;
610 let decoded_image = self.decode_image(
611 decoder_context,
612 Some(roi),
613 None,
614 false,
615 self.retained_metadata_bytes()?,
616 )?;
617 let DecodedImage {
618 decoded_components,
619 boxes: _,
620 } = decoded_image;
621 self.try_borrow_component_planes(
622 decoded_components.as_slice(),
623 decoded_components.capacity(),
624 (width, height),
625 )
626 }
627
628 pub fn decode_native_region_components_with_context(
635 &self,
636 roi: (u32, u32, u32, u32),
637 decoder_context: &mut DecoderContext<'a>,
638 ) -> Result<DecodedNativeComponents> {
639 validate_roi((self.width(), self.height()), roi)?;
640 if self.requires_exact_integer_decode() {
641 return self.decode_native_region_components_via_full_decode(roi, decoder_context);
642 }
643 let (_x, _y, width, height) = roi;
644 let retained_image_bytes = self.retained_metadata_bytes()?;
645 let decoded_image =
646 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
647 let DecodedImage {
648 decoded_components,
649 boxes: _,
650 } = decoded_image;
651 let component_owner_capacity = decoded_components.capacity();
652 self.pack_native_component_planes(
653 decoded_components,
654 component_owner_capacity,
655 (width, height),
656 retained_image_bytes,
657 )
658 }
659
660 #[doc(hidden)]
663 pub fn decode_region_components_with_ht_decoder<'ctx>(
664 &self,
665 decoder_context: &'ctx mut DecoderContext<'a>,
666 roi: (u32, u32, u32, u32),
667 ht_decoder: &mut dyn HtCodeBlockDecoder,
668 ) -> Result<DecodedComponents<'ctx>> {
669 validate_roi((self.width(), self.height()), roi)?;
670 self.validate_component_plane_precision()?;
671 let (_x, _y, width, height) = roi;
672 let decoded_image = self.decode_image(
673 decoder_context,
674 Some(roi),
675 Some(ht_decoder),
676 false,
677 self.retained_metadata_bytes()?,
678 )?;
679 let DecodedImage {
680 decoded_components,
681 boxes: _,
682 } = decoded_image;
683 self.try_borrow_component_planes(
684 decoded_components.as_slice(),
685 decoded_components.capacity(),
686 (width, height),
687 )
688 }
689
690 pub fn decode_region(&self, roi: (u32, u32, u32, u32)) -> Result<Bitmap> {
696 self.decode_region_with_context(roi, &mut DecoderContext::default())
697 }
698
699 pub fn decode_region_with_context(
706 &self,
707 roi: (u32, u32, u32, u32),
708 decoder_context: &mut DecoderContext<'a>,
709 ) -> Result<Bitmap> {
710 validate_roi((self.width(), self.height()), roi)?;
711 (|| {
712 let retained_image_bytes = self.retained_metadata_bytes()?;
713 let mut decoded_image =
714 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
715 let component_owner_capacity = decoded_image.decoded_components.capacity();
716 let (_x, _y, width, height) = roi;
717 let data_len = checked_decode_byte_len3(
718 width as usize,
719 height as usize,
720 decoded_image.decoded_components.len(),
721 )?;
722 let mut budget = NativeOutputBudget::for_decoded_channels(
723 retained_image_bytes,
724 decoded_image.decoded_components,
725 component_owner_capacity,
726 )?;
727 budget.include_elements::<u8>(data_len)?;
728 budget.include_color_space_clone(&self.color_space)?;
729
730 let color_space = try_clone_color_space(&self.color_space)?;
731 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
732 let mut data = Vec::new();
733 try_resize_decode_elements(&mut data, data_len, 0_u8)?;
734 budget.include_capacity_overage::<u8>(data_len, data.capacity())?;
735 interleave_and_convert_region(
736 &mut decoded_image,
737 width as usize,
738 (0, 0, width, height),
739 &mut data,
740 )?;
741 let bitmap = Bitmap {
742 color_space,
743 data,
744 has_alpha: self.has_alpha,
745 width,
746 height,
747 original_bit_depth: self.original_bit_depth(),
748 };
749 NativeOutputBudget::validate_bitmap_pack(
750 retained_image_bytes,
751 decoded_image.decoded_components,
752 component_owner_capacity,
753 &bitmap,
754 )?;
755 Ok(bitmap)
756 })()
757 }
758
759 pub fn decode_into(
773 &self,
774 buf: &mut [u8],
775 decoder_context: &mut DecoderContext<'a>,
776 ) -> Result<()> {
777 let mut decoded_image = self.decode_image(
778 decoder_context,
779 None,
780 None,
781 true,
782 self.retained_metadata_bytes()?,
783 )?;
784 validate_interleaved_output_buffer(&decoded_image, buf)?;
785 interleave_and_convert(&mut decoded_image, buf)?;
786
787 Ok(())
788 }
789
790 fn decode_image<'ctx>(
791 &self,
792 decoder_context: &'ctx mut DecoderContext<'a>,
793 output_region: Option<(u32, u32, u32, u32)>,
794 ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
795 round_irreversible_output: bool,
796 retained_baseline_bytes: usize,
797 ) -> Result<DecodedImage<'ctx, '_>> {
798 let mut ht_decoder = ht_decoder;
799 decoder_context.set_output_region(output_region);
800 decoder_context.set_round_irreversible_output(round_irreversible_output);
801 let decode_result = j2c::decode(
802 self.codestream,
803 &self.header,
804 retained_baseline_bytes,
805 decoder_context,
806 &mut ht_decoder,
807 );
808 decoder_context.set_output_region(None);
809 decoder_context.set_round_irreversible_output(false);
810 decode_result?;
811 self.finish_decoded_image(decoder_context, retained_baseline_bytes)
812 }
813
814 fn finish_decoded_image<'ctx>(
815 &self,
816 decoder_context: &'ctx mut DecoderContext<'a>,
817 retained_baseline_bytes: usize,
818 ) -> Result<DecodedImage<'ctx, '_>> {
819 let settings = &self.settings;
820 let mut decoded_image = DecodedImage {
821 decoded_components: &mut decoder_context.tile_decode_context.channel_data,
822 boxes: &self.boxes,
823 };
824
825 if settings.resolve_palette_indices {
826 let components = core::mem::take(decoded_image.decoded_components);
827 *decoded_image.decoded_components =
828 resolve_palette_indices(components, decoded_image.boxes, retained_baseline_bytes)?;
829 }
830
831 if let Some(cdef) = decoded_image
832 .boxes
833 .primary_color_specification()
834 .and(decoded_image.boxes.channel_definition.as_ref())
835 {
836 validate_and_reorder_channels(
837 cdef,
838 decoded_image.decoded_components,
839 retained_baseline_bytes,
840 )?;
841 }
842
843 let bit_depth = decoded_image
844 .decoded_components
845 .first()
846 .ok_or(DecodingError::CodeBlockDecodeFailure)?
847 .bit_depth;
848 convert_color_space(&mut decoded_image, bit_depth)?;
849 Ok(decoded_image)
850 }
851}
852
853impl PreparedRegionDecoder<'_, '_, '_> {
854 pub fn decode_region_components(
860 &mut self,
861 roi: (u32, u32, u32, u32),
862 ) -> Result<DecodedComponents<'_>> {
863 validate_roi((self.image.width(), self.image.height()), roi)?;
864 self.image.validate_component_plane_precision()?;
865 self.decoder_context.set_output_region(Some(roi));
866 self.decoder_context.set_round_irreversible_output(false);
867 let decode_result = j2c::decode_preparsed(
868 &self.image.header,
869 self.retained_image_bytes,
870 &self.tiles,
871 self.decoder_context,
872 );
873 self.decoder_context.set_output_region(None);
874 decode_result?;
875 let (_x, _y, width, height) = roi;
876 let decoded_image = self
877 .image
878 .finish_decoded_image(self.decoder_context, self.retained_session_bytes)?;
879 let DecodedImage {
880 decoded_components,
881 boxes: _,
882 } = decoded_image;
883 self.image
884 .try_borrow_component_planes_with_retained_baseline(
885 decoded_components.as_slice(),
886 decoded_components.capacity(),
887 (width, height),
888 self.retained_session_bytes,
889 )
890 }
891}