1use 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#[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#[derive(Clone, Copy)]
127pub(crate) struct ImageSource<'a> {
128 encoded_input: &'a [u8],
129 codestream: &'a [u8],
130}
131
132impl<'a> ImageSource<'a> {
133 pub(crate) const fn new(encoded_input: &'a [u8], codestream: &'a [u8]) -> Self {
134 Self {
135 encoded_input,
136 codestream,
137 }
138 }
139}
140
141pub(crate) struct ImageProperties {
142 boxes: ImageBoxes,
143 settings: DecodeSettings,
144 color_space: ColorSpace,
145 has_alpha: bool,
146 used_lenient_metadata_recovery: bool,
147}
148
149impl ImageProperties {
150 pub(crate) const fn new(
151 boxes: ImageBoxes,
152 settings: DecodeSettings,
153 color_space: ColorSpace,
154 has_alpha: bool,
155 used_lenient_metadata_recovery: bool,
156 ) -> Self {
157 Self {
158 boxes,
159 settings,
160 color_space,
161 has_alpha,
162 used_lenient_metadata_recovery,
163 }
164 }
165}
166
167impl<'a> Image<'a> {
168 pub(crate) fn from_parsed_parts(
169 source: ImageSource<'a>,
170 header: Header<'a>,
171 properties: ImageProperties,
172 ) -> Result<Self> {
173 Self::from_parsed_parts_with_retained_baseline(source, header, properties, 0)
174 }
175
176 pub(crate) fn from_parsed_parts_with_retained_baseline(
177 source: ImageSource<'a>,
178 header: Header<'a>,
179 properties: ImageProperties,
180 retained_baseline_bytes: usize,
181 ) -> Result<Self> {
182 let ImageProperties {
183 boxes,
184 settings,
185 color_space,
186 has_alpha,
187 used_lenient_metadata_recovery,
188 } = properties;
189 let metadata_bytes = retained_metadata_bytes(&header, &boxes, &color_space)?;
190 allocation::combine_retained_bytes(retained_baseline_bytes, metadata_bytes)?;
191 Ok(Self {
192 encoded_input: source.encoded_input,
193 codestream: source.codestream,
194 header,
195 boxes,
196 settings,
197 used_lenient_metadata_recovery,
198 has_alpha,
199 color_space,
200 })
201 }
202
203 pub(crate) fn retained_metadata_bytes(&self) -> Result<usize> {
204 retained_metadata_bytes(&self.header, &self.boxes, &self.color_space)
205 }
206
207 #[doc(hidden)]
214 pub fn retained_allocation_bytes(&self) -> Result<usize> {
215 self.retained_metadata_bytes()
216 }
217
218 #[doc(hidden)]
220 #[must_use]
221 pub const fn used_lenient_metadata_recovery(&self) -> bool {
222 self.used_lenient_metadata_recovery
223 }
224
225 pub fn new(data: &'a [u8], settings: &DecodeSettings) -> Result<Self> {
231 if data.starts_with(JP2_MAGIC) {
232 jp2::parse(data, *settings, None)
233 } else if data.starts_with(CODESTREAM_MAGIC) {
234 j2c::parse(data, settings, None)
235 } else {
236 err!(FormatError::InvalidSignature)
237 }
238 }
239
240 #[doc(hidden)]
251 pub fn new_with_reduction(
252 data: &'a [u8],
253 settings: &DecodeSettings,
254 reduction_levels: u8,
255 ) -> Result<Self> {
256 if settings.target_resolution.is_some() {
257 return err!(DecodingError::UnsupportedFeature(
258 "exact reduction cannot be combined with a target-resolution hint",
259 ));
260 }
261 if data.starts_with(JP2_MAGIC) {
262 jp2::parse(data, *settings, Some(reduction_levels))
263 } else if data.starts_with(CODESTREAM_MAGIC) {
264 j2c::parse(data, settings, Some(reduction_levels))
265 } else {
266 err!(FormatError::InvalidSignature)
267 }
268 }
269
270 #[doc(hidden)]
280 pub fn new_with_retained_baseline(
281 data: &'a [u8],
282 settings: &DecodeSettings,
283 retained_baseline_bytes: usize,
284 ) -> Result<Self> {
285 if retained_baseline_bytes == 0 {
286 return Self::new(data, settings);
287 }
288 if data.starts_with(JP2_MAGIC) {
289 jp2::parse_with_retained_baseline(data, *settings, retained_baseline_bytes, None)
290 } else if data.starts_with(CODESTREAM_MAGIC) {
291 j2c::parse_with_retained_baseline(data, settings, retained_baseline_bytes, None)
292 } else {
293 err!(FormatError::InvalidSignature)
294 }
295 }
296
297 #[must_use]
299 pub fn has_alpha(&self) -> bool {
300 self.has_alpha
301 }
302
303 #[must_use]
305 pub fn color_space(&self) -> &ColorSpace {
306 &self.color_space
307 }
308
309 #[doc(hidden)]
311 #[must_use]
312 pub fn primary_icc_profile(&self) -> Option<&[u8]> {
313 match self
314 .boxes
315 .primary_color_specification()
316 .map(|specification| &specification.color_space)
317 {
318 Some(jp2::colr::ColorSpace::Icc(profile)) => Some(profile),
319 _ => None,
320 }
321 }
322
323 #[must_use]
325 pub fn width(&self) -> u32 {
326 self.header.size_data.image_width()
327 }
328
329 #[must_use]
331 pub fn height(&self) -> u32 {
332 self.header.size_data.image_height()
333 }
334
335 #[must_use]
338 pub fn original_bit_depth(&self) -> u8 {
339 self.header.component_infos[0].size_info.precision
341 }
342
343 #[doc(hidden)]
345 #[must_use]
346 pub fn supports_direct_device_plane_reuse(&self) -> bool {
347 if self.settings.resolve_palette_indices && self.boxes.palette.is_some() {
348 return false;
349 }
350 if self.boxes.channel_definition.is_some() {
351 return false;
352 }
353 !matches!(
354 self.boxes
355 .primary_color_specification()
356 .map(|spec| &spec.color_space),
357 Some(jp2::colr::ColorSpace::Enumerated(
358 EnumeratedColorspace::Sycc | EnumeratedColorspace::CieLab(_)
359 ))
360 )
361 }
362
363 pub fn decode(&self) -> Result<Vec<u8>> {
370 let bitmap = self.decode_with_context(&mut DecoderContext::default())?;
371 Ok(bitmap.data)
372 }
373
374 pub fn decode_with_context(&self, decoder_context: &mut DecoderContext<'a>) -> Result<Bitmap> {
381 (|| {
382 let retained_image_bytes = self.retained_metadata_bytes()?;
383 let mut decoded_image =
384 self.decode_image(decoder_context, None, None, true, retained_image_bytes)?;
385 let component_owner_capacity = decoded_image.decoded_components.capacity();
386 let buffer_size = checked_decode_byte_len3(
387 self.width() as usize,
388 self.height() as usize,
389 decoded_image.decoded_components.len(),
390 )?;
391 let mut budget = NativeOutputBudget::for_decoded_channels(
392 retained_image_bytes,
393 decoded_image.decoded_components,
394 component_owner_capacity,
395 )?;
396 budget.include_elements::<u8>(buffer_size)?;
397 budget.include_color_space_clone(&self.color_space)?;
398
399 let color_space = try_clone_color_space(&self.color_space)?;
400 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
401 let mut data = Vec::new();
402 try_resize_decode_elements(&mut data, buffer_size, 0_u8)?;
403 budget.include_capacity_overage::<u8>(buffer_size, data.capacity())?;
404 validate_interleaved_output_buffer(&decoded_image, &data)?;
405 interleave_and_convert(&mut decoded_image, &mut data)?;
406 let bitmap = Bitmap {
407 color_space,
408 data,
409 has_alpha: self.has_alpha,
410 width: self.width(),
411 height: self.height(),
412 original_bit_depth: self.original_bit_depth(),
413 };
414 NativeOutputBudget::validate_bitmap_pack(
415 retained_image_bytes,
416 decoded_image.decoded_components,
417 component_owner_capacity,
418 &bitmap,
419 )?;
420 Ok(bitmap)
421 })()
422 }
423
424 pub fn decode_components_with_context<'ctx>(
431 &self,
432 decoder_context: &'ctx mut DecoderContext<'a>,
433 ) -> Result<DecodedComponents<'ctx>> {
434 self.validate_component_plane_precision()?;
435 let decoded_image = self.decode_image(
436 decoder_context,
437 None,
438 None,
439 false,
440 self.retained_metadata_bytes()?,
441 )?;
442 let DecodedImage {
443 decoded_components,
444 boxes: _,
445 } = decoded_image;
446 self.try_borrow_component_planes(
447 decoded_components.as_slice(),
448 decoded_components.capacity(),
449 (self.width(), self.height()),
450 )
451 }
452
453 pub fn decode_native_components(&self) -> Result<DecodedNativeComponents> {
463 let mut decoder_context = DecoderContext::default();
464 self.decode_native_components_with_context(&mut decoder_context)
465 }
466
467 #[doc(hidden)]
478 pub fn decode_native_components_with_retained_capacity(
479 &self,
480 retained_capacity: usize,
481 ) -> Result<DecodedNativeComponents> {
482 let retained_baseline_bytes =
483 allocation::combine_retained_bytes(retained_capacity, self.retained_metadata_bytes()?)?;
484 let mut decoder_context = DecoderContext::default();
485 self.decode_native_components_with_context_and_retained_baseline(
486 &mut decoder_context,
487 retained_baseline_bytes,
488 )
489 }
490
491 pub fn decode_native_components_with_context(
498 &self,
499 decoder_context: &mut DecoderContext<'a>,
500 ) -> Result<DecodedNativeComponents> {
501 let retained_baseline_bytes = self.retained_metadata_bytes()?;
502 self.decode_native_components_with_context_and_retained_baseline(
503 decoder_context,
504 retained_baseline_bytes,
505 )
506 }
507
508 fn decode_native_components_with_context_and_retained_baseline(
509 &self,
510 decoder_context: &mut DecoderContext<'a>,
511 retained_baseline_bytes: usize,
512 ) -> Result<DecodedNativeComponents> {
513 let decoded_image =
514 self.decode_image(decoder_context, None, None, true, retained_baseline_bytes)?;
515 let DecodedImage {
516 decoded_components,
517 boxes: _,
518 } = decoded_image;
519 let component_owner_capacity = decoded_components.capacity();
520 self.pack_native_component_planes(
521 decoded_components,
522 component_owner_capacity,
523 (self.width(), self.height()),
524 retained_baseline_bytes,
525 )
526 }
527
528 #[doc(hidden)]
530 pub fn decode_components_with_ht_decoder<'ctx>(
531 &self,
532 decoder_context: &'ctx mut DecoderContext<'a>,
533 ht_decoder: &mut dyn HtCodeBlockDecoder,
534 ) -> Result<DecodedComponents<'ctx>> {
535 self.validate_component_plane_precision()?;
536 let decoded_image = self.decode_image(
537 decoder_context,
538 None,
539 Some(ht_decoder),
540 false,
541 self.retained_metadata_bytes()?,
542 )?;
543 let DecodedImage {
544 decoded_components,
545 boxes: _,
546 } = decoded_image;
547 self.try_borrow_component_planes(
548 decoded_components.as_slice(),
549 decoded_components.capacity(),
550 (self.width(), self.height()),
551 )
552 }
553
554 pub fn decode_region_components_with_context<'ctx>(
561 &self,
562 roi: (u32, u32, u32, u32),
563 decoder_context: &'ctx mut DecoderContext<'a>,
564 ) -> Result<DecodedComponents<'ctx>> {
565 validate_roi((self.width(), self.height()), roi)?;
566 self.validate_component_plane_precision()?;
567 let (_x, _y, width, height) = roi;
568 let decoded_image = self.decode_image(
569 decoder_context,
570 Some(roi),
571 None,
572 false,
573 self.retained_metadata_bytes()?,
574 )?;
575 let DecodedImage {
576 decoded_components,
577 boxes: _,
578 } = decoded_image;
579 self.try_borrow_component_planes(
580 decoded_components.as_slice(),
581 decoded_components.capacity(),
582 (width, height),
583 )
584 }
585
586 pub fn decode_native_region_components_with_context(
593 &self,
594 roi: (u32, u32, u32, u32),
595 decoder_context: &mut DecoderContext<'a>,
596 ) -> Result<DecodedNativeComponents> {
597 validate_roi((self.width(), self.height()), roi)?;
598 if self.requires_exact_integer_decode() {
599 return self.decode_native_region_components_via_full_decode(roi, decoder_context);
600 }
601 let (_x, _y, width, height) = roi;
602 let retained_image_bytes = self.retained_metadata_bytes()?;
603 let decoded_image =
604 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
605 let DecodedImage {
606 decoded_components,
607 boxes: _,
608 } = decoded_image;
609 let component_owner_capacity = decoded_components.capacity();
610 self.pack_native_component_planes(
611 decoded_components,
612 component_owner_capacity,
613 (width, height),
614 retained_image_bytes,
615 )
616 }
617
618 #[doc(hidden)]
621 pub fn decode_region_components_with_ht_decoder<'ctx>(
622 &self,
623 decoder_context: &'ctx mut DecoderContext<'a>,
624 roi: (u32, u32, u32, u32),
625 ht_decoder: &mut dyn HtCodeBlockDecoder,
626 ) -> Result<DecodedComponents<'ctx>> {
627 validate_roi((self.width(), self.height()), roi)?;
628 self.validate_component_plane_precision()?;
629 let (_x, _y, width, height) = roi;
630 let decoded_image = self.decode_image(
631 decoder_context,
632 Some(roi),
633 Some(ht_decoder),
634 false,
635 self.retained_metadata_bytes()?,
636 )?;
637 let DecodedImage {
638 decoded_components,
639 boxes: _,
640 } = decoded_image;
641 self.try_borrow_component_planes(
642 decoded_components.as_slice(),
643 decoded_components.capacity(),
644 (width, height),
645 )
646 }
647
648 pub fn decode_region(&self, roi: (u32, u32, u32, u32)) -> Result<Bitmap> {
654 self.decode_region_with_context(roi, &mut DecoderContext::default())
655 }
656
657 pub fn decode_region_with_context(
664 &self,
665 roi: (u32, u32, u32, u32),
666 decoder_context: &mut DecoderContext<'a>,
667 ) -> Result<Bitmap> {
668 validate_roi((self.width(), self.height()), roi)?;
669 (|| {
670 let retained_image_bytes = self.retained_metadata_bytes()?;
671 let mut decoded_image =
672 self.decode_image(decoder_context, Some(roi), None, true, retained_image_bytes)?;
673 let component_owner_capacity = decoded_image.decoded_components.capacity();
674 let (_x, _y, width, height) = roi;
675 let data_len = checked_decode_byte_len3(
676 width as usize,
677 height as usize,
678 decoded_image.decoded_components.len(),
679 )?;
680 let mut budget = NativeOutputBudget::for_decoded_channels(
681 retained_image_bytes,
682 decoded_image.decoded_components,
683 component_owner_capacity,
684 )?;
685 budget.include_elements::<u8>(data_len)?;
686 budget.include_color_space_clone(&self.color_space)?;
687
688 let color_space = try_clone_color_space(&self.color_space)?;
689 budget.include_color_space_clone_overage(&self.color_space, &color_space)?;
690 let mut data = Vec::new();
691 try_resize_decode_elements(&mut data, data_len, 0_u8)?;
692 budget.include_capacity_overage::<u8>(data_len, data.capacity())?;
693 interleave_and_convert_region(
694 &mut decoded_image,
695 width as usize,
696 (0, 0, width, height),
697 &mut data,
698 )?;
699 let bitmap = Bitmap {
700 color_space,
701 data,
702 has_alpha: self.has_alpha,
703 width,
704 height,
705 original_bit_depth: self.original_bit_depth(),
706 };
707 NativeOutputBudget::validate_bitmap_pack(
708 retained_image_bytes,
709 decoded_image.decoded_components,
710 component_owner_capacity,
711 &bitmap,
712 )?;
713 Ok(bitmap)
714 })()
715 }
716
717 pub fn decode_into(
731 &self,
732 buf: &mut [u8],
733 decoder_context: &mut DecoderContext<'a>,
734 ) -> Result<()> {
735 let mut decoded_image = self.decode_image(
736 decoder_context,
737 None,
738 None,
739 true,
740 self.retained_metadata_bytes()?,
741 )?;
742 validate_interleaved_output_buffer(&decoded_image, buf)?;
743 interleave_and_convert(&mut decoded_image, buf)?;
744
745 Ok(())
746 }
747
748 fn decode_image<'ctx>(
749 &self,
750 decoder_context: &'ctx mut DecoderContext<'a>,
751 output_region: Option<(u32, u32, u32, u32)>,
752 ht_decoder: Option<&mut dyn HtCodeBlockDecoder>,
753 round_irreversible_output: bool,
754 retained_baseline_bytes: usize,
755 ) -> Result<DecodedImage<'ctx, '_>> {
756 let settings = &self.settings;
757 let mut ht_decoder = ht_decoder;
758 decoder_context.set_output_region(output_region);
759 decoder_context.set_round_irreversible_output(round_irreversible_output);
760 let decode_result = j2c::decode(
761 self.codestream,
762 &self.header,
763 retained_baseline_bytes,
764 decoder_context,
765 &mut ht_decoder,
766 );
767 decoder_context.set_output_region(None);
768 decoder_context.set_round_irreversible_output(false);
769 decode_result?;
770 let mut decoded_image = DecodedImage {
771 decoded_components: &mut decoder_context.tile_decode_context.channel_data,
772 boxes: &self.boxes,
773 };
774
775 if settings.resolve_palette_indices {
776 let components = core::mem::take(decoded_image.decoded_components);
777 *decoded_image.decoded_components =
778 resolve_palette_indices(components, decoded_image.boxes, retained_baseline_bytes)?;
779 }
780
781 if let Some(cdef) = decoded_image
782 .boxes
783 .primary_color_specification()
784 .and(decoded_image.boxes.channel_definition.as_ref())
785 {
786 validate_and_reorder_channels(
787 cdef,
788 decoded_image.decoded_components,
789 retained_baseline_bytes,
790 )?;
791 }
792
793 let bit_depth = decoded_image
794 .decoded_components
795 .first()
796 .ok_or(DecodingError::CodeBlockDecodeFailure)?
797 .bit_depth;
798 convert_color_space(&mut decoded_image, bit_depth)?;
799 Ok(decoded_image)
800 }
801}