Skip to main content

j2k_native/
image.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use 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/// Settings to apply during decoding.
29#[derive(Debug, Copy, Clone)]
30pub struct DecodeSettings {
31    /// Whether palette indices should be resolved.
32    ///
33    /// JPEG2000 images can be stored in two different ways. First, by storing
34    /// RGB values (depending on the color space) for each pixel. Secondly, by
35    /// only storing a single index for each channel, and then resolving the
36    /// actual color using the index.
37    ///
38    /// If you disable this option, in case you have an image with palette
39    /// indices, they will not be resolved, but instead a grayscale image
40    /// will be returned, with each pixel value corresponding to the palette
41    /// index of the location.
42    pub resolve_palette_indices: bool,
43    /// Whether strict mode should be enabled when decoding.
44    ///
45    /// The default is lenient for compatibility with older releases. Lenient
46    /// mode may tolerate malformed optional container metadata that strict mode
47    /// rejects. Use [`DecodeSettings::strict`] for fail-closed validation of
48    /// public or adversarial inputs.
49    pub strict: bool,
50    /// A hint for the target resolution that the image should be decoded at.
51    pub target_resolution: Option<(u32, u32)>,
52}
53
54impl DecodeSettings {
55    /// Compatibility decode settings.
56    ///
57    /// Lenient mode keeps the historical behavior of accepting recoverable
58    /// optional metadata problems where possible.
59    #[must_use]
60    pub const fn lenient() -> Self {
61        Self {
62            resolve_palette_indices: true,
63            strict: false,
64            target_resolution: None,
65        }
66    }
67
68    /// Strict decode settings for fail-closed validation.
69    #[must_use]
70    pub const fn strict() -> Self {
71        Self {
72            resolve_palette_indices: true,
73            strict: true,
74            target_resolution: None,
75        }
76    }
77
78    /// Whether the settings permit lenient tolerance of malformed optional
79    /// metadata.
80    #[must_use]
81    pub const fn lenient_tolerance_enabled(&self) -> bool {
82        !self.strict
83    }
84}
85
86impl Default for DecodeSettings {
87    fn default() -> Self {
88        Self::lenient()
89    }
90}
91
92/// A JPEG2000 image or codestream.
93pub struct Image<'a> {
94    /// The tile-part payload used by the legacy JPEG 2000 decoder.
95    pub(crate) codestream: &'a [u8],
96    /// The header of the J2C codestream.
97    pub(crate) header: Header<'a>,
98    /// The JP2 boxes of the image. In the case of a raw codestream, we
99    /// will synthesize the necessary boxes.
100    pub(crate) boxes: ImageBoxes,
101    /// Settings that should be applied during decoding.
102    pub(crate) settings: DecodeSettings,
103    /// Whether the image has an alpha channel.
104    pub(crate) has_alpha: bool,
105    /// The color space of the image.
106    pub(crate) color_space: ColorSpace,
107}
108
109impl<'a> Image<'a> {
110    pub(crate) fn from_parsed_parts(
111        codestream: &'a [u8],
112        header: Header<'a>,
113        boxes: ImageBoxes,
114        settings: DecodeSettings,
115        color_space: ColorSpace,
116        has_alpha: bool,
117    ) -> Result<Self> {
118        Self::from_parsed_parts_with_retained_baseline(
119            codestream,
120            header,
121            boxes,
122            settings,
123            color_space,
124            has_alpha,
125            0,
126        )
127    }
128
129    pub(crate) fn from_parsed_parts_with_retained_baseline(
130        codestream: &'a [u8],
131        header: Header<'a>,
132        boxes: ImageBoxes,
133        settings: DecodeSettings,
134        color_space: ColorSpace,
135        has_alpha: bool,
136        retained_baseline_bytes: usize,
137    ) -> Result<Self> {
138        let metadata_bytes = retained_metadata_bytes(&header, &boxes, &color_space)?;
139        allocation::combine_retained_bytes(retained_baseline_bytes, metadata_bytes)?;
140        Ok(Self {
141            codestream,
142            header,
143            boxes,
144            settings,
145            has_alpha,
146            color_space,
147        })
148    }
149
150    pub(crate) fn retained_metadata_bytes(&self) -> Result<usize> {
151        retained_metadata_bytes(&self.header, &self.boxes, &self.color_space)
152    }
153
154    /// Return the allocator capacities retained by this parsed image.
155    ///
156    /// # Errors
157    ///
158    /// Returns an error if nested metadata capacity arithmetic overflows or
159    /// exceeds the native decode cap.
160    #[doc(hidden)]
161    pub fn retained_allocation_bytes(&self) -> Result<usize> {
162        self.retained_metadata_bytes()
163    }
164
165    /// Try to create a new JPEG2000 image from the given data.
166    ///
167    /// # Errors
168    ///
169    /// Returns an error when the input signature, container, or codestream is invalid.
170    pub fn new(data: &'a [u8], settings: &DecodeSettings) -> Result<Self> {
171        if data.starts_with(JP2_MAGIC) {
172            jp2::parse(data, *settings)
173        } else if data.starts_with(CODESTREAM_MAGIC) {
174            j2c::parse(data, settings)
175        } else {
176            err!(FormatError::InvalidSignature)
177        }
178    }
179
180    /// Parse an image while accounting already-live codec-owned allocations.
181    ///
182    /// This adapter is used when validation parses another image while an
183    /// encoded output and earlier parsed metadata remain live.
184    ///
185    /// # Errors
186    ///
187    /// Returns an error when the input is invalid or aggregate parser-owned
188    /// allocations exceed the native decode cap.
189    #[doc(hidden)]
190    pub fn new_with_retained_baseline(
191        data: &'a [u8],
192        settings: &DecodeSettings,
193        retained_baseline_bytes: usize,
194    ) -> Result<Self> {
195        if retained_baseline_bytes == 0 {
196            return Self::new(data, settings);
197        }
198        if data.starts_with(JP2_MAGIC) {
199            jp2::parse_with_retained_baseline(data, *settings, retained_baseline_bytes)
200        } else if data.starts_with(CODESTREAM_MAGIC) {
201            j2c::parse_with_retained_baseline(data, settings, retained_baseline_bytes)
202        } else {
203            err!(FormatError::InvalidSignature)
204        }
205    }
206
207    /// Whether the image has an alpha channel.
208    #[must_use]
209    pub fn has_alpha(&self) -> bool {
210        self.has_alpha
211    }
212
213    /// The color space of the image.
214    #[must_use]
215    pub fn color_space(&self) -> &ColorSpace {
216        &self.color_space
217    }
218
219    /// The width of the image.
220    #[must_use]
221    pub fn width(&self) -> u32 {
222        self.header.size_data.image_width()
223    }
224
225    /// The height of the image.
226    #[must_use]
227    pub fn height(&self) -> u32 {
228        self.header.size_data.image_height()
229    }
230
231    /// The original bit depth of the image. You usually don't need to do anything
232    /// with this parameter, it just exists for informational purposes.
233    #[must_use]
234    pub fn original_bit_depth(&self) -> u8 {
235        // Note that this only works if all components have the same precision.
236        self.header.component_infos[0].size_info.precision
237    }
238
239    /// Whether decode finishes with additional host-side component mutation or reordering.
240    #[doc(hidden)]
241    #[must_use]
242    pub fn supports_direct_device_plane_reuse(&self) -> bool {
243        if self.settings.resolve_palette_indices && self.boxes.palette.is_some() {
244            return false;
245        }
246        if self.boxes.channel_definition.is_some() {
247            return false;
248        }
249        !matches!(
250            self.boxes
251                .primary_color_specification()
252                .map(|spec| &spec.color_space),
253            Some(jp2::colr::ColorSpace::Enumerated(
254                EnumeratedColorspace::Sycc | EnumeratedColorspace::CieLab(_)
255            ))
256        )
257    }
258
259    /// Decode the image and return its decoded result as a `Vec<u8>`, with each
260    /// channel interleaved.
261    ///
262    /// # Errors
263    ///
264    /// Returns an error when image validation, decoding, or output allocation fails.
265    pub fn decode(&self) -> Result<Vec<u8>> {
266        let bitmap = self.decode_with_context(&mut DecoderContext::default())?;
267        Ok(bitmap.data)
268    }
269
270    /// Decode the image and return its decoded result using a caller-provided
271    /// decoder context so allocations can be reused across repeated decodes.
272    ///
273    /// # Errors
274    ///
275    /// Returns an error when image validation, decoding, or output allocation fails.
276    pub fn decode_with_context(&self, decoder_context: &mut DecoderContext<'a>) -> Result<Bitmap> {
277        (|| {
278            let retained_image_bytes = self.retained_metadata_bytes()?;
279            let mut decoded_image = self.prepare_decoded_image(decoder_context)?;
280            let component_owner_capacity = decoded_image.decoded_components.capacity();
281            let buffer_size = checked_decode_byte_len3(
282                self.width() as usize,
283                self.height() as usize,
284                decoded_image.decoded_components.len(),
285            )?;
286            let mut budget = NativeOutputBudget::for_component_pack(
287                retained_image_bytes,
288                decoded_image.decoded_components,
289                component_owner_capacity,
290            )?;
291            budget.include_elements::<u8>(buffer_size)?;
292            budget.include_color_space_clone(&self.color_space)?;
293
294            let color_space = try_clone_color_space(&self.color_space)?;
295            budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
296            let mut data = Vec::new();
297            try_resize_decode_elements(&mut data, buffer_size, 0_u8)?;
298            budget.include_capacity_overage::<u8>(buffer_size, data.capacity())?;
299            validate_interleaved_output_buffer(&decoded_image, &data)?;
300            interleave_and_convert(&mut decoded_image, &mut data)?;
301            let bitmap = Bitmap {
302                color_space,
303                data,
304                has_alpha: self.has_alpha,
305                width: self.width(),
306                height: self.height(),
307                original_bit_depth: self.original_bit_depth(),
308            };
309            NativeOutputBudget::validate_bitmap_pack(
310                retained_image_bytes,
311                decoded_image.decoded_components,
312                component_owner_capacity,
313                &bitmap,
314            )?;
315            Ok(bitmap)
316        })()
317    }
318
319    /// Decode the image into borrowed component planes using a caller-provided
320    /// decoder context so allocations can be reused across repeated decodes.
321    ///
322    /// # Errors
323    ///
324    /// Returns an error when component precision is unsupported or decoding fails.
325    pub fn decode_components_with_context<'ctx>(
326        &self,
327        decoder_context: &'ctx mut DecoderContext<'a>,
328    ) -> Result<DecodedComponents<'ctx>> {
329        self.validate_component_plane_precision()?;
330        let decoded_image = self.prepare_decoded_image(decoder_context)?;
331        let DecodedImage {
332            decoded_components,
333            boxes: _,
334        } = decoded_image;
335        self.try_borrow_component_planes(
336            decoded_components.as_slice(),
337            decoded_components.capacity(),
338            (self.width(), self.height()),
339        )
340    }
341
342    /// Decode the image into owned native-bit-depth component planes.
343    ///
344    /// Unlike [`Self::decode_native`], this preserves per-component bit depth
345    /// and signedness metadata and does not require all components to share a
346    /// single packed interleaved representation.
347    ///
348    /// # Errors
349    ///
350    /// Returns an error when validation, decoding, or native sample packing fails.
351    pub fn decode_native_components(&self) -> Result<DecodedNativeComponents> {
352        let mut decoder_context = DecoderContext::default();
353        self.decode_native_components_with_context(&mut decoder_context)
354    }
355
356    /// Decode owned native component planes while accounting an already-live
357    /// external allocation, such as the encoded `Vec` being validated.
358    ///
359    /// `retained_capacity` must be the allocator capacity of that external
360    /// owner, not merely its logical length.
361    ///
362    /// # Errors
363    ///
364    /// Returns an error when aggregate retained allocation accounting,
365    /// decoding, or native component packing fails.
366    #[doc(hidden)]
367    pub fn decode_native_components_with_retained_capacity(
368        &self,
369        retained_capacity: usize,
370    ) -> Result<DecodedNativeComponents> {
371        let retained_baseline_bytes =
372            allocation::combine_retained_bytes(retained_capacity, self.retained_metadata_bytes()?)?;
373        let mut decoder_context = DecoderContext::default();
374        self.decode_native_components_with_context_and_retained_baseline(
375            &mut decoder_context,
376            retained_baseline_bytes,
377        )
378    }
379
380    /// Decode the image into owned native-bit-depth component planes using a
381    /// caller-provided decoder context.
382    ///
383    /// # Errors
384    ///
385    /// Returns an error when validation, decoding, or native sample packing fails.
386    pub fn decode_native_components_with_context(
387        &self,
388        decoder_context: &mut DecoderContext<'a>,
389    ) -> Result<DecodedNativeComponents> {
390        let retained_baseline_bytes = self.retained_metadata_bytes()?;
391        self.decode_native_components_with_context_and_retained_baseline(
392            decoder_context,
393            retained_baseline_bytes,
394        )
395    }
396
397    fn decode_native_components_with_context_and_retained_baseline(
398        &self,
399        decoder_context: &mut DecoderContext<'a>,
400        retained_baseline_bytes: usize,
401    ) -> Result<DecodedNativeComponents> {
402        let decoded_image = self.prepare_decoded_image_with_retained_baseline(
403            decoder_context,
404            retained_baseline_bytes,
405        )?;
406        let DecodedImage {
407            decoded_components,
408            boxes: _,
409        } = decoded_image;
410        let component_owner_capacity = decoded_components.capacity();
411        self.pack_native_component_planes(
412            decoded_components,
413            component_owner_capacity,
414            (self.width(), self.height()),
415            retained_baseline_bytes,
416        )
417    }
418
419    /// Decode borrowed component planes while delegating HTJ2K code-block decode.
420    #[doc(hidden)]
421    pub fn decode_components_with_ht_decoder<'ctx>(
422        &self,
423        decoder_context: &'ctx mut DecoderContext<'a>,
424        ht_decoder: &mut dyn HtCodeBlockDecoder,
425    ) -> Result<DecodedComponents<'ctx>> {
426        self.validate_component_plane_precision()?;
427        let decoded_image =
428            self.prepare_decoded_image_with_ht_decoder(decoder_context, ht_decoder)?;
429        let DecodedImage {
430            decoded_components,
431            boxes: _,
432        } = decoded_image;
433        self.try_borrow_component_planes(
434            decoded_components.as_slice(),
435            decoded_components.capacity(),
436            (self.width(), self.height()),
437        )
438    }
439
440    /// Decode borrowed component planes for a requested region using a
441    /// caller-provided decoder context.
442    ///
443    /// # Errors
444    ///
445    /// Returns an error when the region is invalid, precision is unsupported, or decoding fails.
446    pub fn decode_region_components_with_context<'ctx>(
447        &self,
448        roi: (u32, u32, u32, u32),
449        decoder_context: &'ctx mut DecoderContext<'a>,
450    ) -> Result<DecodedComponents<'ctx>> {
451        validate_roi((self.width(), self.height()), roi)?;
452        self.validate_component_plane_precision()?;
453        let (_x, _y, width, height) = roi;
454        let decoded_image = self.prepare_decoded_image_with_region(decoder_context, Some(roi))?;
455        let DecodedImage {
456            decoded_components,
457            boxes: _,
458        } = decoded_image;
459        self.try_borrow_component_planes(
460            decoded_components.as_slice(),
461            decoded_components.capacity(),
462            (width, height),
463        )
464    }
465
466    /// Decode a source-coordinate region into owned native-bit-depth component
467    /// planes using a caller-provided decoder context.
468    ///
469    /// # Errors
470    ///
471    /// Returns an error when the region is invalid or decoding and packing fail.
472    pub fn decode_native_region_components_with_context(
473        &self,
474        roi: (u32, u32, u32, u32),
475        decoder_context: &mut DecoderContext<'a>,
476    ) -> Result<DecodedNativeComponents> {
477        validate_roi((self.width(), self.height()), roi)?;
478        if self.requires_exact_integer_decode() {
479            return self.decode_native_region_components_via_full_decode(roi, decoder_context);
480        }
481        let (_x, _y, width, height) = roi;
482        let decoded_image = self.prepare_decoded_image_with_region(decoder_context, Some(roi))?;
483        let DecodedImage {
484            decoded_components,
485            boxes: _,
486        } = decoded_image;
487        let component_owner_capacity = decoded_components.capacity();
488        self.pack_native_component_planes(
489            decoded_components,
490            component_owner_capacity,
491            (width, height),
492            self.retained_metadata_bytes()?,
493        )
494    }
495
496    /// Decode borrowed component planes for a requested region while
497    /// delegating code-block/transform stages through the adapter backend hook.
498    #[doc(hidden)]
499    pub fn decode_region_components_with_ht_decoder<'ctx>(
500        &self,
501        decoder_context: &'ctx mut DecoderContext<'a>,
502        roi: (u32, u32, u32, u32),
503        ht_decoder: &mut dyn HtCodeBlockDecoder,
504    ) -> Result<DecodedComponents<'ctx>> {
505        validate_roi((self.width(), self.height()), roi)?;
506        self.validate_component_plane_precision()?;
507        let (_x, _y, width, height) = roi;
508        let decoded_image = self.prepare_decoded_image_with_region_and_ht_decoder(
509            decoder_context,
510            Some(roi),
511            Some(ht_decoder),
512        )?;
513        let DecodedImage {
514            decoded_components,
515            boxes: _,
516        } = decoded_image;
517        self.try_borrow_component_planes(
518            decoded_components.as_slice(),
519            decoded_components.capacity(),
520            (width, height),
521        )
522    }
523
524    /// Decode a region of the image and return it as an 8-bit interleaved bitmap.
525    ///
526    /// # Errors
527    ///
528    /// Returns an error when the region is invalid or decoding fails.
529    pub fn decode_region(&self, roi: (u32, u32, u32, u32)) -> Result<Bitmap> {
530        self.decode_region_with_context(roi, &mut DecoderContext::default())
531    }
532
533    /// Decode a region of the image and return it as an 8-bit interleaved bitmap
534    /// using a caller-provided decoder context.
535    ///
536    /// # Errors
537    ///
538    /// Returns an error when the region is invalid, decoding fails, or output sizing overflows.
539    pub fn decode_region_with_context(
540        &self,
541        roi: (u32, u32, u32, u32),
542        decoder_context: &mut DecoderContext<'a>,
543    ) -> Result<Bitmap> {
544        validate_roi((self.width(), self.height()), roi)?;
545        (|| {
546            let retained_image_bytes = self.retained_metadata_bytes()?;
547            let mut decoded_image =
548                self.prepare_decoded_image_with_region(decoder_context, Some(roi))?;
549            let component_owner_capacity = decoded_image.decoded_components.capacity();
550            let (_x, _y, width, height) = roi;
551            let data_len = checked_decode_byte_len3(
552                width as usize,
553                height as usize,
554                decoded_image.decoded_components.len(),
555            )?;
556            let mut budget = NativeOutputBudget::for_component_pack(
557                retained_image_bytes,
558                decoded_image.decoded_components,
559                component_owner_capacity,
560            )?;
561            budget.include_elements::<u8>(data_len)?;
562            budget.include_color_space_clone(&self.color_space)?;
563
564            let color_space = try_clone_color_space(&self.color_space)?;
565            budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
566            let mut data = Vec::new();
567            try_resize_decode_elements(&mut data, data_len, 0_u8)?;
568            budget.include_capacity_overage::<u8>(data_len, data.capacity())?;
569            interleave_and_convert_region(
570                &mut decoded_image,
571                width as usize,
572                (0, 0, width, height),
573                &mut data,
574            );
575            let bitmap = Bitmap {
576                color_space,
577                data,
578                has_alpha: self.has_alpha,
579                width,
580                height,
581                original_bit_depth: self.original_bit_depth(),
582            };
583            NativeOutputBudget::validate_bitmap_pack(
584                retained_image_bytes,
585                decoded_image.decoded_components,
586                component_owner_capacity,
587                &bitmap,
588            )?;
589            Ok(bitmap)
590        })()
591    }
592
593    /// Decode the image into the given buffer.
594    ///
595    /// This method does the same as [`Image::decode`], but you can provide
596    /// a custom buffer for the output, as well as a decoder context. Doing
597    /// so allows the internal decode engine to reuse memory allocations, so
598    /// this is especially recommended if you plan on converting multiple
599    /// images in the same session.
600    ///
601    /// The buffer must have the correct size.
602    ///
603    /// # Errors
604    ///
605    /// Returns an error when decoding fails or `buf` is too small for the image.
606    pub fn decode_into(
607        &self,
608        buf: &mut [u8],
609        decoder_context: &mut DecoderContext<'a>,
610    ) -> Result<()> {
611        let mut decoded_image = self.prepare_decoded_image(decoder_context)?;
612        validate_interleaved_output_buffer(&decoded_image, buf)?;
613        interleave_and_convert(&mut decoded_image, buf)?;
614
615        Ok(())
616    }
617
618    fn prepare_decoded_image<'ctx>(
619        &self,
620        decoder_context: &'ctx mut DecoderContext<'a>,
621    ) -> Result<DecodedImage<'ctx, '_>> {
622        self.prepare_decoded_image_with_region(decoder_context, None)
623    }
624
625    fn prepare_decoded_image_with_retained_baseline<'ctx>(
626        &self,
627        decoder_context: &'ctx mut DecoderContext<'a>,
628        retained_baseline_bytes: usize,
629    ) -> Result<DecodedImage<'ctx, '_>> {
630        self.prepare_decoded_image_with_region_and_ht_decoder_with_retained_baseline(
631            decoder_context,
632            None,
633            None,
634            retained_baseline_bytes,
635        )
636    }
637
638    fn prepare_decoded_image_with_ht_decoder<'ctx>(
639        &self,
640        decoder_context: &'ctx mut DecoderContext<'a>,
641        ht_decoder: &mut dyn HtCodeBlockDecoder,
642    ) -> Result<DecodedImage<'ctx, '_>> {
643        self.prepare_decoded_image_with_region_and_ht_decoder(
644            decoder_context,
645            None,
646            Some(ht_decoder),
647        )
648    }
649
650    fn prepare_decoded_image_with_region<'ctx>(
651        &self,
652        decoder_context: &'ctx mut DecoderContext<'a>,
653        output_region: Option<(u32, u32, u32, u32)>,
654    ) -> Result<DecodedImage<'ctx, '_>> {
655        self.prepare_decoded_image_with_region_and_ht_decoder(decoder_context, output_region, None)
656    }
657
658    fn prepare_decoded_image_with_region_and_ht_decoder<'ctx>(
659        &self,
660        decoder_context: &'ctx mut DecoderContext<'a>,
661        output_region: Option<(u32, u32, u32, u32)>,
662        ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
663    ) -> Result<DecodedImage<'ctx, '_>> {
664        let retained_baseline_bytes = self.retained_metadata_bytes()?;
665        self.prepare_decoded_image_with_region_and_ht_decoder_with_retained_baseline(
666            decoder_context,
667            output_region,
668            ht_decoder,
669            retained_baseline_bytes,
670        )
671    }
672
673    fn prepare_decoded_image_with_region_and_ht_decoder_with_retained_baseline<'ctx>(
674        &self,
675        decoder_context: &'ctx mut DecoderContext<'a>,
676        output_region: Option<(u32, u32, u32, u32)>,
677        ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
678        retained_baseline_bytes: usize,
679    ) -> Result<DecodedImage<'ctx, '_>> {
680        let settings = &self.settings;
681        self.decode_with_output_region_and_ht_decoder_with_retained_baseline(
682            decoder_context,
683            output_region,
684            ht_decoder,
685            retained_baseline_bytes,
686        )?;
687        let mut decoded_image = DecodedImage {
688            decoded_components: &mut decoder_context.tile_decode_context.channel_data,
689            boxes: &self.boxes,
690        };
691
692        if settings.resolve_palette_indices {
693            let components = core::mem::take(decoded_image.decoded_components);
694            *decoded_image.decoded_components =
695                resolve_palette_indices(components, decoded_image.boxes, retained_baseline_bytes)?;
696        }
697
698        if let Some(cdef) = &decoded_image.boxes.channel_definition {
699            validate_and_reorder_channels(
700                cdef,
701                decoded_image.decoded_components,
702                retained_baseline_bytes,
703            )?;
704        }
705
706        let bit_depth = decoded_image
707            .decoded_components
708            .first()
709            .ok_or(DecodingError::CodeBlockDecodeFailure)?
710            .bit_depth;
711        convert_color_space(&mut decoded_image, bit_depth)?;
712        Ok(decoded_image)
713    }
714
715    fn decode_with_output_region(
716        &self,
717        decoder_context: &mut DecoderContext<'a>,
718        output_region: Option<(u32, u32, u32, u32)>,
719    ) -> Result<()> {
720        self.decode_with_output_region_and_ht_decoder(decoder_context, output_region, None)
721    }
722
723    fn decode_with_output_region_and_ht_decoder(
724        &self,
725        decoder_context: &mut DecoderContext<'a>,
726        output_region: Option<(u32, u32, u32, u32)>,
727        ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
728    ) -> Result<()> {
729        let retained_metadata_bytes = self.retained_metadata_bytes()?;
730        self.decode_with_output_region_and_ht_decoder_with_retained_baseline(
731            decoder_context,
732            output_region,
733            ht_decoder,
734            retained_metadata_bytes,
735        )
736    }
737
738    fn decode_with_output_region_and_ht_decoder_with_retained_baseline(
739        &self,
740        decoder_context: &mut DecoderContext<'a>,
741        output_region: Option<(u32, u32, u32, u32)>,
742        mut ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
743        retained_baseline_bytes: usize,
744    ) -> Result<()> {
745        decoder_context.set_output_region(output_region);
746        let decode_result = j2c::decode(
747            self.codestream,
748            &self.header,
749            retained_baseline_bytes,
750            decoder_context,
751            &mut ht_decoder,
752        );
753        decoder_context.set_output_region(None);
754        decode_result
755    }
756}