Skip to main content

pdfluent_jpeg2000/jp2/
mod.rs

1//! Reading a JP2 file, defined in Annex I.
2
3use alloc::vec::Vec;
4
5use crate::error::{FormatError, Result, bail};
6use crate::j2c::ComponentData;
7use crate::jp2::r#box::{FILE_TYPE, JP2_SIGNATURE};
8use crate::jp2::cdef::ChannelDefinitionBox;
9use crate::jp2::cmap::{ComponentMappingBox, ComponentMappingEntry, ComponentMappingType};
10use crate::jp2::colr::ColorSpecificationBox;
11use crate::jp2::pclr::PaletteBox;
12use crate::reader::BitReader;
13use crate::{DecodeSettings, Image, resolve_alpha_and_color_space};
14
15pub(crate) mod r#box;
16pub(crate) mod cdef;
17pub(crate) mod cmap;
18pub(crate) mod colr;
19pub(crate) mod icc;
20pub(crate) mod pclr;
21
22#[derive(Debug, Clone, Default)]
23pub(crate) struct ImageBoxes {
24    pub(crate) color_specification: Option<ColorSpecificationBox>,
25    pub(crate) channel_definition: Option<ChannelDefinitionBox>,
26    pub(crate) palette: Option<PaletteBox>,
27    pub(crate) component_mapping: Option<ComponentMappingBox>,
28}
29
30/// A decoded JPEG2000 image.
31pub struct DecodedImage<'a> {
32    /// The raw decoded JPEG2000 codestream components.
33    pub(crate) decoded_components: &'a mut Vec<ComponentData>,
34    /// The JP2 boxes of the image. In the case of a raw codestream, we
35    /// will synthesize the necessary boxes.
36    pub(crate) boxes: ImageBoxes,
37}
38
39pub(crate) fn parse<'a>(data: &'a [u8], mut settings: DecodeSettings) -> Result<Image<'a>> {
40    let mut reader = BitReader::new(data);
41    let signature_box = r#box::read(&mut reader).ok_or(FormatError::InvalidBox)?;
42
43    if signature_box.box_type != JP2_SIGNATURE {
44        bail!(FormatError::InvalidSignature);
45    }
46
47    let file_type_box = r#box::read(&mut reader).ok_or(FormatError::InvalidBox)?;
48
49    if file_type_box.box_type != FILE_TYPE {
50        bail!(FormatError::InvalidFileType);
51    }
52
53    let mut image_boxes: Option<ImageBoxes> = None;
54    let mut parsed_codestream = None;
55
56    // Read boxes until we find the JP2 Header box
57    while !reader.at_end() {
58        let Some(current_box) = r#box::read(&mut reader) else {
59            if settings.strict {
60                bail!(FormatError::InvalidBox);
61            }
62
63            break;
64        };
65
66        match current_box.box_type {
67            r#box::JP2_HEADER => {
68                let mut boxes = ImageBoxes::default();
69
70                let mut jp2h_reader = BitReader::new(current_box.data);
71
72                // Read child boxes within JP2 Header box
73                while !jp2h_reader.at_end() {
74                    let child_box = r#box::read(&mut jp2h_reader).ok_or(FormatError::InvalidBox)?;
75
76                    match child_box.box_type {
77                        r#box::CHANNEL_DEFINITION => {
78                            if cdef::parse(&mut boxes, child_box.data).is_err() && settings.strict {
79                                bail!(FormatError::InvalidBox);
80                            }
81                            // If not strict decoding, just assume default
82                            // configuration.
83                        }
84                        r#box::COLOUR_SPECIFICATION => {
85                            colr::parse(&mut boxes, child_box.data)?;
86                        }
87                        r#box::PALETTE => {
88                            if pclr::parse(&mut boxes, child_box.data).is_err() && settings.strict {
89                                bail!(FormatError::InvalidBox);
90                            }
91
92                            // If we have a palettized image, decoding at a
93                            // lower resolution will corrupt it, so we can't do
94                            // it in this case.
95                            settings.target_resolution = None;
96                        }
97                        r#box::COMPONENT_MAPPING => {
98                            cmap::parse(&mut boxes, child_box.data)?;
99                        }
100                        _ => {
101                            debug!(
102                                "ignoring header box {}",
103                                r#box::tag_to_string(child_box.box_type)
104                            );
105                        }
106                    }
107                }
108
109                image_boxes = Some(boxes);
110            }
111            r#box::CONTIGUOUS_CODESTREAM => {
112                parsed_codestream = Some(crate::j2c::parse_raw(current_box.data, &settings)?);
113            }
114            _ => {}
115        }
116    }
117
118    let mut image_boxes = image_boxes.ok_or(FormatError::InvalidBox)?;
119    let parsed_codestream = parsed_codestream.ok_or(FormatError::MissingCodestream)?;
120
121    if let Some(palette) = image_boxes.palette.as_ref()
122        && image_boxes.component_mapping.is_none()
123    {
124        // In theory, a cmap is required if we have pclr, but since there are
125        // some files that don't seem to do so, we assume
126        // that all channels are mapped via the palette in case not.
127        let mappings = (0..palette.columns.len())
128            .map(|i| ComponentMappingEntry {
129                component_index: 0,
130                mapping_type: ComponentMappingType::Palette { column: i as u8 },
131            })
132            .collect::<Vec<_>>();
133
134        image_boxes.component_mapping = Some(ComponentMappingBox { entries: mappings });
135    }
136
137    let (color_space, has_alpha) =
138        resolve_alpha_and_color_space(&image_boxes, &parsed_codestream.header, &settings)?;
139
140    Ok(Image {
141        codestream: parsed_codestream.data,
142        header: parsed_codestream.header,
143        boxes: image_boxes,
144        settings,
145        color_space,
146        has_alpha,
147    })
148}