1#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
67#![forbid(unsafe_code)]
68#![forbid(missing_docs)]
69extern crate alloc;
70
71#[cfg(test)]
72use alloc::vec;
73use alloc::vec::Vec;
74
75use crate::error::bail;
76#[cfg(test)]
77use crate::jp2::colr::CieLab;
78
79macro_rules! define_ht_code_block_job {
80 (
81 $(#[$meta:meta])*
82 pub struct $name:ident $(<$lt:lifetime>)? {
83 $($prefix:tt)*
84 }
85 ) => {
86 $(#[$meta])*
87 pub struct $name $(<$lt>)? {
88 $($prefix)*
89 pub cleanup_length: u32,
91 pub refinement_length: u32,
93 pub width: u32,
95 pub height: u32,
97 pub output_stride: usize,
99 pub missing_bit_planes: u8,
101 pub number_of_coding_passes: u8,
103 pub num_bitplanes: u8,
105 pub roi_shift: u8,
107 pub stripe_causal: bool,
109 pub strict: bool,
111 pub dequantization_step: f32,
113 }
114 };
115}
116
117#[doc(hidden)]
118#[macro_export]
119macro_rules! __j2k_component_plane_metadata_accessors {
120 () => {
121 #[must_use]
123 pub fn dimensions(&self) -> (u32, u32) {
124 self.dimensions
125 }
126
127 #[must_use]
129 pub fn sampling(&self) -> (u8, u8) {
130 self.sampling
131 }
132
133 #[must_use]
135 pub fn bit_depth(&self) -> u8 {
136 self.bit_depth
137 }
138
139 #[must_use]
141 pub fn signed(&self) -> bool {
142 self.signed
143 }
144 };
145}
146
147mod backend;
148mod color;
149mod error;
150mod ht_adapter;
151mod inspect;
152#[macro_use]
153pub(crate) mod log;
154mod direct_cpu;
155mod direct_plan;
156mod direct_roi;
157pub(crate) mod math;
158mod move_only;
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_htj2k_capabilities, inspect_j2k_codestream_header, looks_like_j2k_codestream,
210 J2kCodestreamComponentHeader, J2kCodestreamHeaderError, J2kCodestreamHeaderMetadata,
211};
212#[doc(hidden)]
213pub use j2c::capabilities::required_magnitude_bound as htj2k_required_magnitude_bound;
214pub use j2c::capabilities::{Htj2kCapabilities, Htj2kCapabilityMode, J2kCorrespondingProfile};
215#[doc(hidden)]
216pub use jp2::{
217 extract_jp2_codestream_payload, inspect_jp2_container, Jp2ChannelAssociation,
218 Jp2ChannelDefinition, Jp2ChannelType, Jp2ColorSpec, Jp2ComponentMapping,
219 Jp2ComponentMappingType, Jp2ComponentMetadata, Jp2Container, Jp2FileKind, Jp2FileMetadata,
220 Jp2ImageHeaderMetadata, Jp2PaletteColumn, Jp2PaletteMetadata,
221};
222#[doc(hidden)]
223pub use roi::idwt_band_index;
224pub(crate) use roi::{
225 add_roi_shift_to_bitplanes, apply_roi_maxshift_inverse_f32, apply_roi_maxshift_inverse_i32,
226 apply_roi_maxshift_inverse_i64, validate_roi,
227};
228
229pub use error::{
230 ColorError, DecodeError, DecodeErrorClass, DecodingError, DirectPlanUnsupportedReason,
231 EncodeError, EncodeResult, FormatError, MarkerError, Result, TileError, ValidationError,
232};
233#[cfg(test)]
234pub(crate) use j2c::encode::NativeEncodeRetainedInput;
235pub use j2c::encode::{
236 encode, encode_component_planes_53, encode_htj2k, encode_precomputed_htj2k_53,
237 encode_precomputed_htj2k_53_with_accelerator,
238 encode_precomputed_htj2k_53_with_accelerator_and_max_host_bytes,
239 encode_precomputed_htj2k_53_with_mct, encode_precomputed_htj2k_53_with_mct_and_accelerator,
240 encode_precomputed_htj2k_97, encode_precomputed_htj2k_97_batch_owned_with_accelerator,
241 encode_precomputed_htj2k_97_batch_owned_with_accelerator_and_max_host_bytes,
242 encode_precomputed_htj2k_97_batch_with_accelerator,
243 encode_precomputed_htj2k_97_with_accelerator,
244 encode_precomputed_htj2k_97_with_accelerator_and_max_host_bytes, encode_precomputed_j2k_53,
245 encode_precomputed_j2k_53_with_accelerator, encode_precomputed_j2k_53_with_mct,
246 encode_precomputed_j2k_53_with_mct_and_accelerator, encode_preencoded_htj2k_97,
247 encode_preencoded_htj2k_97_compact_owned_with_accelerator,
248 encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes,
249 encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes_and_required_magnitude_bound,
250 encode_preencoded_htj2k_97_owned_with_accelerator,
251 encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes,
252 encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes_and_required_magnitude_bound,
253 encode_preencoded_htj2k_97_with_accelerator, encode_prequantized_htj2k_97,
254 encode_prequantized_htj2k_97_with_accelerator,
255 encode_prequantized_htj2k_97_with_accelerator_and_max_host_bytes,
256 encode_resident_htj2k_with_accelerator, encode_typed_component_planes_53,
257 encode_with_accelerator, encode_with_accelerator_and_roi_regions, encode_with_roi_regions,
258 irreversible_quantization_step_for_subband, EncodeComponentPlane, EncodeOptions,
259 EncodeProgressionOrder, EncodeRoiRegion, EncodeTypedComponentPlane, ResidentHtj2kEncodeError,
260};
261pub use j2c::{
262 CpuDecodeParallelism, DecoderContext, DecoderWorkspace, DecoderWorkspaceStats,
263 Reversible53CoefficientImage,
264};
265#[doc(hidden)]
266pub use j2k_types::{
267 sort_packet_descriptors_for_progression, CpuOnlyJ2kEncodeStageAccelerator,
268 EncodedHtJ2kCodeBlock, EncodedJ2kCodeBlock, IrreversibleQuantizationStep,
269 IrreversibleQuantizationSubbandScales, J2kCodeBlockSegment, J2kCodeBlockStyle,
270 J2kDeinterleaveToF32Job, J2kEncodeContext, J2kEncodeDispatchReport, J2kEncodeStageAccelerator,
271 J2kEncodeStageError, J2kEncodeStageErrorKind, J2kEncodeStageResult, J2kForwardDwt53Job,
272 J2kForwardDwt53Level, J2kForwardDwt53Output, J2kForwardDwt97Job, J2kForwardDwt97Level,
273 J2kForwardDwt97Output, J2kForwardIctJob, J2kForwardRctJob, J2kHtCodeBlockEncodeJob,
274 J2kHtSubbandEncodeJob, J2kHtj2kTileEncodeJob, J2kPacketizationBlockCodingMode,
275 J2kPacketizationCodeBlock, J2kPacketizationEncodeJob, J2kPacketizationPacketDescriptor,
276 J2kPacketizationProgressionOrder, J2kPacketizationResolution, J2kPacketizationSubband,
277 J2kQuantizeSubbandJob, J2kResidentEncodeInput, J2kResidentEncodeInputError,
278 J2kResidentHtj2kTileEncodeJob, J2kSubBandType, J2kTier1CodeBlockEncodeJob,
279 PrecomputedHtj2k53Component, PrecomputedHtj2k53Image, PrecomputedHtj2k97Component,
280 PrecomputedHtj2k97Image, PreencodedHtj2k97CodeBlock, PreencodedHtj2k97CompactCodeBlock,
281 PreencodedHtj2k97CompactComponent, PreencodedHtj2k97CompactImage,
282 PreencodedHtj2k97CompactResolution, PreencodedHtj2k97CompactSubband,
283 PreencodedHtj2k97Component, PreencodedHtj2k97Image, PreencodedHtj2k97Resolution,
284 PreencodedHtj2k97Subband, PrequantizedHtj2k97CodeBlock, PrequantizedHtj2k97Component,
285 PrequantizedHtj2k97Image, PrequantizedHtj2k97Resolution, PrequantizedHtj2k97Subband,
286};
287
288mod j2c;
289mod jp2;
290pub(crate) mod reader;
291#[doc(hidden)]
292pub use j2c::ht_encode_tables::HtUvlcTableEntry;
293
294const MAX_CLASSIC_DECODE_BITPLANES: u8 = j2c::MAX_BITPLANE_COUNT;
295const MAX_DEINTERLEAVE_REFERENCE_BIT_DEPTH: u8 = j2k_types::MAX_JPEG2000_PART1_SAMPLE_BIT_DEPTH;
296pub(crate) use j2k_types::MAX_JPEG2000_PART1_COMPONENTS as MAX_J2K_SPEC_COMPONENTS;
297pub(crate) const MAX_J2K_IMAGE_DIMENSION: u32 = 60_000;
298pub(crate) const MAX_J2K_TILE_COUNT: u64 = u16::MAX as u64 + 1;
299#[doc(hidden)]
301pub const DEFAULT_MAX_CODEC_BYTES: usize = 512 * 1024 * 1024;
302#[doc(hidden)]
304pub const DEFAULT_MAX_DECODE_BYTES: usize = DEFAULT_MAX_CODEC_BYTES;
305
306#[inline]
307pub(crate) fn checked_decode_usize_product2(left: usize, right: usize) -> Result<usize> {
308 left.checked_mul(right)
309 .ok_or(ValidationError::ImageTooLarge.into())
310}
311
312#[inline]
313fn checked_decode_byte_cap(len: usize) -> Result<usize> {
314 if len > DEFAULT_MAX_DECODE_BYTES {
315 bail!(ValidationError::ImageTooLarge);
316 }
317 Ok(len)
318}
319
320#[inline]
321pub(crate) fn checked_decode_byte_len2(left: usize, right: usize) -> Result<usize> {
322 checked_decode_byte_cap(checked_decode_usize_product2(left, right)?)
323}
324
325#[inline]
326pub(crate) fn checked_decode_byte_len3(first: usize, second: usize, third: usize) -> Result<usize> {
327 let partial = checked_decode_usize_product2(first, second)?;
328 checked_decode_byte_cap(checked_decode_usize_product2(partial, third)?)
329}
330
331#[inline]
332pub(crate) fn checked_decode_byte_len4(
333 first: usize,
334 second: usize,
335 third: usize,
336 fourth: usize,
337) -> Result<usize> {
338 let partial = checked_decode_usize_product2(first, second)?;
339 let partial = checked_decode_usize_product2(partial, third)?;
340 checked_decode_byte_cap(checked_decode_usize_product2(partial, fourth)?)
341}
342
343#[inline]
344pub(crate) fn try_reserve_decode_elements<T>(values: &mut Vec<T>, target_len: usize) -> Result<()> {
345 checked_decode_byte_len2(target_len, core::mem::size_of::<T>())?;
346 if target_len > values.capacity() {
347 values
348 .try_reserve_exact(target_len - values.len())
349 .map_err(|_| DecodingError::HostAllocationFailed)?;
350 }
351 Ok(())
352}
353
354#[inline]
355pub(crate) fn try_resize_decode_elements<T: Clone>(
356 values: &mut Vec<T>,
357 target_len: usize,
358 value: T,
359) -> Result<()> {
360 try_reserve_decode_elements(values, target_len)?;
361 values.resize(target_len, value);
362 Ok(())
363}
364
365#[inline]
366pub(crate) fn checked_decode_sample_count(width: u32, height: u32) -> Result<usize> {
367 #[cfg(target_pointer_width = "64")]
368 {
369 usize::try_from(u64::from(width) * u64::from(height))
370 .map_err(|_| ValidationError::ImageTooLarge.into())
371 }
372
373 #[cfg(not(target_pointer_width = "64"))]
374 {
375 checked_decode_usize_product2(width as usize, height as usize)
376 }
377}
378
379#[inline]
380fn native_bytes_per_sample(bit_depth: u8) -> Result<usize> {
381 if bit_depth == 0 || bit_depth > 63 {
382 bail!(ValidationError::ImageTooLarge);
383 }
384 Ok(usize::from(bit_depth).div_ceil(8).max(1))
385}
386
387#[doc(hidden)]
388pub use backend::{
389 HtCleanupEncodeDistribution, HtCodeBlockBatchJob, HtCodeBlockDecodeJob,
390 HtCodeBlockDecodePhaseLimit, HtCodeBlockDecoder, HtSubBandDecodeJob, J2kCodeBlockBatchJob,
391 J2kCodeBlockDecodeJob, J2kIdwtBand, J2kInverseMctJob, J2kRect, J2kSingleDecompositionIdwtJob,
392 J2kStoreComponentJob, J2kSubBandDecodeJob, J2kTier1TokenSegment, J2kWaveletTransform,
393};
394#[doc(hidden)]
395pub use ht_adapter::{
396 decode_ht_sigprop_benchmark_state, ht_uvlc_encode_table, ht_uvlc_encode_table_bytes,
397 ht_uvlc_table0, ht_uvlc_table1, ht_vlc_encode_table0, ht_vlc_encode_table1, ht_vlc_table0,
398 ht_vlc_table1, prepare_ht_sigprop_benchmark_state, HtSigPropBenchmarkState,
399};
400
401mod scalar;
402#[doc(hidden)]
403pub use scalar::{
404 collect_ht_cleanup_encode_distribution, decode_ht_code_block_scalar,
405 decode_ht_code_block_scalar_until_phase, decode_ht_code_block_scalar_with_workspace,
406 decode_ht_code_block_scalar_with_workspace_midpoint,
407 decode_ht_code_block_scalar_with_workspace_midpoint_profiled,
408 decode_ht_code_block_scalar_with_workspace_profiled, decode_j2k_code_block_scalar,
409 decode_j2k_code_block_scalar_profiled, decode_j2k_code_block_scalar_with_workspace,
410 decode_j2k_code_block_scalar_with_workspace_midpoint,
411 decode_j2k_code_block_scalar_with_workspace_midpoint_profiled,
412 decode_j2k_code_block_scalar_with_workspace_profiled, decode_j2k_sub_band_scalar,
413 encode_ht_code_block_scalar, encode_ht_code_block_scalar_with_passes,
414 encode_j2k_code_block_scalar_with_style, encode_j2k_packetization_scalar,
415 forward_dwt53_reference, forward_dwt97_reference, forward_ict_reference, forward_rct_reference,
416 pack_j2k_code_block_scalar_from_tier1_tokens, quantize_reversible_reference,
417 quantize_subband_reference, try_deinterleave_reference, HtCodeBlockDecodeProfile,
418 HtCodeBlockDecodeWorkspace, J2kCodeBlockDecodeProfile, J2kCodeBlockDecodeWorkspace,
419};
420
421pub(crate) const JP2_MAGIC: &[u8] = b"\x00\x00\x00\x0C\x6A\x50\x20\x20";
423pub(crate) const CODESTREAM_MAGIC: &[u8] = b"\xFF\x4F\xFF\x51";
425
426mod image;
427pub use image::{DecodeSettings, Image};
428
429#[cfg(test)]
430mod tests;