1use crate::common::error::{JpegError, Result};
7use crate::common::quant_table::NATURAL_ORDER;
8use crate::common::types::{MarkerSaveConfig, SavedMarker};
9use crate::decode::marker::{JpegMetadata, MarkerReader};
10use crate::encode::huffman_encode::{build_huff_table, BitWriter, HuffTable, HuffmanEncoder};
11use crate::encode::marker_writer;
12use crate::encode::pipeline as encoder_pipeline;
13use crate::encode::tables;
14use crate::transform::spatial;
15use crate::transform::{TransformOp, TransformOptions};
16#[allow(unused_imports)]
17use alloc::{format, vec};
18#[allow(unused_imports)]
19use alloc::{string::ToString, vec::Vec};
20
21#[derive(Debug, Clone)]
23pub struct ComponentCoefficients {
24 pub blocks: Vec<[i16; 64]>,
26 pub blocks_x: usize,
28 pub blocks_y: usize,
30 pub h_sampling: u8,
32 pub v_sampling: u8,
34 pub quant_table_index: u8,
36 pub component_id: u8,
38}
39
40#[derive(Debug, Clone)]
42pub struct JpegCoefficients {
43 pub width: u16,
45 pub height: u16,
47 pub data_precision: u8,
55 pub components: Vec<ComponentCoefficients>,
57 pub quant_tables: Vec<[u16; 64]>,
59 pub restart_interval: u16,
61 pub density_unit: u8,
63 pub x_density: u16,
65 pub y_density: u16,
67 pub adobe_transform: Option<u8>,
72}
73
74impl JpegCoefficients {
75 #[inline]
79 pub fn effective_precision(&self) -> u8 {
80 if self.data_precision == 0 {
81 8
82 } else {
83 self.data_precision
84 }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct EncoderComponentInfo {
91 pub h_sampling: u8,
93 pub v_sampling: u8,
95 pub quant_table_index: u8,
97}
98
99#[derive(Debug, Clone)]
104pub struct EncoderConfig {
105 pub width: usize,
107 pub height: usize,
109 pub num_components: usize,
111 pub component_info: Vec<EncoderComponentInfo>,
113 pub quant_tables: Vec<[u16; 64]>,
115}
116
117pub fn copy_critical_parameters(coeffs: &JpegCoefficients) -> EncoderConfig {
123 let component_info: Vec<EncoderComponentInfo> = coeffs
124 .components
125 .iter()
126 .map(|comp| EncoderComponentInfo {
127 h_sampling: comp.h_sampling,
128 v_sampling: comp.v_sampling,
129 quant_table_index: comp.quant_table_index,
130 })
131 .collect();
132
133 EncoderConfig {
134 width: coeffs.width as usize,
135 height: coeffs.height as usize,
136 num_components: coeffs.components.len(),
137 component_info,
138 quant_tables: coeffs.quant_tables.clone(),
139 }
140}
141
142pub fn read_coefficients(data: &[u8]) -> Result<JpegCoefficients> {
147 let mut reader = MarkerReader::new(data);
148 let metadata = reader.read_markers()?;
149 crate::common::types::DecodeLimits::default().check_frame(
153 metadata.frame.width as usize,
154 metadata.frame.height as usize,
155 )?;
156
157 let frame = &metadata.frame;
158
159 let max_h = frame
160 .components
161 .iter()
162 .map(|c| c.horizontal_sampling as usize)
163 .max()
164 .unwrap_or(1);
165 let max_v = frame
166 .components
167 .iter()
168 .map(|c| c.vertical_sampling as usize)
169 .max()
170 .unwrap_or(1);
171
172 let mcu_w = max_h * 8;
173 let mcu_h = max_v * 8;
174 let mcus_x = (frame.width as usize).div_ceil(mcu_w);
175 let mcus_y = (frame.height as usize).div_ceil(mcu_h);
176
177 let mut slot_to_dense: [Option<u8>; 4] = [None; 4];
185 let mut quant_tables: Vec<[u16; 64]> = Vec::new();
186 for (slot, qt) in metadata.quant_tables.iter().enumerate() {
187 if let Some(q) = qt.as_ref() {
188 slot_to_dense[slot] = Some(quant_tables.len() as u8);
189 quant_tables.push(q.values);
190 }
191 }
192
193 let mut comp_data: Vec<ComponentCoefficients> = frame
195 .components
196 .iter()
197 .map(|comp| {
198 let bx = mcus_x * comp.horizontal_sampling as usize;
199 let by = mcus_y * comp.vertical_sampling as usize;
200 ComponentCoefficients {
201 blocks: vec![[0i16; 64]; bx * by],
202 blocks_x: bx,
203 blocks_y: by,
204 h_sampling: comp.horizontal_sampling,
205 v_sampling: comp.vertical_sampling,
206 quant_table_index: slot_to_dense[comp.quant_table_index as usize].unwrap_or(0),
211 component_id: comp.id,
212 }
213 })
214 .collect();
215
216 if frame.is_progressive && metadata.is_arithmetic {
217 decode_arithmetic_progressive_coefficients(
219 data,
220 &metadata,
221 &mut comp_data,
222 mcus_x,
223 mcus_y,
224 )?;
225 } else if frame.is_progressive {
226 decode_progressive_coefficients(data, &metadata, &mut comp_data, mcus_x, mcus_y)?;
227 } else if metadata.is_arithmetic {
228 decode_arithmetic_coefficients(data, &metadata, &mut comp_data, mcus_x, mcus_y)?;
229 } else {
230 decode_baseline_coefficients(data, &metadata, &mut comp_data, mcus_x, mcus_y)?;
231 }
232
233 convert_all_to_zigzag(&mut comp_data);
236
237 let density: &crate::common::types::DensityInfo = &metadata.density;
238 let density_unit: u8 = match density.unit {
239 crate::common::types::DensityUnit::Unknown => 0,
240 crate::common::types::DensityUnit::Dpi => 1,
241 crate::common::types::DensityUnit::Dpcm => 2,
242 };
243
244 Ok(JpegCoefficients {
245 width: frame.width,
246 height: frame.height,
247 data_precision: frame.precision,
248 components: comp_data,
249 quant_tables,
250 restart_interval: metadata.restart_interval,
251 density_unit,
252 x_density: density.x,
253 y_density: density.y,
254 adobe_transform: if metadata.saw_adobe_marker {
255 Some(metadata.adobe_transform)
256 } else {
257 None
258 },
259 })
260}
261
262pub fn write_coefficients(coeffs: &JpegCoefficients) -> Result<Vec<u8>> {
267 let num_components = coeffs.components.len();
268 let is_grayscale = num_components == 1;
269
270 let precision: u8 = coeffs.effective_precision();
279 if precision > 8 {
280 return Err(JpegError::Unsupported(format!(
281 "write_coefficients: 12-bit (precision={precision}) transcode not yet \
282 supported on the non-optimized path; route through \
283 write_coefficients_optimized (set optimize_coding=1)"
284 )));
285 }
286
287 let dc_luma_table = build_huff_table(&tables::DC_LUMINANCE_BITS, &tables::DC_LUMINANCE_VALUES);
289 let ac_luma_table = build_huff_table(&tables::AC_LUMINANCE_BITS, &tables::AC_LUMINANCE_VALUES);
290 let dc_chroma_table =
291 build_huff_table(&tables::DC_CHROMINANCE_BITS, &tables::DC_CHROMINANCE_VALUES);
292 let ac_chroma_table =
293 build_huff_table(&tables::AC_CHROMINANCE_BITS, &tables::AC_CHROMINANCE_VALUES);
294
295 let max_h: usize = coeffs
296 .components
297 .iter()
298 .map(|c| c.h_sampling as usize)
299 .max()
300 .unwrap_or(1);
301 let max_v: usize = coeffs
302 .components
303 .iter()
304 .map(|c| c.v_sampling as usize)
305 .max()
306 .unwrap_or(1);
307 let mcus_x = coeffs.components[0].blocks_x / coeffs.components[0].h_sampling as usize;
308 let mcus_y = coeffs.components[0].blocks_y / coeffs.components[0].v_sampling as usize;
309
310 let data_blocks_x: Vec<usize> = coeffs
314 .components
315 .iter()
316 .map(|c| (coeffs.width as usize * c.h_sampling as usize).div_ceil(max_h * 8))
317 .collect();
318 let data_blocks_y: Vec<usize> = coeffs
319 .components
320 .iter()
321 .map(|c| (coeffs.height as usize * c.v_sampling as usize).div_ceil(max_v * 8))
322 .collect();
323
324 let mut bit_writer = BitWriter::new(coeffs.width as usize * coeffs.height as usize);
326 let mut prev_dc = vec![0i16; num_components];
327 let dummy_block: [i16; 64] = [0i16; 64];
328 let ri: u32 = coeffs.restart_interval as u32;
329 let mut mcu_count: u32 = 0;
330 let mut restart_idx: u8 = 0;
331
332 for mcu_y in 0..mcus_y {
333 for mcu_x in 0..mcus_x {
334 if ri > 0 && mcu_count > 0 && mcu_count.is_multiple_of(ri) {
336 bit_writer.flush();
337 bit_writer.write_restart_marker(restart_idx);
338 restart_idx = (restart_idx + 1) & 7;
339 for dc in prev_dc.iter_mut() {
341 *dc = 0;
342 }
343 }
344
345 for (ci, comp) in coeffs.components.iter().enumerate() {
346 let dc_table = if ci == 0 {
347 &dc_luma_table
348 } else {
349 &dc_chroma_table
350 };
351 let ac_table = if ci == 0 {
352 &ac_luma_table
353 } else {
354 &ac_chroma_table
355 };
356
357 for v in 0..comp.v_sampling as usize {
358 for h in 0..comp.h_sampling as usize {
359 let bx = mcu_x * comp.h_sampling as usize + h;
360 let by = mcu_y * comp.v_sampling as usize + v;
361 let is_dummy: bool = bx >= data_blocks_x[ci] || by >= data_blocks_y[ci];
362
363 if is_dummy {
364 let mut dblock: [i16; 64] = dummy_block;
365 dblock[0] = prev_dc[ci];
366 HuffmanEncoder::encode_block(
367 &mut bit_writer,
368 &dblock,
369 &mut prev_dc[ci],
370 dc_table,
371 ac_table,
372 );
373 } else {
374 let block_idx = by * comp.blocks_x + bx;
375 let block = &comp.blocks[block_idx];
376 HuffmanEncoder::encode_block(
377 &mut bit_writer,
378 block,
379 &mut prev_dc[ci],
380 dc_table,
381 ac_table,
382 );
383 }
384 }
385 }
386 }
387 mcu_count += 1;
388 }
389 }
390
391 bit_writer.flush();
392
393 let mut output = Vec::with_capacity(bit_writer.data().len() + 1024);
395
396 marker_writer::write_soi(&mut output);
397 marker_writer::write_app0_jfif_with_density(
399 &mut output,
400 coeffs.density_unit,
401 coeffs.x_density,
402 coeffs.y_density,
403 );
404
405 for (i, qt) in coeffs.quant_tables.iter().enumerate() {
407 marker_writer::write_dqt(&mut output, i as u8, qt);
408 }
409
410 let needs_extended: bool = coeffs
416 .quant_tables
417 .iter()
418 .any(|qt| qt.iter().any(|&v| v > 255));
419 let components: Vec<(u8, u8, u8, u8)> = coeffs
420 .components
421 .iter()
422 .map(|c| {
423 (
424 c.component_id,
425 c.h_sampling,
426 c.v_sampling,
427 c.quant_table_index,
428 )
429 })
430 .collect();
431 output.push(0xFF);
432 output.push(if needs_extended { 0xC1 } else { 0xC0 });
433 let sof_len: u16 = 2 + 1 + 2 + 2 + 1 + (components.len() as u16 * 3);
434 output.extend_from_slice(&sof_len.to_be_bytes());
435 output.push(precision); output.extend_from_slice(&coeffs.height.to_be_bytes());
437 output.extend_from_slice(&coeffs.width.to_be_bytes());
438 output.push(components.len() as u8);
439 for &(id, h_samp, v_samp, quant_tbl_id) in &components {
440 output.push(id);
441 output.push((h_samp << 4) | v_samp);
442 output.push(quant_tbl_id);
443 }
444
445 marker_writer::write_dht(
447 &mut output,
448 0,
449 0,
450 &tables::DC_LUMINANCE_BITS,
451 &tables::DC_LUMINANCE_VALUES,
452 );
453 marker_writer::write_dht(
454 &mut output,
455 1,
456 0,
457 &tables::AC_LUMINANCE_BITS,
458 &tables::AC_LUMINANCE_VALUES,
459 );
460 if !is_grayscale {
461 marker_writer::write_dht(
462 &mut output,
463 0,
464 1,
465 &tables::DC_CHROMINANCE_BITS,
466 &tables::DC_CHROMINANCE_VALUES,
467 );
468 marker_writer::write_dht(
469 &mut output,
470 1,
471 1,
472 &tables::AC_CHROMINANCE_BITS,
473 &tables::AC_CHROMINANCE_VALUES,
474 );
475 }
476
477 if coeffs.restart_interval > 0 {
479 marker_writer::write_dri(&mut output, coeffs.restart_interval);
480 }
481
482 let scan_components: Vec<(u8, u8, u8)> = coeffs
484 .components
485 .iter()
486 .enumerate()
487 .map(|(i, c)| {
488 let tbl = if i == 0 { 0u8 } else { 1u8 };
489 (c.component_id, tbl, tbl)
490 })
491 .collect();
492 marker_writer::write_sos(&mut output, &scan_components);
493
494 output.extend_from_slice(bit_writer.data());
495 marker_writer::write_eoi(&mut output);
496
497 Ok(output)
498}
499
500pub fn transform_jpeg(data: &[u8], op: TransformOp) -> Result<Vec<u8>> {
509 transform_jpeg_with_options(
510 data,
511 &TransformOptions {
512 op,
513 ..Default::default()
514 },
515 )
516}
517
518pub fn transform_jpeg_with_options(data: &[u8], options: &TransformOptions) -> Result<Vec<u8>> {
523 let saved_markers: Vec<SavedMarker> = match options.copy_markers {
525 crate::transform::MarkerCopyMode::All => {
526 let mut reader: MarkerReader<'_> = MarkerReader::new(data);
527 reader.set_marker_save_config(MarkerSaveConfig::All);
528 let meta: JpegMetadata = reader.read_markers()?;
529 meta.saved_markers
531 .into_iter()
532 .filter(|m| m.code != 0xE0)
533 .collect()
534 }
535 crate::transform::MarkerCopyMode::IccOnly => {
536 let mut reader: MarkerReader<'_> = MarkerReader::new(data);
537 reader.set_marker_save_config(MarkerSaveConfig::All);
538 let meta: JpegMetadata = reader.read_markers()?;
539 meta.saved_markers
541 .into_iter()
542 .filter(|m| m.code == 0xE2)
543 .collect()
544 }
545 crate::transform::MarkerCopyMode::None => Vec::new(),
546 };
547
548 let mut coeffs = read_coefficients(data)?;
549 let op: TransformOp = options.op;
550
551 let max_h: usize = coeffs
553 .components
554 .iter()
555 .map(|c| c.h_sampling as usize)
556 .max()
557 .unwrap_or(1);
558 let max_v: usize = coeffs
559 .components
560 .iter()
561 .map(|c| c.v_sampling as usize)
562 .max()
563 .unwrap_or(1);
564 let imcu_w: usize = max_h * 8;
565 let imcu_h: usize = max_v * 8;
566
567 let swaps_dims: bool = matches!(
569 op,
570 TransformOp::Transpose | TransformOp::Transverse | TransformOp::Rot90 | TransformOp::Rot270
571 );
572
573 let needs_width_aligned: bool = matches!(
575 op,
576 TransformOp::HFlip
577 | TransformOp::Transverse
578 | TransformOp::Rot90
579 | TransformOp::Rot180
580 | TransformOp::Rot270
581 );
582 let needs_height_aligned: bool = matches!(
583 op,
584 TransformOp::VFlip
585 | TransformOp::Transverse
586 | TransformOp::Rot90
587 | TransformOp::Rot180
588 | TransformOp::Rot270
589 );
590
591 let width_aligned: bool = (coeffs.width as usize).is_multiple_of(imcu_w);
592 let height_aligned: bool = (coeffs.height as usize).is_multiple_of(imcu_h);
593
594 let has_partial_width: bool = needs_width_aligned && !width_aligned;
595 let has_partial_height: bool = needs_height_aligned && !height_aligned;
596
597 if options.perfect && (has_partial_width || has_partial_height) {
599 return Err(JpegError::CorruptData(format!(
600 "perfect transform requested but image {}x{} is not iMCU-aligned (iMCU={}x{})",
601 coeffs.width, coeffs.height, imcu_w, imcu_h
602 )));
603 }
604
605 if options.trim && (has_partial_width || has_partial_height) {
610 let trim_width: bool = match op {
611 TransformOp::Rot90 => false,
613 _ => has_partial_width,
614 };
615 let trim_height: bool = match op {
616 TransformOp::Rot270 => false,
618 _ => has_partial_height,
619 };
620
621 let trimmed_w: usize = if trim_width {
622 (coeffs.width as usize / imcu_w) * imcu_w
623 } else {
624 coeffs.width as usize
625 };
626 let trimmed_h: usize = if trim_height {
627 (coeffs.height as usize / imcu_h) * imcu_h
628 } else {
629 coeffs.height as usize
630 };
631
632 if trimmed_w == 0 || trimmed_h == 0 {
633 return Err(JpegError::CorruptData(
634 "trim would remove all image data".to_string(),
635 ));
636 }
637
638 coeffs.width = trimmed_w as u16;
639 coeffs.height = trimmed_h as u16;
640
641 for comp in &mut coeffs.components {
643 let new_bx: usize = trimmed_w.div_ceil(8) * comp.h_sampling as usize / max_h;
644 let new_by: usize = trimmed_h.div_ceil(8) * comp.v_sampling as usize / max_v;
645
646 if new_bx < comp.blocks_x || new_by < comp.blocks_y {
648 let mut new_blocks: Vec<[i16; 64]> = Vec::with_capacity(new_bx * new_by);
649 for by in 0..new_by {
650 for bx in 0..new_bx {
651 let old_idx: usize = by * comp.blocks_x + bx;
652 new_blocks.push(comp.blocks[old_idx]);
653 }
654 }
655 comp.blocks = new_blocks;
656 comp.blocks_x = new_bx;
657 comp.blocks_y = new_by;
658 }
659 }
660 }
661
662 if options.grayscale && coeffs.components.len() > 1 {
667 let orig_bx: usize = coeffs.components[0].blocks_x;
668 let orig_by: usize = coeffs.components[0].blocks_y;
669
670 let target_bx: usize = (coeffs.width as usize).div_ceil(8);
672 let target_by: usize = (coeffs.height as usize).div_ceil(8);
673
674 if orig_bx < target_bx || orig_by < target_by {
682 return Err(JpegError::Unsupported(format!(
683 "grayscale conversion requires Y component grid {}x{} \
684 to cover image raster {}x{}; sampling factors are incompatible",
685 orig_bx, orig_by, target_bx, target_by
686 )));
687 }
688
689 if orig_bx != target_bx || orig_by != target_by {
690 let mut new_blocks: Vec<[i16; 64]> = Vec::with_capacity(target_bx * target_by);
693 for by in 0..target_by {
694 for bx in 0..target_bx {
695 new_blocks.push(coeffs.components[0].blocks[by * orig_bx + bx]);
696 }
697 }
698 coeffs.components[0].blocks = new_blocks;
699 coeffs.components[0].blocks_x = target_bx;
700 coeffs.components[0].blocks_y = target_by;
701 }
702
703 coeffs.components.truncate(1);
704 coeffs.components[0].h_sampling = 1;
705 coeffs.components[0].v_sampling = 1;
706 if coeffs.quant_tables.len() > 1 {
707 coeffs.quant_tables.truncate(1);
708 }
709 coeffs.components[0].quant_table_index = 0;
710 }
711
712 let max_h: usize = coeffs
714 .components
715 .iter()
716 .map(|c| c.h_sampling as usize)
717 .max()
718 .unwrap_or(1);
719 let max_v: usize = coeffs
720 .components
721 .iter()
722 .map(|c| c.v_sampling as usize)
723 .max()
724 .unwrap_or(1);
725
726 if op != TransformOp::None {
731 let map_op: &spatial::ZigzagMap = spatial::zigzag_map(op);
738 let map_transpose: &spatial::ZigzagMap = &spatial::MAP_TRANSPOSE;
739 let map_rot90: &spatial::ZigzagMap = &spatial::MAP_ROT90;
740 let map_rot270: &spatial::ZigzagMap = &spatial::MAP_ROT270;
741 let map_flip_h: &spatial::ZigzagMap = &spatial::MAP_HFLIP;
742 let map_flip_v: &spatial::ZigzagMap = &spatial::MAP_VFLIP;
743 let map_transverse: &spatial::ZigzagMap = &spatial::MAP_TRANSVERSE;
744 let map_rot180: &spatial::ZigzagMap = &spatial::MAP_ROT180;
745
746 let mcu_cols: usize = coeffs.width as usize / (max_h * 8);
748 let mcu_rows: usize = coeffs.height as usize / (max_v * 8);
749
750 for comp in &mut coeffs.components {
751 let old_bx: usize = comp.blocks_x;
752 let old_by: usize = comp.blocks_y;
753 let comp_w: usize = mcu_cols * comp.h_sampling as usize;
755 let comp_h: usize = mcu_rows * comp.v_sampling as usize;
756 let mut new_blocks: Vec<[i16; 64]> = if swaps_dims {
763 vec![[0i16; 64]; old_bx * old_by]
764 } else {
765 comp.blocks.clone()
766 };
767
768 if matches!(op, TransformOp::Transpose) {
769 for by in 0..old_by {
770 for bx in 0..old_bx {
771 let src_idx: usize = by * old_bx + bx;
772 let dst_idx: usize = bx * old_by + by;
773 map_transpose.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
774 }
775 }
776 comp.blocks_x = old_by;
777 comp.blocks_y = old_bx;
778 } else if matches!(op, TransformOp::Rot90) {
779 let new_bx: usize = old_by;
780 for by in 0..old_by {
781 for bx in 0..old_bx {
782 let src_idx: usize = by * old_bx + bx;
783 if by < comp_h {
784 let dst_idx: usize = bx * new_bx + (comp_h - 1 - by);
785 map_rot90.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
786 } else {
787 let dst_idx: usize = bx * new_bx + by;
788 map_transpose.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
789 }
790 }
791 }
792 comp.blocks_x = old_by;
793 comp.blocks_y = old_bx;
794 } else if matches!(op, TransformOp::Rot270) {
795 let new_bx: usize = old_by;
796 for by in 0..old_by {
797 for bx in 0..old_bx {
798 let src_idx: usize = by * old_bx + bx;
799 if bx < comp_w {
800 let dst_idx: usize = (comp_w - 1 - bx) * new_bx + by;
801 map_rot270.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
802 } else {
803 let dst_idx: usize = bx * new_bx + by;
804 map_transpose.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
805 }
806 }
807 }
808 comp.blocks_x = old_by;
809 comp.blocks_y = old_bx;
810 } else if matches!(op, TransformOp::Transverse) {
811 let new_bx: usize = old_by;
812 for by in 0..old_by {
813 for bx in 0..old_bx {
814 let src_idx: usize = by * old_bx + bx;
815 let in_h: bool = by < comp_h;
816 let in_w: bool = bx < comp_w;
817 if in_h && in_w {
818 let dst_idx: usize = (comp_w - 1 - bx) * new_bx + (comp_h - 1 - by);
819 map_transverse.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
820 } else if !in_h && in_w {
821 let dst_idx: usize = (comp_w - 1 - bx) * new_bx + by;
822 map_rot270.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
823 } else if in_h && !in_w {
824 let dst_idx: usize = bx * new_bx + (comp_h - 1 - by);
825 map_rot90.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
826 } else {
827 let dst_idx: usize = bx * new_bx + by;
828 map_transpose.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
829 }
830 }
831 }
832 comp.blocks_x = old_by;
833 comp.blocks_y = old_bx;
834 } else if matches!(op, TransformOp::HFlip) {
835 for by in 0..old_by {
838 for bx in 0..comp_w {
839 let src_idx: usize = by * old_bx + bx;
840 let dst_idx: usize = by * old_bx + (comp_w - 1 - bx);
841 map_flip_h.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
842 }
843 }
844 } else if matches!(op, TransformOp::VFlip) {
845 for by in 0..comp_h {
847 for bx in 0..old_bx {
848 let src_idx: usize = by * old_bx + bx;
849 let dst_idx: usize = (comp_h - 1 - by) * old_bx + bx;
850 map_flip_v.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
851 }
852 }
853 } else if matches!(op, TransformOp::Rot180) {
854 for by in 0..old_by {
860 for bx in 0..old_bx {
861 let src_idx: usize = by * old_bx + bx;
862 if by < comp_h && bx < comp_w {
863 let dst_idx: usize = (comp_h - 1 - by) * old_bx + (comp_w - 1 - bx);
865 map_rot180.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
866 } else if by < comp_h {
867 let dst_idx: usize = (comp_h - 1 - by) * old_bx + bx;
869 map_flip_v.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
870 } else if bx < comp_w {
871 let dst_idx: usize = by * old_bx + (comp_w - 1 - bx);
873 map_flip_h.apply(&comp.blocks[src_idx], &mut new_blocks[dst_idx]);
874 }
875 }
877 }
878 } else {
879 for (i, new_block) in new_blocks.iter_mut().enumerate() {
880 map_op.apply(&comp.blocks[i], new_block);
881 }
882 }
883
884 comp.blocks = new_blocks;
885 }
886
887 if swaps_dims {
888 core::mem::swap(&mut coeffs.width, &mut coeffs.height);
889 for comp in &mut coeffs.components {
890 core::mem::swap(&mut comp.h_sampling, &mut comp.v_sampling);
891 }
892 for qt in &mut coeffs.quant_tables {
893 transpose_quant_table(qt);
894 }
895 }
896 }
897
898 if let Some(crop) = &options.crop {
903 let post_max_h: usize = coeffs
906 .components
907 .iter()
908 .map(|c| c.h_sampling as usize)
909 .max()
910 .unwrap_or(1);
911 let post_max_v: usize = coeffs
912 .components
913 .iter()
914 .map(|c| c.v_sampling as usize)
915 .max()
916 .unwrap_or(1);
917 let imcu_w: usize = post_max_h * 8;
918 let imcu_h: usize = post_max_v * 8;
919
920 if crop.x >= coeffs.width as usize || crop.y >= coeffs.height as usize {
930 return Err(JpegError::Unsupported(format!(
931 "crop origin (x={}, y={}) lies outside post-transform image \
932 ({}x{}); crop coordinates must be in output space",
933 crop.x, crop.y, coeffs.width, coeffs.height,
934 )));
935 }
936
937 let remainder_x: usize = crop.x % imcu_w;
938 let remainder_y: usize = crop.y % imcu_h;
939
940 let crop_x_blocks: usize = crop.x / imcu_w * post_max_h;
942 let crop_y_blocks: usize = crop.y / imcu_h * post_max_v;
943
944 let out_w: usize =
947 (crop.width + remainder_x).min(coeffs.width as usize - (crop.x - remainder_x));
948 let out_h: usize =
949 (crop.height + remainder_y).min(coeffs.height as usize - (crop.y - remainder_y));
950 let crop_w_blocks: usize = out_w.div_ceil(imcu_w) * post_max_h;
954 let crop_h_blocks: usize = out_h.div_ceil(imcu_h) * post_max_v;
955
956 coeffs.width = out_w as u16;
957 coeffs.height = out_h as u16;
958
959 for comp in &mut coeffs.components {
960 let comp_crop_x: usize = crop_x_blocks * comp.h_sampling as usize / post_max_h;
961 let comp_crop_y: usize = crop_y_blocks * comp.v_sampling as usize / post_max_v;
962 let comp_crop_w: usize = crop_w_blocks * comp.h_sampling as usize / post_max_h;
963 let comp_crop_h: usize = crop_h_blocks * comp.v_sampling as usize / post_max_v;
964
965 let new_bx: usize = comp_crop_w.min(comp.blocks_x - comp_crop_x);
966 let new_by: usize = comp_crop_h.min(comp.blocks_y - comp_crop_y);
967
968 let mut new_blocks: Vec<[i16; 64]> = Vec::with_capacity(new_bx * new_by);
969 for by in 0..new_by {
970 for bx in 0..new_bx {
971 let old_idx: usize = (comp_crop_y + by) * comp.blocks_x + (comp_crop_x + bx);
972 new_blocks.push(comp.blocks[old_idx]);
973 }
974 }
975 comp.blocks = new_blocks;
976 comp.blocks_x = new_bx;
977 comp.blocks_y = new_by;
978 }
979 }
980
981 if let Some(ref filter) = options.custom_filter {
983 for (ci, comp) in coeffs.components.iter_mut().enumerate() {
984 let blocks_x: usize = comp.blocks_x;
985 for by in 0..comp.blocks_y {
986 for bx in 0..blocks_x {
987 let block_idx: usize = by * blocks_x + bx;
988 filter(&mut comp.blocks[block_idx], ci, bx, by);
989 }
990 }
991 }
992 }
993
994 if options.no_output {
996 return Ok(Vec::new());
997 }
998
999 let progressive_restart_rows: Option<u16> =
1011 if options.progressive && options.restart_interval > 0 && options.restart_in_rows {
1012 Some(options.restart_interval)
1013 } else {
1014 None
1015 };
1016
1017 if options.restart_interval > 0 {
1018 if options.restart_in_rows {
1019 let max_h: usize = coeffs
1020 .components
1021 .iter()
1022 .map(|c| c.h_sampling as usize)
1023 .max()
1024 .unwrap_or(1);
1025 let output_mcus_per_row: usize = (coeffs.width as usize).div_ceil(max_h * 8);
1026 let dri: usize = options.restart_interval as usize * output_mcus_per_row;
1027 coeffs.restart_interval = dri.min(u16::MAX as usize) as u16;
1028 } else {
1029 coeffs.restart_interval = options.restart_interval;
1030 }
1031 }
1032 let swaps_dimensions: bool = matches!(
1036 options.op,
1037 crate::transform::TransformOp::Rot90
1038 | crate::transform::TransformOp::Rot270
1039 | crate::transform::TransformOp::Transpose
1040 | crate::transform::TransformOp::Transverse
1041 );
1042 if swaps_dimensions && options.trim && options.restart_interval == 0 {
1043 coeffs.restart_interval = 0;
1044 }
1045
1046 let progressive_safe: bool = options.progressive && {
1062 let max_h: usize = coeffs
1063 .components
1064 .iter()
1065 .map(|c| c.h_sampling as usize)
1066 .max()
1067 .unwrap_or(1);
1068 let max_v: usize = coeffs
1069 .components
1070 .iter()
1071 .map(|c| c.v_sampling as usize)
1072 .max()
1073 .unwrap_or(1);
1074 let standard_factors: bool =
1075 max_h.is_power_of_two() && max_v.is_power_of_two() && max_h <= 4 && max_v <= 4;
1076 standard_factors
1077 && coeffs.components.iter().all(|comp| {
1078 let dbx: usize =
1079 (coeffs.width as usize * comp.h_sampling as usize).div_ceil(max_h * 8);
1080 let dby: usize =
1081 (coeffs.height as usize * comp.v_sampling as usize).div_ceil(max_v * 8);
1082 dbx <= comp.blocks_x && dby <= comp.blocks_y
1083 })
1084 };
1085 let force_optimize: bool =
1094 coeffs.effective_precision() > 8 || needs_optimized_baseline_huffman(&coeffs);
1095 let output: Vec<u8> = if options.arithmetic && progressive_safe {
1096 write_coefficients_progressive_arithmetic(&coeffs, progressive_restart_rows)?
1097 } else if options.arithmetic {
1098 write_coefficients_arithmetic(&coeffs)?
1099 } else if progressive_safe {
1100 write_coefficients_progressive(&coeffs, progressive_restart_rows)?
1101 } else if options.optimize || force_optimize {
1102 write_coefficients_optimized(&coeffs)?
1103 } else {
1104 write_coefficients(&coeffs)?
1105 };
1106
1107 if !saved_markers.is_empty() {
1109 Ok(encoder_pipeline::inject_saved_markers(
1110 &output,
1111 &saved_markers,
1112 ))
1113 } else {
1114 Ok(output)
1115 }
1116}
1117
1118fn huffman_category(value: i16) -> u8 {
1119 let magnitude: u16 = value.unsigned_abs();
1120 if magnitude == 0 {
1121 0
1122 } else {
1123 (16 - magnitude.leading_zeros()) as u8
1124 }
1125}
1126
1127fn needs_optimized_baseline_huffman(coeffs: &JpegCoefficients) -> bool {
1128 if coeffs.components.is_empty() {
1129 return false;
1130 }
1131
1132 let max_h: usize = coeffs
1133 .components
1134 .iter()
1135 .map(|c| c.h_sampling as usize)
1136 .max()
1137 .unwrap_or(1);
1138 let max_v: usize = coeffs
1139 .components
1140 .iter()
1141 .map(|c| c.v_sampling as usize)
1142 .max()
1143 .unwrap_or(1);
1144 let mcus_x: usize = coeffs.components[0].blocks_x / coeffs.components[0].h_sampling as usize;
1145 let mcus_y: usize = coeffs.components[0].blocks_y / coeffs.components[0].v_sampling as usize;
1146
1147 let data_blocks_x: Vec<usize> = coeffs
1148 .components
1149 .iter()
1150 .map(|c| (coeffs.width as usize * c.h_sampling as usize).div_ceil(max_h * 8))
1151 .collect();
1152 let data_blocks_y: Vec<usize> = coeffs
1153 .components
1154 .iter()
1155 .map(|c| (coeffs.height as usize * c.v_sampling as usize).div_ceil(max_v * 8))
1156 .collect();
1157
1158 let mut prev_dc: Vec<i16> = vec![0; coeffs.components.len()];
1159 let ri: u32 = coeffs.restart_interval as u32;
1160 let mut mcu_count: u32 = 0;
1161
1162 for mcu_y in 0..mcus_y {
1163 for mcu_x in 0..mcus_x {
1164 if ri > 0 && mcu_count > 0 && mcu_count.is_multiple_of(ri) {
1165 prev_dc.fill(0);
1166 }
1167
1168 for (ci, comp) in coeffs.components.iter().enumerate() {
1169 for v in 0..comp.v_sampling as usize {
1170 for h in 0..comp.h_sampling as usize {
1171 let bx: usize = mcu_x * comp.h_sampling as usize + h;
1172 let by: usize = mcu_y * comp.v_sampling as usize + v;
1173 let is_dummy: bool = bx >= data_blocks_x[ci] || by >= data_blocks_y[ci];
1174
1175 if is_dummy {
1176 continue;
1177 }
1178
1179 let block: &[i16; 64] = &comp.blocks[by * comp.blocks_x + bx];
1180 let dc_diff: i16 = block[0].wrapping_sub(prev_dc[ci]);
1181 prev_dc[ci] = block[0];
1182
1183 if huffman_category(dc_diff) > 11 {
1184 return true;
1185 }
1186
1187 if block[1..]
1188 .iter()
1189 .any(|&coef| coef != 0 && huffman_category(coef) > 10)
1190 {
1191 return true;
1192 }
1193 }
1194 }
1195 }
1196 mcu_count += 1;
1197 }
1198 }
1199
1200 false
1201}
1202
1203pub fn write_coefficients_optimized(coeffs: &JpegCoefficients) -> Result<Vec<u8>> {
1208 use crate::encode::huff_opt;
1209
1210 let num_components: usize = coeffs.components.len();
1211 let is_grayscale: bool = num_components == 1;
1212
1213 let opt_max_h: usize = coeffs
1214 .components
1215 .iter()
1216 .map(|c| c.h_sampling as usize)
1217 .max()
1218 .unwrap_or(1);
1219 let opt_max_v: usize = coeffs
1220 .components
1221 .iter()
1222 .map(|c| c.v_sampling as usize)
1223 .max()
1224 .unwrap_or(1);
1225 let mcus_x: usize = coeffs.components[0].blocks_x / coeffs.components[0].h_sampling as usize;
1226 let mcus_y: usize = coeffs.components[0].blocks_y / coeffs.components[0].v_sampling as usize;
1227
1228 let opt_data_bx: Vec<usize> = coeffs
1229 .components
1230 .iter()
1231 .map(|c| (coeffs.width as usize * c.h_sampling as usize).div_ceil(opt_max_h * 8))
1232 .collect();
1233 let opt_data_by: Vec<usize> = coeffs
1234 .components
1235 .iter()
1236 .map(|c| (coeffs.height as usize * c.v_sampling as usize).div_ceil(opt_max_v * 8))
1237 .collect();
1238
1239 let mut dc_luma_freq = [0u32; 257];
1241 let mut dc_chroma_freq = [0u32; 257];
1242 let mut ac_luma_freq = [0u32; 257];
1243 let mut ac_chroma_freq = [0u32; 257];
1244
1245 let mut prev_dc: Vec<i16> = vec![0i16; num_components];
1246 let opt_dummy: [i16; 64] = [0i16; 64];
1247 let p1_ri: u32 = coeffs.restart_interval as u32;
1248 let mut p1_mcu_count: u32 = 0;
1249
1250 for mcu_y in 0..mcus_y {
1251 for mcu_x in 0..mcus_x {
1252 if p1_ri > 0 && p1_mcu_count > 0 && p1_mcu_count.is_multiple_of(p1_ri) {
1254 for dc in prev_dc.iter_mut() {
1255 *dc = 0;
1256 }
1257 }
1258
1259 for (ci, comp) in coeffs.components.iter().enumerate() {
1260 let dc_freq: &mut [u32; 257] = if ci == 0 {
1261 &mut dc_luma_freq
1262 } else {
1263 &mut dc_chroma_freq
1264 };
1265 let ac_freq: &mut [u32; 257] = if ci == 0 {
1266 &mut ac_luma_freq
1267 } else {
1268 &mut ac_chroma_freq
1269 };
1270
1271 for v in 0..comp.v_sampling as usize {
1272 for h in 0..comp.h_sampling as usize {
1273 let bx: usize = mcu_x * comp.h_sampling as usize + h;
1274 let by: usize = mcu_y * comp.v_sampling as usize + v;
1275 let is_dummy: bool = bx >= opt_data_bx[ci] || by >= opt_data_by[ci];
1276
1277 let block: &[i16; 64] = if is_dummy {
1278 &opt_dummy
1279 } else {
1280 let block_idx: usize = by * comp.blocks_x + bx;
1281 &comp.blocks[block_idx]
1282 };
1283
1284 let dc_val: i16 = if is_dummy { prev_dc[ci] } else { block[0] };
1285 let diff: i16 = dc_val.wrapping_sub(prev_dc[ci]);
1290 prev_dc[ci] = dc_val;
1291 if diff == i16::MIN || block[1..].contains(&i16::MIN) {
1308 return Err(JpegError::CorruptData(
1309 "DCT coefficient out of range for Huffman coding".to_string(),
1310 ));
1311 }
1312 huff_opt::gather_dc_symbol(diff, dc_freq);
1313 huff_opt::gather_ac_symbols(block, ac_freq);
1314 }
1315 }
1316 }
1317 p1_mcu_count += 1;
1318 }
1319 }
1320
1321 dc_luma_freq[256] = 1;
1323 ac_luma_freq[256] = 1;
1324 dc_chroma_freq[256] = 1;
1325 ac_chroma_freq[256] = 1;
1326
1327 let (dc_luma_bits, dc_luma_values) = huff_opt::gen_optimal_table(&dc_luma_freq);
1329 let (ac_luma_bits, ac_luma_values) = huff_opt::gen_optimal_table(&ac_luma_freq);
1330 let (dc_chroma_bits, dc_chroma_values) = huff_opt::gen_optimal_table(&dc_chroma_freq);
1331 let (ac_chroma_bits, ac_chroma_values) = huff_opt::gen_optimal_table(&ac_chroma_freq);
1332
1333 let dc_luma_table = build_huff_table(&dc_luma_bits, &dc_luma_values);
1335 let ac_luma_table = build_huff_table(&ac_luma_bits, &ac_luma_values);
1336 let dc_chroma_table = build_huff_table(&dc_chroma_bits, &dc_chroma_values);
1337 let ac_chroma_table = build_huff_table(&ac_chroma_bits, &ac_chroma_values);
1338
1339 let mut bit_writer = BitWriter::new(coeffs.width as usize * coeffs.height as usize);
1341 let mut prev_dc_pass2: Vec<i16> = vec![0i16; num_components];
1342 let opt_ri: u32 = coeffs.restart_interval as u32;
1343 let mut opt_mcu_count: u32 = 0;
1344 let mut opt_restart_idx: u8 = 0;
1345
1346 for mcu_y in 0..mcus_y {
1347 for mcu_x in 0..mcus_x {
1348 if opt_ri > 0 && opt_mcu_count > 0 && opt_mcu_count.is_multiple_of(opt_ri) {
1349 bit_writer.flush();
1350 bit_writer.write_restart_marker(opt_restart_idx);
1351 opt_restart_idx = (opt_restart_idx + 1) & 7;
1352 for dc in prev_dc_pass2.iter_mut() {
1353 *dc = 0;
1354 }
1355 }
1356
1357 for (ci, comp) in coeffs.components.iter().enumerate() {
1358 let dc_table = if ci == 0 {
1359 &dc_luma_table
1360 } else {
1361 &dc_chroma_table
1362 };
1363 let ac_table = if ci == 0 {
1364 &ac_luma_table
1365 } else {
1366 &ac_chroma_table
1367 };
1368
1369 for v in 0..comp.v_sampling as usize {
1370 for h in 0..comp.h_sampling as usize {
1371 let bx: usize = mcu_x * comp.h_sampling as usize + h;
1372 let by: usize = mcu_y * comp.v_sampling as usize + v;
1373 let is_dummy: bool = bx >= opt_data_bx[ci] || by >= opt_data_by[ci];
1374
1375 if is_dummy {
1376 let mut dblock: [i16; 64] = opt_dummy;
1377 dblock[0] = prev_dc_pass2[ci];
1378 HuffmanEncoder::encode_block(
1379 &mut bit_writer,
1380 &dblock,
1381 &mut prev_dc_pass2[ci],
1382 dc_table,
1383 ac_table,
1384 );
1385 } else {
1386 let block_idx: usize = by * comp.blocks_x + bx;
1387 let block: &[i16; 64] = &comp.blocks[block_idx];
1388 HuffmanEncoder::encode_block(
1389 &mut bit_writer,
1390 block,
1391 &mut prev_dc_pass2[ci],
1392 dc_table,
1393 ac_table,
1394 );
1395 }
1396 }
1397 }
1398 }
1399 opt_mcu_count += 1;
1400 }
1401 }
1402
1403 bit_writer.flush();
1404
1405 let mut output: Vec<u8> = Vec::with_capacity(bit_writer.data().len() + 1024);
1407
1408 marker_writer::write_soi(&mut output);
1409 marker_writer::write_app0_jfif_with_density(
1410 &mut output,
1411 coeffs.density_unit,
1412 coeffs.x_density,
1413 coeffs.y_density,
1414 );
1415
1416 for (i, qt) in coeffs.quant_tables.iter().enumerate() {
1418 marker_writer::write_dqt(&mut output, i as u8, qt);
1419 }
1420
1421 let opt_precision: u8 = coeffs.effective_precision();
1424 let opt_needs_ext: bool = opt_precision > 8
1425 || coeffs
1426 .quant_tables
1427 .iter()
1428 .any(|qt| qt.iter().any(|&v| v > 255));
1429 let opt_comps: Vec<(u8, u8, u8, u8)> = coeffs
1430 .components
1431 .iter()
1432 .map(|c| {
1433 (
1434 c.component_id,
1435 c.h_sampling,
1436 c.v_sampling,
1437 c.quant_table_index,
1438 )
1439 })
1440 .collect();
1441 output.push(0xFF);
1442 output.push(if opt_needs_ext { 0xC1 } else { 0xC0 });
1443 let opt_sof_len: u16 = 2 + 1 + 2 + 2 + 1 + (opt_comps.len() as u16 * 3);
1444 output.extend_from_slice(&opt_sof_len.to_be_bytes());
1445 output.push(opt_precision);
1446 output.extend_from_slice(&coeffs.height.to_be_bytes());
1447 output.extend_from_slice(&coeffs.width.to_be_bytes());
1448 output.push(opt_comps.len() as u8);
1449 for &(id, h_samp, v_samp, quant_tbl_id) in &opt_comps {
1450 output.push(id);
1451 output.push((h_samp << 4) | v_samp);
1452 output.push(quant_tbl_id);
1453 }
1454
1455 marker_writer::write_dht(&mut output, 0, 0, &dc_luma_bits, &dc_luma_values);
1457 marker_writer::write_dht(&mut output, 1, 0, &ac_luma_bits, &ac_luma_values);
1458 if !is_grayscale {
1459 marker_writer::write_dht(&mut output, 0, 1, &dc_chroma_bits, &dc_chroma_values);
1460 marker_writer::write_dht(&mut output, 1, 1, &ac_chroma_bits, &ac_chroma_values);
1461 }
1462
1463 if coeffs.restart_interval > 0 {
1465 marker_writer::write_dri(&mut output, coeffs.restart_interval);
1466 }
1467
1468 let scan_components: Vec<(u8, u8, u8)> = coeffs
1470 .components
1471 .iter()
1472 .enumerate()
1473 .map(|(i, c)| {
1474 let tbl: u8 = if i == 0 { 0u8 } else { 1u8 };
1475 (c.component_id, tbl, tbl)
1476 })
1477 .collect();
1478 marker_writer::write_sos(&mut output, &scan_components);
1479
1480 output.extend_from_slice(bit_writer.data());
1481 marker_writer::write_eoi(&mut output);
1482
1483 Ok(output)
1484}
1485
1486pub fn write_coefficients_progressive(
1500 coeffs: &JpegCoefficients,
1501 restart_rows: Option<u16>,
1502) -> Result<Vec<u8>> {
1503 use crate::encode::huff_opt;
1504 use crate::encode::progressive::simple_progression;
1505
1506 let num_components: usize = coeffs.components.len();
1507 let is_grayscale: bool = num_components == 1;
1508
1509 let max_h: usize = coeffs
1510 .components
1511 .iter()
1512 .map(|c| c.h_sampling as usize)
1513 .max()
1514 .unwrap_or(1);
1515 let max_v: usize = coeffs
1516 .components
1517 .iter()
1518 .map(|c| c.v_sampling as usize)
1519 .max()
1520 .unwrap_or(1);
1521 let mcus_x: usize = coeffs.components[0].blocks_x / coeffs.components[0].h_sampling as usize;
1522 let mcus_y: usize = coeffs.components[0].blocks_y / coeffs.components[0].v_sampling as usize;
1523
1524 let data_blocks_x: Vec<usize> = coeffs
1528 .components
1529 .iter()
1530 .map(|c| (coeffs.width as usize * c.h_sampling as usize).div_ceil(max_h * 8))
1531 .collect();
1532 let data_blocks_y: Vec<usize> = coeffs
1533 .components
1534 .iter()
1535 .map(|c| (coeffs.height as usize * c.v_sampling as usize).div_ceil(max_v * 8))
1536 .collect();
1537
1538 let scans = simple_progression(num_components);
1539
1540 let mut output: Vec<u8> = Vec::with_capacity(coeffs.width as usize * coeffs.height as usize);
1542
1543 marker_writer::write_soi(&mut output);
1544 marker_writer::write_app0_jfif_with_density(
1545 &mut output,
1546 coeffs.density_unit,
1547 coeffs.x_density,
1548 coeffs.y_density,
1549 );
1550
1551 for (i, qt) in coeffs.quant_tables.iter().enumerate() {
1552 marker_writer::write_dqt(&mut output, i as u8, qt);
1553 }
1554
1555 let components: Vec<(u8, u8, u8, u8)> = coeffs
1557 .components
1558 .iter()
1559 .map(|c| {
1560 (
1561 c.component_id,
1562 c.h_sampling,
1563 c.v_sampling,
1564 c.quant_table_index,
1565 )
1566 })
1567 .collect();
1568 marker_writer::write_sof2_with_precision(
1569 &mut output,
1570 coeffs.width,
1571 coeffs.height,
1572 &components,
1573 coeffs.effective_precision(),
1574 );
1575
1576 let mut bit_writer: BitWriter =
1577 BitWriter::new(coeffs.width as usize * coeffs.height as usize / 4);
1578
1579 let mut saved_ri: u16 = 0;
1584
1585 let per_scan_ri = |scan_ci: &[usize]| -> u16 {
1591 match restart_rows {
1592 Some(rows) => {
1593 let mcus_per_row: usize = if scan_ci.len() == 1 {
1594 let ci: usize = scan_ci[0];
1596 let comp = &coeffs.components[ci];
1597 (coeffs.width as usize * comp.h_sampling as usize).div_ceil(max_h * 8)
1598 } else {
1599 (coeffs.width as usize).div_ceil(max_h * 8)
1601 };
1602 let dri: usize = rows as usize * mcus_per_row;
1603 dri.min(u16::MAX as usize) as u16
1604 }
1605 None => coeffs.restart_interval,
1606 }
1607 };
1608
1609 for scan in &scans {
1611 let is_dc_scan: bool = scan.ss == 0 && scan.se == 0;
1612 let is_first: bool = scan.ah == 0;
1613 let scan_ri: u16 = per_scan_ri(&scan.component_indices);
1614
1615 let scan_comps: Vec<(u8, u8, u8)> = scan
1618 .component_indices
1619 .iter()
1620 .map(|&ci| {
1621 let tbl: u8 = if ci == 0 { 0 } else { 1 };
1622 let dc_tbl: u8 = if is_dc_scan && is_first { tbl } else { 0 };
1623 let ac_tbl: u8 = if is_dc_scan { 0 } else { tbl };
1624 (coeffs.components[ci].component_id, dc_tbl, ac_tbl)
1625 })
1626 .collect();
1627
1628 if is_dc_scan && is_first {
1629 let mut dc_luma_freq = [0u32; 257];
1632 let mut dc_chroma_freq = [0u32; 257];
1633 dc_luma_freq[256] = 1;
1634 dc_chroma_freq[256] = 1;
1635
1636 let mut prev_dc: Vec<i16> = vec![0i16; scan.component_indices.len()];
1637 let ri: u32 = scan_ri as u32;
1638 let mut restarts_to_go: u32 = ri;
1639
1640 for mcu_y in 0..mcus_y {
1641 for mcu_x in 0..mcus_x {
1642 if ri > 0 && restarts_to_go == 0 {
1643 for dc in prev_dc.iter_mut() {
1644 *dc = 0;
1645 }
1646 restarts_to_go = ri;
1647 }
1648 for (scan_ci, &ci) in scan.component_indices.iter().enumerate() {
1649 let comp = &coeffs.components[ci];
1650 let freq: &mut [u32; 257] = if ci == 0 {
1651 &mut dc_luma_freq
1652 } else {
1653 &mut dc_chroma_freq
1654 };
1655 for v in 0..comp.v_sampling as usize {
1656 for h in 0..comp.h_sampling as usize {
1657 let bx: usize = mcu_x * comp.h_sampling as usize + h;
1658 let by: usize = mcu_y * comp.v_sampling as usize + v;
1659 let is_dummy: bool =
1660 bx >= data_blocks_x[ci] || by >= data_blocks_y[ci];
1661 let dc: i16 = if is_dummy {
1662 prev_dc[scan_ci]
1663 } else {
1664 let block: &[i16; 64] = &comp.blocks[by * comp.blocks_x + bx];
1665 block[0] >> scan.al
1666 };
1667 let diff: i16 = dc.wrapping_sub(prev_dc[scan_ci]);
1668 prev_dc[scan_ci] = dc;
1669 if diff == i16::MIN {
1674 return Err(JpegError::CorruptData(
1675 "DCT coefficient out of range for Huffman coding"
1676 .to_string(),
1677 ));
1678 }
1679 huff_opt::gather_dc_symbol(diff, freq);
1680 }
1681 }
1682 }
1683 if ri > 0 {
1684 restarts_to_go -= 1;
1685 }
1686 }
1687 }
1688
1689 let (dc_luma_bits, dc_luma_values) = huff_opt::gen_optimal_table(&dc_luma_freq);
1691 let dc_luma_table: HuffTable = build_huff_table(&dc_luma_bits, &dc_luma_values);
1692 marker_writer::write_dht(&mut output, 0, 0, &dc_luma_bits, &dc_luma_values);
1693
1694 let dc_chroma_table: HuffTable = if !is_grayscale {
1695 let (bits, vals) = huff_opt::gen_optimal_table(&dc_chroma_freq);
1696 marker_writer::write_dht(&mut output, 0, 1, &bits, &vals);
1697 build_huff_table(&bits, &vals)
1698 } else {
1699 build_huff_table(&tables::DC_CHROMINANCE_BITS, &tables::DC_CHROMINANCE_VALUES)
1701 };
1702
1703 if scan_ri != saved_ri {
1704 marker_writer::write_dri(&mut output, scan_ri);
1705 saved_ri = scan_ri;
1706 }
1707 marker_writer::write_sos_progressive(
1708 &mut output,
1709 &scan_comps,
1710 scan.ss,
1711 scan.se,
1712 scan.ah,
1713 scan.al,
1714 );
1715
1716 bit_writer.reset();
1718 let mut enc_prev_dc: Vec<i16> = vec![0i16; scan.component_indices.len()];
1719 let ri: u32 = scan_ri as u32;
1720 let mut restarts_to_go: u32 = ri;
1721 let mut next_restart_num: u8 = 0;
1722
1723 for mcu_y in 0..mcus_y {
1724 for mcu_x in 0..mcus_x {
1725 if ri > 0 && restarts_to_go == 0 {
1726 bit_writer.flush_restart();
1727 bit_writer.write_restart_marker(next_restart_num);
1728 next_restart_num = (next_restart_num + 1) & 7;
1729 for dc in enc_prev_dc.iter_mut() {
1730 *dc = 0;
1731 }
1732 restarts_to_go = ri;
1733 }
1734 for (scan_ci, &ci) in scan.component_indices.iter().enumerate() {
1735 let comp = &coeffs.components[ci];
1736 let dc_table: &HuffTable = if ci == 0 {
1737 &dc_luma_table
1738 } else {
1739 &dc_chroma_table
1740 };
1741 for v in 0..comp.v_sampling as usize {
1742 for h in 0..comp.h_sampling as usize {
1743 let bx: usize = mcu_x * comp.h_sampling as usize + h;
1744 let by: usize = mcu_y * comp.v_sampling as usize + v;
1745 let is_dummy: bool =
1746 bx >= data_blocks_x[ci] || by >= data_blocks_y[ci];
1747 let dc: i16 = if is_dummy {
1748 enc_prev_dc[scan_ci]
1749 } else {
1750 let block: &[i16; 64] = &comp.blocks[by * comp.blocks_x + bx];
1751 block[0] >> scan.al
1752 };
1753 let diff: i16 = dc.wrapping_sub(enc_prev_dc[scan_ci]);
1754 enc_prev_dc[scan_ci] = dc;
1755 HuffmanEncoder::encode_dc_only(&mut bit_writer, diff, dc_table);
1756 }
1757 }
1758 }
1759 if ri > 0 {
1760 restarts_to_go -= 1;
1761 }
1762 }
1763 }
1764
1765 bit_writer.flush();
1766 output.extend_from_slice(bit_writer.data());
1767 } else if is_dc_scan {
1768 if scan_ri != saved_ri {
1771 marker_writer::write_dri(&mut output, scan_ri);
1772 saved_ri = scan_ri;
1773 }
1774 marker_writer::write_sos_progressive(
1775 &mut output,
1776 &scan_comps,
1777 scan.ss,
1778 scan.se,
1779 scan.ah,
1780 scan.al,
1781 );
1782
1783 bit_writer.reset();
1784 let mut refine_prev_dc: Vec<i16> = vec![0i16; num_components];
1786 let ri: u32 = scan_ri as u32;
1787 let mut restarts_to_go: u32 = ri;
1788 let mut next_restart_num: u8 = 0;
1789
1790 for mcu_y in 0..mcus_y {
1791 for mcu_x in 0..mcus_x {
1792 if ri > 0 && restarts_to_go == 0 {
1793 bit_writer.flush_restart();
1794 bit_writer.write_restart_marker(next_restart_num);
1795 next_restart_num = (next_restart_num + 1) & 7;
1796 restarts_to_go = ri;
1797 }
1798 for &ci in &scan.component_indices {
1799 let comp = &coeffs.components[ci];
1800 for v in 0..comp.v_sampling as usize {
1801 for h in 0..comp.h_sampling as usize {
1802 let bx: usize = mcu_x * comp.h_sampling as usize + h;
1803 let by: usize = mcu_y * comp.v_sampling as usize + v;
1804 let is_dummy: bool =
1805 bx >= data_blocks_x[ci] || by >= data_blocks_y[ci];
1806 let dc_val: i16 = if is_dummy {
1807 refine_prev_dc[ci]
1808 } else {
1809 let block: &[i16; 64] = &comp.blocks[by * comp.blocks_x + bx];
1810 refine_prev_dc[ci] = block[0];
1811 block[0]
1812 };
1813 let bit: u32 = ((dc_val >> scan.al) & 1) as u32;
1814 bit_writer.put_bits(bit, 1);
1815 }
1816 }
1817 }
1818 if ri > 0 {
1819 restarts_to_go -= 1;
1820 }
1821 }
1822 }
1823
1824 bit_writer.flush();
1825 output.extend_from_slice(bit_writer.data());
1826 } else {
1827 let ci: usize = scan.component_indices[0];
1829 let comp = &coeffs.components[ci];
1830 let wib: usize = data_blocks_x[ci].min(comp.blocks_x);
1831 let hib: usize = data_blocks_y[ci].min(comp.blocks_y);
1832 let stride: usize = comp.blocks_x;
1833 let ss: usize = scan.ss as usize;
1834 let se: usize = scan.se as usize;
1835 let al: u8 = scan.al;
1836 let band_len: usize = se - ss + 1;
1837
1838 if is_first {
1839 let mut ac_freq = [0u32; 257];
1842 ac_freq[256] = 1;
1843 let mut eobrun_gather: u32 = 0;
1844 let ri: u32 = scan_ri as u32;
1845 let mut restarts_to_go: u32 = ri;
1846
1847 for by in 0..hib {
1848 for bx in 0..wib {
1849 if ri > 0 && restarts_to_go == 0 {
1850 if eobrun_gather > 0 {
1851 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
1852 ac_freq[(nbits as usize) << 4] += 1;
1853 eobrun_gather = 0;
1854 }
1855 restarts_to_go = ri;
1856 }
1857 let block: &[i16; 64] = &comp.blocks[by * stride + bx];
1858
1859 let mut zerobits: u64 = 0;
1860 let mut values = [0u16; 64];
1861
1862 for i in 0..band_len {
1863 let coeff: i16 = block[ss + i];
1864 if coeff == 0 {
1865 continue;
1866 }
1867 let coeff: i32 = coeff as i32;
1873 let sign_mask: i32 = coeff >> 31;
1874 let abs_coeff: i32 = (coeff ^ sign_mask) - sign_mask;
1875 let temp: u16 = (abs_coeff >> al) as u16;
1876 if temp == 0 {
1877 continue;
1878 }
1879 if temp >= 0x8000 {
1884 return Err(JpegError::CorruptData(
1885 "DCT coefficient out of range for Huffman coding".to_string(),
1886 ));
1887 }
1888 values[i] = temp;
1889 zerobits |= 1u64 << i;
1890 }
1891
1892 if zerobits == 0 {
1893 eobrun_gather += 1;
1894 if eobrun_gather == 0x7FFF {
1895 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
1896 ac_freq[(nbits as usize) << 4] += 1;
1897 eobrun_gather = 0;
1898 }
1899 if ri > 0 {
1900 restarts_to_go -= 1;
1901 }
1902 continue;
1903 }
1904
1905 if eobrun_gather > 0 {
1906 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
1907 ac_freq[(nbits as usize) << 4] += 1;
1908 eobrun_gather = 0;
1909 }
1910
1911 let mut prev_pos: usize = 0;
1912 let mut bits: u64 = zerobits;
1913 while bits != 0 {
1914 let pos: usize = bits.trailing_zeros() as usize;
1915 bits &= bits - 1;
1916 let mut zero_run: usize = pos - prev_pos;
1917 while zero_run >= 16 {
1918 ac_freq[0xF0] += 1;
1919 zero_run -= 16;
1920 }
1921 let nbits: u8 = 16 - values[pos].leading_zeros() as u8;
1922 let symbol: usize = (zero_run << 4) | (nbits as usize);
1923 ac_freq[symbol] += 1;
1924 prev_pos = pos + 1;
1925 }
1926
1927 if prev_pos < band_len {
1928 eobrun_gather += 1;
1929 if eobrun_gather == 0x7FFF {
1930 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
1931 ac_freq[(nbits as usize) << 4] += 1;
1932 eobrun_gather = 0;
1933 }
1934 }
1935 if ri > 0 {
1936 restarts_to_go -= 1;
1937 }
1938 }
1939 }
1940 if eobrun_gather > 0 {
1941 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
1942 ac_freq[(nbits as usize) << 4] += 1;
1943 }
1944
1945 let (ac_bits, ac_values) = huff_opt::gen_optimal_table(&ac_freq);
1947 let table_id: u8 = if ci == 0 { 0 } else { 1 };
1948 marker_writer::write_dht(&mut output, 1, table_id, &ac_bits, &ac_values);
1949 if scan_ri != saved_ri {
1950 marker_writer::write_dri(&mut output, scan_ri);
1951 saved_ri = scan_ri;
1952 }
1953 marker_writer::write_sos_progressive(
1954 &mut output,
1955 &scan_comps,
1956 scan.ss,
1957 scan.se,
1958 scan.ah,
1959 scan.al,
1960 );
1961
1962 let ac_table: HuffTable = build_huff_table(&ac_bits, &ac_values);
1964 bit_writer.reset();
1965 let mut eobrun: u32 = 0;
1966 let ri: u32 = scan_ri as u32;
1967 let mut restarts_to_go: u32 = ri;
1968 let mut next_restart_num: u8 = 0;
1969
1970 for by in 0..hib {
1971 for bx in 0..wib {
1972 if ri > 0 && restarts_to_go == 0 {
1973 if eobrun > 0 {
1974 encoder_pipeline::emit_eobrun(
1975 &ac_table,
1976 &mut bit_writer,
1977 &mut eobrun,
1978 );
1979 }
1980 bit_writer.flush_restart();
1981 bit_writer.write_restart_marker(next_restart_num);
1982 next_restart_num = (next_restart_num + 1) & 7;
1983 restarts_to_go = ri;
1984 }
1985 let block: &[i16; 64] = &comp.blocks[by * stride + bx];
1986 encoder_pipeline::encode_ac_first_block(
1987 block,
1988 ss,
1989 se,
1990 al,
1991 &ac_table,
1992 &mut bit_writer,
1993 &mut eobrun,
1994 );
1995 if ri > 0 {
1996 restarts_to_go -= 1;
1997 }
1998 }
1999 }
2000 if eobrun > 0 {
2001 encoder_pipeline::emit_eobrun(&ac_table, &mut bit_writer, &mut eobrun);
2002 }
2003
2004 bit_writer.flush();
2005 output.extend_from_slice(bit_writer.data());
2006 } else {
2007 let mut ac_freq = [0u32; 257];
2010 ac_freq[256] = 1;
2011 let mut eobrun_gather: u32 = 0;
2012 let mut be: usize = 0;
2013 let ri: u32 = scan_ri as u32;
2014 let mut restarts_to_go: u32 = ri;
2015
2016 for by in 0..hib {
2017 for bx in 0..wib {
2018 if ri > 0 && restarts_to_go == 0 {
2019 if eobrun_gather > 0 {
2020 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
2021 ac_freq[(nbits as usize) << 4] += 1;
2022 }
2023 eobrun_gather = 0;
2030 be = 0;
2031 restarts_to_go = ri;
2032 }
2033 let block: &[i16; 64] = &comp.blocks[by * stride + bx];
2034
2035 let mut absvals = [0u16; 64];
2036 let mut eob_pos: usize = 0;
2037
2038 for i in 0..band_len {
2039 let coeff: i32 = block[ss + i] as i32;
2040 let sign_mask: i32 = coeff >> 31;
2041 let abs_coeff: i32 = (coeff ^ sign_mask) - sign_mask;
2042 let temp: u16 = (abs_coeff >> al) as u16;
2043 absvals[i] = temp;
2044 if temp == 1 {
2045 eob_pos = i + 1;
2046 }
2047 }
2048
2049 let mut r: usize = 0;
2050 let mut br: usize = 0;
2051 let mut idx: usize = 0;
2052
2053 while idx < band_len {
2054 let temp: u16 = absvals[idx];
2055
2056 if temp == 0 {
2057 r += 1;
2058 idx += 1;
2059 continue;
2060 }
2061
2062 while r > 15 && idx < eob_pos {
2063 if eobrun_gather > 0 {
2064 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
2065 ac_freq[(nbits as usize) << 4] += 1;
2066 eobrun_gather = 0;
2067 be = 0;
2068 }
2069 ac_freq[0xF0] += 1;
2070 r -= 16;
2071 br = 0;
2072 }
2073
2074 if temp > 1 {
2075 br += 1;
2076 idx += 1;
2077 continue;
2078 }
2079
2080 if eobrun_gather > 0 {
2081 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
2082 ac_freq[(nbits as usize) << 4] += 1;
2083 eobrun_gather = 0;
2084 be = 0;
2085 }
2086 let symbol: usize = (r << 4) | 1;
2087 ac_freq[symbol] += 1;
2088 r = 0;
2089 br = 0;
2090 idx += 1;
2091 }
2092
2093 if r > 0 || br > 0 {
2094 eobrun_gather += 1;
2095 be += br;
2096 if eobrun_gather == 0x7FFF
2097 || be > (encoder_pipeline::MAX_CORR_BITS - 64 + 1)
2098 {
2099 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
2100 ac_freq[(nbits as usize) << 4] += 1;
2101 eobrun_gather = 0;
2102 be = 0;
2103 }
2104 }
2105 if ri > 0 {
2106 restarts_to_go -= 1;
2107 }
2108 }
2109 }
2110 if eobrun_gather > 0 {
2111 let nbits: u8 = (32 - eobrun_gather.leading_zeros()) as u8 - 1;
2112 ac_freq[(nbits as usize) << 4] += 1;
2113 }
2114
2115 let (ac_bits, ac_values) = huff_opt::gen_optimal_table(&ac_freq);
2117 let table_id: u8 = if ci == 0 { 0 } else { 1 };
2118 marker_writer::write_dht(&mut output, 1, table_id, &ac_bits, &ac_values);
2119 if scan_ri != saved_ri {
2120 marker_writer::write_dri(&mut output, scan_ri);
2121 saved_ri = scan_ri;
2122 }
2123 marker_writer::write_sos_progressive(
2124 &mut output,
2125 &scan_comps,
2126 scan.ss,
2127 scan.se,
2128 scan.ah,
2129 scan.al,
2130 );
2131
2132 let ac_table: HuffTable = build_huff_table(&ac_bits, &ac_values);
2134 bit_writer.reset();
2135 let mut eobrun: u32 = 0;
2136 let mut corr_buffer: Vec<u8> = Vec::with_capacity(encoder_pipeline::MAX_CORR_BITS);
2137 let ri: u32 = scan_ri as u32;
2138 let mut restarts_to_go: u32 = ri;
2139 let mut next_restart_num: u8 = 0;
2140
2141 for by in 0..hib {
2142 for bx in 0..wib {
2143 if ri > 0 && restarts_to_go == 0 {
2144 if eobrun > 0 {
2145 encoder_pipeline::emit_eobrun_with_corr(
2146 &ac_table,
2147 &mut bit_writer,
2148 &mut eobrun,
2149 &mut corr_buffer,
2150 );
2151 }
2152 bit_writer.flush_restart();
2153 bit_writer.write_restart_marker(next_restart_num);
2154 next_restart_num = (next_restart_num + 1) & 7;
2155 restarts_to_go = ri;
2156 }
2157 let block: &[i16; 64] = &comp.blocks[by * stride + bx];
2158 encoder_pipeline::encode_ac_refine_block(
2159 block,
2160 ss,
2161 se,
2162 al,
2163 &ac_table,
2164 &mut bit_writer,
2165 &mut eobrun,
2166 &mut corr_buffer,
2167 );
2168 if ri > 0 {
2169 restarts_to_go -= 1;
2170 }
2171 }
2172 }
2173 if eobrun > 0 {
2174 encoder_pipeline::emit_eobrun_with_corr(
2175 &ac_table,
2176 &mut bit_writer,
2177 &mut eobrun,
2178 &mut corr_buffer,
2179 );
2180 }
2181
2182 bit_writer.flush();
2183 output.extend_from_slice(bit_writer.data());
2184 }
2185 }
2186 }
2187
2188 marker_writer::write_eoi(&mut output);
2189 Ok(output)
2190}
2191
2192pub fn write_coefficients_arithmetic(coeffs: &JpegCoefficients) -> Result<Vec<u8>> {
2197 use crate::encode::arithmetic::ArithEncoder;
2198
2199 let num_components: usize = coeffs.components.len();
2200 let is_grayscale: bool = num_components == 1;
2201 let num_arith_tables: usize = if is_grayscale { 1 } else { 2 };
2202
2203 let max_h: usize = coeffs
2204 .components
2205 .iter()
2206 .map(|c| c.h_sampling as usize)
2207 .max()
2208 .unwrap_or(1);
2209 let max_v: usize = coeffs
2210 .components
2211 .iter()
2212 .map(|c| c.v_sampling as usize)
2213 .max()
2214 .unwrap_or(1);
2215 let mcus_x: usize = coeffs.components[0].blocks_x / coeffs.components[0].h_sampling as usize;
2216 let mcus_y: usize = coeffs.components[0].blocks_y / coeffs.components[0].v_sampling as usize;
2217
2218 let data_blocks_x: Vec<usize> = coeffs
2219 .components
2220 .iter()
2221 .map(|c| (coeffs.width as usize * c.h_sampling as usize).div_ceil(max_h * 8))
2222 .collect();
2223 let data_blocks_y: Vec<usize> = coeffs
2224 .components
2225 .iter()
2226 .map(|c| (coeffs.height as usize * c.v_sampling as usize).div_ceil(max_v * 8))
2227 .collect();
2228
2229 let mut arith_enc: ArithEncoder =
2230 ArithEncoder::new(coeffs.width as usize * coeffs.height as usize);
2231 let mut prev_dc: Vec<i16> = vec![0; num_components];
2232 let ri: u32 = coeffs.restart_interval as u32;
2233 let mut mcu_count: u32 = 0;
2234 let mut restart_idx: u8 = 0;
2235
2236 for mcu_y in 0..mcus_y {
2237 for mcu_x in 0..mcus_x {
2238 if ri > 0 && mcu_count > 0 && mcu_count.is_multiple_of(ri) {
2243 arith_enc.emit_restart(restart_idx);
2244 restart_idx = restart_idx.wrapping_add(1) & 7;
2245 prev_dc.iter_mut().for_each(|v| *v = 0);
2246 }
2247 for (ci, comp) in coeffs.components.iter().enumerate() {
2248 let dc_tbl: usize = arithmetic_table_for_component(ci);
2249 let ac_tbl: usize = arithmetic_table_for_component(ci);
2250
2251 for v in 0..comp.v_sampling as usize {
2252 for h in 0..comp.h_sampling as usize {
2253 let bx: usize = mcu_x * comp.h_sampling as usize + h;
2254 let by: usize = mcu_y * comp.v_sampling as usize + v;
2255
2256 let mut dummy = [0i16; 64];
2257 let block: &[i16; 64] =
2258 if bx >= data_blocks_x[ci] || by >= data_blocks_y[ci] {
2259 dummy[0] = prev_dc[ci];
2260 &dummy
2261 } else {
2262 let real_block: &[i16; 64] = &comp.blocks[by * comp.blocks_x + bx];
2263 prev_dc[ci] = real_block[0];
2264 real_block
2265 };
2266
2267 arith_enc.encode_dc_sequential(block, ci, dc_tbl);
2268 arith_enc.encode_ac_sequential(block, ac_tbl);
2269 }
2270 }
2271 }
2272 mcu_count += 1;
2273 }
2274 }
2275
2276 arith_enc.finish();
2277
2278 let mut output: Vec<u8> = Vec::with_capacity(arith_enc.data().len() + 1024);
2279
2280 marker_writer::write_soi(&mut output);
2281 marker_writer::write_app0_jfif_with_density(
2282 &mut output,
2283 coeffs.density_unit,
2284 coeffs.x_density,
2285 coeffs.y_density,
2286 );
2287
2288 for (i, qt) in coeffs.quant_tables.iter().enumerate() {
2289 marker_writer::write_dqt(&mut output, i as u8, qt);
2290 }
2291
2292 let components: Vec<(u8, u8, u8, u8)> = coeffs
2293 .components
2294 .iter()
2295 .map(|c| {
2296 (
2297 c.component_id,
2298 c.h_sampling,
2299 c.v_sampling,
2300 c.quant_table_index,
2301 )
2302 })
2303 .collect();
2304 marker_writer::write_sof9_with_precision(
2305 &mut output,
2306 coeffs.width,
2307 coeffs.height,
2308 &components,
2309 coeffs.effective_precision(),
2310 );
2311
2312 let dc_params = [(0u8, 1u8); crate::decode::arithmetic::NUM_ARITH_TBLS];
2313 let ac_params = [5u8; crate::decode::arithmetic::NUM_ARITH_TBLS];
2314 let mut dc_in_use = [false; crate::decode::arithmetic::NUM_ARITH_TBLS];
2315 let mut ac_in_use = [false; crate::decode::arithmetic::NUM_ARITH_TBLS];
2316 for table in 0..num_arith_tables {
2317 dc_in_use[table] = true;
2318 ac_in_use[table] = true;
2319 }
2320 marker_writer::write_dac_selected(&mut output, &dc_in_use, &dc_params, &ac_in_use, &ac_params);
2321
2322 if coeffs.restart_interval > 0 {
2323 marker_writer::write_dri(&mut output, coeffs.restart_interval);
2324 }
2325
2326 let scan_components: Vec<(u8, u8, u8)> = coeffs
2327 .components
2328 .iter()
2329 .enumerate()
2330 .map(|(ci, c)| {
2331 let tbl: u8 = arithmetic_table_for_component(ci) as u8;
2332 (c.component_id, tbl, tbl)
2333 })
2334 .collect();
2335 marker_writer::write_sos(&mut output, &scan_components);
2336
2337 output.extend_from_slice(arith_enc.data());
2338 marker_writer::write_eoi(&mut output);
2339
2340 Ok(output)
2341}
2342
2343pub fn write_coefficients_progressive_arithmetic(
2357 coeffs: &JpegCoefficients,
2358 restart_rows: Option<u16>,
2359) -> Result<Vec<u8>> {
2360 use crate::encode::arithmetic::ArithEncoder;
2361 use crate::encode::progressive::simple_progression;
2362
2363 let num_components: usize = coeffs.components.len();
2364
2365 let max_h: usize = coeffs
2366 .components
2367 .iter()
2368 .map(|c| c.h_sampling as usize)
2369 .max()
2370 .unwrap_or(1);
2371 let max_v: usize = coeffs
2372 .components
2373 .iter()
2374 .map(|c| c.v_sampling as usize)
2375 .max()
2376 .unwrap_or(1);
2377 let mcus_x: usize = coeffs.components[0].blocks_x / coeffs.components[0].h_sampling as usize;
2378 let mcus_y: usize = coeffs.components[0].blocks_y / coeffs.components[0].v_sampling as usize;
2379
2380 let data_blocks_x: Vec<usize> = coeffs
2381 .components
2382 .iter()
2383 .map(|c| (coeffs.width as usize * c.h_sampling as usize).div_ceil(max_h * 8))
2384 .collect();
2385 let data_blocks_y: Vec<usize> = coeffs
2386 .components
2387 .iter()
2388 .map(|c| (coeffs.height as usize * c.v_sampling as usize).div_ceil(max_v * 8))
2389 .collect();
2390
2391 let scans = simple_progression(num_components);
2392 let dc_params = [(0u8, 1u8); crate::decode::arithmetic::NUM_ARITH_TBLS];
2393 let ac_params = [5u8; crate::decode::arithmetic::NUM_ARITH_TBLS];
2394
2395 let mut output: Vec<u8> = Vec::with_capacity(coeffs.width as usize * coeffs.height as usize);
2396
2397 marker_writer::write_soi(&mut output);
2398 marker_writer::write_app0_jfif_with_density(
2399 &mut output,
2400 coeffs.density_unit,
2401 coeffs.x_density,
2402 coeffs.y_density,
2403 );
2404
2405 for (i, qt) in coeffs.quant_tables.iter().enumerate() {
2406 marker_writer::write_dqt(&mut output, i as u8, qt);
2407 }
2408
2409 let components: Vec<(u8, u8, u8, u8)> = coeffs
2410 .components
2411 .iter()
2412 .map(|c| {
2413 (
2414 c.component_id,
2415 c.h_sampling,
2416 c.v_sampling,
2417 c.quant_table_index,
2418 )
2419 })
2420 .collect();
2421 marker_writer::write_sof10_with_precision(
2422 &mut output,
2423 coeffs.width,
2424 coeffs.height,
2425 &components,
2426 coeffs.effective_precision(),
2427 );
2428
2429 let mut arith_enc: ArithEncoder =
2430 ArithEncoder::new(coeffs.width as usize * coeffs.height as usize / 4);
2431
2432 let per_scan_ri = |scan_ci: &[usize]| -> u16 {
2439 match restart_rows {
2440 Some(rows) => {
2441 let mcus_per_row: usize = if scan_ci.len() == 1 {
2442 let ci: usize = scan_ci[0];
2443 let comp = &coeffs.components[ci];
2444 (coeffs.width as usize * comp.h_sampling as usize).div_ceil(max_h * 8)
2445 } else {
2446 (coeffs.width as usize).div_ceil(max_h * 8)
2447 };
2448 let dri: usize = rows as usize * mcus_per_row;
2449 dri.min(u16::MAX as usize) as u16
2450 }
2451 None => coeffs.restart_interval,
2452 }
2453 };
2454
2455 let mut saved_ri: u16 = 0;
2458
2459 for scan in &scans {
2460 arith_enc.reset();
2461
2462 let is_dc_scan: bool = scan.ss == 0 && scan.se == 0;
2463 let is_first: bool = scan.ah == 0;
2464 let scan_ri: u16 = per_scan_ri(&scan.component_indices);
2465
2466 let scan_components: Vec<(u8, u8, u8)> = scan
2467 .component_indices
2468 .iter()
2469 .map(|&ci| {
2470 let tbl: u8 = arithmetic_table_for_component(ci) as u8;
2471 let dc_tbl: u8 = if is_dc_scan && is_first { tbl } else { 0 };
2472 let ac_tbl: u8 = if scan.se > 0 { tbl } else { 0 };
2473 (coeffs.components[ci].component_id, dc_tbl, ac_tbl)
2474 })
2475 .collect();
2476
2477 let mut dc_in_use = [false; crate::decode::arithmetic::NUM_ARITH_TBLS];
2478 let mut ac_in_use = [false; crate::decode::arithmetic::NUM_ARITH_TBLS];
2479 if is_dc_scan && is_first {
2480 for &ci in &scan.component_indices {
2481 dc_in_use[arithmetic_table_for_component(ci)] = true;
2482 }
2483 }
2484 if scan.se > 0 {
2485 for &ci in &scan.component_indices {
2486 ac_in_use[arithmetic_table_for_component(ci)] = true;
2487 }
2488 }
2489
2490 marker_writer::write_dac_selected(
2491 &mut output,
2492 &dc_in_use,
2493 &dc_params,
2494 &ac_in_use,
2495 &ac_params,
2496 );
2497 if scan_ri != saved_ri {
2501 marker_writer::write_dri(&mut output, scan_ri);
2502 saved_ri = scan_ri;
2503 }
2504 marker_writer::write_sos_progressive(
2505 &mut output,
2506 &scan_components,
2507 scan.ss,
2508 scan.se,
2509 scan.ah,
2510 scan.al,
2511 );
2512
2513 let ri: u32 = scan_ri as u32;
2514 let mut restarts_to_go: u32 = ri;
2515 let mut next_restart_num: u8 = 0;
2516
2517 if is_dc_scan && is_first {
2518 let mut prev_dc: Vec<i16> = vec![0; num_components];
2519
2520 for mcu_y in 0..mcus_y {
2521 for mcu_x in 0..mcus_x {
2522 if ri > 0 && restarts_to_go == 0 {
2527 arith_enc.emit_restart(next_restart_num);
2528 next_restart_num = (next_restart_num + 1) & 7;
2529 prev_dc.iter_mut().for_each(|v| *v = 0);
2530 restarts_to_go = ri;
2531 }
2532 for &ci in &scan.component_indices {
2533 let comp = &coeffs.components[ci];
2534 let dc_tbl: usize = arithmetic_table_for_component(ci);
2535
2536 for v in 0..comp.v_sampling as usize {
2537 for h in 0..comp.h_sampling as usize {
2538 let bx: usize = mcu_x * comp.h_sampling as usize + h;
2539 let by: usize = mcu_y * comp.v_sampling as usize + v;
2540
2541 let mut dummy = [0i16; 64];
2542 let block: &[i16; 64] =
2543 if bx >= data_blocks_x[ci] || by >= data_blocks_y[ci] {
2544 dummy[0] = prev_dc[ci];
2545 &dummy
2546 } else {
2547 let real_block: &[i16; 64] =
2548 &comp.blocks[by * comp.blocks_x + bx];
2549 prev_dc[ci] = real_block[0];
2550 real_block
2551 };
2552
2553 arith_enc.encode_dc_first(block, ci, dc_tbl, scan.al);
2554 }
2555 }
2556 }
2557 if ri > 0 {
2558 restarts_to_go -= 1;
2559 }
2560 }
2561 }
2562 } else if is_dc_scan {
2563 let mut prev_dc: Vec<i16> = vec![0; num_components];
2564
2565 for mcu_y in 0..mcus_y {
2566 for mcu_x in 0..mcus_x {
2567 if ri > 0 && restarts_to_go == 0 {
2568 arith_enc.emit_restart(next_restart_num);
2569 next_restart_num = (next_restart_num + 1) & 7;
2570 prev_dc.iter_mut().for_each(|v| *v = 0);
2571 restarts_to_go = ri;
2572 }
2573 for &ci in &scan.component_indices {
2574 let comp = &coeffs.components[ci];
2575
2576 for v in 0..comp.v_sampling as usize {
2577 for h in 0..comp.h_sampling as usize {
2578 let bx: usize = mcu_x * comp.h_sampling as usize + h;
2579 let by: usize = mcu_y * comp.v_sampling as usize + v;
2580
2581 let mut dummy = [0i16; 64];
2582 let block: &[i16; 64] =
2583 if bx >= data_blocks_x[ci] || by >= data_blocks_y[ci] {
2584 dummy[0] = prev_dc[ci];
2585 &dummy
2586 } else {
2587 let real_block: &[i16; 64] =
2588 &comp.blocks[by * comp.blocks_x + bx];
2589 prev_dc[ci] = real_block[0];
2590 real_block
2591 };
2592
2593 arith_enc.encode_dc_refine(block, scan.al);
2594 }
2595 }
2596 }
2597 if ri > 0 {
2598 restarts_to_go -= 1;
2599 }
2600 }
2601 }
2602 } else if is_first {
2603 let ci: usize = scan.component_indices[0];
2604 let comp = &coeffs.components[ci];
2605 let ac_tbl: usize = arithmetic_table_for_component(ci);
2606 let wib: usize = data_blocks_x[ci].min(comp.blocks_x);
2607 let hib: usize = data_blocks_y[ci].min(comp.blocks_y);
2608
2609 for by in 0..hib {
2612 for bx in 0..wib {
2613 if ri > 0 && restarts_to_go == 0 {
2614 arith_enc.emit_restart(next_restart_num);
2615 next_restart_num = (next_restart_num + 1) & 7;
2616 restarts_to_go = ri;
2617 }
2618 let block: &[i16; 64] = &comp.blocks[by * comp.blocks_x + bx];
2619 arith_enc.encode_ac_first(block, ac_tbl, scan.ss, scan.se, scan.al);
2620 if ri > 0 {
2621 restarts_to_go -= 1;
2622 }
2623 }
2624 }
2625 } else {
2626 let ci: usize = scan.component_indices[0];
2627 let comp = &coeffs.components[ci];
2628 let ac_tbl: usize = arithmetic_table_for_component(ci);
2629 let wib: usize = data_blocks_x[ci].min(comp.blocks_x);
2630 let hib: usize = data_blocks_y[ci].min(comp.blocks_y);
2631
2632 for by in 0..hib {
2633 for bx in 0..wib {
2634 if ri > 0 && restarts_to_go == 0 {
2635 arith_enc.emit_restart(next_restart_num);
2636 next_restart_num = (next_restart_num + 1) & 7;
2637 restarts_to_go = ri;
2638 }
2639 let block: &[i16; 64] = &comp.blocks[by * comp.blocks_x + bx];
2640 arith_enc.encode_ac_refine(block, ac_tbl, scan.ss, scan.se, scan.al, scan.ah);
2641 if ri > 0 {
2642 restarts_to_go -= 1;
2643 }
2644 }
2645 }
2646 }
2647
2648 arith_enc.finish();
2649 output.extend_from_slice(arith_enc.data());
2650 }
2651
2652 marker_writer::write_eoi(&mut output);
2653 Ok(output)
2654}
2655
2656fn arithmetic_table_for_component(component_index: usize) -> usize {
2657 if component_index == 0 {
2658 0
2659 } else {
2660 1
2661 }
2662}
2663
2664fn transpose_quant_table(qt: &mut [u16; 64]) {
2668 let mut transposed: [u16; 64] = [0u16; 64];
2669 for row in 0..8 {
2670 for col in 0..8 {
2671 transposed[col * 8 + row] = qt[row * 8 + col];
2672 }
2673 }
2674 *qt = transposed;
2675}
2676
2677fn natural_to_zigzag(natural: &[i16; 64]) -> [i16; 64] {
2679 let mut zigzag = [0i16; 64];
2680 for i in 0..64 {
2681 zigzag[NATURAL_ORDER[i]] = natural[i];
2682 }
2683 zigzag
2684}
2685
2686fn convert_all_to_zigzag(comp_data: &mut [ComponentCoefficients]) {
2688 for comp in comp_data.iter_mut() {
2689 for block in &mut comp.blocks {
2690 *block = natural_to_zigzag(block);
2691 }
2692 }
2693}
2694
2695fn decode_baseline_coefficients(
2698 data: &[u8],
2699 metadata: &JpegMetadata,
2700 comp_data: &mut [ComponentCoefficients],
2701 mcus_x: usize,
2702 mcus_y: usize,
2703) -> Result<()> {
2704 use crate::decode::bitstream::BitReader;
2705 use crate::decode::entropy;
2706
2707 let frame = &metadata.frame;
2708 let scan = &metadata.scan;
2709
2710 let mcu_plan = entropy::resolve_mcu_plan(
2711 frame,
2712 scan,
2713 &metadata.dc_huffman_tables,
2714 &metadata.ac_huffman_tables,
2715 )?;
2716
2717 if mcu_plan.len() != comp_data.len() {
2722 return Err(crate::common::error::JpegError::CorruptData(format!(
2723 "baseline SOS covers {} components but frame has {}",
2724 mcu_plan.len(),
2725 comp_data.len()
2726 )));
2727 }
2728
2729 let entropy_data = &data[metadata.entropy_data_offset..];
2730 let mut bit_reader = BitReader::new(entropy_data);
2731 let mut mcu_decoder = entropy::McuDecoder::new(frame.components.len());
2732 let mut mcu_count: u32 = 0;
2733 let mut coeffs = [0i16; 64];
2734
2735 for mcu_y in 0..mcus_y {
2736 for mcu_x in 0..mcus_x {
2737 if metadata.restart_interval > 0
2738 && mcu_count > 0
2739 && mcu_count.is_multiple_of(metadata.restart_interval as u32)
2740 {
2741 bit_reader.reset();
2742 mcu_decoder.reset();
2743 }
2744
2745 for (comp_idx, comp) in comp_data.iter_mut().enumerate() {
2746 let plan = &mcu_plan[comp_idx];
2747
2748 let h_blocks = frame.components[comp_idx].horizontal_sampling as usize;
2749 let v_blocks = frame.components[comp_idx].vertical_sampling as usize;
2750
2751 for v in 0..v_blocks {
2752 for h in 0..h_blocks {
2753 mcu_decoder.decode_block(
2754 &mut bit_reader,
2755 plan.comp_idx,
2756 plan.dc_table,
2757 plan.ac_table,
2758 &mut coeffs,
2759 )?;
2760
2761 let bx = mcu_x * h_blocks + h;
2762 let by = mcu_y * v_blocks + v;
2763 let block_idx = by * comp.blocks_x + bx;
2764 comp.blocks[block_idx] = coeffs;
2765 }
2766 }
2767 }
2768
2769 mcu_count += 1;
2770 }
2771 }
2772
2773 Ok(())
2774}
2775
2776fn decode_arithmetic_coefficients(
2777 data: &[u8],
2778 metadata: &JpegMetadata,
2779 comp_data: &mut [ComponentCoefficients],
2780 mcus_x: usize,
2781 mcus_y: usize,
2782) -> Result<()> {
2783 use crate::decode::arithmetic::ArithDecoder;
2784
2785 let frame = &metadata.frame;
2786 let scan = &metadata.scan;
2787
2788 let scan_comps: Vec<(usize, usize, usize)> = scan
2789 .components
2790 .iter()
2791 .map(|sc| {
2792 let comp_idx = frame
2793 .components
2794 .iter()
2795 .position(|fc| fc.id == sc.component_id)
2796 .unwrap_or(0);
2797 (
2798 comp_idx,
2799 sc.dc_table_index as usize,
2800 sc.ac_table_index as usize,
2801 )
2802 })
2803 .collect();
2804
2805 let entropy_data = &data[metadata.entropy_data_offset..];
2806 let mut arith = ArithDecoder::new(entropy_data, 0);
2807
2808 for i in 0..crate::decode::arithmetic::NUM_ARITH_TBLS {
2809 let (l, u) = metadata.arith_dc_params[i];
2810 arith.set_dc_conditioning(i, l, u);
2811 arith.set_ac_conditioning(i, metadata.arith_ac_params[i]);
2812 }
2813
2814 let layouts: Vec<(usize, usize, usize)> = comp_data
2816 .iter()
2817 .map(|c| (c.h_sampling as usize, c.v_sampling as usize, c.blocks_x))
2818 .collect();
2819 let mut coeffs: [i16; 64];
2820
2821 for mcu_y in 0..mcus_y {
2822 for mcu_x in 0..mcus_x {
2823 for &(comp_idx, dc_tbl, ac_tbl) in &scan_comps {
2824 let (h_blocks, v_blocks, blocks_x) = layouts[comp_idx];
2825
2826 for v in 0..v_blocks {
2827 for h in 0..h_blocks {
2828 coeffs = [0i16; 64];
2829 arith.decode_dc_sequential(&mut coeffs, comp_idx, dc_tbl)?;
2830 arith.decode_ac_sequential(&mut coeffs, ac_tbl)?;
2831
2832 let bx = mcu_x * h_blocks + h;
2833 let by = mcu_y * v_blocks + v;
2834 let block_idx = by * blocks_x + bx;
2835 comp_data[comp_idx].blocks[block_idx] = coeffs;
2836 }
2837 }
2838 }
2839 }
2840 }
2841
2842 Ok(())
2843}
2844
2845fn decode_arithmetic_progressive_coefficients(
2847 data: &[u8],
2848 metadata: &JpegMetadata,
2849 comp_data: &mut [ComponentCoefficients],
2850 _mcus_x: usize,
2851 _mcus_y: usize,
2852) -> Result<()> {
2853 use crate::decode::arithmetic::ArithDecoder;
2854
2855 let frame = &metadata.frame;
2856
2857 for scan_info in &metadata.scans {
2858 let scan = &scan_info.header;
2859 let ss: u8 = scan.spec_start;
2860 let se: u8 = scan.spec_end;
2861 let ah: u8 = scan.succ_high;
2862 let al: u8 = scan.succ_low;
2863 let is_dc: bool = ss == 0 && se == 0;
2864
2865 let entropy_data: &[u8] = &data[scan_info.data_offset..];
2866 let mut arith: ArithDecoder<'_> = ArithDecoder::new(entropy_data, 0);
2867
2868 for i in 0..crate::decode::arithmetic::NUM_ARITH_TBLS {
2870 let (l, u) = metadata.arith_dc_params[i];
2871 arith.set_dc_conditioning(i, l, u);
2872 arith.set_ac_conditioning(i, metadata.arith_ac_params[i]);
2873 }
2874
2875 let scan_comp_indices: Vec<usize> = scan
2876 .components
2877 .iter()
2878 .map(|sc| {
2879 frame
2880 .components
2881 .iter()
2882 .position(|fc| fc.id == sc.component_id)
2883 .unwrap_or(0)
2884 })
2885 .collect();
2886
2887 if scan.components.len() > 1 {
2888 let max_h: usize = frame
2890 .components
2891 .iter()
2892 .map(|c| c.horizontal_sampling as usize)
2893 .max()
2894 .unwrap_or(1);
2895 let max_v: usize = frame
2896 .components
2897 .iter()
2898 .map(|c| c.vertical_sampling as usize)
2899 .max()
2900 .unwrap_or(1);
2901 let mcu_w: usize = max_h * 8;
2902 let mcu_h: usize = max_v * 8;
2903 let mcus_x: usize = (frame.width as usize).div_ceil(mcu_w);
2904 let mcus_y: usize = (frame.height as usize).div_ceil(mcu_h);
2905
2906 for _mcu_y in 0..mcus_y {
2907 for _mcu_x in 0..mcus_x {
2908 for (si, &comp_idx) in scan_comp_indices.iter().enumerate() {
2909 let h_samp: usize = frame.components[comp_idx].horizontal_sampling as usize;
2910 let v_samp: usize = frame.components[comp_idx].vertical_sampling as usize;
2911 let blocks_x: usize = comp_data[comp_idx].blocks_x;
2912 let dc_tbl: usize = scan.components[si].dc_table_index as usize;
2913
2914 for v in 0..v_samp {
2915 for h in 0..h_samp {
2916 let bx: usize = _mcu_x * h_samp + h;
2917 let by: usize = _mcu_y * v_samp + v;
2918 let block_idx: usize = by * blocks_x + bx;
2919 let block: &mut [i16; 64] =
2920 &mut comp_data[comp_idx].blocks[block_idx];
2921
2922 if is_dc && ah == 0 {
2923 arith
2924 .decode_dc_first_progressive(block, comp_idx, dc_tbl, al)?;
2925 } else if is_dc {
2926 arith.decode_dc_refine_progressive(block, al)?;
2927 }
2928 }
2929 }
2930 }
2931 }
2932 }
2933 } else {
2934 let comp_idx: usize = scan_comp_indices[0];
2936 let arith_max_h: usize = frame
2940 .components
2941 .iter()
2942 .map(|c| c.horizontal_sampling as usize)
2943 .max()
2944 .unwrap_or(1);
2945 let arith_max_v: usize = frame
2946 .components
2947 .iter()
2948 .map(|c| c.vertical_sampling as usize)
2949 .max()
2950 .unwrap_or(1);
2951 let h_samp: usize = comp_data[comp_idx].h_sampling as usize;
2952 let v_samp: usize = comp_data[comp_idx].v_sampling as usize;
2953 let comp_blocks_x: usize = (frame.width as usize * h_samp).div_ceil(arith_max_h * 8);
2954 let comp_blocks_y: usize = (frame.height as usize * v_samp).div_ceil(arith_max_v * 8);
2955 let stride_x: usize = comp_data[comp_idx].blocks_x;
2956 let dc_tbl: usize = scan.components[0].dc_table_index as usize;
2957 let ac_tbl: usize = scan.components[0].ac_table_index as usize;
2958
2959 for by in 0..comp_blocks_y {
2960 for bx in 0..comp_blocks_x {
2961 let block_idx: usize = by * stride_x + bx;
2962 let block: &mut [i16; 64] = &mut comp_data[comp_idx].blocks[block_idx];
2963
2964 if is_dc {
2965 if ah == 0 {
2966 arith.decode_dc_first_progressive(block, comp_idx, dc_tbl, al)?;
2967 } else {
2968 arith.decode_dc_refine_progressive(block, al)?;
2969 }
2970 } else if ah == 0 {
2971 arith.decode_ac_first_progressive(block, ac_tbl, ss, se, al)?;
2972 } else {
2973 arith.decode_ac_refine_progressive(block, ac_tbl, ss, se, al)?;
2974 }
2975 }
2976 }
2977 }
2978 }
2979
2980 Ok(())
2981}
2982
2983fn decode_progressive_coefficients(
2984 data: &[u8],
2985 metadata: &JpegMetadata,
2986 comp_data: &mut [ComponentCoefficients],
2987 mcus_x: usize,
2988 mcus_y: usize,
2989) -> Result<()> {
2990 use crate::decode::bitstream::BitReader;
2991 use crate::decode::progressive;
2992
2993 let frame = &metadata.frame;
2994 let max_h = frame
2995 .components
2996 .iter()
2997 .map(|c| c.horizontal_sampling as usize)
2998 .max()
2999 .unwrap_or(1);
3000 let max_v = frame
3001 .components
3002 .iter()
3003 .map(|c| c.vertical_sampling as usize)
3004 .max()
3005 .unwrap_or(1);
3006
3007 let mut ac_max_k: Vec<Vec<u8>> = comp_data
3010 .iter()
3011 .map(|cd| vec![0u8; cd.blocks.len()])
3012 .collect();
3013
3014 for scan_info in &metadata.scans {
3015 let scan = &scan_info.header;
3016 let ss = scan.spec_start;
3017 let se = scan.spec_end;
3018 let ah = scan.succ_high;
3019 let al = scan.succ_low;
3020 let is_dc = ss == 0 && se == 0;
3021
3022 let entropy_data = &data[scan_info.data_offset..];
3023 let mut bit_reader = BitReader::new(entropy_data);
3024
3025 let scan_comp_indices: Vec<usize> = scan
3026 .components
3027 .iter()
3028 .map(|sc| {
3029 frame
3030 .components
3031 .iter()
3032 .position(|fc| fc.id == sc.component_id)
3033 .ok_or_else(|| {
3034 JpegError::CorruptData(format!(
3035 "scan references unknown component {}",
3036 sc.component_id
3037 ))
3038 })
3039 })
3040 .collect::<Result<Vec<_>>>()?;
3041
3042 if scan.components.len() > 1 {
3043 let mut dc_preds = [0i16; 4];
3045 let mut mcu_count: u32 = 0;
3046
3047 for mcu_y in 0..mcus_y {
3048 for mcu_x in 0..mcus_x {
3049 if scan_info.restart_interval > 0
3050 && mcu_count > 0
3051 && mcu_count.is_multiple_of(scan_info.restart_interval as u32)
3052 {
3053 bit_reader.reset();
3054 dc_preds = [0i16; 4];
3055 }
3056
3057 for (si, &comp_idx) in scan_comp_indices.iter().enumerate() {
3058 let h_samp = comp_data[comp_idx].h_sampling as usize;
3059 let v_samp = comp_data[comp_idx].v_sampling as usize;
3060 let blocks_x = comp_data[comp_idx].blocks_x;
3061 let scan_comp = &scan.components[si];
3062
3063 let dc_table = scan_info.dc_huffman_tables
3064 [scan_comp.dc_table_index as usize]
3065 .as_ref()
3066 .ok_or_else(|| {
3067 JpegError::CorruptData(format!(
3068 "missing DC table {}",
3069 scan_comp.dc_table_index
3070 ))
3071 })?;
3072
3073 for v in 0..v_samp {
3074 for h in 0..h_samp {
3075 let bx = mcu_x * h_samp + h;
3076 let by = mcu_y * v_samp + v;
3077 let block_idx = by * blocks_x + bx;
3078 let coeffs = &mut comp_data[comp_idx].blocks[block_idx];
3079
3080 if is_dc {
3081 if ah == 0 {
3082 progressive::decode_dc_first(
3083 &mut bit_reader,
3084 dc_table,
3085 &mut dc_preds[comp_idx],
3086 coeffs,
3087 al,
3088 )?;
3089 } else {
3090 progressive::decode_dc_refine(&mut bit_reader, coeffs, al)?;
3091 }
3092 }
3093 }
3094 }
3095 }
3096
3097 mcu_count += 1;
3098 }
3099 }
3100 } else {
3101 let comp_idx = scan_comp_indices[0];
3103 let scan_comp = &scan.components[0];
3104 let h_samp: usize = comp_data[comp_idx].h_sampling as usize;
3108 let v_samp: usize = comp_data[comp_idx].v_sampling as usize;
3109 let comp_blocks_x: usize = (frame.width as usize * h_samp).div_ceil(max_h * 8);
3110 let comp_blocks_y: usize = (frame.height as usize * v_samp).div_ceil(max_v * 8);
3111 let stride_x: usize = comp_data[comp_idx].blocks_x;
3112 let mut dc_pred = 0i16;
3113 let mut eob_run = 0u16;
3114 let mut mcu_count: u32 = 0;
3115
3116 let dc_table = if is_dc {
3117 Some(
3118 scan_info.dc_huffman_tables[scan_comp.dc_table_index as usize]
3119 .as_ref()
3120 .ok_or_else(|| {
3121 JpegError::CorruptData(format!(
3122 "missing DC table {}",
3123 scan_comp.dc_table_index
3124 ))
3125 })?,
3126 )
3127 } else {
3128 None
3129 };
3130 let ac_table = if !is_dc || se > 0 {
3131 Some(
3132 scan_info.ac_huffman_tables[scan_comp.ac_table_index as usize]
3133 .as_ref()
3134 .ok_or_else(|| {
3135 JpegError::CorruptData(format!(
3136 "missing AC table {}",
3137 scan_comp.ac_table_index
3138 ))
3139 })?,
3140 )
3141 } else {
3142 None
3143 };
3144
3145 let restart_interval = scan_info.restart_interval as u32;
3146
3147 for by in 0..comp_blocks_y {
3148 for bx in 0..comp_blocks_x {
3149 if restart_interval > 0
3150 && mcu_count > 0
3151 && mcu_count.is_multiple_of(restart_interval)
3152 {
3153 bit_reader.reset();
3154 dc_pred = 0;
3155 eob_run = 0;
3156 }
3157
3158 let block_idx = by * stride_x + bx;
3159 let coeffs = &mut comp_data[comp_idx].blocks[block_idx];
3160
3161 if is_dc {
3162 if ah == 0 {
3163 progressive::decode_dc_first(
3164 &mut bit_reader,
3165 dc_table.unwrap(),
3166 &mut dc_pred,
3167 coeffs,
3168 al,
3169 )?;
3170 } else {
3171 progressive::decode_dc_refine(&mut bit_reader, coeffs, al)?;
3172 }
3173 } else if ah == 0 {
3174 progressive::decode_ac_first_tracked(
3175 &mut bit_reader,
3176 ac_table.unwrap(),
3177 coeffs,
3178 ss,
3179 se,
3180 al,
3181 &mut eob_run,
3182 &mut ac_max_k[comp_idx][block_idx],
3183 )?;
3184 } else {
3185 progressive::decode_ac_refine_tracked(
3186 &mut bit_reader,
3187 ac_table.unwrap(),
3188 coeffs,
3189 ss,
3190 se,
3191 al,
3192 &mut eob_run,
3193 &mut ac_max_k[comp_idx][block_idx],
3194 )?;
3195 }
3196
3197 mcu_count += 1;
3198 }
3199 }
3200 }
3201 }
3202
3203 Ok(())
3204}