1#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
67#![forbid(unsafe_code)]
68#![forbid(missing_docs)]
69
70extern crate alloc;
71
72#[cfg(test)]
73use alloc::vec;
74use alloc::vec::Vec;
75
76use crate::error::bail;
77#[cfg(test)]
78use crate::jp2::colr::CieLab;
79
80macro_rules! define_ht_code_block_job {
81 (
82 $(#[$meta:meta])*
83 pub struct $name:ident $(<$lt:lifetime>)? {
84 $($prefix:tt)*
85 }
86 ) => {
87 $(#[$meta])*
88 pub struct $name $(<$lt>)? {
89 $($prefix)*
90 pub cleanup_length: u32,
92 pub refinement_length: u32,
94 pub width: u32,
96 pub height: u32,
98 pub output_stride: usize,
100 pub missing_bit_planes: u8,
102 pub number_of_coding_passes: u8,
104 pub num_bitplanes: u8,
106 pub roi_shift: u8,
108 pub stripe_causal: bool,
110 pub strict: bool,
112 pub dequantization_step: f32,
114 }
115 };
116}
117
118#[doc(hidden)]
119#[macro_export]
120macro_rules! __j2k_component_plane_metadata_accessors {
121 () => {
122 #[must_use]
124 pub fn dimensions(&self) -> (u32, u32) {
125 self.dimensions
126 }
127
128 #[must_use]
130 pub fn sampling(&self) -> (u8, u8) {
131 self.sampling
132 }
133
134 #[must_use]
136 pub fn bit_depth(&self) -> u8 {
137 self.bit_depth
138 }
139
140 #[must_use]
142 pub fn signed(&self) -> bool {
143 self.signed
144 }
145 };
146}
147
148mod backend;
149mod color;
150mod error;
151mod ht_adapter;
152mod inspect;
153#[macro_use]
154pub(crate) mod log;
155mod direct_cpu;
156mod direct_plan;
157mod direct_roi;
158pub(crate) mod math;
159#[doc(hidden)]
160pub mod packet_math;
161pub(crate) mod profile;
162mod roi;
163pub(crate) mod writer;
164
165#[cfg(test)]
166use crate::math::{dispatch, Level};
167#[cfg(test)]
168use color::cielab_to_rgb;
169pub(crate) use color::{
170 convert_color_space, interleave_and_convert, interleave_and_convert_region,
171 resolve_alpha_and_color_space, resolve_palette_indices, validate_and_reorder_channels,
172 validate_interleaved_output_buffer,
173};
174pub use color::{
175 Bitmap, ColorSpace, ComponentPlane, DecodedComponents, DecodedNativeComponents,
176 NativeComponentPlane, RawBitmap,
177};
178#[doc(hidden)]
179pub use color::{ComponentPlaneParts, NativeComponentPlaneParts};
180#[doc(hidden)]
181pub use direct_cpu::{
182 execute_direct_color_plan_rgb8_into, execute_direct_color_plan_rgba8_into, J2kDirectCpuScratch,
183};
184#[doc(hidden)]
185pub use direct_plan::{
186 HtOwnedCodeBlockBatchJob, HtOwnedSubBandPlan, J2kDirectBandId, J2kDirectColorPlan,
187 J2kDirectGrayscalePlan, J2kDirectGrayscaleStep, J2kDirectIdwtStep, J2kDirectStoreStep,
188 J2kOwnedCodeBlockBatchJob, J2kOwnedSubBandPlan,
189};
190#[doc(hidden)]
191pub use direct_roi::{
192 idwt_required_input_window_for_rects, idwt_required_input_windows, idwt_required_output_margin,
193 J2kIdwtRequiredInputWindows, J2kRequiredBandRegion,
194};
195pub use inspect::{
196 inspect_j2k_codestream_header, looks_like_j2k_codestream, J2kCodestreamComponentHeader,
197 J2kCodestreamHeaderError, J2kCodestreamHeaderMetadata,
198};
199#[doc(hidden)]
200pub use jp2::{
201 extract_jp2_codestream_payload, inspect_jp2_container, Jp2ChannelAssociation,
202 Jp2ChannelDefinition, Jp2ChannelType, Jp2ColorSpec, Jp2ComponentMapping,
203 Jp2ComponentMappingType, Jp2ComponentMetadata, Jp2Container, Jp2FileKind, Jp2FileMetadata,
204 Jp2ImageHeaderMetadata, Jp2PaletteColumn, Jp2PaletteMetadata,
205};
206#[doc(hidden)]
207pub use roi::idwt_band_index;
208pub(crate) use roi::{
209 add_roi_shift_to_bitplanes, apply_roi_maxshift_inverse_i32, apply_roi_maxshift_inverse_i64,
210 validate_roi,
211};
212
213pub use error::{
214 ColorError, DecodeError, DecodeErrorClass, DecodingError, DirectPlanUnsupportedReason,
215 EncodeError, EncodeResult, FormatError, MarkerError, Result, TileError, ValidationError,
216};
217#[cfg(test)]
218pub(crate) use j2c::encode::NativeEncodeRetainedInput;
219pub use j2c::encode::{
220 encode, encode_component_planes_53, encode_htj2k, encode_precomputed_htj2k_53,
221 encode_precomputed_htj2k_53_with_accelerator,
222 encode_precomputed_htj2k_53_with_accelerator_and_max_host_bytes,
223 encode_precomputed_htj2k_53_with_mct, encode_precomputed_htj2k_53_with_mct_and_accelerator,
224 encode_precomputed_htj2k_97, encode_precomputed_htj2k_97_batch_owned_with_accelerator,
225 encode_precomputed_htj2k_97_batch_owned_with_accelerator_and_max_host_bytes,
226 encode_precomputed_htj2k_97_batch_with_accelerator,
227 encode_precomputed_htj2k_97_with_accelerator,
228 encode_precomputed_htj2k_97_with_accelerator_and_max_host_bytes, encode_precomputed_j2k_53,
229 encode_precomputed_j2k_53_with_accelerator, encode_precomputed_j2k_53_with_mct,
230 encode_precomputed_j2k_53_with_mct_and_accelerator, encode_preencoded_htj2k_97,
231 encode_preencoded_htj2k_97_compact_owned_with_accelerator,
232 encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes,
233 encode_preencoded_htj2k_97_owned_with_accelerator,
234 encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes,
235 encode_preencoded_htj2k_97_with_accelerator, encode_prequantized_htj2k_97,
236 encode_prequantized_htj2k_97_with_accelerator,
237 encode_prequantized_htj2k_97_with_accelerator_and_max_host_bytes,
238 encode_resident_htj2k_with_accelerator, encode_typed_component_planes_53,
239 encode_with_accelerator, encode_with_accelerator_and_roi_regions, encode_with_roi_regions,
240 irreversible_quantization_step_for_subband, EncodeComponentPlane, EncodeOptions,
241 EncodeProgressionOrder, EncodeRoiRegion, EncodeTypedComponentPlane, ResidentHtj2kEncodeError,
242};
243pub use j2c::{CpuDecodeParallelism, DecoderContext, Reversible53CoefficientImage};
244#[doc(hidden)]
245pub use j2k_types::{
246 sort_packet_descriptors_for_progression, CpuOnlyJ2kEncodeStageAccelerator,
247 EncodedHtJ2kCodeBlock, EncodedJ2kCodeBlock, IrreversibleQuantizationStep,
248 IrreversibleQuantizationSubbandScales, J2kCodeBlockSegment, J2kCodeBlockStyle,
249 J2kDeinterleaveToF32Job, J2kEncodeDispatchReport, J2kEncodeStageAccelerator,
250 J2kEncodeStageError, J2kEncodeStageErrorKind, J2kEncodeStageResult, J2kForwardDwt53Job,
251 J2kForwardDwt53Level, J2kForwardDwt53Output, J2kForwardDwt97Job, J2kForwardDwt97Level,
252 J2kForwardDwt97Output, J2kForwardIctJob, J2kForwardRctJob, J2kHtCodeBlockEncodeJob,
253 J2kHtSubbandEncodeJob, J2kHtj2kTileEncodeJob, J2kPacketizationBlockCodingMode,
254 J2kPacketizationCodeBlock, J2kPacketizationEncodeJob, J2kPacketizationPacketDescriptor,
255 J2kPacketizationProgressionOrder, J2kPacketizationResolution, J2kPacketizationSubband,
256 J2kQuantizeSubbandJob, J2kResidentEncodeInput, J2kResidentEncodeInputError,
257 J2kResidentHtj2kTileEncodeJob, J2kSubBandType, J2kTier1CodeBlockEncodeJob,
258 PrecomputedHtj2k53Component, PrecomputedHtj2k53Image, PrecomputedHtj2k97Component,
259 PrecomputedHtj2k97Image, PreencodedHtj2k97CodeBlock, PreencodedHtj2k97CompactCodeBlock,
260 PreencodedHtj2k97CompactComponent, PreencodedHtj2k97CompactImage,
261 PreencodedHtj2k97CompactResolution, PreencodedHtj2k97CompactSubband,
262 PreencodedHtj2k97Component, PreencodedHtj2k97Image, PreencodedHtj2k97Resolution,
263 PreencodedHtj2k97Subband, PrequantizedHtj2k97CodeBlock, PrequantizedHtj2k97Component,
264 PrequantizedHtj2k97Image, PrequantizedHtj2k97Resolution, PrequantizedHtj2k97Subband,
265};
266
267mod j2c;
268mod jp2;
269pub(crate) mod reader;
270#[doc(hidden)]
271pub use j2c::ht_encode_tables::HtUvlcTableEntry;
272
273const MAX_CLASSIC_DECODE_BITPLANES: u8 = j2c::MAX_BITPLANE_COUNT;
274const MAX_DEINTERLEAVE_REFERENCE_BIT_DEPTH: u8 = j2k_types::MAX_JPEG2000_PART1_SAMPLE_BIT_DEPTH;
275pub(crate) use j2k_types::MAX_JPEG2000_PART1_COMPONENTS as MAX_J2K_SPEC_COMPONENTS;
276pub(crate) const MAX_J2K_IMAGE_DIMENSION: u32 = 60_000;
277pub(crate) const MAX_J2K_TILE_COUNT: u64 = u16::MAX as u64 + 1;
278#[doc(hidden)]
280pub const DEFAULT_MAX_CODEC_BYTES: usize = 512 * 1024 * 1024;
281#[doc(hidden)]
283pub const DEFAULT_MAX_DECODE_BYTES: usize = DEFAULT_MAX_CODEC_BYTES;
284
285#[inline]
286pub(crate) fn checked_decode_usize_product2(left: usize, right: usize) -> Result<usize> {
287 left.checked_mul(right)
288 .ok_or(ValidationError::ImageTooLarge.into())
289}
290
291#[inline]
292fn checked_decode_byte_cap(len: usize) -> Result<usize> {
293 if len > DEFAULT_MAX_DECODE_BYTES {
294 bail!(ValidationError::ImageTooLarge);
295 }
296 Ok(len)
297}
298
299#[inline]
300pub(crate) fn checked_decode_byte_len2(left: usize, right: usize) -> Result<usize> {
301 checked_decode_byte_cap(checked_decode_usize_product2(left, right)?)
302}
303
304#[inline]
305pub(crate) fn checked_decode_byte_len3(first: usize, second: usize, third: usize) -> Result<usize> {
306 let partial = checked_decode_usize_product2(first, second)?;
307 checked_decode_byte_cap(checked_decode_usize_product2(partial, third)?)
308}
309
310#[inline]
311pub(crate) fn checked_decode_byte_len4(
312 first: usize,
313 second: usize,
314 third: usize,
315 fourth: usize,
316) -> Result<usize> {
317 let partial = checked_decode_usize_product2(first, second)?;
318 let partial = checked_decode_usize_product2(partial, third)?;
319 checked_decode_byte_cap(checked_decode_usize_product2(partial, fourth)?)
320}
321
322#[inline]
323pub(crate) fn try_reserve_decode_elements<T>(values: &mut Vec<T>, target_len: usize) -> Result<()> {
324 checked_decode_byte_len2(target_len, core::mem::size_of::<T>())?;
325 if target_len > values.capacity() {
326 values
327 .try_reserve_exact(target_len - values.len())
328 .map_err(|_| DecodingError::HostAllocationFailed)?;
329 }
330 Ok(())
331}
332
333#[inline]
334pub(crate) fn try_resize_decode_elements<T: Clone>(
335 values: &mut Vec<T>,
336 target_len: usize,
337 value: T,
338) -> Result<()> {
339 try_reserve_decode_elements(values, target_len)?;
340 values.resize(target_len, value);
341 Ok(())
342}
343
344#[inline]
345pub(crate) fn checked_decode_sample_count(width: u32, height: u32) -> Result<usize> {
346 #[cfg(target_pointer_width = "64")]
347 {
348 usize::try_from(u64::from(width) * u64::from(height))
349 .map_err(|_| ValidationError::ImageTooLarge.into())
350 }
351
352 #[cfg(not(target_pointer_width = "64"))]
353 {
354 checked_decode_usize_product2(width as usize, height as usize)
355 }
356}
357
358#[inline]
359fn native_bytes_per_sample(bit_depth: u8) -> Result<usize> {
360 if bit_depth == 0 || bit_depth > 63 {
361 bail!(ValidationError::ImageTooLarge);
362 }
363 Ok(usize::from(bit_depth).div_ceil(8).max(1))
364}
365
366#[doc(hidden)]
367pub use backend::{
368 HtCleanupEncodeDistribution, HtCodeBlockBatchJob, HtCodeBlockDecodeJob,
369 HtCodeBlockDecodePhaseLimit, HtCodeBlockDecoder, HtSubBandDecodeJob, J2kCodeBlockBatchJob,
370 J2kCodeBlockDecodeJob, J2kIdwtBand, J2kInverseMctJob, J2kRect, J2kSingleDecompositionIdwtJob,
371 J2kStoreComponentJob, J2kSubBandDecodeJob, J2kTier1TokenSegment, J2kWaveletTransform,
372};
373#[doc(hidden)]
374pub use ht_adapter::{
375 decode_ht_sigprop_benchmark_state, ht_uvlc_encode_table, ht_uvlc_encode_table_bytes,
376 ht_uvlc_table0, ht_uvlc_table1, ht_vlc_encode_table0, ht_vlc_encode_table1, ht_vlc_table0,
377 ht_vlc_table1, prepare_ht_sigprop_benchmark_state, HtSigPropBenchmarkState,
378};
379
380mod scalar;
381#[doc(hidden)]
382pub use scalar::{
383 collect_ht_cleanup_encode_distribution, decode_ht_code_block_scalar,
384 decode_ht_code_block_scalar_until_phase, decode_ht_code_block_scalar_with_workspace,
385 decode_ht_code_block_scalar_with_workspace_profiled, decode_j2k_code_block_scalar,
386 decode_j2k_code_block_scalar_profiled, decode_j2k_code_block_scalar_with_workspace,
387 decode_j2k_code_block_scalar_with_workspace_profiled, decode_j2k_sub_band_scalar,
388 encode_ht_code_block_scalar, encode_ht_code_block_scalar_with_passes,
389 encode_j2k_code_block_scalar_with_style, encode_j2k_packetization_scalar,
390 forward_dwt53_reference, forward_dwt97_reference, forward_ict_reference, forward_rct_reference,
391 pack_j2k_code_block_scalar_from_tier1_tokens, quantize_reversible_reference,
392 quantize_subband_reference, try_deinterleave_reference, HtCodeBlockDecodeProfile,
393 HtCodeBlockDecodeWorkspace, J2kCodeBlockDecodeProfile, J2kCodeBlockDecodeWorkspace,
394};
395
396pub(crate) const JP2_MAGIC: &[u8] = b"\x00\x00\x00\x0C\x6A\x50\x20\x20";
398pub(crate) const CODESTREAM_MAGIC: &[u8] = b"\xFF\x4F\xFF\x51";
400
401mod image;
402pub use image::{DecodeSettings, Image};
403
404#[cfg(test)]
405mod tests;