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