use alloc::vec;
use alloc::vec::Vec;
use super::bitplane::BITPLANE_BIT_SIZE;
use super::build::SubBandType;
use super::DecodeSettings;
use crate::error::{bail, err, DecodingError, MarkerError, Result, ValidationError};
use crate::reader::BitReader;
use crate::{MAX_J2K_SPEC_COMPONENTS, MAX_NATIVE_DECODE_COMPONENTS};
const MAX_LAYER_COUNT: u8 = 32;
const MAX_RESOLUTION_COUNT: u8 = 32;
const MAX_PRECINCT_EXPONENT: u8 = 31;
#[derive(Debug)]
pub(crate) struct Header<'a> {
pub(crate) size_data: SizeData,
pub(crate) global_coding_style: CodingStyleDefault,
pub(crate) component_infos: Vec<ComponentInfo>,
pub(crate) progression_changes: Vec<ProgressionChange>,
pub(crate) plm_packet_lengths: Vec<u32>,
pub(crate) ppm_packets: Vec<PpmPacket<'a>>,
pub(crate) skipped_resolution_levels: u8,
pub(crate) strict: bool,
}
#[derive(Debug, Clone)]
pub(crate) struct PpmMarkerData<'a> {
pub(crate) sequence_idx: u8,
pub(crate) packets: Vec<PpmPacket<'a>>,
}
#[derive(Debug, Clone)]
pub(crate) struct PpmPacket<'a> {
pub(crate) data: &'a [u8],
}
#[derive(Debug, Clone)]
pub(crate) struct PacketLengthMarker {
pub(crate) sequence_idx: u8,
pub(crate) packet_lengths: Vec<u32>,
}
pub(crate) fn read_header<'a>(
reader: &mut BitReader<'a>,
settings: &DecodeSettings,
) -> Result<Header<'a>> {
if reader.read_marker()? != markers::SIZ {
bail!(MarkerError::Expected("SIZ"));
}
let mut size_data = size_marker(reader)?;
let mut cod = None;
let mut qcd = None;
let num_components = size_data.component_sizes.len() as u16;
let mut cod_components = vec![None; num_components as usize];
let mut qcd_components = vec![None; num_components as usize];
let mut rgn_components = vec![None; num_components as usize];
let mut progression_changes = vec![];
let mut plm_markers = vec![];
let mut ppm_markers = vec![];
loop {
match reader.peek_marker().ok_or(MarkerError::Invalid)? {
markers::SOT => break,
markers::CAP | markers::CPF => {
reader.read_marker()?;
skip_marker_segment(reader).ok_or(MarkerError::ParseFailure("CAP/CPF"))?;
}
markers::COD => {
reader.read_marker()?;
cod = Some(cod_marker(reader).ok_or(MarkerError::ParseFailure("COD"))?);
}
markers::COC => {
reader.read_marker()?;
let (component_index, coc) =
coc_marker(reader, num_components).ok_or(MarkerError::ParseFailure("COC"))?;
*cod_components
.get_mut(component_index as usize)
.ok_or(MarkerError::ParseFailure("COC"))? = Some(coc);
}
markers::QCD => {
reader.read_marker()?;
qcd = Some(qcd_marker(reader).ok_or(MarkerError::ParseFailure("QCD"))?);
}
markers::QCC => {
reader.read_marker()?;
let (component_index, qcc) =
qcc_marker(reader, num_components).ok_or(MarkerError::ParseFailure("QCC"))?;
*qcd_components
.get_mut(component_index as usize)
.ok_or(MarkerError::ParseFailure("QCC"))? = Some(qcc);
}
markers::POC => {
reader.read_marker()?;
let num_layers = cod
.as_ref()
.ok_or(MarkerError::ParseFailure("POC"))?
.num_layers;
progression_changes.extend(
poc_marker(reader, num_components, num_layers)
.ok_or(MarkerError::ParseFailure("POC"))?,
);
}
markers::RGN => {
reader.read_marker()?;
let rgn =
rgn_marker(reader, num_components).ok_or(MarkerError::ParseFailure("RGN"))?;
if rgn.style != 0 {
bail!(DecodingError::UnsupportedFeature("explicit ROI coding"));
}
*rgn_components
.get_mut(rgn.component_index as usize)
.ok_or(MarkerError::ParseFailure("RGN"))? = Some(rgn.shift);
}
markers::TLM => {
reader.read_marker()?;
tlm_marker(reader).ok_or(MarkerError::ParseFailure("TLM"))?;
}
markers::PLM => {
reader.read_marker()?;
plm_markers.push(plm_marker(reader).ok_or(MarkerError::ParseFailure("PLM"))?);
}
markers::COM => {
reader.read_marker()?;
com_marker(reader).ok_or(MarkerError::ParseFailure("COM"))?;
}
markers::PPM => {
reader.read_marker()?;
ppm_markers.push(ppm_marker(reader).ok_or(MarkerError::ParseFailure("PPM"))?);
}
markers::CRG => {
reader.read_marker()?;
skip_marker_segment(reader);
}
(0x30..=0x3F) => {
reader.read_marker()?;
}
_ => {
bail!(MarkerError::Unsupported);
}
}
}
let cod = cod.ok_or(MarkerError::Missing("COD"))?;
let qcd = qcd.ok_or(MarkerError::Missing("QCD"))?;
let component_infos: Vec<ComponentInfo> = size_data
.component_sizes
.iter()
.enumerate()
.map(|(idx, csi)| ComponentInfo {
size_info: *csi,
coding_style: cod_components[idx]
.clone()
.map(|mut c| {
c.flags.raw |= cod.component_parameters.flags.raw;
c
})
.unwrap_or(cod.component_parameters.clone()),
quantization_info: qcd_components[idx].clone().unwrap_or(qcd.clone()),
roi_shift: rgn_components[idx].unwrap_or(0),
})
.collect();
let min_num_resolution_levels = component_infos
.iter()
.map(|c| c.num_resolution_levels())
.min()
.ok_or(ValidationError::InvalidComponentMetadata)?;
let skipped_resolution_levels =
if let Some((target_width, target_height)) = settings.target_resolution {
if target_width == 0 || target_height == 0 {
bail!(ValidationError::InvalidDimensions);
}
let width_log = (size_data.image_width() / target_width)
.checked_ilog2()
.unwrap_or(0);
let height_log = (size_data.image_height() / target_height)
.checked_ilog2()
.unwrap_or(0);
width_log.min(height_log) as u8
} else {
0
}
.min(min_num_resolution_levels - 1);
size_data.x_resolution_shrink_factor *= 1 << skipped_resolution_levels;
size_data.y_resolution_shrink_factor *= 1 << skipped_resolution_levels;
ppm_markers.sort_by_key(|ppm_marker| ppm_marker.sequence_idx);
plm_markers.sort_by_key(|plm_marker| plm_marker.sequence_idx);
let header = Header {
size_data,
global_coding_style: cod.clone(),
component_infos,
progression_changes,
plm_packet_lengths: plm_markers
.into_iter()
.flat_map(|marker| marker.packet_lengths)
.collect(),
ppm_packets: ppm_markers
.into_iter()
.flat_map(|i| i.packets)
.filter_map(|p| if p.data.is_empty() { None } else { Some(p) })
.collect(),
skipped_resolution_levels,
strict: settings.strict,
};
validate(&header)?;
Ok(header)
}
fn validate(header: &Header<'_>) -> Result<()> {
for info in &header.component_infos {
let max_resolution_idx = info.coding_style.parameters.num_resolution_levels - 1;
let quantization_style = info.quantization_info.quantization_style;
let num_precinct_exponents = info.quantization_info.step_sizes.len();
if num_precinct_exponents == 0 {
bail!(ValidationError::MissingPrecinctExponents);
} else if matches!(
quantization_style,
QuantizationStyle::NoQuantization | QuantizationStyle::ScalarExpounded
) {
if max_resolution_idx == 0 {
if num_precinct_exponents == 0 {
bail!(ValidationError::InsufficientExponents);
}
} else if 1 + (max_resolution_idx as usize - 1) * 3 + 2 >= num_precinct_exponents {
bail!(ValidationError::InsufficientExponents);
}
}
}
Ok(())
}
#[derive(Debug, Clone)]
pub(crate) struct ComponentInfo {
pub(crate) size_info: ComponentSizeInfo,
pub(crate) coding_style: CodingStyleComponent,
pub(crate) quantization_info: QuantizationInfo,
pub(crate) roi_shift: u8,
}
impl ComponentInfo {
pub(crate) fn exponent_mantissa(
&self,
sub_band_type: SubBandType,
resolution: u8,
) -> Result<(u16, u16)> {
let n_ll = self.coding_style.parameters.num_decomposition_levels;
let sb_index = match sub_band_type {
SubBandType::LowLow => u16::MAX,
SubBandType::HighLow => 0,
SubBandType::LowHigh => 1,
SubBandType::HighHigh => 2,
};
let step_sizes = &self.quantization_info.step_sizes;
match self.quantization_info.quantization_style {
QuantizationStyle::NoQuantization | QuantizationStyle::ScalarExpounded => {
let entry = if resolution == 0 {
step_sizes.first()
} else {
step_sizes.get(1 + (resolution as usize - 1) * 3 + sb_index as usize)
};
Ok(entry
.map(|s| (s.exponent, s.mantissa))
.ok_or(ValidationError::MissingStepSize)?)
}
QuantizationStyle::ScalarDerived => {
let (e_0, mantissa) = step_sizes
.first()
.map(|s| (s.exponent, s.mantissa))
.ok_or(ValidationError::MissingStepSize)?;
let n_b = if resolution == 0 {
n_ll as u16
} else {
n_ll as u16 + 1 - resolution as u16
};
let exponent = e_0
.checked_sub(n_ll as u16)
.and_then(|e| e.checked_add(n_b))
.ok_or(ValidationError::InvalidExponents)?;
Ok((exponent, mantissa))
}
}
}
pub(crate) fn wavelet_transform(&self) -> WaveletTransform {
self.coding_style.parameters.transformation
}
pub(crate) fn num_resolution_levels(&self) -> u8 {
self.coding_style.parameters.num_resolution_levels
}
pub(crate) fn num_decomposition_levels(&self) -> u8 {
self.coding_style.parameters.num_decomposition_levels
}
pub(crate) fn code_block_style(&self) -> CodeBlockStyle {
self.coding_style.parameters.code_block_style
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::J2kWaveletTransform;
#[test]
fn wavelet_transform_converts_to_external_selector() {
assert_eq!(
J2kWaveletTransform::from(WaveletTransform::Reversible53),
J2kWaveletTransform::Reversible53
);
assert_eq!(
J2kWaveletTransform::from(WaveletTransform::Irreversible97),
J2kWaveletTransform::Irreversible97
);
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum ProgressionOrder {
LayerResolutionComponentPosition,
ResolutionLayerComponentPosition,
ResolutionPositionComponentLayer,
PositionComponentResolutionLayer,
ComponentPositionResolutionLayer,
}
#[derive(Debug, Clone)]
pub(crate) struct ProgressionChange {
pub(crate) resolution_start: u8,
pub(crate) component_start: u8,
pub(crate) layer_end: u8,
pub(crate) resolution_end: u8,
pub(crate) component_end: u8,
pub(crate) progression_order: ProgressionOrder,
}
impl ProgressionOrder {
fn from_u8(value: u8) -> Result<Self> {
match value {
0 => Ok(Self::LayerResolutionComponentPosition),
1 => Ok(Self::ResolutionLayerComponentPosition),
2 => Ok(Self::ResolutionPositionComponentLayer),
3 => Ok(Self::PositionComponentResolutionLayer),
4 => Ok(Self::ComponentPositionResolutionLayer),
_ => err!(ValidationError::InvalidProgressionOrder),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum WaveletTransform {
Irreversible97,
Reversible53,
}
impl WaveletTransform {
fn from_u8(value: u8) -> Result<Self> {
match value {
0 => Ok(Self::Irreversible97),
1 => Ok(Self::Reversible53),
_ => err!(ValidationError::InvalidTransformation),
}
}
}
impl From<WaveletTransform> for crate::J2kWaveletTransform {
fn from(transform: WaveletTransform) -> Self {
match transform {
WaveletTransform::Reversible53 => Self::Reversible53,
WaveletTransform::Irreversible97 => Self::Irreversible97,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub(crate) struct CodingStyleFlags {
pub(crate) raw: u8,
}
impl CodingStyleFlags {
fn from_u8(value: u8) -> Self {
Self { raw: value }
}
pub(crate) fn has_precincts(&self) -> bool {
(self.raw & 0x01) != 0
}
pub(crate) fn may_use_sop_markers(&self) -> bool {
(self.raw & 0x02) != 0
}
pub(crate) fn uses_eph_marker(&self) -> bool {
(self.raw & 0x04) != 0
}
}
#[derive(Debug, Clone, Copy, Default)]
pub(crate) struct CodeBlockStyle {
pub(crate) selective_arithmetic_coding_bypass: bool,
pub(crate) reset_context_probabilities: bool,
pub(crate) termination_on_each_pass: bool,
pub(crate) vertically_causal_context: bool,
pub(crate) segmentation_symbols: bool,
pub(crate) high_throughput_block_coding: bool,
}
impl CodeBlockStyle {
fn from_u8(value: u8) -> Self {
Self {
selective_arithmetic_coding_bypass: (value & 0x01) != 0,
reset_context_probabilities: (value & 0x02) != 0,
termination_on_each_pass: (value & 0x04) != 0,
vertically_causal_context: (value & 0x08) != 0,
segmentation_symbols: (value & 0x20) != 0,
high_throughput_block_coding: (value & 0x40) != 0,
}
}
pub(crate) fn uses_high_throughput_block_coding(&self) -> bool {
self.high_throughput_block_coding
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum QuantizationStyle {
NoQuantization,
ScalarDerived,
ScalarExpounded,
}
impl QuantizationStyle {
fn from_u8(value: u8) -> Result<Self> {
match value & 0x1F {
0 => Ok(Self::NoQuantization),
1 => Ok(Self::ScalarDerived),
2 => Ok(Self::ScalarExpounded),
_ => err!(ValidationError::InvalidQuantizationStyle),
}
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct StepSize {
pub(crate) mantissa: u16,
pub(crate) exponent: u16,
}
#[derive(Clone, Debug)]
pub(crate) struct QuantizationInfo {
pub(crate) quantization_style: QuantizationStyle,
pub(crate) guard_bits: u8,
pub(crate) step_sizes: Vec<StepSize>,
}
#[derive(Debug, Clone)]
pub(crate) struct CodingStyleDefault {
pub(crate) progression_order: ProgressionOrder,
pub(crate) num_layers: u8,
pub(crate) mct: bool,
pub(crate) component_parameters: CodingStyleComponent,
}
#[derive(Clone, Debug)]
pub(crate) struct CodingStyleComponent {
pub(crate) flags: CodingStyleFlags,
pub(crate) parameters: CodingStyleParameters,
}
#[derive(Clone, Debug)]
pub(crate) struct CodingStyleParameters {
pub(crate) num_decomposition_levels: u8,
pub(crate) num_resolution_levels: u8,
pub(crate) code_block_width: u8,
pub(crate) code_block_height: u8,
pub(crate) code_block_style: CodeBlockStyle,
pub(crate) transformation: WaveletTransform,
pub(crate) precinct_exponents: Vec<(u8, u8)>,
}
#[derive(Debug)]
pub(crate) struct SizeData {
pub(crate) reference_grid_width: u32,
pub(crate) reference_grid_height: u32,
pub(crate) image_area_x_offset: u32,
pub(crate) image_area_y_offset: u32,
pub(crate) tile_width: u32,
pub(crate) tile_height: u32,
pub(crate) tile_x_offset: u32,
pub(crate) tile_y_offset: u32,
pub(crate) component_sizes: Vec<ComponentSizeInfo>,
pub(crate) x_shrink_factor: u32,
pub(crate) y_shrink_factor: u32,
pub(crate) x_resolution_shrink_factor: u32,
pub(crate) y_resolution_shrink_factor: u32,
}
impl SizeData {
pub(crate) fn tile_x_coord(&self, idx: u32) -> u32 {
idx % self.num_x_tiles()
}
pub(crate) fn tile_y_coord(&self, idx: u32) -> u32 {
idx / self.num_x_tiles()
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ComponentSizeInfo {
pub(crate) precision: u8,
pub(crate) horizontal_resolution: u8,
pub(crate) vertical_resolution: u8,
}
impl SizeData {
pub(crate) fn num_x_tiles(&self) -> u32 {
(self.reference_grid_width - self.tile_x_offset).div_ceil(self.tile_width)
}
pub(crate) fn num_y_tiles(&self) -> u32 {
(self.reference_grid_height - self.tile_y_offset).div_ceil(self.tile_height)
}
pub(crate) fn num_tiles(&self) -> u32 {
self.num_x_tiles().saturating_mul(self.num_y_tiles())
}
pub(crate) fn image_width(&self) -> u32 {
(self.reference_grid_width - self.image_area_x_offset)
.div_ceil(self.x_shrink_factor * self.x_resolution_shrink_factor)
}
pub(crate) fn image_height(&self) -> u32 {
(self.reference_grid_height - self.image_area_y_offset)
.div_ceil(self.y_shrink_factor * self.y_resolution_shrink_factor)
}
}
fn size_marker(reader: &mut BitReader<'_>) -> Result<SizeData> {
let size_data = size_marker_inner(reader)?;
if size_data.tile_width == 0
|| size_data.tile_height == 0
|| size_data.reference_grid_width == 0
|| size_data.reference_grid_height == 0
{
bail!(ValidationError::InvalidDimensions);
}
if size_data.tile_x_offset >= size_data.reference_grid_width
|| size_data.tile_y_offset >= size_data.reference_grid_height
{
bail!(ValidationError::InvalidDimensions);
}
if size_data.tile_x_offset > size_data.image_area_x_offset
|| size_data.tile_y_offset > size_data.image_area_y_offset
{
bail!(crate::TileError::InvalidOffsets);
}
if size_data
.tile_x_offset
.checked_add(size_data.tile_width)
.ok_or(crate::TileError::InvalidOffsets)?
<= size_data.image_area_x_offset
|| size_data
.tile_y_offset
.checked_add(size_data.tile_height)
.ok_or(crate::TileError::InvalidOffsets)?
<= size_data.image_area_y_offset
{
bail!(crate::TileError::InvalidOffsets);
}
for comp in &size_data.component_sizes {
if comp.precision == 0 || comp.vertical_resolution == 0 || comp.horizontal_resolution == 0 {
bail!(ValidationError::InvalidComponentMetadata);
}
}
if size_data.image_width() > crate::MAX_J2K_IMAGE_DIMENSION
|| size_data.image_height() > crate::MAX_J2K_IMAGE_DIMENSION
{
bail!(ValidationError::ImageTooLarge);
}
let num_tiles = u64::from(size_data.num_x_tiles()) * u64::from(size_data.num_y_tiles());
if num_tiles > crate::MAX_J2K_TILE_COUNT {
bail!(ValidationError::TooManyTiles);
}
Ok(size_data)
}
fn read_siz_byte(reader: &mut BitReader<'_>) -> Result<u8> {
reader
.read_byte()
.ok_or(MarkerError::ParseFailure("SIZ").into())
}
fn read_siz_u16(reader: &mut BitReader<'_>) -> Result<u16> {
reader
.read_u16()
.ok_or(MarkerError::ParseFailure("SIZ").into())
}
fn read_siz_u32(reader: &mut BitReader<'_>) -> Result<u32> {
reader
.read_u32()
.ok_or(MarkerError::ParseFailure("SIZ").into())
}
fn size_marker_inner(reader: &mut BitReader<'_>) -> Result<SizeData> {
let _ = read_siz_u16(reader)?;
let _ = read_siz_u16(reader)?;
let xsiz = read_siz_u32(reader)?;
let ysiz = read_siz_u32(reader)?;
let x_osiz = read_siz_u32(reader)?;
let y_osiz = read_siz_u32(reader)?;
let xt_siz = read_siz_u32(reader)?;
let yt_siz = read_siz_u32(reader)?;
let xto_siz = read_siz_u32(reader)?;
let yto_siz = read_siz_u32(reader)?;
let csiz = read_siz_u16(reader)?;
if x_osiz >= xsiz || y_osiz >= ysiz {
bail!(ValidationError::InvalidDimensions);
}
if csiz == 0 {
bail!(ValidationError::InvalidComponentMetadata);
}
if csiz > MAX_J2K_SPEC_COMPONENTS || csiz > MAX_NATIVE_DECODE_COMPONENTS {
bail!(ValidationError::TooManyChannels);
}
let mut components = Vec::with_capacity(csiz as usize);
for _ in 0..csiz {
let ssiz = read_siz_byte(reader)?;
let x_rsiz = read_siz_byte(reader)?;
let y_rsiz = read_siz_byte(reader)?;
let precision = (ssiz & 0x7F) + 1;
let _is_signed = (ssiz & 0x80) != 0;
if precision as u32 > BITPLANE_BIT_SIZE {
bail!(ValidationError::InvalidComponentMetadata);
}
components.push(ComponentSizeInfo {
precision,
horizontal_resolution: x_rsiz,
vertical_resolution: y_rsiz,
});
}
let mut x_shrink_factor = 1;
let mut y_shrink_factor = 1;
let hr = components[0].horizontal_resolution;
let vr = components[0].vertical_resolution;
let mut same_resolution = true;
for component in &components[1..] {
same_resolution &= component.horizontal_resolution == hr;
same_resolution &= component.vertical_resolution == vr;
}
if same_resolution {
x_shrink_factor = hr as u32;
y_shrink_factor = vr as u32;
}
Ok(SizeData {
reference_grid_width: xsiz,
reference_grid_height: ysiz,
image_area_x_offset: x_osiz,
image_area_y_offset: y_osiz,
tile_width: xt_siz,
tile_height: yt_siz,
tile_x_offset: xto_siz,
tile_y_offset: yto_siz,
component_sizes: components,
x_shrink_factor,
y_shrink_factor,
x_resolution_shrink_factor: 1,
y_resolution_shrink_factor: 1,
})
}
fn coding_style_parameters(
reader: &mut BitReader<'_>,
coding_style: &CodingStyleFlags,
) -> Option<CodingStyleParameters> {
let num_decomposition_levels = reader.read_byte()?;
if num_decomposition_levels > MAX_RESOLUTION_COUNT {
return None;
}
let num_resolution_levels = num_decomposition_levels.checked_add(1)?;
let code_block_width = reader.read_byte()?.checked_add(2)?;
let code_block_height = reader.read_byte()?.checked_add(2)?;
let code_block_style = CodeBlockStyle::from_u8(reader.read_byte()?);
let transformation = WaveletTransform::from_u8(reader.read_byte()?).ok()?;
let mut precinct_exponents = Vec::new();
if coding_style.has_precincts() {
for _ in 0..num_resolution_levels {
let precinct_size = reader.read_byte()?;
let width_exp = precinct_size & 0xF;
let height_exp = precinct_size >> 4;
if width_exp > MAX_PRECINCT_EXPONENT || height_exp > MAX_PRECINCT_EXPONENT {
return None;
}
precinct_exponents.push((width_exp, height_exp));
}
} else {
for _ in 0..num_resolution_levels {
precinct_exponents.push((15, 15));
}
}
Some(CodingStyleParameters {
num_decomposition_levels,
num_resolution_levels,
code_block_width,
code_block_height,
code_block_style,
transformation,
precinct_exponents,
})
}
fn com_marker(reader: &mut BitReader<'_>) -> Option<()> {
skip_marker_segment(reader)
}
fn tlm_marker(reader: &mut BitReader<'_>) -> Option<()> {
skip_marker_segment(reader)
}
fn plm_marker(reader: &mut BitReader<'_>) -> Option<PacketLengthMarker> {
let segment_len = reader.read_u16()?.checked_sub(2)? as usize;
let segment = reader.read_bytes(segment_len)?;
let mut reader = BitReader::new(segment);
let sequence_idx = reader.read_byte()?;
let mut packet_lengths = vec![];
while !reader.at_end() {
let length_data_len = reader.read_u32()? as usize;
let length_data = reader.read_bytes(length_data_len)?;
packet_lengths.extend(decode_packet_lengths(length_data)?);
}
Some(PacketLengthMarker {
sequence_idx,
packet_lengths,
})
}
pub(crate) fn plt_marker(reader: &mut BitReader<'_>) -> Option<PacketLengthMarker> {
let segment_len = reader.read_u16()?.checked_sub(2)? as usize;
let segment = reader.read_bytes(segment_len)?;
let mut reader = BitReader::new(segment);
let sequence_idx = reader.read_byte()?;
let packet_lengths = decode_packet_lengths(reader.tail()?)?;
Some(PacketLengthMarker {
sequence_idx,
packet_lengths,
})
}
pub(crate) fn decode_packet_lengths(data: &[u8]) -> Option<Vec<u32>> {
let mut packet_lengths = vec![];
let mut value = 0_u32;
let mut in_progress = false;
for byte in data {
value = value.checked_shl(7)?.checked_add(u32::from(byte & 0x7F))?;
in_progress = true;
if byte & 0x80 == 0 {
packet_lengths.push(value);
value = 0;
in_progress = false;
}
}
if in_progress {
return None;
}
Some(packet_lengths)
}
fn ppm_marker<'a>(reader: &mut BitReader<'a>) -> Option<PpmMarkerData<'a>> {
let segment_len = reader.read_u16()?.checked_sub(2)? as usize;
let ppm_data = reader.read_bytes(segment_len)?;
let mut packets = vec![];
let mut reader = BitReader::new(ppm_data);
let sequence_idx = reader.read_byte()?;
while !reader.at_end() {
let packet_len = reader.read_u16()? as usize;
let data = reader.read_bytes(packet_len)?;
packets.push(PpmPacket { data });
}
Some(PpmMarkerData {
sequence_idx,
packets,
})
}
pub(crate) fn rgn_marker(reader: &mut BitReader<'_>, csiz: u16) -> Option<RgnMarkerData> {
let length = reader.read_u16()?;
let component_index_bytes = if csiz < 257 { 1 } else { 2 };
if length != 4 + component_index_bytes {
return None;
}
let component_index = read_component_index(reader, csiz)?;
if component_index >= csiz {
return None;
}
let style = reader.read_byte()?;
let shift = reader.read_byte()?;
Some(RgnMarkerData {
component_index,
style,
shift,
})
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct RgnMarkerData {
pub(crate) component_index: u16,
pub(crate) style: u8,
pub(crate) shift: u8,
}
pub(crate) fn skip_marker_segment(reader: &mut BitReader<'_>) -> Option<()> {
let length = reader.read_u16()?.checked_sub(2)?;
reader.skip_bytes(length as usize)?;
Some(())
}
pub(crate) fn cod_marker(reader: &mut BitReader<'_>) -> Option<CodingStyleDefault> {
let _ = reader.read_u16()?;
let coding_style_flags = CodingStyleFlags::from_u8(reader.read_byte()?);
let progression_order = ProgressionOrder::from_u8(reader.read_byte()?).ok()?;
let num_layers = reader.read_u16()?;
if num_layers == 0 || num_layers > MAX_LAYER_COUNT as u16 {
return None;
}
let mct = reader.read_byte()? == 1;
let coding_style_parameters = coding_style_parameters(reader, &coding_style_flags)?;
Some(CodingStyleDefault {
progression_order,
num_layers: num_layers as u8,
mct,
component_parameters: CodingStyleComponent {
flags: coding_style_flags,
parameters: coding_style_parameters,
},
})
}
pub(crate) fn coc_marker(
reader: &mut BitReader<'_>,
csiz: u16,
) -> Option<(u16, CodingStyleComponent)> {
let _ = reader.read_u16()?;
let component_index = if csiz < 257 {
reader.read_byte()? as u16
} else {
reader.read_u16()?
};
let coding_style = CodingStyleFlags::from_u8(reader.read_byte()?);
let parameters = coding_style_parameters(reader, &coding_style)?;
let coc = CodingStyleComponent {
flags: coding_style,
parameters,
};
Some((component_index, coc))
}
pub(crate) fn qcd_marker(reader: &mut BitReader<'_>) -> Option<QuantizationInfo> {
let length = reader.read_u16()?;
let sqcd_val = reader.read_byte()?;
let quantization_style = QuantizationStyle::from_u8(sqcd_val & 0x1F).ok()?;
let guard_bits = (sqcd_val >> 5) & 0x07;
let remaining_bytes = length.checked_sub(3)? as usize;
let mut parameters = quantization_parameters(reader, quantization_style, remaining_bytes)?;
parameters.guard_bits = guard_bits;
Some(parameters)
}
pub(crate) fn qcc_marker(reader: &mut BitReader<'_>, csiz: u16) -> Option<(u16, QuantizationInfo)> {
let length = reader.read_u16()?;
let component_index = if csiz < 257 {
reader.read_byte()? as u16
} else {
reader.read_u16()?
};
let sqcc_val = reader.read_byte()?;
let quantization_style = QuantizationStyle::from_u8(sqcc_val & 0x1F).ok()?;
let guard_bits = (sqcc_val >> 5) & 0x07;
let component_index_size = if csiz < 257 { 1 } else { 2 };
let remaining_bytes = length
.checked_sub(2)?
.checked_sub(component_index_size)?
.checked_sub(1)? as usize;
let mut parameters = quantization_parameters(reader, quantization_style, remaining_bytes)?;
parameters.guard_bits = guard_bits;
Some((component_index, parameters))
}
pub(crate) fn poc_marker(
reader: &mut BitReader<'_>,
csiz: u16,
_num_layers: u8,
) -> Option<Vec<ProgressionChange>> {
let length = reader.read_u16()?;
let remaining_bytes = length.checked_sub(2)?;
let component_index_size = if csiz < 257 { 1u16 } else { 2u16 };
let change_size = 1 + component_index_size + 2 + 1 + component_index_size + 1;
if remaining_bytes == 0 || remaining_bytes % change_size != 0 {
return None;
}
let change_count = remaining_bytes / change_size;
let mut changes = Vec::with_capacity(change_count as usize);
for _ in 0..change_count {
let resolution_start = reader.read_byte()?;
let component_start = read_component_index(reader, csiz)?;
let layer_end = reader.read_u16()?;
let resolution_end = reader.read_byte()?;
let component_end = read_component_index(reader, csiz)?;
let progression_order = ProgressionOrder::from_u8(reader.read_byte()?).ok()?;
if resolution_start >= resolution_end
|| component_start >= component_end
|| component_start >= csiz
|| layer_end == 0
|| layer_end > u16::from(u8::MAX)
|| component_end > u16::from(u8::MAX)
{
return None;
}
changes.push(ProgressionChange {
resolution_start,
component_start: component_start as u8,
layer_end: layer_end as u8,
resolution_end,
component_end: component_end as u8,
progression_order,
});
}
Some(changes)
}
fn read_component_index(reader: &mut BitReader<'_>, csiz: u16) -> Option<u16> {
if csiz < 257 {
Some(u16::from(reader.read_byte()?))
} else {
reader.read_u16()
}
}
fn quantization_parameters(
reader: &mut BitReader<'_>,
quantization_style: QuantizationStyle,
remaining_bytes: usize,
) -> Option<QuantizationInfo> {
let mut step_sizes = Vec::new();
let irreversible = |val: u16| {
let exponent = val >> 11;
let mantissa = val & ((1 << 11) - 1);
StepSize { exponent, mantissa }
};
match quantization_style {
QuantizationStyle::NoQuantization => {
for _ in 0..remaining_bytes {
let value = reader.read_byte()? as u16;
step_sizes.push(StepSize {
mantissa: 0,
exponent: (value >> 3),
});
}
}
QuantizationStyle::ScalarDerived => {
let value = reader.read_u16()?;
step_sizes.push(irreversible(value));
}
QuantizationStyle::ScalarExpounded => {
let num_bands = remaining_bytes / 2;
for _ in 0..num_bands {
let value = reader.read_u16()?;
step_sizes.push(irreversible(value));
}
}
}
Some(QuantizationInfo {
quantization_style,
guard_bits: 0,
step_sizes,
})
}
#[allow(
unused,
reason = "Not all marker codes are used in every decoding path yet"
)]
pub(crate) mod markers {
pub(crate) const SOC: u8 = 0x4F;
pub(crate) const SOT: u8 = 0x90;
pub(crate) const SOD: u8 = 0x93;
pub(crate) const EOC: u8 = 0xD9;
pub(crate) const CAP: u8 = 0x50;
pub(crate) const SIZ: u8 = 0x51;
pub(crate) const COD: u8 = 0x52;
pub(crate) const COC: u8 = 0x53;
pub(crate) const RGN: u8 = 0x5E;
pub(crate) const QCD: u8 = 0x5C;
pub(crate) const QCC: u8 = 0x5D;
pub(crate) const POC: u8 = 0x5F;
pub(crate) const TLM: u8 = 0x55;
pub(crate) const PLM: u8 = 0x57;
pub(crate) const PLT: u8 = 0x58;
pub(crate) const CPF: u8 = 0x59;
pub(crate) const PPM: u8 = 0x60;
pub(crate) const PPT: u8 = 0x61;
pub(crate) const SOP: u8 = 0x91;
pub(crate) const EPH: u8 = 0x92;
pub(crate) const CRG: u8 = 0x63;
pub(crate) const COM: u8 = 0x64;
pub(crate) fn to_string(marker: u8) -> &'static str {
match marker {
SOC => "SOC",
SOT => "SOT",
SOD => "SOD",
EOC => "EOC",
CAP => "CAP",
SIZ => "SIZ",
COD => "COD",
COC => "COC",
RGN => "RGN",
QCD => "QCD",
QCC => "QCC",
POC => "POC",
TLM => "TLM",
PLM => "PLM",
PLT => "PLT",
CPF => "CPF",
PPM => "PPM",
PPT => "PPT",
SOP => "SOP",
EPH => "EPH",
CRG => "CRG",
COM => "COM",
_ => "UNKNOWN",
}
}
}