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,
183 execute_referenced_classic_entropy_job, execute_referenced_classic_plan,
184 execute_referenced_classic_plan_from_payloads, execute_referenced_htj2k_entropy_job,
185 execute_referenced_htj2k_plan, execute_referenced_htj2k_plan_from_payloads,
186 finish_referenced_classic_staged, finish_referenced_classic_tile_staged,
187 finish_referenced_htj2k_staged, finish_referenced_htj2k_tile_staged,
188 prepare_referenced_classic_entropy_workspace, prepare_referenced_classic_staged,
189 prepare_referenced_classic_tile_staged, prepare_referenced_htj2k_entropy_workspace,
190 prepare_referenced_htj2k_staged, prepare_referenced_htj2k_tile_staged, J2kDirectCodeBlockIndex,
191 J2kDirectCpuEntropyWorkspace, J2kDirectCpuScratch, J2kDirectDecodedComponents,
192 J2kDirectDecodedPlane,
193};
194#[doc(hidden)]
195pub use direct_plan::{
196 HtCodeBlockPayloadRanges, HtOwnedCodeBlockBatchJob, HtOwnedSubBandPlan,
197 J2kClassicCodeBlockPayload, J2kCodestreamRange, J2kDirectBandId, J2kDirectColorPlan,
198 J2kDirectGrayscalePlan, J2kDirectGrayscaleStep, J2kDirectIdwtStep, J2kDirectRgbaPlan,
199 J2kDirectStoreStep, J2kOwnedCodeBlockBatchJob, J2kOwnedSubBandPlan, J2kReferencedClassicPlan,
200 J2kReferencedHtj2kPlan, J2kReferencedPayloadRecordSpan, J2kReferencedTileGeometry,
201 J2kReferencedTilePlan,
202};
203#[doc(hidden)]
204pub use direct_roi::{
205 idwt_required_input_window_for_rects, idwt_required_input_windows, idwt_required_output_margin,
206 J2kIdwtRequiredInputWindows, J2kRequiredBandRegion,
207};
208pub use inspect::{
209 inspect_j2k_codestream_header, looks_like_j2k_codestream, J2kCodestreamComponentHeader,
210 J2kCodestreamHeaderError, J2kCodestreamHeaderMetadata,
211};
212#[doc(hidden)]
213pub use jp2::{
214 extract_jp2_codestream_payload, inspect_jp2_container, Jp2ChannelAssociation,
215 Jp2ChannelDefinition, Jp2ChannelType, Jp2ColorSpec, Jp2ComponentMapping,
216 Jp2ComponentMappingType, Jp2ComponentMetadata, Jp2Container, Jp2FileKind, Jp2FileMetadata,
217 Jp2ImageHeaderMetadata, Jp2PaletteColumn, Jp2PaletteMetadata,
218};
219#[doc(hidden)]
220pub use roi::idwt_band_index;
221pub(crate) use roi::{
222 add_roi_shift_to_bitplanes, apply_roi_maxshift_inverse_i32, apply_roi_maxshift_inverse_i64,
223 validate_roi,
224};
225
226pub use error::{
227 ColorError, DecodeError, DecodeErrorClass, DecodingError, DirectPlanUnsupportedReason,
228 EncodeError, EncodeResult, FormatError, MarkerError, Result, TileError, ValidationError,
229};
230#[cfg(test)]
231pub(crate) use j2c::encode::NativeEncodeRetainedInput;
232pub use j2c::encode::{
233 encode, encode_component_planes_53, encode_htj2k, encode_precomputed_htj2k_53,
234 encode_precomputed_htj2k_53_with_accelerator,
235 encode_precomputed_htj2k_53_with_accelerator_and_max_host_bytes,
236 encode_precomputed_htj2k_53_with_mct, encode_precomputed_htj2k_53_with_mct_and_accelerator,
237 encode_precomputed_htj2k_97, encode_precomputed_htj2k_97_batch_owned_with_accelerator,
238 encode_precomputed_htj2k_97_batch_owned_with_accelerator_and_max_host_bytes,
239 encode_precomputed_htj2k_97_batch_with_accelerator,
240 encode_precomputed_htj2k_97_with_accelerator,
241 encode_precomputed_htj2k_97_with_accelerator_and_max_host_bytes, encode_precomputed_j2k_53,
242 encode_precomputed_j2k_53_with_accelerator, encode_precomputed_j2k_53_with_mct,
243 encode_precomputed_j2k_53_with_mct_and_accelerator, encode_preencoded_htj2k_97,
244 encode_preencoded_htj2k_97_compact_owned_with_accelerator,
245 encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes,
246 encode_preencoded_htj2k_97_owned_with_accelerator,
247 encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes,
248 encode_preencoded_htj2k_97_with_accelerator, encode_prequantized_htj2k_97,
249 encode_prequantized_htj2k_97_with_accelerator,
250 encode_prequantized_htj2k_97_with_accelerator_and_max_host_bytes,
251 encode_resident_htj2k_with_accelerator, encode_typed_component_planes_53,
252 encode_with_accelerator, encode_with_accelerator_and_roi_regions, encode_with_roi_regions,
253 irreversible_quantization_step_for_subband, EncodeComponentPlane, EncodeOptions,
254 EncodeProgressionOrder, EncodeRoiRegion, EncodeTypedComponentPlane, ResidentHtj2kEncodeError,
255};
256pub use j2c::{
257 CpuDecodeParallelism, DecoderContext, DecoderWorkspace, DecoderWorkspaceStats,
258 Reversible53CoefficientImage,
259};
260#[doc(hidden)]
261pub use j2k_types::{
262 sort_packet_descriptors_for_progression, CpuOnlyJ2kEncodeStageAccelerator,
263 EncodedHtJ2kCodeBlock, EncodedJ2kCodeBlock, IrreversibleQuantizationStep,
264 IrreversibleQuantizationSubbandScales, J2kCodeBlockSegment, J2kCodeBlockStyle,
265 J2kDeinterleaveToF32Job, J2kEncodeDispatchReport, J2kEncodeStageAccelerator,
266 J2kEncodeStageError, J2kEncodeStageErrorKind, J2kEncodeStageResult, J2kForwardDwt53Job,
267 J2kForwardDwt53Level, J2kForwardDwt53Output, J2kForwardDwt97Job, J2kForwardDwt97Level,
268 J2kForwardDwt97Output, J2kForwardIctJob, J2kForwardRctJob, J2kHtCodeBlockEncodeJob,
269 J2kHtSubbandEncodeJob, J2kHtj2kTileEncodeJob, J2kPacketizationBlockCodingMode,
270 J2kPacketizationCodeBlock, J2kPacketizationEncodeJob, J2kPacketizationPacketDescriptor,
271 J2kPacketizationProgressionOrder, J2kPacketizationResolution, J2kPacketizationSubband,
272 J2kQuantizeSubbandJob, J2kResidentEncodeInput, J2kResidentEncodeInputError,
273 J2kResidentHtj2kTileEncodeJob, J2kSubBandType, J2kTier1CodeBlockEncodeJob,
274 PrecomputedHtj2k53Component, PrecomputedHtj2k53Image, PrecomputedHtj2k97Component,
275 PrecomputedHtj2k97Image, PreencodedHtj2k97CodeBlock, PreencodedHtj2k97CompactCodeBlock,
276 PreencodedHtj2k97CompactComponent, PreencodedHtj2k97CompactImage,
277 PreencodedHtj2k97CompactResolution, PreencodedHtj2k97CompactSubband,
278 PreencodedHtj2k97Component, PreencodedHtj2k97Image, PreencodedHtj2k97Resolution,
279 PreencodedHtj2k97Subband, PrequantizedHtj2k97CodeBlock, PrequantizedHtj2k97Component,
280 PrequantizedHtj2k97Image, PrequantizedHtj2k97Resolution, PrequantizedHtj2k97Subband,
281};
282
283mod j2c;
284mod jp2;
285pub(crate) mod reader;
286#[doc(hidden)]
287pub use j2c::ht_encode_tables::HtUvlcTableEntry;
288
289const MAX_CLASSIC_DECODE_BITPLANES: u8 = j2c::MAX_BITPLANE_COUNT;
290const MAX_DEINTERLEAVE_REFERENCE_BIT_DEPTH: u8 = j2k_types::MAX_JPEG2000_PART1_SAMPLE_BIT_DEPTH;
291pub(crate) use j2k_types::MAX_JPEG2000_PART1_COMPONENTS as MAX_J2K_SPEC_COMPONENTS;
292pub(crate) const MAX_J2K_IMAGE_DIMENSION: u32 = 60_000;
293pub(crate) const MAX_J2K_TILE_COUNT: u64 = u16::MAX as u64 + 1;
294#[doc(hidden)]
296pub const DEFAULT_MAX_CODEC_BYTES: usize = 512 * 1024 * 1024;
297#[doc(hidden)]
299pub const DEFAULT_MAX_DECODE_BYTES: usize = DEFAULT_MAX_CODEC_BYTES;
300
301#[inline]
302pub(crate) fn checked_decode_usize_product2(left: usize, right: usize) -> Result<usize> {
303 left.checked_mul(right)
304 .ok_or(ValidationError::ImageTooLarge.into())
305}
306
307#[inline]
308fn checked_decode_byte_cap(len: usize) -> Result<usize> {
309 if len > DEFAULT_MAX_DECODE_BYTES {
310 bail!(ValidationError::ImageTooLarge);
311 }
312 Ok(len)
313}
314
315#[inline]
316pub(crate) fn checked_decode_byte_len2(left: usize, right: usize) -> Result<usize> {
317 checked_decode_byte_cap(checked_decode_usize_product2(left, right)?)
318}
319
320#[inline]
321pub(crate) fn checked_decode_byte_len3(first: usize, second: usize, third: usize) -> Result<usize> {
322 let partial = checked_decode_usize_product2(first, second)?;
323 checked_decode_byte_cap(checked_decode_usize_product2(partial, third)?)
324}
325
326#[inline]
327pub(crate) fn checked_decode_byte_len4(
328 first: usize,
329 second: usize,
330 third: usize,
331 fourth: usize,
332) -> Result<usize> {
333 let partial = checked_decode_usize_product2(first, second)?;
334 let partial = checked_decode_usize_product2(partial, third)?;
335 checked_decode_byte_cap(checked_decode_usize_product2(partial, fourth)?)
336}
337
338#[inline]
339pub(crate) fn try_reserve_decode_elements<T>(values: &mut Vec<T>, target_len: usize) -> Result<()> {
340 checked_decode_byte_len2(target_len, core::mem::size_of::<T>())?;
341 if target_len > values.capacity() {
342 values
343 .try_reserve_exact(target_len - values.len())
344 .map_err(|_| DecodingError::HostAllocationFailed)?;
345 }
346 Ok(())
347}
348
349#[inline]
350pub(crate) fn try_resize_decode_elements<T: Clone>(
351 values: &mut Vec<T>,
352 target_len: usize,
353 value: T,
354) -> Result<()> {
355 try_reserve_decode_elements(values, target_len)?;
356 values.resize(target_len, value);
357 Ok(())
358}
359
360#[inline]
361pub(crate) fn checked_decode_sample_count(width: u32, height: u32) -> Result<usize> {
362 #[cfg(target_pointer_width = "64")]
363 {
364 usize::try_from(u64::from(width) * u64::from(height))
365 .map_err(|_| ValidationError::ImageTooLarge.into())
366 }
367
368 #[cfg(not(target_pointer_width = "64"))]
369 {
370 checked_decode_usize_product2(width as usize, height as usize)
371 }
372}
373
374#[inline]
375fn native_bytes_per_sample(bit_depth: u8) -> Result<usize> {
376 if bit_depth == 0 || bit_depth > 63 {
377 bail!(ValidationError::ImageTooLarge);
378 }
379 Ok(usize::from(bit_depth).div_ceil(8).max(1))
380}
381
382#[doc(hidden)]
383pub use backend::{
384 HtCleanupEncodeDistribution, HtCodeBlockBatchJob, HtCodeBlockDecodeJob,
385 HtCodeBlockDecodePhaseLimit, HtCodeBlockDecoder, HtSubBandDecodeJob, J2kCodeBlockBatchJob,
386 J2kCodeBlockDecodeJob, J2kIdwtBand, J2kInverseMctJob, J2kRect, J2kSingleDecompositionIdwtJob,
387 J2kStoreComponentJob, J2kSubBandDecodeJob, J2kTier1TokenSegment, J2kWaveletTransform,
388};
389#[doc(hidden)]
390pub use ht_adapter::{
391 decode_ht_sigprop_benchmark_state, ht_uvlc_encode_table, ht_uvlc_encode_table_bytes,
392 ht_uvlc_table0, ht_uvlc_table1, ht_vlc_encode_table0, ht_vlc_encode_table1, ht_vlc_table0,
393 ht_vlc_table1, prepare_ht_sigprop_benchmark_state, HtSigPropBenchmarkState,
394};
395
396mod scalar;
397#[doc(hidden)]
398pub use scalar::{
399 collect_ht_cleanup_encode_distribution, decode_ht_code_block_scalar,
400 decode_ht_code_block_scalar_until_phase, decode_ht_code_block_scalar_with_workspace,
401 decode_ht_code_block_scalar_with_workspace_profiled, decode_j2k_code_block_scalar,
402 decode_j2k_code_block_scalar_profiled, decode_j2k_code_block_scalar_with_workspace,
403 decode_j2k_code_block_scalar_with_workspace_profiled, decode_j2k_sub_band_scalar,
404 encode_ht_code_block_scalar, encode_ht_code_block_scalar_with_passes,
405 encode_j2k_code_block_scalar_with_style, encode_j2k_packetization_scalar,
406 forward_dwt53_reference, forward_dwt97_reference, forward_ict_reference, forward_rct_reference,
407 pack_j2k_code_block_scalar_from_tier1_tokens, quantize_reversible_reference,
408 quantize_subband_reference, try_deinterleave_reference, HtCodeBlockDecodeProfile,
409 HtCodeBlockDecodeWorkspace, J2kCodeBlockDecodeProfile, J2kCodeBlockDecodeWorkspace,
410};
411
412pub(crate) const JP2_MAGIC: &[u8] = b"\x00\x00\x00\x0C\x6A\x50\x20\x20";
414pub(crate) const CODESTREAM_MAGIC: &[u8] = b"\xFF\x4F\xFF\x51";
416
417mod image;
418pub use image::{DecodeSettings, Image};
419
420#[cfg(test)]
421mod tests;