1use alloc::vec::Vec;
9use core::cmp::Ordering;
10use core::ops::Range;
11use j2k_types::encode_geometry::maximum_decomposition_levels;
12
13use super::bitplane_encode;
14use super::build::SubBandType;
15use super::codestream::CodeBlockStyle;
16use super::codestream_write::{self, BlockCodingMode, EncodeComponentSampleInfo, EncodeParams};
17use super::fdwt::{self, DwtDecomposition};
18use super::forward_mct;
19use super::ht_block_encode;
20use super::packet_encode::{self, CodeBlockPacketData, ResolutionPacket, SubbandPrecinct};
21#[doc(hidden)]
22pub use super::quantize::irreversible_quantization_step_for_subband;
23use super::quantize::{self, QuantStepSize};
24use crate::profile;
25pub(crate) use crate::J2kSubBandType;
26use crate::{
27 CpuOnlyJ2kEncodeStageAccelerator, EncodedHtJ2kCodeBlock, EncodedJ2kCodeBlock,
28 J2kDeinterleaveMctToF32Job, J2kDeinterleaveToF32Job, J2kEncodeContext,
29 J2kEncodeStageAccelerator, J2kForwardDwt53Job, J2kForwardDwt53Level, J2kForwardDwt53Output,
30 J2kForwardDwt97Job, J2kForwardDwt97Level, J2kForwardDwt97Output, J2kForwardIctJob,
31 J2kForwardRctJob, J2kHtSubbandEncodeJob, J2kHtj2kTileEncodeJob,
32 J2kPacketizationBlockCodingMode, J2kPacketizationCodeBlock, J2kPacketizationEncodeJob,
33 J2kPacketizationPacketDescriptor, J2kPacketizationResolution, J2kPacketizationSubband,
34 J2kQuantizeSubbandJob, J2kResidentEncodeInput, J2kResidentHtj2kTileEncodeJob,
35 J2kTier1CodeBlockEncodeJob, PrecomputedHtj2k53Component, PrecomputedHtj2k53Image,
36 PrecomputedHtj2k97Component, PrecomputedHtj2k97Image, PreencodedHtj2k97CodeBlock,
37 PreencodedHtj2k97CompactCodeBlock, PreencodedHtj2k97CompactComponent,
38 PreencodedHtj2k97CompactImage, PreencodedHtj2k97CompactResolution,
39 PreencodedHtj2k97CompactSubband, PreencodedHtj2k97Component, PreencodedHtj2k97Image,
40 PreencodedHtj2k97Resolution, PreencodedHtj2k97Subband, PrequantizedHtj2k97Component,
41 PrequantizedHtj2k97Image, PrequantizedHtj2k97Resolution, PrequantizedHtj2k97Subband,
42 MAX_J2K_SPEC_COMPONENTS,
43};
44
45const HT_CPU_PARALLEL_FALLBACK_MIN_JOBS: usize = 4;
46const MAX_RAW_PIXEL_ENCODE_BIT_DEPTH: u8 = 24;
47const MAX_PART1_SAMPLE_BIT_DEPTH: u8 = j2k_types::MAX_JPEG2000_PART1_SAMPLE_BIT_DEPTH;
48const MAX_REVERSIBLE_NO_QUANT_EXPONENT: u16 = 31;
49const MAX_REVERSIBLE_NO_QUANT_GUARD_BITS: u8 = 7;
50const MAX_CLASSIC_REVERSIBLE_MARKER_BITPLANES: u16 =
51 MAX_REVERSIBLE_NO_QUANT_GUARD_BITS as u16 + MAX_REVERSIBLE_NO_QUANT_EXPONENT - 1;
52const MAX_CLASSIC_ROI_CODED_BITPLANES: u8 = 55;
56const MAX_HT_ROI_CODED_BITPLANES: u8 = 31;
57
58mod api_helpers;
59pub(crate) use self::api_helpers::try_deinterleave_to_f32;
60use self::api_helpers::{
61 default_public_code_block_style, internal_sub_band_type, public_sub_band_type,
62};
63#[cfg(test)]
64pub(crate) use self::api_helpers::{deinterleave_rgb8_unsigned_to_f32, deinterleave_to_f32};
65pub(crate) mod allocation;
66mod code_block_metadata;
67use self::allocation::{checked_add_bytes, checked_element_bytes, host_allocation_failed};
68mod retained_api;
69pub(crate) use self::retained_api::encode_with_accelerator_and_retained_input;
70mod retained_input;
71pub(crate) use self::retained_input::NativeEncodeRetainedInput;
72use self::retained_input::{
73 NativeEncodePhase, NativeEncodePipelineError, NativeEncodePipelineResult, NativeEncodeSession,
74};
75mod options;
76use self::options::{
77 validate_code_block_geometry, validate_irreversible_quantization_profile,
78 validate_precinct_exponents_for_options, CodeBlockGeometry,
79};
80pub use self::options::{
81 EncodeComponentPlane, EncodeOptions, EncodeProgressionOrder, EncodeRoiRegion,
82 EncodeTypedComponentPlane,
83};
84mod resident_contract;
85#[doc(hidden)]
86pub use self::resident_contract::ResidentHtj2kEncodeError;
87mod exact;
88use self::exact::{
89 forward_rct_i64, validate_htj2k_codestream, validate_reversible_i64_encode_options,
90};
91mod i64_packetize;
92mod magnitude;
93use self::i64_packetize::{packetize_i64_component_resolution_packets, I64PacketizeRequest};
94mod multitile;
95mod tile_parts;
96use self::tile_parts::{
97 validate_packet_header_marker_payloads, write_single_tile_packetized_codestream_for_session,
98};
99mod precomputed;
100use self::precomputed::encode_precomputed_53_with_component_sample_info_for_session;
101pub(in crate::j2c) use self::precomputed::encode_precomputed_htj2k_53_with_mct_and_retained_owner;
102#[cfg(test)]
103use self::precomputed::prepared_subband_from_preencoded_owned_for_tests as prepared_subband_from_preencoded_owned;
104pub use self::precomputed::{
105 encode_precomputed_htj2k_53, encode_precomputed_htj2k_53_with_accelerator,
106 encode_precomputed_htj2k_53_with_accelerator_and_max_host_bytes,
107 encode_precomputed_htj2k_53_with_mct, encode_precomputed_htj2k_53_with_mct_and_accelerator,
108 encode_precomputed_htj2k_97, encode_precomputed_htj2k_97_batch_owned_with_accelerator,
109 encode_precomputed_htj2k_97_batch_owned_with_accelerator_and_max_host_bytes,
110 encode_precomputed_htj2k_97_batch_with_accelerator,
111 encode_precomputed_htj2k_97_with_accelerator,
112 encode_precomputed_htj2k_97_with_accelerator_and_max_host_bytes, encode_precomputed_j2k_53,
113 encode_precomputed_j2k_53_with_accelerator, encode_precomputed_j2k_53_with_mct,
114 encode_precomputed_j2k_53_with_mct_and_accelerator, encode_preencoded_htj2k_97,
115 encode_preencoded_htj2k_97_compact_owned_with_accelerator,
116 encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes,
117 encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes_and_required_magnitude_bound,
118 encode_preencoded_htj2k_97_owned_with_accelerator,
119 encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes,
120 encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes_and_required_magnitude_bound,
121 encode_preencoded_htj2k_97_with_accelerator, encode_prequantized_htj2k_97,
122 encode_prequantized_htj2k_97_with_accelerator,
123 encode_prequantized_htj2k_97_with_accelerator_and_max_host_bytes,
124};
125#[cfg(test)]
126use self::precomputed::{validate_precomputed_dwt97_geometry, validate_precomputed_dwt_geometry};
127mod precomputed_batch;
128use self::precomputed_batch::prepare_precomputed_htj2k97_image_for_batch;
129#[cfg(test)]
130use self::precomputed_batch::{copy_code_block_coefficients, downcast_i64_coefficients_to_i32};
131mod prepared_packets;
132use self::prepared_packets::{
133 encode_prepared_resolution_packets_for_session,
134 encode_prepared_resolution_packets_layered_for_session,
135};
136mod packet_plan;
137use self::packet_plan::{
138 count_compact_code_blocks, ordered_prepared_resolution_packets_for_session,
139 packet_descriptors_for_order_for_session, packetization_requires_scalar,
140 packetize_resolution_packets_with_options_for_session,
141 split_component_resolution_packets_by_precinct_for_session,
142};
143mod rate_control;
144#[cfg(test)]
145use self::rate_control::{
146 assign_classic_segment_layers_by_slope, assign_ht_segment_layers_by_budget,
147 ht_layer_contributions,
148};
149use self::rate_control::{
150 assign_classic_segment_layers_by_slope_accounted, assign_ht_segment_layers_by_budget_accounted,
151 classic_layer_contributions_accounted, classic_multilayer_code_block_style,
152 classic_unbudgeted_segment_layers_accounted, enforce_classic_segment_layer_monotonicity,
153 enforce_ht_segment_layer_monotonicity, ht_layer_contributions_accounted, ht_segment_count,
154 ht_segment_rate, ht_unbudgeted_segment_layers_accounted, ClassicSegmentAssignmentCandidate,
155 ClassicSegmentLocation, HtSegmentAssignmentCandidate, HtSegmentLocation, LayeredPreparedBlock,
156 LayeredPreparedPacket, LayeredPreparedSubband,
157};
158mod roi_plan;
159use self::roi_plan::{
160 max_total_bitplanes_for_components, roi_subband_scale,
161 validate_roi_encode_options_nonallocating, ComponentRoiEncodePlan, ComponentRoiEncodeRegion,
162};
163mod samples;
164use self::samples::{
165 native_samples_equal, raw_pixel_bytes_per_sample, read_le_sample_value, sign_extend_sample,
166};
167mod single_tile;
168use self::single_tile::ownership::{cpu_dwt_transient_bytes, dwt_decompositions_retained_bytes};
169use self::single_tile::{
170 encode_impl, encode_precomputed_53_single_tile, encode_precomputed_97_single_tile,
171 encode_resident_impl,
172};
173mod subband;
174#[cfg(test)]
175use self::subband::prepare_subband;
176use self::subband::{
177 prepare_subband_for_session, F32SubbandEncodeRequest, I64SubbandEncodeSettings,
178};
179mod tier1_allocation;
180mod tier1_driver;
181use self::tier1_driver::encode_prepared_subbands_for_session;
182#[cfg(test)]
183use self::tier1_driver::{
184 encode_all_ht_code_blocks_parallel, encode_all_ht_code_blocks_serial_cpu,
185 encode_prepared_subbands,
186};
187mod transform;
188#[cfg(test)]
189use self::transform::forward_dwt53_output_from_decomposition;
190use self::transform::{
191 adjust_component_step_sizes_for_guard_delta, adjust_reversible_step_sizes_for_guard_delta,
192 encode_forward_dwt, forward_dwt53_output_retained_bytes,
193 reversible_guard_bits_for_marker_limit, try_component_plane_to_f32_for_session,
194 try_encode_forward_ict, try_encode_forward_rct, try_forward_dwt53_output_from_decomposition,
195 validate_band_len, validate_component_sample_info, validate_deinterleaved_components,
196 ForwardDwtRequest,
197};
198mod typed_i64;
199use self::typed_i64::encode_typed_component_planes_53_i64;
200mod typed_components;
201use self::typed_components::encode_typed_component_planes_53_for_session;
202
203pub fn encode(
222 pixels: &[u8],
223 width: u32,
224 height: u32,
225 num_components: u16,
226 bit_depth: u8,
227 signed: bool,
228 options: &EncodeOptions,
229) -> crate::EncodeResult<Vec<u8>> {
230 let mut accelerator = CpuOnlyJ2kEncodeStageAccelerator;
231 encode_with_accelerator(
232 pixels,
233 width,
234 height,
235 num_components,
236 bit_depth,
237 signed,
238 options,
239 &mut accelerator,
240 )
241}
242
243#[expect(
257 clippy::too_many_arguments,
258 reason = "this codec boundary keeps geometry, sample representation, and quantization policy explicit"
259)]
260pub fn encode_htj2k_with_qfactor(
261 pixels: &[u8],
262 width: u32,
263 height: u32,
264 num_components: u16,
265 bit_depth: u8,
266 signed: bool,
267 qfactor: u8,
268 options: &EncodeOptions,
269) -> crate::EncodeResult<Vec<u8>> {
270 let mut accelerator = CpuOnlyJ2kEncodeStageAccelerator;
271 encode_htj2k_with_qfactor_and_accelerator(
272 pixels,
273 width,
274 height,
275 num_components,
276 bit_depth,
277 signed,
278 qfactor,
279 options,
280 &mut accelerator,
281 )
282}
283
284#[doc(hidden)]
286#[expect(
287 clippy::too_many_arguments,
288 reason = "this codec boundary keeps geometry, sample representation, quantization policy, and accelerator explicit"
289)]
290pub fn encode_htj2k_with_qfactor_and_accelerator(
291 pixels: &[u8],
292 width: u32,
293 height: u32,
294 num_components: u16,
295 bit_depth: u8,
296 signed: bool,
297 qfactor: u8,
298 options: &EncodeOptions,
299 accelerator: &mut impl J2kEncodeStageAccelerator,
300) -> crate::EncodeResult<Vec<u8>> {
301 validate_openhtj2k_qfactor_request(qfactor, num_components, options)?;
302 let session = NativeEncodeSession::try_new_with_openhtj2k_qfactor(
303 NativeEncodeRetainedInput::none(),
304 qfactor,
305 )?;
306 let component_sample_info = [EncodeComponentSampleInfo { bit_depth, signed }; 3];
307 encode_with_accelerator_and_component_sample_info_for_session(
308 pixels,
309 width,
310 height,
311 num_components,
312 bit_depth,
313 signed,
314 options,
315 &component_sample_info[..usize::from(num_components)],
316 &session,
317 accelerator,
318 )
319}
320
321fn validate_openhtj2k_qfactor_request(
322 qfactor: u8,
323 num_components: u16,
324 options: &EncodeOptions,
325) -> crate::EncodeResult<()> {
326 if !(1..=100).contains(&qfactor) {
327 return Err(crate::EncodeError::InvalidInput {
328 what: "OpenHTJ2K Qfactor must be in 1..=100",
329 });
330 }
331 if options.reversible || !options.use_ht_block_coding {
332 return Err(crate::EncodeError::InvalidInput {
333 what: "OpenHTJ2K Qfactor requires irreversible HT block coding",
334 });
335 }
336 if options.guard_bits != 1 {
337 return Err(crate::EncodeError::InvalidInput {
338 what: "OpenHTJ2K Qfactor requires one quantization guard bit",
339 });
340 }
341 if !matches!(num_components, 1 | 3) || (num_components == 3 && !options.use_mct) {
342 return Err(crate::EncodeError::InvalidInput {
343 what: "OpenHTJ2K Qfactor requires grayscale or three-component RGB with MCT",
344 });
345 }
346 Ok(())
347}
348
349#[doc(hidden)]
355#[expect(
356 clippy::too_many_arguments,
357 reason = "this codec boundary keeps geometry, state buffers, and validated options explicit without allocation or indirection"
358)]
359pub fn encode_with_accelerator(
360 pixels: &[u8],
361 width: u32,
362 height: u32,
363 num_components: u16,
364 bit_depth: u8,
365 signed: bool,
366 options: &EncodeOptions,
367 accelerator: &mut impl J2kEncodeStageAccelerator,
368) -> crate::EncodeResult<Vec<u8>> {
369 encode_with_accelerator_and_retained_input(
370 pixels,
371 width,
372 height,
373 num_components,
374 bit_depth,
375 signed,
376 options,
377 NativeEncodeRetainedInput::none(),
378 accelerator,
379 )
380}
381
382#[doc(hidden)]
388pub fn encode_resident_htj2k_with_accelerator(
389 input: J2kResidentEncodeInput,
390 options: &EncodeOptions,
391 accelerator: &mut impl J2kEncodeStageAccelerator,
392) -> Result<Vec<u8>, ResidentHtj2kEncodeError> {
393 encode_resident_impl(input, options, block_coding_mode(options), accelerator)
394}
395
396#[expect(
397 clippy::too_many_arguments,
398 reason = "this codec boundary keeps geometry, state buffers, and validated options explicit without allocation or indirection"
399)]
400fn encode_with_accelerator_and_component_sample_info_for_session(
401 pixels: &[u8],
402 width: u32,
403 height: u32,
404 num_components: u16,
405 bit_depth: u8,
406 signed: bool,
407 options: &EncodeOptions,
408 component_sample_info: &[EncodeComponentSampleInfo],
409 session: &NativeEncodeSession<'_>,
410 accelerator: &mut impl J2kEncodeStageAccelerator,
411) -> crate::EncodeResult<Vec<u8>> {
412 let block_coding_mode = block_coding_mode(options);
413 encode_with_accelerator_and_mode_for_session(
414 pixels,
415 width,
416 height,
417 num_components,
418 bit_depth,
419 signed,
420 options,
421 component_sample_info,
422 block_coding_mode,
423 session,
424 accelerator,
425 )
426}
427
428#[expect(
429 clippy::too_many_arguments,
430 reason = "this internal mode boundary keeps caller geometry and validated coding policy explicit"
431)]
432fn encode_with_accelerator_and_mode_for_session(
433 pixels: &[u8],
434 width: u32,
435 height: u32,
436 num_components: u16,
437 bit_depth: u8,
438 signed: bool,
439 options: &EncodeOptions,
440 component_sample_info: &[EncodeComponentSampleInfo],
441 block_coding_mode: BlockCodingMode,
442 session: &NativeEncodeSession<'_>,
443 accelerator: &mut impl J2kEncodeStageAccelerator,
444) -> crate::EncodeResult<Vec<u8>> {
445 let codestream = encode_impl(
446 pixels,
447 width,
448 height,
449 num_components,
450 bit_depth,
451 signed,
452 options,
453 block_coding_mode,
454 &[],
455 component_sample_info,
456 session,
457 accelerator,
458 )
459 .map_err(NativeEncodePipelineError::into_encode_error)?;
460
461 if block_coding_mode == BlockCodingMode::HighThroughput
462 && options.validate_high_throughput_codestream
463 {
464 validate_htj2k_codestream(
465 &codestream,
466 codestream.capacity(),
467 pixels,
468 width,
469 height,
470 num_components,
471 bit_depth,
472 signed,
473 options.reversible,
474 )?;
475 }
476
477 Ok(codestream)
478}
479
480#[expect(
491 clippy::too_many_arguments,
492 reason = "this codec boundary keeps geometry, state buffers, and validated options explicit without allocation or indirection"
493)]
494pub fn encode_with_roi_regions(
495 pixels: &[u8],
496 width: u32,
497 height: u32,
498 num_components: u16,
499 bit_depth: u8,
500 signed: bool,
501 options: &EncodeOptions,
502 roi_regions: &[EncodeRoiRegion],
503) -> crate::EncodeResult<Vec<u8>> {
504 let mut accelerator = CpuOnlyJ2kEncodeStageAccelerator;
505 encode_with_accelerator_and_roi_regions(
506 pixels,
507 width,
508 height,
509 num_components,
510 bit_depth,
511 signed,
512 options,
513 roi_regions,
514 &mut accelerator,
515 )
516}
517
518#[doc(hidden)]
520#[expect(
521 clippy::too_many_arguments,
522 reason = "this codec boundary keeps geometry, state buffers, and validated options explicit without allocation or indirection"
523)]
524pub fn encode_with_accelerator_and_roi_regions(
525 pixels: &[u8],
526 width: u32,
527 height: u32,
528 num_components: u16,
529 bit_depth: u8,
530 signed: bool,
531 options: &EncodeOptions,
532 roi_regions: &[EncodeRoiRegion],
533 accelerator: &mut impl J2kEncodeStageAccelerator,
534) -> crate::EncodeResult<Vec<u8>> {
535 let session = NativeEncodeSession::try_new(NativeEncodeRetainedInput::none())?;
536 let block_coding_mode = block_coding_mode(options);
537 let codestream = encode_impl(
538 pixels,
539 width,
540 height,
541 num_components,
542 bit_depth,
543 signed,
544 options,
545 block_coding_mode,
546 roi_regions,
547 &[],
548 &session,
549 accelerator,
550 )
551 .map_err(NativeEncodePipelineError::into_encode_error)?;
552
553 if block_coding_mode == BlockCodingMode::HighThroughput
554 && options.validate_high_throughput_codestream
555 {
556 validate_htj2k_codestream(
557 &codestream,
558 codestream.capacity(),
559 pixels,
560 width,
561 height,
562 num_components,
563 bit_depth,
564 signed,
565 options.reversible,
566 )?;
567 }
568
569 Ok(codestream)
570}
571
572pub fn encode_htj2k(
581 pixels: &[u8],
582 width: u32,
583 height: u32,
584 num_components: u16,
585 bit_depth: u8,
586 signed: bool,
587 options: &EncodeOptions,
588) -> crate::EncodeResult<Vec<u8>> {
589 let session = NativeEncodeSession::try_new(NativeEncodeRetainedInput::none())?;
590 let mut accelerator = CpuOnlyJ2kEncodeStageAccelerator;
591 encode_with_accelerator_and_mode_for_session(
592 pixels,
593 width,
594 height,
595 num_components,
596 bit_depth,
597 signed,
598 options,
599 &[],
600 BlockCodingMode::HighThroughput,
601 &session,
602 &mut accelerator,
603 )
604}
605
606pub fn encode_component_planes_53(
618 planes: &[EncodeComponentPlane<'_>],
619 width: u32,
620 height: u32,
621 bit_depth: u8,
622 signed: bool,
623 options: &EncodeOptions,
624) -> crate::EncodeResult<Vec<u8>> {
625 let session = NativeEncodeSession::try_new(NativeEncodeRetainedInput::none())?;
626 let requested_bytes = checked_element_bytes::<EncodeTypedComponentPlane<'_>>(
627 planes.len(),
628 "component-plane typed descriptor owners",
629 )?;
630 session.checked_phase(requested_bytes, "component-plane typed descriptor owners")?;
631 let mut typed_planes = Vec::new();
632 typed_planes.try_reserve_exact(planes.len()).map_err(|_| {
633 host_allocation_failed("component-plane typed descriptor owners", requested_bytes)
634 })?;
635 typed_planes.extend(planes.iter().map(|plane| EncodeTypedComponentPlane {
636 data: plane.data,
637 x_rsiz: plane.x_rsiz,
638 y_rsiz: plane.y_rsiz,
639 bit_depth,
640 signed,
641 }));
642 let actual_bytes = checked_element_bytes::<EncodeTypedComponentPlane<'_>>(
643 typed_planes.capacity(),
644 "component-plane typed descriptor owners",
645 )?;
646 let typed_session = session.checked_child_session(
647 &typed_planes,
648 actual_bytes,
649 "component-plane typed descriptor owners",
650 )?;
651 encode_typed_component_planes_53_for_session(
652 &typed_planes,
653 width,
654 height,
655 options,
656 &typed_session,
657 )
658 .map_err(NativeEncodePipelineError::into_encode_error)
659}
660
661pub fn encode_typed_component_planes_53(
674 planes: &[EncodeTypedComponentPlane<'_>],
675 width: u32,
676 height: u32,
677 options: &EncodeOptions,
678) -> crate::EncodeResult<Vec<u8>> {
679 let session = NativeEncodeSession::try_new(NativeEncodeRetainedInput::none())?;
680 encode_typed_component_planes_53_for_session(planes, width, height, options, &session)
681 .map_err(NativeEncodePipelineError::into_encode_error)
682}
683
684fn block_coding_mode(options: &EncodeOptions) -> BlockCodingMode {
688 if options.use_ht_block_coding {
689 BlockCodingMode::HighThroughput
690 } else {
691 BlockCodingMode::Classic
692 }
693}
694
695fn ht_target_coding_passes_for_options(
696 options: &EncodeOptions,
697 block_coding_mode: BlockCodingMode,
698) -> u8 {
699 if block_coding_mode == BlockCodingMode::HighThroughput
700 && !options.reversible
701 && options.num_layers > 1
702 {
703 options.num_layers.min(3)
704 } else {
705 1
706 }
707}
708
709fn requested_guard_bits(options: &EncodeOptions, use_mct: bool, openhtj2k_qfactor: bool) -> u8 {
710 if openhtj2k_qfactor {
711 1
712 } else if options.reversible && !use_mct {
713 options.guard_bits
714 } else {
715 options.guard_bits.max(2)
716 }
717}
718
719enum PreparedCodeBlockCoefficients {
720 I32(Vec<i32>),
721 I64(Vec<i64>),
722 Empty,
723}
724
725#[cfg(test)]
726impl PreparedCodeBlockCoefficients {
727 fn is_empty(&self) -> bool {
728 match self {
729 Self::I32(values) => values.is_empty(),
730 Self::I64(values) => values.is_empty(),
731 Self::Empty => true,
732 }
733 }
734}
735
736struct PreparedEncodeCodeBlock {
737 coefficients: PreparedCodeBlockCoefficients,
738 width: u32,
739 height: u32,
740}
741
742struct PreparedEncodeSubband {
743 code_blocks: Vec<PreparedEncodeCodeBlock>,
744 preencoded_ht_code_blocks: Option<Vec<EncodedHtJ2kCodeBlock>>,
745 preencoded_ht_maximum_cleanup_magnitude: Option<u64>,
746 num_cbs_x: u32,
747 num_cbs_y: u32,
748 code_block_width: u32,
749 code_block_height: u32,
750 width: u32,
751 height: u32,
752 sub_band_type: SubBandType,
753 total_bitplanes: u8,
754 block_coding_mode: BlockCodingMode,
755 ht_target_coding_passes: u8,
756}
757
758struct PreparedResolutionPacket {
759 component: u16,
760 resolution: u32,
761 precinct: u64,
762 subbands: Vec<PreparedEncodeSubband>,
763}
764
765struct PreparedCompactCodeBlock<'a> {
766 data: &'a [u8],
767 cleanup_length: u32,
768 refinement_length: u32,
769 num_coding_passes: u8,
770 num_zero_bitplanes: u8,
771}
772
773struct PreparedCompactSubband<'a> {
774 code_blocks: Vec<PreparedCompactCodeBlock<'a>>,
775 num_cbs_x: u32,
776 num_cbs_y: u32,
777}
778
779struct PreparedCompactResolutionPacket<'a> {
780 component: u16,
781 resolution: u32,
782 precinct: u64,
783 subbands: Vec<PreparedCompactSubband<'a>>,
784}
785
786#[cfg(test)]
787#[path = "encode_tests.rs"]
788mod tests;