#![no_std]
#![forbid(unsafe_code)]
#![forbid(missing_docs)]
extern crate alloc;
use alloc::vec::Vec;
use core::ops::Range;
mod limits;
#[doc(hidden)]
pub use limits::{MAX_JPEG2000_PART1_COMPONENTS, MAX_JPEG2000_PART1_SAMPLE_BIT_DEPTH};
mod resident;
#[doc(hidden)]
pub use resident::{
J2kResidentEncodeInput, J2kResidentEncodeInputError, J2kResidentHtj2kTileEncodeJob,
};
mod stage_error;
pub use stage_error::{J2kEncodeStageError, J2kEncodeStageErrorKind, J2kEncodeStageResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum J2kSubBandType {
LowLow,
HighLow,
LowHigh,
HighHigh,
}
#[derive(Debug, Clone, Copy)]
#[expect(
clippy::struct_excessive_bools,
reason = "the five booleans model independent JPEG 2000 COD code-block style flags"
)]
pub struct J2kCodeBlockStyle {
pub selective_arithmetic_coding_bypass: bool,
pub reset_context_probabilities: bool,
pub termination_on_each_pass: bool,
pub vertically_causal_context: bool,
pub segmentation_symbols: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct J2kCodeBlockSegment {
pub data_offset: u32,
pub data_length: u32,
pub start_coding_pass: u8,
pub end_coding_pass: u8,
pub use_arithmetic: bool,
}
#[derive(Debug)]
pub struct EncodedJ2kCodeBlock {
pub data: Vec<u8>,
pub segments: Vec<J2kCodeBlockSegment>,
pub number_of_coding_passes: u8,
pub missing_bit_planes: u8,
}
#[derive(Debug)]
pub struct EncodedHtJ2kCodeBlock {
pub data: Vec<u8>,
pub cleanup_length: u32,
pub refinement_length: u32,
pub num_coding_passes: u8,
pub num_zero_bitplanes: u8,
}
#[derive(Debug, Clone, Copy)]
pub struct J2kDeinterleaveToF32Job<'a> {
pub pixels: &'a [u8],
pub num_pixels: usize,
pub num_components: u16,
pub bit_depth: u8,
pub signed: bool,
}
#[derive(Debug)]
pub struct J2kForwardRctJob<'a> {
pub plane0: &'a mut [f32],
pub plane1: &'a mut [f32],
pub plane2: &'a mut [f32],
}
#[derive(Debug)]
pub struct J2kForwardIctJob<'a> {
pub plane0: &'a mut [f32],
pub plane1: &'a mut [f32],
pub plane2: &'a mut [f32],
}
#[derive(Debug, Clone, Copy)]
pub struct J2kForwardDwt53Job<'a> {
pub samples: &'a [f32],
pub width: u32,
pub height: u32,
pub num_levels: u8,
}
#[derive(Debug)]
pub struct J2kForwardDwt53Output {
pub ll: Vec<f32>,
pub ll_width: u32,
pub ll_height: u32,
pub levels: Vec<J2kForwardDwt53Level>,
}
#[derive(Debug)]
pub struct J2kForwardDwt53Level {
pub hl: Vec<f32>,
pub lh: Vec<f32>,
pub hh: Vec<f32>,
pub width: u32,
pub height: u32,
pub low_width: u32,
pub low_height: u32,
pub high_width: u32,
pub high_height: u32,
}
#[derive(Debug, Clone, Copy)]
pub struct J2kForwardDwt97Job<'a> {
pub samples: &'a [f32],
pub width: u32,
pub height: u32,
pub num_levels: u8,
}
#[derive(Debug)]
pub struct J2kForwardDwt97Output {
pub ll: Vec<f32>,
pub ll_width: u32,
pub ll_height: u32,
pub levels: Vec<J2kForwardDwt97Level>,
}
#[derive(Debug)]
pub struct J2kForwardDwt97Level {
pub hl: Vec<f32>,
pub lh: Vec<f32>,
pub hh: Vec<f32>,
pub width: u32,
pub height: u32,
pub low_width: u32,
pub low_height: u32,
pub high_width: u32,
pub high_height: u32,
}
#[derive(Debug, Clone, Copy)]
pub struct J2kQuantizeSubbandJob<'a> {
pub coefficients: &'a [f32],
pub step_exponent: u16,
pub step_mantissa: u16,
pub range_bits: u8,
pub reversible: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct J2kTier1CodeBlockEncodeJob<'a> {
pub coefficients: &'a [i32],
pub width: u32,
pub height: u32,
pub sub_band_type: J2kSubBandType,
pub total_bitplanes: u8,
pub style: J2kCodeBlockStyle,
}
#[derive(Debug, Clone, Copy)]
pub struct J2kHtCodeBlockEncodeJob<'a> {
pub coefficients: &'a [i32],
pub width: u32,
pub height: u32,
pub total_bitplanes: u8,
pub target_coding_passes: u8,
}
#[derive(Debug, Clone, Copy)]
pub struct J2kHtSubbandEncodeJob<'a> {
pub coefficients: &'a [f32],
pub width: u32,
pub height: u32,
pub step_exponent: u16,
pub step_mantissa: u16,
pub range_bits: u8,
pub reversible: bool,
pub code_block_width: u32,
pub code_block_height: u32,
pub total_bitplanes: u8,
}
#[derive(Debug, Clone, Copy)]
pub struct J2kHtj2kTileEncodeJob<'a> {
pub pixels: &'a [u8],
pub width: u32,
pub height: u32,
pub num_components: u16,
pub bit_depth: u8,
pub signed: bool,
pub num_decomposition_levels: u8,
pub reversible: bool,
pub use_mct: bool,
pub guard_bits: u8,
pub code_block_width: u32,
pub code_block_height: u32,
pub progression_order: J2kPacketizationProgressionOrder,
pub component_sampling: &'a [(u8, u8)],
pub quantization_steps: &'a [(u16, u16)],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct J2kPacketizationCodeBlock<'a> {
pub data: &'a [u8],
pub ht_cleanup_length: u32,
pub ht_refinement_length: u32,
pub num_coding_passes: u8,
pub num_zero_bitplanes: u8,
pub previously_included: bool,
pub l_block: u32,
pub block_coding_mode: J2kPacketizationBlockCodingMode,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum J2kPacketizationBlockCodingMode {
Classic,
HighThroughput,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum J2kPacketizationProgressionOrder {
Lrcp,
Rlcp,
Rpcl,
Pcrl,
Cprl,
}
impl J2kPacketizationProgressionOrder {
pub const fn codestream_order_code(self) -> u8 {
match self {
Self::Lrcp => 0x00,
Self::Rlcp => 0x01,
Self::Rpcl => 0x02,
Self::Pcrl => 0x03,
Self::Cprl => 0x04,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct J2kPacketizationSubband<'a> {
pub code_blocks: Vec<J2kPacketizationCodeBlock<'a>>,
pub num_cbs_x: u32,
pub num_cbs_y: u32,
}
#[derive(Debug, PartialEq, Eq)]
pub struct J2kPacketizationResolution<'a> {
pub subbands: Vec<J2kPacketizationSubband<'a>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct J2kPacketizationPacketDescriptor {
pub packet_index: u32,
pub state_index: u32,
pub layer: u8,
pub resolution: u32,
pub component: u16,
pub precinct: u64,
}
pub fn sort_packet_descriptors_for_progression(
descriptors: &mut [J2kPacketizationPacketDescriptor],
progression_order: J2kPacketizationProgressionOrder,
) {
match progression_order {
J2kPacketizationProgressionOrder::Lrcp => descriptors.sort_by_key(|descriptor| {
(
descriptor.layer,
descriptor.resolution,
descriptor.component,
descriptor.precinct,
)
}),
J2kPacketizationProgressionOrder::Rlcp => descriptors.sort_by_key(|descriptor| {
(
descriptor.resolution,
descriptor.layer,
descriptor.component,
descriptor.precinct,
)
}),
J2kPacketizationProgressionOrder::Rpcl => descriptors.sort_by_key(|descriptor| {
(
descriptor.resolution,
descriptor.precinct,
descriptor.component,
descriptor.layer,
)
}),
J2kPacketizationProgressionOrder::Pcrl => descriptors.sort_by_key(|descriptor| {
(
descriptor.precinct,
descriptor.component,
descriptor.resolution,
descriptor.layer,
)
}),
J2kPacketizationProgressionOrder::Cprl => descriptors.sort_by_key(|descriptor| {
(
descriptor.component,
descriptor.precinct,
descriptor.resolution,
descriptor.layer,
)
}),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct J2kPacketizationEncodeJob<'a> {
pub resolution_count: u32,
pub num_layers: u8,
pub num_components: u16,
pub code_block_count: u32,
pub progression_order: J2kPacketizationProgressionOrder,
pub packet_descriptors: &'a [J2kPacketizationPacketDescriptor],
pub resolutions: &'a [J2kPacketizationResolution<'a>],
}
#[cfg(test)]
mod packet_order_tests {
use super::{
sort_packet_descriptors_for_progression, J2kPacketizationPacketDescriptor,
J2kPacketizationProgressionOrder,
};
fn descriptors() -> [J2kPacketizationPacketDescriptor; 3] {
[
J2kPacketizationPacketDescriptor {
packet_index: 0,
state_index: 0,
layer: 1,
resolution: 0,
component: 2,
precinct: 1,
},
J2kPacketizationPacketDescriptor {
packet_index: 1,
state_index: 1,
layer: 0,
resolution: 1,
component: 1,
precinct: 0,
},
J2kPacketizationPacketDescriptor {
packet_index: 2,
state_index: 2,
layer: 0,
resolution: 0,
component: 0,
precinct: 2,
},
]
}
#[test]
fn progression_order_codes_match_codestream_values() {
assert_eq!(
J2kPacketizationProgressionOrder::Lrcp.codestream_order_code(),
0
);
assert_eq!(
J2kPacketizationProgressionOrder::Rlcp.codestream_order_code(),
1
);
assert_eq!(
J2kPacketizationProgressionOrder::Rpcl.codestream_order_code(),
2
);
assert_eq!(
J2kPacketizationProgressionOrder::Pcrl.codestream_order_code(),
3
);
assert_eq!(
J2kPacketizationProgressionOrder::Cprl.codestream_order_code(),
4
);
}
#[test]
fn packet_descriptor_sort_uses_requested_progression_order() {
let mut lrcp = descriptors();
sort_packet_descriptors_for_progression(&mut lrcp, J2kPacketizationProgressionOrder::Lrcp);
assert_eq!(lrcp.map(|descriptor| descriptor.packet_index), [2, 1, 0]);
let mut pcrl = descriptors();
sort_packet_descriptors_for_progression(&mut pcrl, J2kPacketizationProgressionOrder::Pcrl);
assert_eq!(pcrl.map(|descriptor| descriptor.packet_index), [1, 0, 2]);
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct J2kEncodeDispatchReport {
pub deinterleave: usize,
pub forward_rct: usize,
pub forward_ict: usize,
pub forward_dwt53: usize,
pub forward_dwt97: usize,
pub quantize_subband: usize,
pub tier1_code_block: usize,
pub ht_code_block: usize,
pub packetization: usize,
}
impl J2kEncodeDispatchReport {
#[must_use]
pub fn saturating_delta(self, before: Self) -> Self {
Self {
deinterleave: self.deinterleave.saturating_sub(before.deinterleave),
forward_rct: self.forward_rct.saturating_sub(before.forward_rct),
forward_ict: self.forward_ict.saturating_sub(before.forward_ict),
forward_dwt53: self.forward_dwt53.saturating_sub(before.forward_dwt53),
forward_dwt97: self.forward_dwt97.saturating_sub(before.forward_dwt97),
quantize_subband: self
.quantize_subband
.saturating_sub(before.quantize_subband),
tier1_code_block: self
.tier1_code_block
.saturating_sub(before.tier1_code_block),
ht_code_block: self.ht_code_block.saturating_sub(before.ht_code_block),
packetization: self.packetization.saturating_sub(before.packetization),
}
}
#[must_use]
pub fn total(self) -> usize {
self.forward_rct
.saturating_add(self.deinterleave)
.saturating_add(self.forward_ict)
.saturating_add(self.forward_dwt53)
.saturating_add(self.forward_dwt97)
.saturating_add(self.quantize_subband)
.saturating_add(self.tier1_code_block)
.saturating_add(self.ht_code_block)
.saturating_add(self.packetization)
}
#[must_use]
pub fn any(self) -> bool {
self.total() > 0
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct CpuOnlyJ2kEncodeStageAccelerator;
pub trait J2kEncodeStageAccelerator {
fn dispatch_report(&self) -> J2kEncodeDispatchReport {
J2kEncodeDispatchReport::default()
}
fn encode_deinterleave(
&mut self,
_job: J2kDeinterleaveToF32Job<'_>,
) -> J2kEncodeStageResult<Option<Vec<Vec<f32>>>> {
Ok(None)
}
fn encode_forward_rct(&mut self, _job: J2kForwardRctJob<'_>) -> J2kEncodeStageResult<bool> {
Ok(false)
}
fn encode_forward_ict(&mut self, _job: J2kForwardIctJob<'_>) -> J2kEncodeStageResult<bool> {
Ok(false)
}
fn encode_forward_dwt53(
&mut self,
_job: J2kForwardDwt53Job<'_>,
) -> J2kEncodeStageResult<Option<J2kForwardDwt53Output>> {
Ok(None)
}
fn encode_forward_dwt97(
&mut self,
_job: J2kForwardDwt97Job<'_>,
) -> J2kEncodeStageResult<Option<J2kForwardDwt97Output>> {
Ok(None)
}
fn encode_quantize_subband(
&mut self,
_job: J2kQuantizeSubbandJob<'_>,
) -> J2kEncodeStageResult<Option<Vec<i32>>> {
Ok(None)
}
fn encode_tier1_code_block(
&mut self,
_job: J2kTier1CodeBlockEncodeJob<'_>,
) -> J2kEncodeStageResult<Option<EncodedJ2kCodeBlock>> {
Ok(None)
}
fn encode_tier1_code_blocks(
&mut self,
_jobs: &[J2kTier1CodeBlockEncodeJob<'_>],
) -> J2kEncodeStageResult<Option<Vec<EncodedJ2kCodeBlock>>> {
Ok(None)
}
fn encode_ht_code_block(
&mut self,
_job: J2kHtCodeBlockEncodeJob<'_>,
) -> J2kEncodeStageResult<Option<EncodedHtJ2kCodeBlock>> {
Ok(None)
}
fn encode_ht_code_blocks(
&mut self,
_jobs: &[J2kHtCodeBlockEncodeJob<'_>],
) -> J2kEncodeStageResult<Option<Vec<EncodedHtJ2kCodeBlock>>> {
Ok(None)
}
fn encode_ht_subband(
&mut self,
_job: J2kHtSubbandEncodeJob<'_>,
) -> J2kEncodeStageResult<Option<Vec<EncodedHtJ2kCodeBlock>>> {
Ok(None)
}
fn encode_htj2k_tile(
&mut self,
_job: J2kHtj2kTileEncodeJob<'_>,
) -> J2kEncodeStageResult<Option<Vec<u8>>> {
Ok(None)
}
fn encode_resident_htj2k_tile(
&mut self,
_job: J2kResidentHtj2kTileEncodeJob<'_>,
) -> J2kEncodeStageResult<Option<Vec<u8>>> {
Ok(None)
}
fn prefer_parallel_cpu_code_block_fallback(&self) -> bool {
false
}
fn prefer_parallel_cpu_tile_encode(&self) -> bool {
false
}
fn encode_packetization(
&mut self,
_job: J2kPacketizationEncodeJob<'_>,
) -> J2kEncodeStageResult<Option<Vec<u8>>> {
Ok(None)
}
}
#[doc(hidden)]
impl J2kEncodeStageAccelerator for CpuOnlyJ2kEncodeStageAccelerator {
fn prefer_parallel_cpu_code_block_fallback(&self) -> bool {
true
}
fn prefer_parallel_cpu_tile_encode(&self) -> bool {
true
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct IrreversibleQuantizationSubbandScales {
pub low_low: f32,
pub high_low: f32,
pub low_high: f32,
pub high_high: f32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IrreversibleQuantizationStep {
pub exponent: u8,
pub mantissa: u16,
}
impl Default for IrreversibleQuantizationSubbandScales {
fn default() -> Self {
Self {
low_low: 1.0,
high_low: 1.0,
low_high: 1.0,
high_high: 1.0,
}
}
}
#[derive(Debug)]
pub struct PrecomputedHtj2k53Component {
pub x_rsiz: u8,
pub y_rsiz: u8,
pub dwt: J2kForwardDwt53Output,
}
#[derive(Debug)]
pub struct PrecomputedHtj2k53Image {
pub width: u32,
pub height: u32,
pub bit_depth: u8,
pub signed: bool,
pub components: Vec<PrecomputedHtj2k53Component>,
}
#[derive(Debug)]
pub struct PrecomputedHtj2k97Component {
pub x_rsiz: u8,
pub y_rsiz: u8,
pub dwt: J2kForwardDwt97Output,
}
#[derive(Debug)]
pub struct PrecomputedHtj2k97Image {
pub width: u32,
pub height: u32,
pub bit_depth: u8,
pub signed: bool,
pub components: Vec<PrecomputedHtj2k97Component>,
}
#[derive(Debug)]
pub struct PrequantizedHtj2k97Image {
pub width: u32,
pub height: u32,
pub bit_depth: u8,
pub signed: bool,
pub components: Vec<PrequantizedHtj2k97Component>,
}
#[derive(Debug)]
pub struct PrequantizedHtj2k97Component {
pub x_rsiz: u8,
pub y_rsiz: u8,
pub resolutions: Vec<PrequantizedHtj2k97Resolution>,
}
#[derive(Debug)]
pub struct PrequantizedHtj2k97Resolution {
pub subbands: Vec<PrequantizedHtj2k97Subband>,
}
#[derive(Debug)]
pub struct PrequantizedHtj2k97Subband {
pub sub_band_type: J2kSubBandType,
pub num_cbs_x: u32,
pub num_cbs_y: u32,
pub total_bitplanes: u8,
pub code_blocks: Vec<PrequantizedHtj2k97CodeBlock>,
}
#[derive(Debug)]
pub struct PrequantizedHtj2k97CodeBlock {
pub coefficients: Vec<i32>,
pub width: u32,
pub height: u32,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97Image {
pub width: u32,
pub height: u32,
pub bit_depth: u8,
pub signed: bool,
pub components: Vec<PreencodedHtj2k97Component>,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97Component {
pub x_rsiz: u8,
pub y_rsiz: u8,
pub resolutions: Vec<PreencodedHtj2k97Resolution>,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97Resolution {
pub subbands: Vec<PreencodedHtj2k97Subband>,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97Subband {
pub sub_band_type: J2kSubBandType,
pub num_cbs_x: u32,
pub num_cbs_y: u32,
pub total_bitplanes: u8,
pub code_blocks: Vec<PreencodedHtj2k97CodeBlock>,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97CodeBlock {
pub width: u32,
pub height: u32,
pub encoded: EncodedHtJ2kCodeBlock,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97CompactImage {
pub width: u32,
pub height: u32,
pub bit_depth: u8,
pub signed: bool,
pub payload: Vec<u8>,
pub components: Vec<PreencodedHtj2k97CompactComponent>,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97CompactComponent {
pub x_rsiz: u8,
pub y_rsiz: u8,
pub resolutions: Vec<PreencodedHtj2k97CompactResolution>,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97CompactResolution {
pub subbands: Vec<PreencodedHtj2k97CompactSubband>,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97CompactSubband {
pub sub_band_type: J2kSubBandType,
pub num_cbs_x: u32,
pub num_cbs_y: u32,
pub total_bitplanes: u8,
pub code_blocks: Vec<PreencodedHtj2k97CompactCodeBlock>,
}
#[derive(Debug)]
pub struct PreencodedHtj2k97CompactCodeBlock {
pub width: u32,
pub height: u32,
pub payload_range: Range<usize>,
pub cleanup_length: u32,
pub refinement_length: u32,
pub num_coding_passes: u8,
pub num_zero_bitplanes: u8,
}