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}
146mod backend;
147mod color;
148mod error;
149mod ht_adapter;
150mod inspect;
151#[macro_use]
152pub(crate) mod log;
153mod direct_cpu;
154mod direct_plan;
155mod direct_roi;
156pub(crate) mod math;
157mod move_only;
158#[doc(hidden)]
159pub mod packet_math;
160pub(crate) mod profile;
161mod roi;
162pub(crate) mod writer;
163#[cfg(test)]
164use crate::math::{dispatch, Level};
165#[cfg(test)]
166use color::cielab_to_rgb;
167pub(crate) use color::{
168 convert_color_space, interleave_and_convert_after_mct, interleave_and_convert_region,
169 resolve_alpha_and_color_space, resolve_palette_indices, validate_and_reorder_channels,
170 validate_interleaved_output_buffer,
171};
172pub use color::{
173 Bitmap, ColorSpace, ComponentPlane, DecodedComponents, DecodedNativeComponents,
174 NativeComponentPlane, RawBitmap,
175};
176#[doc(hidden)]
177pub use color::{ComponentPlaneParts, NativeComponentPlaneParts};
178#[doc(hidden)]
179pub use color::{DecodedComponentsParts, DecodedNativeComponentsParts};
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, J2kReferencedImageGeometry, J2kReferencedPayloadRecordSpan,
201 J2kReferencedTileGeometry, 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::{add_roi_shift_to_bitplanes, apply_roi_maxshift_inverse_i64, validate_roi};
225#[cfg(test)]
226pub(crate) use roi::{apply_roi_maxshift_inverse_f32, apply_roi_maxshift_inverse_i32};
227
228pub use error::{
229 ColorError, DecodeError, DecodeErrorClass, DecodingError, DirectPlanUnsupportedReason,
230 EncodeError, EncodeResult, FormatError, MarkerError, Result, TileError, ValidationError,
231};
232#[cfg(test)]
233pub(crate) use j2c::encode::NativeEncodeRetainedInput;
234pub use j2c::encode::{
235 encode, encode_component_planes_53, encode_htj2k, encode_htj2k_with_qfactor,
236 encode_htj2k_with_qfactor_and_accelerator, 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_profile_scale_ceiling, irreversible_quantization_scale_bounds,
259 irreversible_quantization_step_for_subband, EncodeComponentPlane, EncodeOptions,
260 EncodeProgressionOrder, EncodeRoiRegion, EncodeTypedComponentPlane, IrreversibleScaleEncoder,
261 ResidentHtj2kEncodeError,
262};
263pub use j2c::{
264 CpuDecodeParallelism, DecoderContext, DecoderWorkspace, DecoderWorkspaceStats,
265 Reversible53CoefficientImage,
266};
267#[doc(hidden)]
268pub use j2k_types::{
269 sort_packet_descriptors_for_progression, CpuOnlyJ2kEncodeStageAccelerator,
270 EncodedHtJ2kCodeBlock, EncodedHtJ2kCodeBlockSet, EncodedJ2kCodeBlock,
271 IrreversibleQuantizationStep, IrreversibleQuantizationSubbandScales, J2kCodeBlockSegment,
272 J2kCodeBlockStyle, J2kDeinterleaveMctToF32Job, J2kDeinterleaveToF32Job, J2kEncodeContext,
273 J2kEncodeDispatchReport, J2kEncodeStageAccelerator, J2kEncodeStageError,
274 J2kEncodeStageErrorKind, J2kEncodeStageResult, J2kForwardDwt53Job, J2kForwardDwt53Level,
275 J2kForwardDwt53Output, J2kForwardDwt97Job, J2kForwardDwt97Level, J2kForwardDwt97Output,
276 J2kForwardIctJob, J2kForwardRctJob, J2kHtCodeBlockEncodeJob, J2kHtCodeBlockSetEncodeJob,
277 J2kHtSubbandEncodeJob, J2kHtj2kTileEncodeJob, J2kPacketizationBlockCodingMode,
278 J2kPacketizationCodeBlock, J2kPacketizationEncodeJob, J2kPacketizationPacketDescriptor,
279 J2kPacketizationProgressionOrder, J2kPacketizationResolution, J2kPacketizationSubband,
280 J2kQuantizeSubbandJob, J2kResidentEncodeInput, J2kResidentEncodeInputError,
281 J2kResidentHtj2kTileEncodeJob, J2kSubBandType, J2kTier1CodeBlockEncodeJob,
282 PrecomputedHtj2k53Component, PrecomputedHtj2k53Image, PrecomputedHtj2k97Component,
283 PrecomputedHtj2k97Image, PreencodedHtj2k97CodeBlock, PreencodedHtj2k97CompactCodeBlock,
284 PreencodedHtj2k97CompactComponent, PreencodedHtj2k97CompactImage,
285 PreencodedHtj2k97CompactResolution, PreencodedHtj2k97CompactSubband,
286 PreencodedHtj2k97Component, PreencodedHtj2k97Image, PreencodedHtj2k97Resolution,
287 PreencodedHtj2k97Subband, PrequantizedHtj2k97CodeBlock, PrequantizedHtj2k97Component,
288 PrequantizedHtj2k97Image, PrequantizedHtj2k97Resolution, PrequantizedHtj2k97Subband,
289};
290pub use j2k_types::{
291 WaveletBand, WaveletBandKind, WaveletComponent, WaveletImage, WaveletRect, WaveletSamples,
292 WaveletSelection, WaveletTile, WaveletTransform,
293};
294
295mod j2c;
296mod jp2;
297pub(crate) mod reader;
298#[doc(hidden)]
299pub use j2c::ht_encode_tables::HtUvlcTableEntry;
300
301const MAX_CLASSIC_DECODE_BITPLANES: u8 = j2c::MAX_BITPLANE_COUNT;
302const MAX_DEINTERLEAVE_REFERENCE_BIT_DEPTH: u8 = j2k_types::MAX_JPEG2000_PART1_SAMPLE_BIT_DEPTH;
303pub(crate) use j2k_types::MAX_JPEG2000_PART1_COMPONENTS as MAX_J2K_SPEC_COMPONENTS;
304pub(crate) const MAX_J2K_TILE_COUNT: u64 = u16::MAX as u64 + 1;
305#[doc(hidden)]
306pub use j2k_types::{DEFAULT_MAX_CODEC_BYTES, DEFAULT_MAX_DECODE_BYTES};
307
308#[inline]
309pub(crate) fn checked_decode_usize_product2(left: usize, right: usize) -> Result<usize> {
310 left.checked_mul(right)
311 .ok_or(ValidationError::ImageTooLarge.into())
312}
313
314#[inline]
315fn checked_decode_byte_cap(len: usize) -> Result<usize> {
316 if len > DEFAULT_MAX_DECODE_BYTES {
317 bail!(ValidationError::ImageTooLarge);
318 }
319 Ok(len)
320}
321
322#[inline]
323pub(crate) fn checked_decode_byte_len2(left: usize, right: usize) -> Result<usize> {
324 checked_decode_byte_cap(checked_decode_usize_product2(left, right)?)
325}
326
327#[inline]
328pub(crate) fn checked_decode_byte_len3(first: usize, second: usize, third: usize) -> Result<usize> {
329 let partial = checked_decode_usize_product2(first, second)?;
330 checked_decode_byte_cap(checked_decode_usize_product2(partial, third)?)
331}
332
333#[inline]
334pub(crate) fn checked_decode_byte_len4(
335 first: usize,
336 second: usize,
337 third: usize,
338 fourth: usize,
339) -> Result<usize> {
340 let partial = checked_decode_usize_product2(first, second)?;
341 let partial = checked_decode_usize_product2(partial, third)?;
342 checked_decode_byte_cap(checked_decode_usize_product2(partial, fourth)?)
343}
344
345#[inline]
346pub(crate) fn try_reserve_decode_elements<T>(values: &mut Vec<T>, target_len: usize) -> Result<()> {
347 checked_decode_byte_len2(target_len, core::mem::size_of::<T>())?;
348 if target_len > values.capacity() {
349 values
350 .try_reserve_exact(target_len - values.len())
351 .map_err(|_| DecodingError::HostAllocationFailed)?;
352 }
353 Ok(())
354}
355
356#[inline]
357pub(crate) fn try_resize_decode_elements<T: Clone>(
358 values: &mut Vec<T>,
359 target_len: usize,
360 value: T,
361) -> Result<()> {
362 try_reserve_decode_elements(values, target_len)?;
363 values.resize(target_len, value);
364 Ok(())
365}
366
367#[inline]
368pub(crate) fn checked_decode_sample_count(width: u32, height: u32) -> Result<usize> {
369 #[cfg(target_pointer_width = "64")]
370 {
371 usize::try_from(u64::from(width) * u64::from(height))
372 .map_err(|_| ValidationError::ImageTooLarge.into())
373 }
374
375 #[cfg(not(target_pointer_width = "64"))]
376 {
377 checked_decode_usize_product2(width as usize, height as usize)
378 }
379}
380
381#[inline]
382fn native_bytes_per_sample(bit_depth: u8) -> Result<usize> {
383 if bit_depth == 0 || bit_depth > 63 {
384 bail!(ValidationError::ImageTooLarge);
385 }
386 Ok(usize::from(bit_depth).div_ceil(8).max(1))
387}
388
389#[doc(hidden)]
390pub use backend::{
391 HtCleanupEncodeDistribution, HtCodeBlockBatchJob, HtCodeBlockDecodeJob,
392 HtCodeBlockDecodePhaseLimit, HtCodeBlockDecoder, HtSubBandDecodeJob, J2kClassicReconstruction,
393 J2kCodeBlockBatchJob, J2kCodeBlockDecodeJob, J2kIdwtBand, J2kIdwtNormalization,
394 J2kInverseMctJob, J2kRect, J2kSingleDecompositionIdwtJob, J2kStoreComponentJob,
395 J2kSubBandDecodeJob, J2kTier1TokenSegment, J2kWaveletTransform,
396};
397#[doc(hidden)]
398pub use ht_adapter::{
399 decode_ht_sigprop_benchmark_state, ht_uvlc_encode_table, ht_uvlc_encode_table_bytes,
400 ht_uvlc_table0, ht_uvlc_table1, ht_vlc_encode_table0, ht_vlc_encode_table1, ht_vlc_table0,
401 ht_vlc_table1, prepare_ht_sigprop_benchmark_state, HtSigPropBenchmarkState,
402};
403
404mod scalar;
405#[doc(hidden)]
406pub use scalar::{
407 collect_ht_cleanup_encode_distribution, decode_ht_code_block_scalar,
408 decode_ht_code_block_scalar_until_phase, decode_ht_code_block_scalar_with_workspace,
409 decode_ht_code_block_scalar_with_workspace_midpoint,
410 decode_ht_code_block_scalar_with_workspace_midpoint_profiled,
411 decode_ht_code_block_scalar_with_workspace_profiled, decode_j2k_code_block_scalar,
412 decode_j2k_code_block_scalar_profiled, decode_j2k_code_block_scalar_with_workspace,
413 decode_j2k_code_block_scalar_with_workspace_midpoint,
414 decode_j2k_code_block_scalar_with_workspace_midpoint_profiled,
415 decode_j2k_code_block_scalar_with_workspace_profiled, decode_j2k_sub_band_scalar,
416 encode_ht_code_block_scalar, encode_ht_code_block_scalar_with_passes,
417 encode_ht_code_block_scalar_with_passes_and_workspace, encode_j2k_code_block_scalar_with_style,
418 encode_j2k_packetization_scalar, forward_dwt53_reference, forward_dwt97_reference,
419 forward_ict_reference, forward_rct_reference, inverse_dwt97_reference, inverse_ict_reference,
420 pack_j2k_code_block_scalar_from_tier1_tokens, quantize_reversible_reference,
421 quantize_subband_reference, try_deinterleave_reference, HtCodeBlockDecodeProfile,
422 HtCodeBlockDecodeWorkspace, HtCodeBlockEncodeWorkspace, J2kCodeBlockDecodeProfile,
423 J2kCodeBlockDecodeWorkspace,
424};
425
426pub(crate) const JP2_MAGIC: &[u8] = b"\x00\x00\x00\x0C\x6A\x50\x20\x20";
428pub(crate) const CODESTREAM_MAGIC: &[u8] = b"\xFF\x4F\xFF\x51";
430
431mod image;
432pub use image::{DecodeSettings, Image, PreparedRegionDecoder};
433
434#[cfg(test)]
435mod tests;