Skip to main content

j2k_native/j2c/
encode.rs

1//! Top-level JPEG 2000 encode orchestration.
2//!
3//! Coordinates the full encoding pipeline:
4//!   pixels → MCT → DWT → quantize → EBCOT T1 → T2 → codestream
5//!
6//! Supports both lossless (5-3 reversible) and lossy (9-7 irreversible) encoding.
7
8use alloc::vec::Vec;
9use core::cmp::Ordering;
10use core::ops::Range;
11use j2k_codec_math::dwt::max_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    J2kDeinterleaveToF32Job, J2kEncodeStageAccelerator, J2kForwardDwt53Job, J2kForwardDwt53Level,
29    J2kForwardDwt53Output, J2kForwardDwt97Job, J2kForwardDwt97Level, J2kForwardDwt97Output,
30    J2kForwardIctJob, J2kForwardRctJob, J2kHtSubbandEncodeJob, J2kHtj2kTileEncodeJob,
31    J2kPacketizationBlockCodingMode, J2kPacketizationCodeBlock, J2kPacketizationEncodeJob,
32    J2kPacketizationPacketDescriptor, J2kPacketizationResolution, J2kPacketizationSubband,
33    J2kQuantizeSubbandJob, J2kResidentEncodeInput, J2kResidentHtj2kTileEncodeJob,
34    J2kTier1CodeBlockEncodeJob, PrecomputedHtj2k53Component, PrecomputedHtj2k53Image,
35    PrecomputedHtj2k97Component, PrecomputedHtj2k97Image, PreencodedHtj2k97CodeBlock,
36    PreencodedHtj2k97CompactCodeBlock, PreencodedHtj2k97CompactComponent,
37    PreencodedHtj2k97CompactImage, PreencodedHtj2k97CompactResolution,
38    PreencodedHtj2k97CompactSubband, PreencodedHtj2k97Component, PreencodedHtj2k97Image,
39    PreencodedHtj2k97Resolution, PreencodedHtj2k97Subband, PrequantizedHtj2k97Component,
40    PrequantizedHtj2k97Image, PrequantizedHtj2k97Resolution, PrequantizedHtj2k97Subband,
41    MAX_J2K_SPEC_COMPONENTS,
42};
43
44const HT_CPU_PARALLEL_FALLBACK_MIN_JOBS: usize = 4;
45const MAX_RAW_PIXEL_ENCODE_BIT_DEPTH: u8 = 24;
46const MAX_PART1_SAMPLE_BIT_DEPTH: u8 = j2k_types::MAX_JPEG2000_PART1_SAMPLE_BIT_DEPTH;
47const MAX_REVERSIBLE_NO_QUANT_EXPONENT: u16 = 31;
48const MAX_REVERSIBLE_NO_QUANT_GUARD_BITS: u8 = 7;
49const MAX_CLASSIC_REVERSIBLE_MARKER_BITPLANES: u16 =
50    MAX_REVERSIBLE_NO_QUANT_GUARD_BITS as u16 + MAX_REVERSIBLE_NO_QUANT_EXPONENT - 1;
51// Classic packet headers can signal at most 164 coding passes, i.e.
52// 1 cleanup pass for the first bitplane plus 3 passes for each additional
53// bitplane: 1 + 3 * (55 - 1) = 163.
54const MAX_CLASSIC_ROI_CODED_BITPLANES: u8 = 55;
55const MAX_HT_ROI_CODED_BITPLANES: u8 = 31;
56
57mod api_helpers;
58pub(crate) use self::api_helpers::try_deinterleave_to_f32;
59use self::api_helpers::{
60    default_public_code_block_style, internal_sub_band_type, public_sub_band_type,
61};
62#[cfg(test)]
63pub(crate) use self::api_helpers::{deinterleave_rgb8_unsigned_to_f32, deinterleave_to_f32};
64pub(crate) mod allocation;
65mod code_block_metadata;
66use self::allocation::{checked_add_bytes, checked_element_bytes, host_allocation_failed};
67mod retained_api;
68pub(crate) use self::retained_api::encode_with_accelerator_and_retained_input;
69mod retained_input;
70pub(crate) use self::retained_input::NativeEncodeRetainedInput;
71use self::retained_input::{
72    NativeEncodePhase, NativeEncodePipelineError, NativeEncodePipelineResult, NativeEncodeSession,
73};
74mod options;
75use self::options::{
76    validate_code_block_geometry, validate_irreversible_quantization_profile,
77    validate_precinct_exponents_for_options, CodeBlockGeometry,
78};
79pub use self::options::{
80    EncodeComponentPlane, EncodeOptions, EncodeProgressionOrder, EncodeRoiRegion,
81    EncodeTypedComponentPlane,
82};
83mod resident_contract;
84#[doc(hidden)]
85pub use self::resident_contract::ResidentHtj2kEncodeError;
86mod exact;
87use self::exact::{
88    forward_rct_i64, validate_htj2k_codestream, validate_reversible_i64_encode_options,
89};
90mod i64_packetize;
91use self::i64_packetize::{packetize_i64_component_resolution_packets, I64PacketizeRequest};
92mod multitile;
93mod tile_parts;
94use self::tile_parts::{
95    validate_packet_header_marker_payloads, write_single_tile_packetized_codestream_for_session,
96};
97mod precomputed;
98use self::precomputed::encode_precomputed_53_with_component_sample_info_for_session;
99pub(in crate::j2c) use self::precomputed::encode_precomputed_htj2k_53_with_mct_and_retained_owner;
100#[cfg(test)]
101use self::precomputed::prepared_subband_from_preencoded_owned_for_tests as prepared_subband_from_preencoded_owned;
102pub use self::precomputed::{
103    encode_precomputed_htj2k_53, encode_precomputed_htj2k_53_with_accelerator,
104    encode_precomputed_htj2k_53_with_accelerator_and_max_host_bytes,
105    encode_precomputed_htj2k_53_with_mct, encode_precomputed_htj2k_53_with_mct_and_accelerator,
106    encode_precomputed_htj2k_97, encode_precomputed_htj2k_97_batch_owned_with_accelerator,
107    encode_precomputed_htj2k_97_batch_owned_with_accelerator_and_max_host_bytes,
108    encode_precomputed_htj2k_97_batch_with_accelerator,
109    encode_precomputed_htj2k_97_with_accelerator,
110    encode_precomputed_htj2k_97_with_accelerator_and_max_host_bytes, encode_precomputed_j2k_53,
111    encode_precomputed_j2k_53_with_accelerator, encode_precomputed_j2k_53_with_mct,
112    encode_precomputed_j2k_53_with_mct_and_accelerator, encode_preencoded_htj2k_97,
113    encode_preencoded_htj2k_97_compact_owned_with_accelerator,
114    encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes,
115    encode_preencoded_htj2k_97_owned_with_accelerator,
116    encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes,
117    encode_preencoded_htj2k_97_with_accelerator, encode_prequantized_htj2k_97,
118    encode_prequantized_htj2k_97_with_accelerator,
119    encode_prequantized_htj2k_97_with_accelerator_and_max_host_bytes,
120};
121#[cfg(test)]
122use self::precomputed::{validate_precomputed_dwt97_geometry, validate_precomputed_dwt_geometry};
123mod precomputed_batch;
124use self::precomputed_batch::prepare_precomputed_htj2k97_image_for_batch;
125#[cfg(test)]
126use self::precomputed_batch::{copy_code_block_coefficients, downcast_i64_coefficients_to_i32};
127mod prepared_packets;
128use self::prepared_packets::{
129    encode_prepared_resolution_packets_for_session,
130    encode_prepared_resolution_packets_layered_for_session,
131};
132mod packet_plan;
133use self::packet_plan::{
134    count_compact_code_blocks, ordered_prepared_resolution_packets_for_session,
135    packet_descriptors_for_order_for_session, packetization_requires_scalar,
136    packetize_resolution_packets_with_options_for_session, public_packetization_progression_order,
137    split_component_resolution_packets_by_precinct_for_session,
138};
139mod rate_control;
140#[cfg(test)]
141use self::rate_control::{
142    assign_classic_segment_layers_by_slope, assign_ht_segment_layers_by_budget,
143    ht_layer_contributions,
144};
145use self::rate_control::{
146    assign_classic_segment_layers_by_slope_accounted, assign_ht_segment_layers_by_budget_accounted,
147    classic_layer_contributions_accounted, classic_multilayer_code_block_style,
148    classic_unbudgeted_segment_layers_accounted, enforce_classic_segment_layer_monotonicity,
149    enforce_ht_segment_layer_monotonicity, ht_layer_contributions_accounted, ht_segment_count,
150    ht_segment_rate, ht_unbudgeted_segment_layers_accounted, ClassicSegmentAssignmentCandidate,
151    ClassicSegmentLocation, HtSegmentAssignmentCandidate, HtSegmentLocation, LayeredPreparedBlock,
152    LayeredPreparedPacket, LayeredPreparedSubband,
153};
154mod roi_plan;
155use self::roi_plan::{
156    max_total_bitplanes_for_components, roi_subband_scale,
157    validate_roi_encode_options_nonallocating, ComponentRoiEncodePlan, ComponentRoiEncodeRegion,
158};
159mod samples;
160use self::samples::{
161    native_samples_equal, raw_pixel_bytes_per_sample, read_le_sample_value, sign_extend_sample,
162};
163mod single_tile;
164use self::single_tile::ownership::{cpu_dwt_transient_bytes, dwt_decompositions_retained_bytes};
165use self::single_tile::{
166    encode_impl, encode_precomputed_53_single_tile, encode_precomputed_97_single_tile,
167    encode_resident_impl,
168};
169mod subband;
170#[cfg(test)]
171use self::subband::prepare_subband;
172use self::subband::{
173    prepare_subband_for_session, F32SubbandEncodeRequest, I64SubbandEncodeSettings,
174};
175mod tier1_allocation;
176mod tier1_driver;
177use self::tier1_driver::encode_prepared_subbands_for_session;
178#[cfg(test)]
179use self::tier1_driver::{
180    encode_all_ht_code_blocks_parallel, encode_all_ht_code_blocks_serial_cpu,
181    encode_prepared_subbands,
182};
183mod transform;
184#[cfg(test)]
185use self::transform::forward_dwt53_output_from_decomposition;
186use self::transform::{
187    adjust_component_step_sizes_for_guard_delta, adjust_reversible_step_sizes_for_guard_delta,
188    encode_forward_dwt, forward_dwt53_output_retained_bytes,
189    reversible_guard_bits_for_marker_limit, try_component_plane_to_f32_for_session,
190    try_encode_forward_ict, try_encode_forward_rct, try_forward_dwt53_output_from_decomposition,
191    validate_band_len, validate_component_sample_info, validate_deinterleaved_components,
192    ForwardDwtRequest,
193};
194mod typed_i64;
195use self::typed_i64::encode_typed_component_planes_53_i64;
196mod typed_components;
197use self::typed_components::encode_typed_component_planes_53_for_session;
198
199/// Encode pixel data into a JPEG 2000 codestream.
200///
201/// # Arguments
202/// * `pixels` — Raw pixel data. For 8-bit: one byte per sample. For >8-bit: two bytes per sample (little-endian u16).
203/// * `width` — Image width in pixels.
204/// * `height` — Image height in pixels.
205/// * `num_components` — Number of components (1 for grayscale, 3 for RGB).
206/// * `bit_depth` — Bits per sample (e.g., 8, 12, 16).
207/// * `signed` — Whether samples are signed.
208/// * `options` — Encoding parameters.
209///
210/// # Returns
211/// The encoded JPEG 2000 codestream bytes (`.j2c` format).
212///
213/// # Errors
214///
215/// Returns an error when dimensions, sample data, component metadata, or
216/// encoding options are invalid, or when a codec stage cannot encode them.
217pub fn encode(
218    pixels: &[u8],
219    width: u32,
220    height: u32,
221    num_components: u16,
222    bit_depth: u8,
223    signed: bool,
224    options: &EncodeOptions,
225) -> crate::EncodeResult<Vec<u8>> {
226    let mut accelerator = CpuOnlyJ2kEncodeStageAccelerator;
227    encode_with_accelerator(
228        pixels,
229        width,
230        height,
231        num_components,
232        bit_depth,
233        signed,
234        options,
235        &mut accelerator,
236    )
237}
238
239/// Encode pixel data into a JPEG 2000 codestream using optional encode-stage hooks.
240///
241/// Stage hooks may accelerate forward RCT, forward 5/3 DWT, Tier-1 code-block
242/// encode, and packetization. Returning fallback from a hook preserves the CPU
243/// baseline for that stage.
244#[doc(hidden)]
245#[expect(
246    clippy::too_many_arguments,
247    reason = "this codec boundary keeps geometry, state buffers, and validated options explicit without allocation or indirection"
248)]
249pub fn encode_with_accelerator(
250    pixels: &[u8],
251    width: u32,
252    height: u32,
253    num_components: u16,
254    bit_depth: u8,
255    signed: bool,
256    options: &EncodeOptions,
257    accelerator: &mut impl J2kEncodeStageAccelerator,
258) -> crate::EncodeResult<Vec<u8>> {
259    encode_with_accelerator_and_retained_input(
260        pixels,
261        width,
262        height,
263        num_components,
264        bit_depth,
265        signed,
266        options,
267        NativeEncodeRetainedInput::none(),
268        accelerator,
269    )
270}
271
272/// Encode a complete HTJ2K tile whose input pixels remain backend-resident.
273///
274/// This implementation-facing entry point reuses native request planning and
275/// codestream finalization, but has no CPU fallback because no host samples are
276/// present. A declined resident hook is returned as an explicit error.
277#[doc(hidden)]
278pub fn encode_resident_htj2k_with_accelerator(
279    input: J2kResidentEncodeInput,
280    options: &EncodeOptions,
281    accelerator: &mut impl J2kEncodeStageAccelerator,
282) -> Result<Vec<u8>, ResidentHtj2kEncodeError> {
283    encode_resident_impl(input, options, block_coding_mode(options), accelerator)
284}
285
286#[expect(
287    clippy::too_many_arguments,
288    reason = "this codec boundary keeps geometry, state buffers, and validated options explicit without allocation or indirection"
289)]
290fn encode_with_accelerator_and_component_sample_info_for_session(
291    pixels: &[u8],
292    width: u32,
293    height: u32,
294    num_components: u16,
295    bit_depth: u8,
296    signed: bool,
297    options: &EncodeOptions,
298    component_sample_info: &[EncodeComponentSampleInfo],
299    session: &NativeEncodeSession<'_>,
300    accelerator: &mut impl J2kEncodeStageAccelerator,
301) -> crate::EncodeResult<Vec<u8>> {
302    let block_coding_mode = block_coding_mode(options);
303    encode_with_accelerator_and_mode_for_session(
304        pixels,
305        width,
306        height,
307        num_components,
308        bit_depth,
309        signed,
310        options,
311        component_sample_info,
312        block_coding_mode,
313        session,
314        accelerator,
315    )
316}
317
318#[expect(
319    clippy::too_many_arguments,
320    reason = "this internal mode boundary keeps caller geometry and validated coding policy explicit"
321)]
322fn encode_with_accelerator_and_mode_for_session(
323    pixels: &[u8],
324    width: u32,
325    height: u32,
326    num_components: u16,
327    bit_depth: u8,
328    signed: bool,
329    options: &EncodeOptions,
330    component_sample_info: &[EncodeComponentSampleInfo],
331    block_coding_mode: BlockCodingMode,
332    session: &NativeEncodeSession<'_>,
333    accelerator: &mut impl J2kEncodeStageAccelerator,
334) -> crate::EncodeResult<Vec<u8>> {
335    let codestream = encode_impl(
336        pixels,
337        width,
338        height,
339        num_components,
340        bit_depth,
341        signed,
342        options,
343        block_coding_mode,
344        &[],
345        component_sample_info,
346        session,
347        accelerator,
348    )
349    .map_err(NativeEncodePipelineError::into_encode_error)?;
350
351    if block_coding_mode == BlockCodingMode::HighThroughput
352        && options.validate_high_throughput_codestream
353    {
354        validate_htj2k_codestream(
355            &codestream,
356            codestream.capacity(),
357            pixels,
358            width,
359            height,
360            num_components,
361            bit_depth,
362            signed,
363            options.reversible,
364        )?;
365    }
366
367    Ok(codestream)
368}
369
370/// Encode pixel data into a JPEG 2000 codestream with rectangular ROI maxshift.
371///
372/// This uses the normal native encoder pipeline. Non-empty `roi_regions`
373/// produce RGN markers and shift selected quantized coefficients before
374/// code-block encoding.
375///
376/// # Errors
377///
378/// Returns an error for invalid image/sample metadata, invalid ROI regions or
379/// options, or a failure in any codec stage.
380#[expect(
381    clippy::too_many_arguments,
382    reason = "this codec boundary keeps geometry, state buffers, and validated options explicit without allocation or indirection"
383)]
384pub fn encode_with_roi_regions(
385    pixels: &[u8],
386    width: u32,
387    height: u32,
388    num_components: u16,
389    bit_depth: u8,
390    signed: bool,
391    options: &EncodeOptions,
392    roi_regions: &[EncodeRoiRegion],
393) -> crate::EncodeResult<Vec<u8>> {
394    let mut accelerator = CpuOnlyJ2kEncodeStageAccelerator;
395    encode_with_accelerator_and_roi_regions(
396        pixels,
397        width,
398        height,
399        num_components,
400        bit_depth,
401        signed,
402        options,
403        roi_regions,
404        &mut accelerator,
405    )
406}
407
408/// Encode pixel data with rectangular ROI maxshift and optional stage hooks.
409#[doc(hidden)]
410#[expect(
411    clippy::too_many_arguments,
412    reason = "this codec boundary keeps geometry, state buffers, and validated options explicit without allocation or indirection"
413)]
414pub fn encode_with_accelerator_and_roi_regions(
415    pixels: &[u8],
416    width: u32,
417    height: u32,
418    num_components: u16,
419    bit_depth: u8,
420    signed: bool,
421    options: &EncodeOptions,
422    roi_regions: &[EncodeRoiRegion],
423    accelerator: &mut impl J2kEncodeStageAccelerator,
424) -> crate::EncodeResult<Vec<u8>> {
425    let session = NativeEncodeSession::try_new(NativeEncodeRetainedInput::none())?;
426    let block_coding_mode = block_coding_mode(options);
427    let codestream = encode_impl(
428        pixels,
429        width,
430        height,
431        num_components,
432        bit_depth,
433        signed,
434        options,
435        block_coding_mode,
436        roi_regions,
437        &[],
438        &session,
439        accelerator,
440    )
441    .map_err(NativeEncodePipelineError::into_encode_error)?;
442
443    if block_coding_mode == BlockCodingMode::HighThroughput
444        && options.validate_high_throughput_codestream
445    {
446        validate_htj2k_codestream(
447            &codestream,
448            codestream.capacity(),
449            pixels,
450            width,
451            height,
452            num_components,
453            bit_depth,
454            signed,
455            options.reversible,
456        )?;
457    }
458
459    Ok(codestream)
460}
461
462/// Encode pixel data into an HTJ2K codestream.
463///
464/// Lossless HTJ2K output is self-validated before it is returned.
465///
466/// # Errors
467///
468/// Returns an error when the input or options are invalid, encoding fails, or
469/// the requested output fails HTJ2K self-validation.
470pub fn encode_htj2k(
471    pixels: &[u8],
472    width: u32,
473    height: u32,
474    num_components: u16,
475    bit_depth: u8,
476    signed: bool,
477    options: &EncodeOptions,
478) -> crate::EncodeResult<Vec<u8>> {
479    let session = NativeEncodeSession::try_new(NativeEncodeRetainedInput::none())?;
480    let mut accelerator = CpuOnlyJ2kEncodeStageAccelerator;
481    encode_with_accelerator_and_mode_for_session(
482        pixels,
483        width,
484        height,
485        num_components,
486        bit_depth,
487        signed,
488        options,
489        &[],
490        BlockCodingMode::HighThroughput,
491        &session,
492        &mut accelerator,
493    )
494}
495
496/// Encode reversible 5/3 component planes into a classic J2K or HTJ2K
497/// codestream.
498///
499/// Plane buffers are supplied at each component's own SIZ sampling grid. Set
500/// [`EncodeOptions::use_ht_block_coding`] to select HTJ2K block coding; the
501/// default writes classic Part 1 block coding.
502///
503/// # Errors
504///
505/// Returns an error for invalid component geometry, sampling, sample buffers,
506/// or options, or when a codec stage fails.
507pub fn encode_component_planes_53(
508    planes: &[EncodeComponentPlane<'_>],
509    width: u32,
510    height: u32,
511    bit_depth: u8,
512    signed: bool,
513    options: &EncodeOptions,
514) -> crate::EncodeResult<Vec<u8>> {
515    let session = NativeEncodeSession::try_new(NativeEncodeRetainedInput::none())?;
516    let requested_bytes = checked_element_bytes::<EncodeTypedComponentPlane<'_>>(
517        planes.len(),
518        "component-plane typed descriptor owners",
519    )?;
520    session.checked_phase(requested_bytes, "component-plane typed descriptor owners")?;
521    let mut typed_planes = Vec::new();
522    typed_planes.try_reserve_exact(planes.len()).map_err(|_| {
523        host_allocation_failed("component-plane typed descriptor owners", requested_bytes)
524    })?;
525    typed_planes.extend(planes.iter().map(|plane| EncodeTypedComponentPlane {
526        data: plane.data,
527        x_rsiz: plane.x_rsiz,
528        y_rsiz: plane.y_rsiz,
529        bit_depth,
530        signed,
531    }));
532    let actual_bytes = checked_element_bytes::<EncodeTypedComponentPlane<'_>>(
533        typed_planes.capacity(),
534        "component-plane typed descriptor owners",
535    )?;
536    let typed_session = session.checked_child_session(
537        &typed_planes,
538        actual_bytes,
539        "component-plane typed descriptor owners",
540    )?;
541    encode_typed_component_planes_53_for_session(
542        &typed_planes,
543        width,
544        height,
545        options,
546        &typed_session,
547    )
548    .map_err(NativeEncodePipelineError::into_encode_error)
549}
550
551/// Encode reversible 5/3 typed component planes into a classic J2K or HTJ2K
552/// codestream.
553///
554/// This is the component-plane entry point for JPEG 2000 codestreams whose
555/// components have different precision or signedness. Plane buffers are
556/// supplied at each component's own SIZ sampling grid. Components are encoded
557/// without a reversible color transform.
558///
559/// # Errors
560///
561/// Returns an error for invalid component count, dimensions, sampling,
562/// precision, sample buffers, or options, or when a codec stage fails.
563pub fn encode_typed_component_planes_53(
564    planes: &[EncodeTypedComponentPlane<'_>],
565    width: u32,
566    height: u32,
567    options: &EncodeOptions,
568) -> crate::EncodeResult<Vec<u8>> {
569    let session = NativeEncodeSession::try_new(NativeEncodeRetainedInput::none())?;
570    encode_typed_component_planes_53_for_session(planes, width, height, options, &session)
571        .map_err(NativeEncodePipelineError::into_encode_error)
572}
573
574/// Encode precomputed reversible 5/3 wavelet coefficients into a classic
575/// JPEG 2000 Part 1 codestream.
576///
577fn block_coding_mode(options: &EncodeOptions) -> BlockCodingMode {
578    if options.use_ht_block_coding {
579        BlockCodingMode::HighThroughput
580    } else {
581        BlockCodingMode::Classic
582    }
583}
584
585fn ht_target_coding_passes_for_options(
586    options: &EncodeOptions,
587    block_coding_mode: BlockCodingMode,
588) -> u8 {
589    if block_coding_mode == BlockCodingMode::HighThroughput && options.num_layers > 1 {
590        options.num_layers.min(3)
591    } else {
592        1
593    }
594}
595
596enum PreparedCodeBlockCoefficients {
597    I32(Vec<i32>),
598    I64(Vec<i64>),
599    Empty,
600}
601
602#[cfg(test)]
603impl PreparedCodeBlockCoefficients {
604    fn is_empty(&self) -> bool {
605        match self {
606            Self::I32(values) => values.is_empty(),
607            Self::I64(values) => values.is_empty(),
608            Self::Empty => true,
609        }
610    }
611}
612
613struct PreparedEncodeCodeBlock {
614    coefficients: PreparedCodeBlockCoefficients,
615    width: u32,
616    height: u32,
617}
618
619struct PreparedEncodeSubband {
620    code_blocks: Vec<PreparedEncodeCodeBlock>,
621    preencoded_ht_code_blocks: Option<Vec<EncodedHtJ2kCodeBlock>>,
622    num_cbs_x: u32,
623    num_cbs_y: u32,
624    code_block_width: u32,
625    code_block_height: u32,
626    width: u32,
627    height: u32,
628    sub_band_type: SubBandType,
629    total_bitplanes: u8,
630    block_coding_mode: BlockCodingMode,
631    ht_target_coding_passes: u8,
632}
633
634struct PreparedResolutionPacket {
635    component: u16,
636    resolution: u32,
637    precinct: u64,
638    subbands: Vec<PreparedEncodeSubband>,
639}
640
641struct PreparedCompactCodeBlock<'a> {
642    data: &'a [u8],
643    cleanup_length: u32,
644    refinement_length: u32,
645    num_coding_passes: u8,
646    num_zero_bitplanes: u8,
647}
648
649struct PreparedCompactSubband<'a> {
650    code_blocks: Vec<PreparedCompactCodeBlock<'a>>,
651    num_cbs_x: u32,
652    num_cbs_y: u32,
653}
654
655struct PreparedCompactResolutionPacket<'a> {
656    component: u16,
657    resolution: u32,
658    precinct: u64,
659    subbands: Vec<PreparedCompactSubband<'a>>,
660}
661
662#[cfg(test)]
663#[path = "encode_tests.rs"]
664mod tests;