1use alloc::vec::Vec;
4
5use crate::error::{err, ValidationError};
6use crate::j2c::mct::DeferredMct;
7use crate::j2c::{self, ComponentData, Header};
8use crate::jp2::colr::EnumeratedColorspace;
9use crate::jp2::{self, DecodedImage, ImageBoxes};
10use crate::CpuDecodeParallelism;
11use crate::{
12 checked_decode_byte_len3, convert_color_space, interleave_and_convert_after_mct,
13 interleave_and_convert_region, resolve_palette_indices, try_resize_decode_elements,
14 validate_and_reorder_channels, validate_interleaved_output_buffer, validate_roi, Bitmap,
15 ColorSpace, DecodedComponents, DecodedNativeComponents, DecoderContext, DecodingError,
16 FormatError, HtCodeBlockDecoder, Result, CODESTREAM_MAGIC, JP2_MAGIC,
17};
18
19mod allocation;
20mod compare;
21#[cfg(test)]
22mod contract_tests;
23mod direct_api;
24mod native;
25mod output_api;
26use self::allocation::retained_metadata_bytes;
27pub(crate) use self::allocation::{retained_container_metadata_bytes, DecodeOwnerBudget};
28use self::native::{try_clone_color_space, NativeOutputBudget};
29
30type Rgb8DecodedImage<'ctx, 'boxes> = (
34 Option<DeferredMct>,
35 &'ctx [f32],
36 [&'ctx mut [f32]; 2],
37 DecodedImage<'ctx, 'boxes>,
38);
39
40#[derive(Debug, Copy, Clone)]
42pub struct DecodeSettings {
43 pub resolve_palette_indices: bool,
55 pub strict: bool,
61 pub target_resolution: Option<(u32, u32)>,
63}
64
65impl DecodeSettings {
66 #[must_use]
83 pub const fn lenient() -> Self {
84 Self {
85 resolve_palette_indices: true,
86 strict: false,
87 target_resolution: None,
88 }
89 }
90
91 #[must_use]
93 pub const fn strict() -> Self {
94 Self {
95 resolve_palette_indices: true,
96 strict: true,
97 target_resolution: None,
98 }
99 }
100
101 #[must_use]
104 pub const fn lenient_tolerance_enabled(&self) -> bool {
105 !self.strict
106 }
107}
108
109impl Default for DecodeSettings {
110 fn default() -> Self {
111 Self::strict()
112 }
113}
114
115pub struct Image<'a> {
117 pub(crate) encoded_input: &'a [u8],
120 pub(crate) codestream: &'a [u8],
122 pub(crate) header: Header<'a>,
124 pub(crate) boxes: ImageBoxes,
127 pub(crate) settings: DecodeSettings,
129 pub(crate) used_lenient_metadata_recovery: bool,
132 pub(crate) has_alpha: bool,
134 pub(crate) color_space: ColorSpace,
136 retained_baseline_bytes: usize,
144}
145
146#[doc(hidden)]
151pub struct PreparedRegionDecoder<'image, 'context, 'a> {
152 image: &'image Image<'a>,
153 decoder_context: &'context mut DecoderContext<'a>,
154 tiles: j2c::ParsedTiles<'a>,
155 retained_image_bytes: usize,
156 retained_session_bytes: usize,
157}
158
159#[derive(Clone, Copy)]
160pub(crate) struct ImageSource<'a> {
161 encoded_input: &'a [u8],
162 codestream: &'a [u8],
163}
164
165impl<'a> ImageSource<'a> {
166 pub(crate) const fn new(encoded_input: &'a [u8], codestream: &'a [u8]) -> Self {
167 Self {
168 encoded_input,
169 codestream,
170 }
171 }
172}
173
174pub(crate) struct ImageProperties {
175 boxes: ImageBoxes,
176 settings: DecodeSettings,
177 color_space: ColorSpace,
178 has_alpha: bool,
179 used_lenient_metadata_recovery: bool,
180}
181
182impl ImageProperties {
183 pub(crate) const fn new(
184 boxes: ImageBoxes,
185 settings: DecodeSettings,
186 color_space: ColorSpace,
187 has_alpha: bool,
188 used_lenient_metadata_recovery: bool,
189 ) -> Self {
190 Self {
191 boxes,
192 settings,
193 color_space,
194 has_alpha,
195 used_lenient_metadata_recovery,
196 }
197 }
198}
199
200impl<'a> Image<'a> {
201 #[doc(hidden)]
207 pub fn prepare_region_decoder_with_context<'image, 'context>(
208 &'image self,
209 decoder_context: &'context mut DecoderContext<'a>,
210 ) -> Result<PreparedRegionDecoder<'image, 'context, 'a>> {
211 let retained_image_bytes = self.retained_planning_bytes()?;
212 let tiles = j2c::prepare_region_tiles(
213 self.codestream,
214 &self.header,
215 retained_image_bytes,
216 decoder_context,
217 )?;
218 let retained_session_bytes = retained_image_bytes
219 .checked_add(tiles.metadata_owner_bytes())
220 .ok_or(ValidationError::ImageTooLarge)?;
221 Ok(PreparedRegionDecoder {
222 image: self,
223 decoder_context,
224 tiles,
225 retained_image_bytes,
226 retained_session_bytes,
227 })
228 }
229
230 pub(crate) fn from_parsed_parts(
231 source: ImageSource<'a>,
232 header: Header<'a>,
233 properties: ImageProperties,
234 ) -> Result<Self> {
235 Self::from_parsed_parts_with_retained_baseline(source, header, properties, 0)
236 }
237
238 pub(crate) fn from_parsed_parts_with_retained_baseline(
239 source: ImageSource<'a>,
240 header: Header<'a>,
241 properties: ImageProperties,
242 retained_baseline_bytes: usize,
243 ) -> Result<Self> {
244 let ImageProperties {
245 boxes,
246 settings,
247 color_space,
248 has_alpha,
249 used_lenient_metadata_recovery,
250 } = properties;
251 let metadata_bytes = retained_metadata_bytes(&header, &boxes, &color_space)?;
252 allocation::combine_retained_bytes(retained_baseline_bytes, metadata_bytes)?;
253 Ok(Self {
254 encoded_input: source.encoded_input,
255 codestream: source.codestream,
256 header,
257 boxes,
258 settings,
259 used_lenient_metadata_recovery,
260 has_alpha,
261 color_space,
262 retained_baseline_bytes,
263 })
264 }
265
266 pub(crate) fn retained_metadata_bytes(&self) -> Result<usize> {
267 retained_metadata_bytes(&self.header, &self.boxes, &self.color_space)
268 }
269
270 pub(crate) fn retained_planning_bytes(&self) -> Result<usize> {
271 allocation::combine_retained_bytes(
272 self.retained_baseline_bytes,
273 self.retained_metadata_bytes()?,
274 )
275 }
276
277 #[doc(hidden)]
284 pub fn retained_allocation_bytes(&self) -> Result<usize> {
285 self.retained_metadata_bytes()
286 }
287
288 #[doc(hidden)]
290 #[must_use]
291 pub const fn used_lenient_metadata_recovery(&self) -> bool {
292 self.used_lenient_metadata_recovery
293 }
294
295 pub fn new(data: &'a [u8], settings: &DecodeSettings) -> Result<Self> {
301 if data.starts_with(JP2_MAGIC) {
302 jp2::parse(data, *settings, None)
303 } else if data.starts_with(CODESTREAM_MAGIC) {
304 j2c::parse(data, settings, None)
305 } else {
306 err!(FormatError::InvalidSignature)
307 }
308 }
309
310 #[doc(hidden)]
321 pub fn new_with_reduction(
322 data: &'a [u8],
323 settings: &DecodeSettings,
324 reduction_levels: u8,
325 ) -> Result<Self> {
326 if settings.target_resolution.is_some() {
327 return err!(DecodingError::UnsupportedFeature(
328 "exact reduction cannot be combined with a target-resolution hint",
329 ));
330 }
331 if data.starts_with(JP2_MAGIC) {
332 jp2::parse(data, *settings, Some(reduction_levels))
333 } else if data.starts_with(CODESTREAM_MAGIC) {
334 j2c::parse(data, settings, Some(reduction_levels))
335 } else {
336 err!(FormatError::InvalidSignature)
337 }
338 }
339
340 #[doc(hidden)]
351 pub fn new_with_retained_baseline(
352 data: &'a [u8],
353 settings: &DecodeSettings,
354 retained_baseline_bytes: usize,
355 ) -> Result<Self> {
356 if retained_baseline_bytes == 0 {
357 return Self::new(data, settings);
358 }
359 if data.starts_with(JP2_MAGIC) {
360 jp2::parse_with_retained_baseline(data, *settings, retained_baseline_bytes, None)
361 } else if data.starts_with(CODESTREAM_MAGIC) {
362 j2c::parse_with_retained_baseline(data, settings, retained_baseline_bytes, None)
363 } else {
364 err!(FormatError::InvalidSignature)
365 }
366 }
367
368 #[must_use]
370 pub fn has_alpha(&self) -> bool {
371 self.has_alpha
372 }
373
374 #[must_use]
376 pub fn color_space(&self) -> &ColorSpace {
377 &self.color_space
378 }
379
380 #[doc(hidden)]
382 #[must_use]
383 pub fn primary_icc_profile(&self) -> Option<&[u8]> {
384 match self
385 .boxes
386 .primary_color_specification()
387 .map(|specification| &specification.color_space)
388 {
389 Some(jp2::colr::ColorSpace::Icc(profile)) => Some(profile),
390 _ => None,
391 }
392 }
393
394 #[must_use]
396 pub fn width(&self) -> u32 {
397 self.header.size_data.image_width()
398 }
399
400 #[must_use]
402 pub fn height(&self) -> u32 {
403 self.header.size_data.image_height()
404 }
405
406 #[doc(hidden)]
408 #[must_use]
409 pub fn uses_high_throughput_block_coding(&self) -> bool {
410 self.header
411 .global_coding_style
412 .component_parameters
413 .parameters
414 .code_block_style
415 .uses_high_throughput_block_coding()
416 }
417
418 #[must_use]
421 pub fn original_bit_depth(&self) -> u8 {
422 self.header.component_infos[0].size_info.precision
424 }
425
426 #[doc(hidden)]
428 #[must_use]
429 pub fn supports_direct_device_plane_reuse(&self) -> bool {
430 if self.settings.resolve_palette_indices && self.boxes.palette.is_some() {
431 return false;
432 }
433 if self.boxes.channel_definition.is_some() {
434 return false;
435 }
436 !matches!(
437 self.boxes
438 .primary_color_specification()
439 .map(|spec| &spec.color_space),
440 Some(jp2::colr::ColorSpace::Enumerated(
441 EnumeratedColorspace::Sycc | EnumeratedColorspace::CieLab(_)
442 ))
443 )
444 }
445
446 #[doc(hidden)]
448 #[must_use]
449 pub fn tile_count(&self) -> u32 {
450 self.header.size_data.num_tiles()
451 }
452
453 pub fn decode(&self) -> Result<Vec<u8>> {
460 let bitmap = self.decode_with_context(&mut DecoderContext::default())?;
461 Ok(bitmap.data)
462 }
463
464 pub fn decode_with_context(&self, decoder_context: &mut DecoderContext<'a>) -> Result<Bitmap> {
471 (|| {
472 let retained_image_bytes = self.retained_metadata_bytes()?;
473 let parallel = decoder_context.cpu_decode_parallelism() == CpuDecodeParallelism::Auto;
474 let (mct, first_ll, scratch, mut decoded_image) =
475 self.decode_image_for_rgb8(decoder_context, retained_image_bytes)?;
476 let component_owner_capacity = decoded_image.decoded_components.capacity();
477 let buffer_size = checked_decode_byte_len3(
478 self.width() as usize,
479 self.height() as usize,
480 decoded_image.decoded_components.len(),
481 )?;
482 let mut budget = NativeOutputBudget::for_decoded_channels(
483 retained_image_bytes,
484 decoded_image.decoded_components,
485 component_owner_capacity,
486 )?;
487 budget.include_elements::<u8>(buffer_size)?;
488 budget.include_color_space_clone(&self.color_space)?;
489
490 let color_space = try_clone_color_space(&self.color_space)?;
491 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
492 let mut data = Vec::new();
493 try_resize_decode_elements(&mut data, buffer_size, 0_u8)?;
494 budget.include_capacity_overage::<u8>(buffer_size, data.capacity())?;
495 validate_interleaved_output_buffer(&decoded_image, &data)?;
496 interleave_and_convert_after_mct(
497 &mut decoded_image,
498 &mut data,
499 mct,
500 first_ll,
501 scratch,
502 parallel,
503 )?;
504 let bitmap = Bitmap {
505 color_space,
506 data,
507 has_alpha: self.has_alpha,
508 width: self.width(),
509 height: self.height(),
510 original_bit_depth: self.original_bit_depth(),
511 };
512 NativeOutputBudget::validate_bitmap_pack(
513 retained_image_bytes,
514 decoded_image.decoded_components,
515 component_owner_capacity,
516 &bitmap,
517 )?;
518 Ok(bitmap)
519 })()
520 }
521
522 pub fn decode_components_with_context<'ctx>(
529 &self,
530 decoder_context: &'ctx mut DecoderContext<'a>,
531 ) -> Result<DecodedComponents<'ctx>> {
532 self.decode_borrowed_component_planes(decoder_context, None, None, false)
533 }
534
535 pub fn decode_native_components(&self) -> Result<DecodedNativeComponents> {
545 let mut decoder_context = DecoderContext::default();
546 self.decode_native_components_with_context(&mut decoder_context)
547 }
548
549 #[doc(hidden)]
560 pub fn decode_native_components_with_retained_capacity(
561 &self,
562 retained_capacity: usize,
563 ) -> Result<DecodedNativeComponents> {
564 let retained_baseline_bytes =
565 allocation::combine_retained_bytes(retained_capacity, self.retained_metadata_bytes()?)?;
566 let mut decoder_context = DecoderContext::default();
567 self.decode_native_components_with_context_and_retained_baseline(
568 &mut decoder_context,
569 retained_baseline_bytes,
570 )
571 }
572
573 pub fn decode_native_components_with_context(
580 &self,
581 decoder_context: &mut DecoderContext<'a>,
582 ) -> Result<DecodedNativeComponents> {
583 let retained_baseline_bytes = self.retained_metadata_bytes()?;
584 self.decode_native_components_with_context_and_retained_baseline(
585 decoder_context,
586 retained_baseline_bytes,
587 )
588 }
589
590 fn decode_native_components_with_context_and_retained_baseline(
591 &self,
592 decoder_context: &mut DecoderContext<'a>,
593 retained_baseline_bytes: usize,
594 ) -> Result<DecodedNativeComponents> {
595 let parallel = decoder_context.cpu_decode_parallelism() == CpuDecodeParallelism::Auto;
596 let decoded_image =
597 self.decode_image(decoder_context, None, None, true, retained_baseline_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 (self.width(), self.height()),
607 retained_baseline_bytes,
608 parallel,
609 )
610 }
611
612 #[doc(hidden)]
614 pub fn decode_components_with_ht_decoder<'ctx>(
615 &self,
616 decoder_context: &'ctx mut DecoderContext<'a>,
617 ht_decoder: &mut dyn HtCodeBlockDecoder,
618 ) -> Result<DecodedComponents<'ctx>> {
619 self.decode_borrowed_component_planes(decoder_context, None, Some(ht_decoder), false)
620 }
621
622 pub fn decode_region_components_with_context<'ctx>(
629 &self,
630 roi: (u32, u32, u32, u32),
631 decoder_context: &'ctx mut DecoderContext<'a>,
632 ) -> Result<DecodedComponents<'ctx>> {
633 self.decode_borrowed_component_planes(decoder_context, Some(roi), None, false)
634 }
635
636 pub fn decode_native_region_components_with_context(
643 &self,
644 roi: (u32, u32, u32, u32),
645 decoder_context: &mut DecoderContext<'a>,
646 ) -> Result<DecodedNativeComponents> {
647 validate_roi((self.width(), self.height()), roi)?;
648 if self.requires_exact_integer_decode() {
649 return self.decode_native_region_components_via_full_decode(roi, decoder_context);
650 }
651 let (_x, _y, width, height) = roi;
652 let retained_image_bytes = self.retained_metadata_bytes()?;
653 let parallel = decoder_context.cpu_decode_parallelism() == CpuDecodeParallelism::Auto;
654 let decoded_image =
655 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
656 let DecodedImage {
657 decoded_components,
658 boxes: _,
659 } = decoded_image;
660 let component_owner_capacity = decoded_components.capacity();
661 self.pack_native_component_planes(
662 decoded_components,
663 component_owner_capacity,
664 (width, height),
665 retained_image_bytes,
666 parallel,
667 )
668 }
669
670 #[doc(hidden)]
673 pub fn decode_region_components_with_ht_decoder<'ctx>(
674 &self,
675 decoder_context: &'ctx mut DecoderContext<'a>,
676 roi: (u32, u32, u32, u32),
677 ht_decoder: &mut dyn HtCodeBlockDecoder,
678 ) -> Result<DecodedComponents<'ctx>> {
679 self.decode_borrowed_component_planes(decoder_context, Some(roi), Some(ht_decoder), false)
680 }
681
682 pub fn decode_region(&self, roi: (u32, u32, u32, u32)) -> Result<Bitmap> {
688 self.decode_region_with_context(roi, &mut DecoderContext::default())
689 }
690
691 pub fn decode_region_with_context(
698 &self,
699 roi: (u32, u32, u32, u32),
700 decoder_context: &mut DecoderContext<'a>,
701 ) -> Result<Bitmap> {
702 validate_roi((self.width(), self.height()), roi)?;
703 (|| {
704 let retained_image_bytes = self.retained_metadata_bytes()?;
705 let mut decoded_image =
706 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
707 let component_owner_capacity = decoded_image.decoded_components.capacity();
708 let (_x, _y, width, height) = roi;
709 let data_len = checked_decode_byte_len3(
710 width as usize,
711 height as usize,
712 decoded_image.decoded_components.len(),
713 )?;
714 let mut budget = NativeOutputBudget::for_decoded_channels(
715 retained_image_bytes,
716 decoded_image.decoded_components,
717 component_owner_capacity,
718 )?;
719 budget.include_elements::<u8>(data_len)?;
720 budget.include_color_space_clone(&self.color_space)?;
721
722 let color_space = try_clone_color_space(&self.color_space)?;
723 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
724 let mut data = Vec::new();
725 try_resize_decode_elements(&mut data, data_len, 0_u8)?;
726 budget.include_capacity_overage::<u8>(data_len, data.capacity())?;
727 interleave_and_convert_region(
728 &mut decoded_image,
729 width as usize,
730 (0, 0, width, height),
731 &mut data,
732 )?;
733 let bitmap = Bitmap {
734 color_space,
735 data,
736 has_alpha: self.has_alpha,
737 width,
738 height,
739 original_bit_depth: self.original_bit_depth(),
740 };
741 NativeOutputBudget::validate_bitmap_pack(
742 retained_image_bytes,
743 decoded_image.decoded_components,
744 component_owner_capacity,
745 &bitmap,
746 )?;
747 Ok(bitmap)
748 })()
749 }
750
751 pub fn decode_into(
765 &self,
766 buf: &mut [u8],
767 decoder_context: &mut DecoderContext<'a>,
768 ) -> Result<()> {
769 let parallel = decoder_context.cpu_decode_parallelism() == CpuDecodeParallelism::Auto;
770 let retained = self.retained_metadata_bytes()?;
771 let (mct, first_ll, scratch, mut decoded_image) =
772 self.decode_image_for_rgb8(decoder_context, retained)?;
773 validate_interleaved_output_buffer(&decoded_image, buf)?;
774 interleave_and_convert_after_mct(
775 &mut decoded_image,
776 buf,
777 mct,
778 first_ll,
779 scratch,
780 parallel,
781 )?;
782
783 Ok(())
784 }
785
786 fn decode_image<'ctx>(
787 &self,
788 decoder_context: &'ctx mut DecoderContext<'a>,
789 output_region: Option<(u32, u32, u32, u32)>,
790 ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
791 round_irreversible_output: bool,
792 retained_baseline_bytes: usize,
793 ) -> Result<DecodedImage<'ctx, '_>> {
794 self.run_decode(
795 decoder_context,
796 output_region,
797 ht_decoder,
798 round_irreversible_output,
799 retained_baseline_bytes,
800 )?;
801 self.finish_decoded_image(
802 &mut decoder_context.tile_decode_context.channel_data,
803 retained_baseline_bytes,
804 )
805 }
806
807 fn decode_image_for_rgb8<'ctx>(
812 &self,
813 decoder_context: &'ctx mut DecoderContext<'a>,
814 retained_baseline_bytes: usize,
815 ) -> Result<Rgb8DecodedImage<'ctx, '_>> {
816 decoder_context.set_defer_mct(self.permits_line_region_idwt());
817 let decoded = self.run_decode(decoder_context, None, None, true, retained_baseline_bytes);
818 decoder_context.set_defer_mct(false);
819 decoded?;
820 let tile_ctx = &mut decoder_context.tile_decode_context;
821 let mct = tile_ctx.deferred_mct.take();
822 let image =
823 self.finish_decoded_image(&mut tile_ctx.channel_data, retained_baseline_bytes)?;
824 Ok((
825 mct,
826 &tile_ctx.idwt_output.coefficients,
827 [
828 &mut tile_ctx.idwt_scratch_buffer,
829 &mut tile_ctx.idwt_band_scratch,
830 ],
831 image,
832 ))
833 }
834
835 fn run_decode(
836 &self,
837 decoder_context: &mut DecoderContext<'a>,
838 output_region: Option<(u32, u32, u32, u32)>,
839 ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
840 round_irreversible_output: bool,
841 retained_baseline_bytes: usize,
842 ) -> Result<()> {
843 let mut ht_decoder = ht_decoder;
844 decoder_context.set_output_region(output_region);
845 decoder_context.set_round_irreversible_output(round_irreversible_output);
846 decoder_context.permit_line_region_idwt(self.permits_line_region_idwt());
847 let decode_result = j2c::decode(
848 self.codestream,
849 &self.header,
850 retained_baseline_bytes,
851 decoder_context,
852 &mut ht_decoder,
853 );
854 decoder_context.set_output_region(None);
855 decoder_context.set_round_irreversible_output(false);
856 decoder_context.permit_line_region_idwt(false);
857 decode_result
858 }
859
860 pub(crate) fn permits_line_region_idwt(&self) -> bool {
864 self.boxes.palette.is_none()
865 && self.boxes.channel_definition.is_none()
866 && !matches!(
867 self.boxes
868 .primary_color_specification()
869 .map(|specification| &specification.color_space),
870 Some(jp2::colr::ColorSpace::Enumerated(
871 EnumeratedColorspace::Sycc | EnumeratedColorspace::CieLab(_)
872 ))
873 )
874 }
875
876 fn finish_decoded_image<'ctx>(
877 &self,
878 channel_data: &'ctx mut Vec<ComponentData>,
879 retained_baseline_bytes: usize,
880 ) -> Result<DecodedImage<'ctx, '_>> {
881 let settings = &self.settings;
882 let mut decoded_image = DecodedImage {
883 decoded_components: channel_data,
884 boxes: &self.boxes,
885 };
886
887 if settings.resolve_palette_indices {
888 let components = core::mem::take(decoded_image.decoded_components);
889 *decoded_image.decoded_components =
890 resolve_palette_indices(components, decoded_image.boxes, retained_baseline_bytes)?;
891 }
892
893 if let Some(cdef) = decoded_image
894 .boxes
895 .primary_color_specification()
896 .and(decoded_image.boxes.channel_definition.as_ref())
897 {
898 validate_and_reorder_channels(
899 cdef,
900 decoded_image.decoded_components,
901 retained_baseline_bytes,
902 )?;
903 }
904
905 let bit_depth = decoded_image
906 .decoded_components
907 .first()
908 .ok_or(DecodingError::CodeBlockDecodeFailure)?
909 .bit_depth;
910 convert_color_space(&mut decoded_image, bit_depth)?;
911 Ok(decoded_image)
912 }
913}
914
915impl PreparedRegionDecoder<'_, '_, '_> {
916 pub fn decode_region_components(
922 &mut self,
923 roi: (u32, u32, u32, u32),
924 ) -> Result<DecodedComponents<'_>> {
925 self.decode_region_component_planes(roi, false)
926 }
927
928 #[doc(hidden)]
936 pub fn decode_region_components_for_integer_output(
937 &mut self,
938 roi: (u32, u32, u32, u32),
939 ) -> Result<DecodedComponents<'_>> {
940 self.decode_region_component_planes(roi, true)
941 }
942
943 fn decode_region_component_planes(
944 &mut self,
945 roi: (u32, u32, u32, u32),
946 round_irreversible_output: bool,
947 ) -> Result<DecodedComponents<'_>> {
948 validate_roi((self.image.width(), self.image.height()), roi)?;
949 self.image.validate_component_plane_precision()?;
950 self.decoder_context.set_output_region(Some(roi));
951 self.decoder_context
952 .set_round_irreversible_output(round_irreversible_output);
953 self.decoder_context
954 .permit_line_region_idwt(self.image.permits_line_region_idwt());
955 let decode_result = j2c::decode_preparsed(
956 &self.image.header,
957 self.retained_image_bytes,
958 &self.tiles,
959 self.decoder_context,
960 );
961 self.decoder_context.set_output_region(None);
962 self.decoder_context.set_round_irreversible_output(false);
963 self.decoder_context.permit_line_region_idwt(false);
964 decode_result?;
965 let (_x, _y, width, height) = roi;
966 let decoded_image = self.image.finish_decoded_image(
967 &mut self.decoder_context.tile_decode_context.channel_data,
968 self.retained_session_bytes,
969 )?;
970 let DecodedImage {
971 decoded_components,
972 boxes: _,
973 } = decoded_image;
974 self.image
975 .try_borrow_component_planes_with_retained_baseline(
976 decoded_components.as_slice(),
977 decoded_components.capacity(),
978 (width, height),
979 self.retained_session_bytes,
980 )
981 }
982}