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.decode_borrowed_component_planes(decoder_context, None, None, false)
477 }
478
479 pub fn decode_native_components(&self) -> Result<DecodedNativeComponents> {
489 let mut decoder_context = DecoderContext::default();
490 self.decode_native_components_with_context(&mut decoder_context)
491 }
492
493 #[doc(hidden)]
504 pub fn decode_native_components_with_retained_capacity(
505 &self,
506 retained_capacity: usize,
507 ) -> Result<DecodedNativeComponents> {
508 let retained_baseline_bytes =
509 allocation::combine_retained_bytes(retained_capacity, self.retained_metadata_bytes()?)?;
510 let mut decoder_context = DecoderContext::default();
511 self.decode_native_components_with_context_and_retained_baseline(
512 &mut decoder_context,
513 retained_baseline_bytes,
514 )
515 }
516
517 pub fn decode_native_components_with_context(
524 &self,
525 decoder_context: &mut DecoderContext<'a>,
526 ) -> Result<DecodedNativeComponents> {
527 let retained_baseline_bytes = self.retained_metadata_bytes()?;
528 self.decode_native_components_with_context_and_retained_baseline(
529 decoder_context,
530 retained_baseline_bytes,
531 )
532 }
533
534 fn decode_native_components_with_context_and_retained_baseline(
535 &self,
536 decoder_context: &mut DecoderContext<'a>,
537 retained_baseline_bytes: usize,
538 ) -> Result<DecodedNativeComponents> {
539 let decoded_image =
540 self.decode_image(decoder_context, None, None, true, retained_baseline_bytes)?;
541 let DecodedImage {
542 decoded_components,
543 boxes: _,
544 } = decoded_image;
545 let component_owner_capacity = decoded_components.capacity();
546 self.pack_native_component_planes(
547 decoded_components,
548 component_owner_capacity,
549 (self.width(), self.height()),
550 retained_baseline_bytes,
551 )
552 }
553
554 #[doc(hidden)]
556 pub fn decode_components_with_ht_decoder<'ctx>(
557 &self,
558 decoder_context: &'ctx mut DecoderContext<'a>,
559 ht_decoder: &mut dyn HtCodeBlockDecoder,
560 ) -> Result<DecodedComponents<'ctx>> {
561 self.decode_borrowed_component_planes(decoder_context, None, Some(ht_decoder), false)
562 }
563
564 pub fn decode_region_components_with_context<'ctx>(
571 &self,
572 roi: (u32, u32, u32, u32),
573 decoder_context: &'ctx mut DecoderContext<'a>,
574 ) -> Result<DecodedComponents<'ctx>> {
575 self.decode_borrowed_component_planes(decoder_context, Some(roi), None, false)
576 }
577
578 pub fn decode_native_region_components_with_context(
585 &self,
586 roi: (u32, u32, u32, u32),
587 decoder_context: &mut DecoderContext<'a>,
588 ) -> Result<DecodedNativeComponents> {
589 validate_roi((self.width(), self.height()), roi)?;
590 if self.requires_exact_integer_decode() {
591 return self.decode_native_region_components_via_full_decode(roi, decoder_context);
592 }
593 let (_x, _y, width, height) = roi;
594 let retained_image_bytes = self.retained_metadata_bytes()?;
595 let decoded_image =
596 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
597 let DecodedImage {
598 decoded_components,
599 boxes: _,
600 } = decoded_image;
601 let component_owner_capacity = decoded_components.capacity();
602 self.pack_native_component_planes(
603 decoded_components,
604 component_owner_capacity,
605 (width, height),
606 retained_image_bytes,
607 )
608 }
609
610 #[doc(hidden)]
613 pub fn decode_region_components_with_ht_decoder<'ctx>(
614 &self,
615 decoder_context: &'ctx mut DecoderContext<'a>,
616 roi: (u32, u32, u32, u32),
617 ht_decoder: &mut dyn HtCodeBlockDecoder,
618 ) -> Result<DecodedComponents<'ctx>> {
619 self.decode_borrowed_component_planes(decoder_context, Some(roi), Some(ht_decoder), false)
620 }
621
622 pub fn decode_region(&self, roi: (u32, u32, u32, u32)) -> Result<Bitmap> {
628 self.decode_region_with_context(roi, &mut DecoderContext::default())
629 }
630
631 pub fn decode_region_with_context(
638 &self,
639 roi: (u32, u32, u32, u32),
640 decoder_context: &mut DecoderContext<'a>,
641 ) -> Result<Bitmap> {
642 validate_roi((self.width(), self.height()), roi)?;
643 (|| {
644 let retained_image_bytes = self.retained_metadata_bytes()?;
645 let mut decoded_image =
646 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
647 let component_owner_capacity = decoded_image.decoded_components.capacity();
648 let (_x, _y, width, height) = roi;
649 let data_len = checked_decode_byte_len3(
650 width as usize,
651 height as usize,
652 decoded_image.decoded_components.len(),
653 )?;
654 let mut budget = NativeOutputBudget::for_decoded_channels(
655 retained_image_bytes,
656 decoded_image.decoded_components,
657 component_owner_capacity,
658 )?;
659 budget.include_elements::<u8>(data_len)?;
660 budget.include_color_space_clone(&self.color_space)?;
661
662 let color_space = try_clone_color_space(&self.color_space)?;
663 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
664 let mut data = Vec::new();
665 try_resize_decode_elements(&mut data, data_len, 0_u8)?;
666 budget.include_capacity_overage::<u8>(data_len, data.capacity())?;
667 interleave_and_convert_region(
668 &mut decoded_image,
669 width as usize,
670 (0, 0, width, height),
671 &mut data,
672 )?;
673 let bitmap = Bitmap {
674 color_space,
675 data,
676 has_alpha: self.has_alpha,
677 width,
678 height,
679 original_bit_depth: self.original_bit_depth(),
680 };
681 NativeOutputBudget::validate_bitmap_pack(
682 retained_image_bytes,
683 decoded_image.decoded_components,
684 component_owner_capacity,
685 &bitmap,
686 )?;
687 Ok(bitmap)
688 })()
689 }
690
691 pub fn decode_into(
705 &self,
706 buf: &mut [u8],
707 decoder_context: &mut DecoderContext<'a>,
708 ) -> Result<()> {
709 let mut decoded_image = self.decode_image(
710 decoder_context,
711 None,
712 None,
713 true,
714 self.retained_metadata_bytes()?,
715 )?;
716 validate_interleaved_output_buffer(&decoded_image, buf)?;
717 interleave_and_convert(&mut decoded_image, buf)?;
718
719 Ok(())
720 }
721
722 fn decode_image<'ctx>(
723 &self,
724 decoder_context: &'ctx mut DecoderContext<'a>,
725 output_region: Option<(u32, u32, u32, u32)>,
726 ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
727 round_irreversible_output: bool,
728 retained_baseline_bytes: usize,
729 ) -> Result<DecodedImage<'ctx, '_>> {
730 let mut ht_decoder = ht_decoder;
731 decoder_context.set_output_region(output_region);
732 decoder_context.set_round_irreversible_output(round_irreversible_output);
733 let decode_result = j2c::decode(
734 self.codestream,
735 &self.header,
736 retained_baseline_bytes,
737 decoder_context,
738 &mut ht_decoder,
739 );
740 decoder_context.set_output_region(None);
741 decoder_context.set_round_irreversible_output(false);
742 decode_result?;
743 self.finish_decoded_image(decoder_context, retained_baseline_bytes)
744 }
745
746 fn finish_decoded_image<'ctx>(
747 &self,
748 decoder_context: &'ctx mut DecoderContext<'a>,
749 retained_baseline_bytes: usize,
750 ) -> Result<DecodedImage<'ctx, '_>> {
751 let settings = &self.settings;
752 let mut decoded_image = DecodedImage {
753 decoded_components: &mut decoder_context.tile_decode_context.channel_data,
754 boxes: &self.boxes,
755 };
756
757 if settings.resolve_palette_indices {
758 let components = core::mem::take(decoded_image.decoded_components);
759 *decoded_image.decoded_components =
760 resolve_palette_indices(components, decoded_image.boxes, retained_baseline_bytes)?;
761 }
762
763 if let Some(cdef) = decoded_image
764 .boxes
765 .primary_color_specification()
766 .and(decoded_image.boxes.channel_definition.as_ref())
767 {
768 validate_and_reorder_channels(
769 cdef,
770 decoded_image.decoded_components,
771 retained_baseline_bytes,
772 )?;
773 }
774
775 let bit_depth = decoded_image
776 .decoded_components
777 .first()
778 .ok_or(DecodingError::CodeBlockDecodeFailure)?
779 .bit_depth;
780 convert_color_space(&mut decoded_image, bit_depth)?;
781 Ok(decoded_image)
782 }
783}
784
785impl PreparedRegionDecoder<'_, '_, '_> {
786 pub fn decode_region_components(
792 &mut self,
793 roi: (u32, u32, u32, u32),
794 ) -> Result<DecodedComponents<'_>> {
795 self.decode_region_component_planes(roi, false)
796 }
797
798 #[doc(hidden)]
806 pub fn decode_region_components_for_integer_output(
807 &mut self,
808 roi: (u32, u32, u32, u32),
809 ) -> Result<DecodedComponents<'_>> {
810 self.decode_region_component_planes(roi, true)
811 }
812
813 fn decode_region_component_planes(
814 &mut self,
815 roi: (u32, u32, u32, u32),
816 round_irreversible_output: bool,
817 ) -> Result<DecodedComponents<'_>> {
818 validate_roi((self.image.width(), self.image.height()), roi)?;
819 self.image.validate_component_plane_precision()?;
820 self.decoder_context.set_output_region(Some(roi));
821 self.decoder_context
822 .set_round_irreversible_output(round_irreversible_output);
823 let decode_result = j2c::decode_preparsed(
824 &self.image.header,
825 self.retained_image_bytes,
826 &self.tiles,
827 self.decoder_context,
828 );
829 self.decoder_context.set_output_region(None);
830 self.decoder_context.set_round_irreversible_output(false);
831 decode_result?;
832 let (_x, _y, width, height) = roi;
833 let decoded_image = self
834 .image
835 .finish_decoded_image(self.decoder_context, self.retained_session_bytes)?;
836 let DecodedImage {
837 decoded_components,
838 boxes: _,
839 } = decoded_image;
840 self.image
841 .try_borrow_component_planes_with_retained_baseline(
842 decoded_components.as_slice(),
843 decoded_components.capacity(),
844 (width, height),
845 self.retained_session_bytes,
846 )
847 }
848}