use alloc::vec::Vec;
use crate::error::{FormatError, Result};
use crate::jp2::allocation::Jp2AllocationBudget;
use crate::jp2::ImageBoxes;
use crate::reader::BitReader;
use crate::DecodeError;
pub(super) fn parse(
boxes: &mut ImageBoxes,
data: &[u8],
budget: &mut Jp2AllocationBudget,
) -> Result<()> {
let mut reader = BitReader::new(data);
let meth = reader.read_byte().ok_or(FormatError::InvalidBox)?;
let _prec = reader.read_byte().ok_or(FormatError::InvalidBox)?;
let _approx = reader.read_byte().ok_or(FormatError::InvalidBox)?;
let mut enumerated_value = None;
let method = match meth {
1 => {
let enumerated = reader.read_u32().ok_or(FormatError::InvalidBox)?;
enumerated_value = Some(enumerated);
ColorSpace::Enumerated(
EnumeratedColorspace::from_raw(enumerated, &mut reader)
.ok_or(FormatError::InvalidBox)?,
)
}
2 => {
let profile_data = budget.try_copy_bytes(
reader.tail().ok_or(FormatError::InvalidBox)?,
"JP2 ICC profile",
)?;
ColorSpace::Icc(profile_data)
}
_ => ColorSpace::Unknown,
};
let parsed = ColorSpecificationBox {
method: meth,
enumerated_value,
color_space: method,
};
if boxes.color_specifications.len() == boxes.color_specifications.capacity() {
return Err(DecodeError::AllocationTooLarge {
what: "JP2 COLR metadata plan",
requested: usize::MAX,
cap: crate::DEFAULT_MAX_DECODE_BYTES,
});
}
boxes.color_specifications.push(parsed);
Ok(())
}
#[derive(Debug)]
pub(crate) struct ColorSpecificationBox {
pub(crate) method: u8,
pub(crate) enumerated_value: Option<u32>,
pub(crate) color_space: ColorSpace,
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum ColorSpace {
Enumerated(EnumeratedColorspace),
Icc(Vec<u8>),
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum EnumeratedColorspace {
BiLevel1,
YCbCr1,
YCbCr2,
YCbCr3,
PhotoYcc,
Cmy,
Cmyk,
Ycck,
CieLab(CieLab),
BiLevel2,
Srgb,
Greyscale,
Sycc,
CieJab,
EsRgb,
RommRgb,
YPbPr112560,
YPbPr125050,
EsYcc,
ScRgb,
ScRgbGray,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct CieLab {
pub(crate) rl: Option<u32>,
pub(crate) ol: Option<u32>,
pub(crate) ra: Option<u32>,
pub(crate) oa: Option<u32>,
pub(crate) rb: Option<u32>,
pub(crate) ob: Option<u32>,
}
impl EnumeratedColorspace {
fn from_raw(value: u32, reader: &mut BitReader<'_>) -> Option<Self> {
match value {
0 => Some(Self::BiLevel1),
1 => Some(Self::YCbCr1),
3 => Some(Self::YCbCr2),
4 => Some(Self::YCbCr3),
9 => Some(Self::PhotoYcc),
11 => Some(Self::Cmy),
12 => Some(Self::Cmyk),
13 => Some(Self::Ycck),
14 => {
let rl = reader.read_u32();
let ol = reader.read_u32();
let ra = reader.read_u32();
let oa = reader.read_u32();
let rb = reader.read_u32();
let ob = reader.read_u32();
let _il = reader.read_u32();
Some(Self::CieLab(CieLab {
rl,
ol,
ra,
oa,
rb,
ob,
}))
}
15 => Some(Self::BiLevel2),
16 => Some(Self::Srgb),
17 => Some(Self::Greyscale),
18 => Some(Self::Sycc),
19 => Some(Self::CieJab),
20 => Some(Self::EsRgb),
21 => Some(Self::RommRgb),
22 => Some(Self::YPbPr112560),
23 => Some(Self::YPbPr125050),
24 => Some(Self::EsYcc),
25 => Some(Self::ScRgb),
26 => Some(Self::ScRgbGray),
_ => None,
}
}
}