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, 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::{
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 J2kDeinterleaveMctToF32Job, J2kDeinterleaveToF32Job, J2kEncodeContext, J2kEncodeDispatchReport,
271 J2kEncodeStageAccelerator, J2kEncodeStageError, J2kEncodeStageErrorKind, J2kEncodeStageResult,
272 J2kForwardDwt53Job, J2kForwardDwt53Level, J2kForwardDwt53Output, J2kForwardDwt97Job,
273 J2kForwardDwt97Level, J2kForwardDwt97Output, J2kForwardIctJob, J2kForwardRctJob,
274 J2kHtCodeBlockEncodeJob, J2kHtSubbandEncodeJob, J2kHtj2kTileEncodeJob,
275 J2kPacketizationBlockCodingMode, J2kPacketizationCodeBlock, J2kPacketizationEncodeJob,
276 J2kPacketizationPacketDescriptor, J2kPacketizationProgressionOrder, J2kPacketizationResolution,
277 J2kPacketizationSubband, J2kQuantizeSubbandJob, J2kResidentEncodeInput,
278 J2kResidentEncodeInputError, J2kResidentHtj2kTileEncodeJob, J2kSubBandType,
279 J2kTier1CodeBlockEncodeJob, PrecomputedHtj2k53Component, PrecomputedHtj2k53Image,
280 PrecomputedHtj2k97Component, PrecomputedHtj2k97Image, PreencodedHtj2k97CodeBlock,
281 PreencodedHtj2k97CompactCodeBlock, PreencodedHtj2k97CompactComponent,
282 PreencodedHtj2k97CompactImage, PreencodedHtj2k97CompactResolution,
283 PreencodedHtj2k97CompactSubband, PreencodedHtj2k97Component, PreencodedHtj2k97Image,
284 PreencodedHtj2k97Resolution, PreencodedHtj2k97Subband, PrequantizedHtj2k97CodeBlock,
285 PrequantizedHtj2k97Component, PrequantizedHtj2k97Image, PrequantizedHtj2k97Resolution,
286 PrequantizedHtj2k97Subband,
287};
288
289mod j2c;
290mod jp2;
291pub(crate) mod reader;
292#[doc(hidden)]
293pub use j2c::ht_encode_tables::HtUvlcTableEntry;
294
295const MAX_CLASSIC_DECODE_BITPLANES: u8 = j2c::MAX_BITPLANE_COUNT;
296const MAX_DEINTERLEAVE_REFERENCE_BIT_DEPTH: u8 = j2k_types::MAX_JPEG2000_PART1_SAMPLE_BIT_DEPTH;
297pub(crate) use j2k_types::MAX_JPEG2000_PART1_COMPONENTS as MAX_J2K_SPEC_COMPONENTS;
298pub(crate) const MAX_J2K_IMAGE_DIMENSION: u32 = 60_000;
299pub(crate) const MAX_J2K_TILE_COUNT: u64 = u16::MAX as u64 + 1;
300#[doc(hidden)]
301pub use j2k_types::{DEFAULT_MAX_CODEC_BYTES, DEFAULT_MAX_DECODE_BYTES};
302
303#[inline]
304pub(crate) fn checked_decode_usize_product2(left: usize, right: usize) -> Result<usize> {
305 left.checked_mul(right)
306 .ok_or(ValidationError::ImageTooLarge.into())
307}
308
309#[inline]
310fn checked_decode_byte_cap(len: usize) -> Result<usize> {
311 if len > DEFAULT_MAX_DECODE_BYTES {
312 bail!(ValidationError::ImageTooLarge);
313 }
314 Ok(len)
315}
316
317#[inline]
318pub(crate) fn checked_decode_byte_len2(left: usize, right: usize) -> Result<usize> {
319 checked_decode_byte_cap(checked_decode_usize_product2(left, right)?)
320}
321
322#[inline]
323pub(crate) fn checked_decode_byte_len3(first: usize, second: usize, third: usize) -> Result<usize> {
324 let partial = checked_decode_usize_product2(first, second)?;
325 checked_decode_byte_cap(checked_decode_usize_product2(partial, third)?)
326}
327
328#[inline]
329pub(crate) fn checked_decode_byte_len4(
330 first: usize,
331 second: usize,
332 third: usize,
333 fourth: usize,
334) -> Result<usize> {
335 let partial = checked_decode_usize_product2(first, second)?;
336 let partial = checked_decode_usize_product2(partial, third)?;
337 checked_decode_byte_cap(checked_decode_usize_product2(partial, fourth)?)
338}
339
340#[inline]
341pub(crate) fn try_reserve_decode_elements<T>(values: &mut Vec<T>, target_len: usize) -> Result<()> {
342 checked_decode_byte_len2(target_len, core::mem::size_of::<T>())?;
343 if target_len > values.capacity() {
344 values
345 .try_reserve_exact(target_len - values.len())
346 .map_err(|_| DecodingError::HostAllocationFailed)?;
347 }
348 Ok(())
349}
350
351#[inline]
352pub(crate) fn try_resize_decode_elements<T: Clone>(
353 values: &mut Vec<T>,
354 target_len: usize,
355 value: T,
356) -> Result<()> {
357 try_reserve_decode_elements(values, target_len)?;
358 values.resize(target_len, value);
359 Ok(())
360}
361
362#[inline]
363pub(crate) fn checked_decode_sample_count(width: u32, height: u32) -> Result<usize> {
364 #[cfg(target_pointer_width = "64")]
365 {
366 usize::try_from(u64::from(width) * u64::from(height))
367 .map_err(|_| ValidationError::ImageTooLarge.into())
368 }
369
370 #[cfg(not(target_pointer_width = "64"))]
371 {
372 checked_decode_usize_product2(width as usize, height as usize)
373 }
374}
375
376#[inline]
377fn native_bytes_per_sample(bit_depth: u8) -> Result<usize> {
378 if bit_depth == 0 || bit_depth > 63 {
379 bail!(ValidationError::ImageTooLarge);
380 }
381 Ok(usize::from(bit_depth).div_ceil(8).max(1))
382}
383
384#[doc(hidden)]
385pub use backend::{
386 HtCleanupEncodeDistribution, HtCodeBlockBatchJob, HtCodeBlockDecodeJob,
387 HtCodeBlockDecodePhaseLimit, HtCodeBlockDecoder, HtSubBandDecodeJob, J2kCodeBlockBatchJob,
388 J2kCodeBlockDecodeJob, J2kIdwtBand, J2kIdwtNormalization, J2kInverseMctJob, J2kRect,
389 J2kSingleDecompositionIdwtJob, J2kStoreComponentJob, J2kSubBandDecodeJob, J2kTier1TokenSegment,
390 J2kWaveletTransform,
391};
392#[doc(hidden)]
393pub use ht_adapter::{
394 decode_ht_sigprop_benchmark_state, ht_uvlc_encode_table, ht_uvlc_encode_table_bytes,
395 ht_uvlc_table0, ht_uvlc_table1, ht_vlc_encode_table0, ht_vlc_encode_table1, ht_vlc_table0,
396 ht_vlc_table1, prepare_ht_sigprop_benchmark_state, HtSigPropBenchmarkState,
397};
398
399mod scalar;
400#[doc(hidden)]
401pub use scalar::{
402 collect_ht_cleanup_encode_distribution, decode_ht_code_block_scalar,
403 decode_ht_code_block_scalar_until_phase, decode_ht_code_block_scalar_with_workspace,
404 decode_ht_code_block_scalar_with_workspace_midpoint,
405 decode_ht_code_block_scalar_with_workspace_midpoint_profiled,
406 decode_ht_code_block_scalar_with_workspace_profiled, decode_j2k_code_block_scalar,
407 decode_j2k_code_block_scalar_profiled, decode_j2k_code_block_scalar_with_workspace,
408 decode_j2k_code_block_scalar_with_workspace_midpoint,
409 decode_j2k_code_block_scalar_with_workspace_midpoint_profiled,
410 decode_j2k_code_block_scalar_with_workspace_profiled, decode_j2k_sub_band_scalar,
411 encode_ht_code_block_scalar, encode_ht_code_block_scalar_with_passes,
412 encode_j2k_code_block_scalar_with_style, encode_j2k_packetization_scalar,
413 forward_dwt53_reference, forward_dwt97_reference, forward_ict_reference, forward_rct_reference,
414 pack_j2k_code_block_scalar_from_tier1_tokens, quantize_reversible_reference,
415 quantize_subband_reference, try_deinterleave_reference, HtCodeBlockDecodeProfile,
416 HtCodeBlockDecodeWorkspace, J2kCodeBlockDecodeProfile, J2kCodeBlockDecodeWorkspace,
417};
418
419pub(crate) const JP2_MAGIC: &[u8] = b"\x00\x00\x00\x0C\x6A\x50\x20\x20";
421pub(crate) const CODESTREAM_MAGIC: &[u8] = b"\xFF\x4F\xFF\x51";
423
424mod image;
425pub use image::{DecodeSettings, Image};
426
427#[cfg(test)]
428mod tests;