1pub mod arch;
98pub mod arg;
99pub mod codestream;
100pub mod coding;
101pub mod error;
102pub mod file;
103pub mod mem;
104pub mod message;
105pub mod params;
106pub mod transform;
107pub mod types;
108
109pub use error::{OjphError, Result};
110pub use types::*;
111
112#[cfg(test)]
113mod pipeline_tests {
114 use crate::codestream::Codestream;
115 use crate::file::{MemInfile, MemOutfile};
116 use crate::types::*;
117
118 #[test]
121 fn roundtrip_8x8_single_component() {
122 let width = 8u32;
123 let height = 8u32;
124
125 let image: Vec<Vec<i32>> = vec![vec![131i32; width as usize]; height as usize];
127
128 let mut cs = Codestream::new();
130 cs.access_siz_mut()
131 .set_image_extent(Point::new(width, height));
132 cs.access_siz_mut().set_num_components(1);
133 cs.access_siz_mut()
134 .set_comp_info(0, Point::new(1, 1), 8, false);
135 cs.access_siz_mut().set_tile_size(Size::new(width, height));
136 cs.access_cod_mut().set_num_decomposition(1);
137 cs.access_cod_mut().set_reversible(true);
138 cs.access_cod_mut().set_color_transform(false);
139 cs.set_planar(0);
140
141 let mut outfile = MemOutfile::new();
142 cs.write_headers(&mut outfile, &[]).unwrap();
143
144 for row in &image {
145 cs.exchange(row, 0).unwrap();
146 }
147 cs.flush(&mut outfile).unwrap();
148
149 let encoded = outfile.get_data().to_vec();
150 assert!(
151 encoded.len() > 20,
152 "encoded data too small: {} bytes",
153 encoded.len()
154 );
155
156 let mut infile = MemInfile::new(&encoded);
158 let mut cs2 = Codestream::new();
159 cs2.read_headers(&mut infile).unwrap();
160 cs2.create(&mut infile).unwrap();
161
162 for (y, expected_row) in image.iter().enumerate() {
163 let line = cs2.pull(0).expect("expected decoded line");
164 assert_eq!(
165 line,
166 *expected_row,
167 "mismatch at row {y}: got {:?}, expected {:?}",
168 &line[..],
169 &expected_row[..]
170 );
171 }
172
173 assert!(cs2.pull(0).is_none());
175 }
176
177 #[test]
179 fn roundtrip_8x8_constant() {
180 let width = 8u32;
181 let height = 8u32;
182 let image: Vec<Vec<i32>> = vec![vec![125i32; width as usize]; height as usize];
184
185 let mut cs = Codestream::new();
186 cs.access_siz_mut()
187 .set_image_extent(Point::new(width, height));
188 cs.access_siz_mut().set_num_components(1);
189 cs.access_siz_mut()
190 .set_comp_info(0, Point::new(1, 1), 8, false);
191 cs.access_siz_mut().set_tile_size(Size::new(width, height));
192 cs.access_cod_mut().set_num_decomposition(1);
193 cs.access_cod_mut().set_reversible(true);
194 cs.access_cod_mut().set_color_transform(false);
195 cs.set_planar(0);
196
197 let mut outfile = MemOutfile::new();
198 cs.write_headers(&mut outfile, &[]).unwrap();
199 for row in &image {
200 cs.exchange(row, 0).unwrap();
201 }
202 cs.flush(&mut outfile).unwrap();
203
204 let encoded = outfile.get_data().to_vec();
205 let mut infile = MemInfile::new(&encoded);
206 let mut cs2 = Codestream::new();
207 cs2.read_headers(&mut infile).unwrap();
208 cs2.create(&mut infile).unwrap();
209
210 for (y, expected_row) in image.iter().enumerate() {
211 let line = cs2.pull(0).expect("expected decoded line");
212 assert_eq!(line, *expected_row, "mismatch at row {y}");
213 }
214 }
215
216 #[test]
218 fn roundtrip_8x8_no_dwt() {
219 let width = 8u32;
220 let height = 8u32;
221 let image: Vec<Vec<i32>> = vec![vec![131i32; width as usize]; height as usize];
223
224 let mut cs = Codestream::new();
225 cs.access_siz_mut()
226 .set_image_extent(Point::new(width, height));
227 cs.access_siz_mut().set_num_components(1);
228 cs.access_siz_mut()
229 .set_comp_info(0, Point::new(1, 1), 8, false);
230 cs.access_siz_mut().set_tile_size(Size::new(width, height));
231 cs.access_cod_mut().set_num_decomposition(0);
232 cs.access_cod_mut().set_reversible(true);
233 cs.access_cod_mut().set_color_transform(false);
234 cs.set_planar(0);
235
236 let mut outfile = MemOutfile::new();
237 cs.write_headers(&mut outfile, &[]).unwrap();
238 for row in &image {
239 cs.exchange(row, 0).unwrap();
240 }
241 cs.flush(&mut outfile).unwrap();
242
243 let encoded = outfile.get_data().to_vec();
244 let mut infile = MemInfile::new(&encoded);
245 let mut cs2 = Codestream::new();
246 cs2.read_headers(&mut infile).unwrap();
247 cs2.create(&mut infile).unwrap();
248
249 for (y, expected_row) in image.iter().enumerate() {
250 let line = cs2.pull(0).expect("expected decoded line");
251 assert_eq!(line, *expected_row, "mismatch at row {y}");
252 }
253 }
254
255 #[test]
257 fn block_coder_roundtrip_magnitude_3() {
258 use crate::coding::decoder32::decode_codeblock32;
259 use crate::coding::encoder::encode_codeblock32;
260
261 let mag = 3u32;
263 let u32_val = (1u32 << 31) | mag;
264 let buf = vec![u32_val; 16];
265 let num_bits = 32 - mag.leading_zeros();
266 let missing_msbs = 31 - num_bits; let enc = encode_codeblock32(&buf, missing_msbs, 1, 4, 4, 4).unwrap();
269 assert!(enc.length >= 2);
270
271 let mut coded = enc.data.clone();
272 coded.resize(coded.len() + 16, 0);
273 let mut decoded = vec![0u32; 16];
274 decode_codeblock32(
275 &mut coded,
276 &mut decoded,
277 missing_msbs,
278 1,
279 enc.length,
280 0,
281 4,
282 4,
283 4,
284 false,
285 )
286 .unwrap();
287
288 for i in 0..16 {
289 assert_eq!(
290 decoded[i], buf[i],
291 "mismatch at {}: got 0x{:08X}, expected 0x{:08X}",
292 i, decoded[i], buf[i]
293 );
294 }
295 }
296}
297
298#[cfg(test)]
299mod debug_roundtrip_test {
300 use crate::codestream::Codestream;
301 use crate::coding::decoder32::decode_codeblock32;
302 use crate::coding::encoder::encode_codeblock32;
303 use crate::file::{MemInfile, MemOutfile};
304 use crate::types::{Point, Size};
305
306 #[test]
307 fn debug_no_dwt_value100() {
308 let width = 8u32;
309 let height = 8u32;
310 let pixels = vec![100i32; (width * height) as usize];
311
312 let mut cs = Codestream::new();
313 cs.access_siz_mut()
314 .set_image_extent(Point::new(width, height));
315 cs.access_siz_mut().set_num_components(1);
316 cs.access_siz_mut()
317 .set_comp_info(0, Point::new(1, 1), 8, false);
318 cs.access_siz_mut().set_tile_size(Size::new(width, height));
319 cs.access_cod_mut().set_num_decomposition(0);
320 cs.access_cod_mut().set_reversible(true);
321 cs.access_cod_mut().set_color_transform(false);
322 cs.set_planar(0);
323
324 let mut outfile = MemOutfile::new();
325 cs.write_headers(&mut outfile, &[]).unwrap();
326 for y in 0..height as usize {
327 let start = y * width as usize;
328 let end = start + width as usize;
329 cs.exchange(&pixels[start..end], 0).unwrap();
330 }
331 cs.flush(&mut outfile).unwrap();
332
333 let encoded = outfile.get_data().to_vec();
334 let mut infile = MemInfile::new(&encoded);
335 let mut cs2 = Codestream::new();
336 cs2.read_headers(&mut infile).unwrap();
337 cs2.create(&mut infile).unwrap();
338
339 for y in 0..height as usize {
340 let line = cs2.pull(0).expect("expected decoded line");
341 for x in 0..width as usize {
342 if line[x] != pixels[y * width as usize + x] {
343 panic!(
344 "Mismatch at ({},{}): expected {}, got {}",
345 x,
346 y,
347 pixels[y * width as usize + x],
348 line[x]
349 );
350 }
351 }
352 }
353 }
354
355 #[test]
356 fn debug_no_dwt_33x33_packet_preserves_block_bytes() {
357 let width = 33u32;
358 let height = 33u32;
359 let mut image = Vec::with_capacity((width * height) as usize);
360 for y in 0..height {
361 for x in 0..width {
362 image.push(((3 * x + 7 * y) & 0xFF) as i32);
363 }
364 }
365
366 let kmax = 8u32;
367 let shift = 31 - kmax;
368 let missing_msbs = kmax - 1;
369 let stride = 64u32;
370 let nominal_h = 64u32;
371 let mut direct_samples = vec![0u32; (stride * nominal_h) as usize];
372 for y in 0..height as usize {
373 for x in 0..width as usize {
374 let pixel = image[y * width as usize + x];
375 let centered = pixel - 128;
376 let sign = if centered < 0 { 0x8000_0000 } else { 0 };
377 let mag = centered.unsigned_abs() << shift;
378 direct_samples[y * stride as usize + x] = sign | mag;
379 }
380 }
381 let direct = encode_codeblock32(&direct_samples, missing_msbs, 1, width, height, stride)
382 .expect("direct block encode failed");
383 let direct_bytes = direct.data[..direct.length as usize].to_vec();
384
385 let mut cs = Codestream::new();
386 cs.access_siz_mut()
387 .set_image_extent(Point::new(width, height));
388 cs.access_siz_mut().set_num_components(1);
389 cs.access_siz_mut()
390 .set_comp_info(0, Point::new(1, 1), 8, false);
391 cs.access_siz_mut().set_tile_size(Size::new(width, height));
392 cs.access_cod_mut().set_num_decomposition(0);
393 cs.access_cod_mut().set_reversible(true);
394 cs.access_cod_mut().set_color_transform(false);
395 cs.set_planar(0);
396
397 let mut outfile = MemOutfile::new();
398 cs.write_headers(&mut outfile, &[]).unwrap();
399 for y in 0..height as usize {
400 let start = y * width as usize;
401 let end = start + width as usize;
402 cs.exchange(&image[start..end], 0).unwrap();
403 }
404 cs.flush(&mut outfile).unwrap();
405
406 let enc_cb =
407 &cs.debug_inner().tiles[0].tile_comps[0].resolutions[0].subbands[0].codeblocks[0];
408 let enc_state = enc_cb.enc_state.as_ref().expect("missing encode state");
409 assert_eq!(enc_state.pass1_bytes as usize, direct_bytes.len());
410 assert_eq!(enc_cb.coded_data, direct_bytes);
411
412 let encoded = outfile.get_data().to_vec();
413 let mut infile = MemInfile::new(&encoded);
414 let mut dec = Codestream::new();
415 dec.read_headers(&mut infile).unwrap();
416 dec.create(&mut infile).unwrap();
417
418 let dec_cb =
419 &dec.debug_inner().tiles[0].tile_comps[0].resolutions[0].subbands[0].codeblocks[0];
420 let dec_state = dec_cb.dec_state.as_ref().expect("missing decode state");
421 assert_eq!(dec_state.pass1_len as usize, direct_bytes.len());
422 assert_eq!(dec_cb.coded_data, direct_bytes);
423
424 let mut decoded = Vec::with_capacity((width * height) as usize);
425 for _ in 0..height {
426 decoded.extend(dec.pull(0).expect("missing decoded line"));
427 }
428 assert_eq!(decoded, image);
429 }
430
431 #[test]
432 fn debug_d2_subband_coeffs_survive_roundtrip() {
433 let width = 64u32;
434 let height = 64u32;
435 let mut image = Vec::with_capacity((width * height) as usize);
436 for y in 0..height {
437 for x in 0..width {
438 image.push(((3 * x + 7 * y) & 0xFF) as i32);
439 }
440 }
441
442 let mut cs = Codestream::new();
443 cs.access_siz_mut()
444 .set_image_extent(Point::new(width, height));
445 cs.access_siz_mut().set_num_components(1);
446 cs.access_siz_mut()
447 .set_comp_info(0, Point::new(1, 1), 8, false);
448 cs.access_siz_mut().set_tile_size(Size::new(width, height));
449 cs.access_cod_mut().set_num_decomposition(2);
450 cs.access_cod_mut().set_reversible(true);
451 cs.access_cod_mut().set_color_transform(false);
452 cs.set_planar(0);
453
454 let mut outfile = MemOutfile::new();
455 cs.write_headers(&mut outfile, &[]).unwrap();
456 for y in 0..height as usize {
457 let start = y * width as usize;
458 let end = start + width as usize;
459 cs.exchange(&image[start..end], 0).unwrap();
460 }
461 cs.flush(&mut outfile).unwrap();
462
463 let enc_tc = &cs.debug_inner().tiles[0].tile_comps[0];
464 let enc_coeffs: Vec<Vec<Vec<i32>>> = enc_tc
465 .resolutions
466 .iter()
467 .map(|res| res.subbands.iter().map(|sb| sb.coeffs.clone()).collect())
468 .collect();
469
470 let encoded = outfile.get_data().to_vec();
471 let mut infile = MemInfile::new(&encoded);
472 let mut dec = Codestream::new();
473 dec.read_headers(&mut infile).unwrap();
474 dec.create(&mut infile).unwrap();
475
476 let dec_tc = &dec.debug_inner().tiles[0].tile_comps[0];
477 for (res_idx, (enc_res, dec_res)) in enc_coeffs.iter().zip(&dec_tc.resolutions).enumerate()
478 {
479 for (sb_idx, (enc_sb, dec_sb)) in enc_res.iter().zip(&dec_res.subbands).enumerate() {
480 assert_eq!(
481 enc_sb, &dec_sb.coeffs,
482 "subband mismatch at resolution {res_idx}, subband {sb_idx}"
483 );
484 }
485 }
486 }
487
488 #[test]
489 fn debug_tiled_d5_encoder_codeblocks_are_decodable() {
490 let width = 256u32;
491 let height = 256u32;
492 let mut components = (0..3)
493 .map(|_| Vec::<i32>::with_capacity((width * height) as usize))
494 .collect::<Vec<_>>();
495 for y in 0..height {
496 for x in 0..width {
497 components[0].push(((x * 255) / width.max(1)) as i32);
498 components[1].push(((y * 255) / height.max(1)) as i32);
499 components[2].push((((x + y) * 127) / (width + height).max(1)) as i32);
500 }
501 }
502
503 let mut cs = Codestream::new();
504 cs.access_siz_mut()
505 .set_image_extent(Point::new(width, height));
506 cs.access_siz_mut().set_tile_size(Size::new(33, 33));
507 cs.access_siz_mut().set_num_components(3);
508 for c in 0..3 {
509 cs.access_siz_mut()
510 .set_comp_info(c, Point::new(1, 1), 8, false);
511 }
512 cs.access_cod_mut().set_num_decomposition(5);
513 cs.access_cod_mut().set_reversible(true);
514 cs.access_cod_mut().set_color_transform(true);
515
516 let mut outfile = MemOutfile::new();
517 cs.write_headers(&mut outfile, &[]).unwrap();
518 for y in 0..height as usize {
519 let start = y * width as usize;
520 let end = start + width as usize;
521 for (c, comp) in components.iter().enumerate() {
522 cs.exchange(&comp[start..end], c as u32).unwrap();
523 }
524 }
525 cs.flush(&mut outfile).unwrap();
526
527 for (tile_idx, tile) in cs.debug_inner().tiles.iter().enumerate() {
528 for (comp_idx, tc) in tile.tile_comps.iter().enumerate() {
529 for (res_idx, res) in tc.resolutions.iter().enumerate() {
530 for (sb_idx, sb) in res.subbands.iter().enumerate() {
531 for (cb_idx, cb) in sb.codeblocks.iter().enumerate() {
532 let Some(enc) = cb.enc_state.as_ref() else {
533 continue;
534 };
535 if !enc.has_data || enc.num_passes == 0 {
536 continue;
537 }
538
539 let mut coded = cb.coded_data.clone();
540 let nominal_w = 1u32 << cb.log_block_dims.w;
541 let nominal_h = 1u32 << cb.log_block_dims.h;
542 let stride = (nominal_w + 7) & !7;
543 let mut decoded = vec![0u32; (stride * nominal_h) as usize];
544 let result =
545 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
546 decode_codeblock32(
547 &mut coded,
548 &mut decoded,
549 enc.missing_msbs,
550 enc.num_passes,
551 enc.pass1_bytes,
552 enc.pass2_bytes,
553 cb.width(),
554 cb.height(),
555 stride,
556 false,
557 )
558 }));
559
560 match result {
561 Ok(Ok(true)) | Ok(Ok(false)) => {}
562 Ok(Err(err)) => panic!(
563 "decode error for tile={tile_idx} comp={comp_idx} res={res_idx} sb={sb_idx} cb={cb_idx} rect={:?} passes={} p1={} p2={} mmsbs={}: {err:?}",
564 cb.cb_rect,
565 enc.num_passes,
566 enc.pass1_bytes,
567 enc.pass2_bytes,
568 enc.missing_msbs,
569 ),
570 Err(_) => panic!(
571 "decode panic for tile={tile_idx} comp={comp_idx} res={res_idx} sb={sb_idx} cb={cb_idx} rect={:?} passes={} p1={} p2={} mmsbs={} bytes={:02X?}",
572 cb.cb_rect,
573 enc.num_passes,
574 enc.pass1_bytes,
575 enc.pass2_bytes,
576 enc.missing_msbs,
577 cb.coded_data,
578 ),
579 }
580 }
581 }
582 }
583 }
584 }
585 }
586
587 #[test]
588 fn debug_rev53_4x1024_encoder_codeblocks_are_decodable() {
589 let width = 256u32;
590 let height = 256u32;
591 let mut components = (0..3)
592 .map(|_| Vec::<i32>::with_capacity((width * height) as usize))
593 .collect::<Vec<_>>();
594 for y in 0..height {
595 for x in 0..width {
596 components[0].push(((x * 255) / width.max(1)) as i32);
597 components[1].push(((y * 255) / height.max(1)) as i32);
598 components[2].push((((x + y) * 127) / (width + height).max(1)) as i32);
599 }
600 }
601
602 let mut cs = Codestream::new();
603 cs.access_siz_mut()
604 .set_image_extent(Point::new(width, height));
605 cs.access_siz_mut().set_tile_size(Size::new(width, height));
606 cs.access_siz_mut().set_num_components(3);
607 for c in 0..3 {
608 cs.access_siz_mut()
609 .set_comp_info(c, Point::new(1, 1), 8, false);
610 }
611 cs.access_cod_mut().set_num_decomposition(5);
612 cs.access_cod_mut().set_reversible(true);
613 cs.access_cod_mut().set_color_transform(true);
614 cs.access_cod_mut().set_block_dims(4, 1024);
615
616 let mut outfile = MemOutfile::new();
617 cs.write_headers(&mut outfile, &[]).unwrap();
618 for y in 0..height as usize {
619 let start = y * width as usize;
620 let end = start + width as usize;
621 for (c, comp) in components.iter().enumerate() {
622 cs.exchange(&comp[start..end], c as u32).unwrap();
623 }
624 }
625 cs.flush(&mut outfile).unwrap();
626
627 for (tile_idx, tile) in cs.debug_inner().tiles.iter().enumerate() {
628 for (comp_idx, tc) in tile.tile_comps.iter().enumerate() {
629 for (res_idx, res) in tc.resolutions.iter().enumerate() {
630 for (sb_idx, sb) in res.subbands.iter().enumerate() {
631 for (cb_idx, cb) in sb.codeblocks.iter().enumerate() {
632 let Some(enc) = cb.enc_state.as_ref() else {
633 continue;
634 };
635 if !enc.has_data || enc.num_passes == 0 {
636 continue;
637 }
638
639 let nominal_w = 1u32 << cb.log_block_dims.w;
640 let nominal_h = 1u32 << cb.log_block_dims.h;
641 let stride = (nominal_w + 7) & !7;
642 let mut coded = cb.coded_data.clone();
643 let mut decoded = vec![0u32; (stride * nominal_h) as usize];
644 let result =
645 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
646 decode_codeblock32(
647 &mut coded,
648 &mut decoded,
649 enc.missing_msbs,
650 enc.num_passes,
651 enc.pass1_bytes,
652 enc.pass2_bytes,
653 cb.width(),
654 cb.height(),
655 stride,
656 false,
657 )
658 }));
659
660 match result {
661 Ok(Ok(true)) | Ok(Ok(false)) => {}
662 Ok(Err(err)) => panic!(
663 "decode error for tile={tile_idx} comp={comp_idx} res={res_idx} sb={sb_idx} cb={cb_idx} rect={:?} log_dims={:?} passes={} p1={} p2={} mmsbs={} bytes={:02X?}: {err:?}",
664 cb.cb_rect,
665 cb.log_block_dims,
666 enc.num_passes,
667 enc.pass1_bytes,
668 enc.pass2_bytes,
669 enc.missing_msbs,
670 cb.coded_data,
671 ),
672 Err(_) => panic!(
673 "decode panic for tile={tile_idx} comp={comp_idx} res={res_idx} sb={sb_idx} cb={cb_idx} rect={:?} log_dims={:?} passes={} p1={} p2={} mmsbs={} bytes={:02X?}",
674 cb.cb_rect,
675 cb.log_block_dims,
676 enc.num_passes,
677 enc.pass1_bytes,
678 enc.pass2_bytes,
679 enc.missing_msbs,
680 cb.coded_data,
681 ),
682 }
683 }
684 }
685 }
686 }
687 }
688 }
689
690 #[test]
691 fn debug_rev53_4x1024_packet_preserves_codeblocks() {
692 let width = 256u32;
693 let height = 256u32;
694 let mut components = (0..3)
695 .map(|_| Vec::<i32>::with_capacity((width * height) as usize))
696 .collect::<Vec<_>>();
697 for y in 0..height {
698 for x in 0..width {
699 components[0].push(((x * 255) / width.max(1)) as i32);
700 components[1].push(((y * 255) / height.max(1)) as i32);
701 components[2].push((((x + y) * 127) / (width + height).max(1)) as i32);
702 }
703 }
704
705 let mut cs = Codestream::new();
706 cs.access_siz_mut()
707 .set_image_extent(Point::new(width, height));
708 cs.access_siz_mut().set_tile_size(Size::new(width, height));
709 cs.access_siz_mut().set_num_components(3);
710 for c in 0..3 {
711 cs.access_siz_mut()
712 .set_comp_info(c, Point::new(1, 1), 8, false);
713 }
714 cs.access_cod_mut().set_num_decomposition(5);
715 cs.access_cod_mut().set_reversible(true);
716 cs.access_cod_mut().set_color_transform(true);
717 cs.access_cod_mut().set_block_dims(4, 1024);
718
719 let mut outfile = MemOutfile::new();
720 cs.write_headers(&mut outfile, &[]).unwrap();
721 for y in 0..height as usize {
722 let start = y * width as usize;
723 let end = start + width as usize;
724 for (c, comp) in components.iter().enumerate() {
725 cs.exchange(&comp[start..end], c as u32).unwrap();
726 }
727 }
728 cs.flush(&mut outfile).unwrap();
729
730 let encoded = outfile.get_data().to_vec();
731 let mut infile = MemInfile::new(&encoded);
732 let mut dec = Codestream::new();
733 dec.read_headers(&mut infile).unwrap();
734 dec.create(&mut infile).unwrap();
735
736 for (tile_idx, (enc_tile, dec_tile)) in cs
737 .debug_inner()
738 .tiles
739 .iter()
740 .zip(&dec.debug_inner().tiles)
741 .enumerate()
742 {
743 for (comp_idx, (enc_tc, dec_tc)) in enc_tile
744 .tile_comps
745 .iter()
746 .zip(&dec_tile.tile_comps)
747 .enumerate()
748 {
749 for (res_idx, (enc_res, dec_res)) in enc_tc
750 .resolutions
751 .iter()
752 .zip(&dec_tc.resolutions)
753 .enumerate()
754 {
755 for (sb_idx, (enc_sb, dec_sb)) in
756 enc_res.subbands.iter().zip(&dec_res.subbands).enumerate()
757 {
758 for (cb_idx, (enc_cb, dec_cb)) in
759 enc_sb.codeblocks.iter().zip(&dec_sb.codeblocks).enumerate()
760 {
761 let enc_state = enc_cb.enc_state.as_ref();
762 let dec_state = dec_cb.dec_state.as_ref();
763 match (enc_state, dec_state) {
764 (None, None) => continue,
765 (Some(enc), None) if !enc.has_data || enc.num_passes == 0 => continue,
766 (Some(enc), Some(dec_state)) => {
767 if enc.has_data != (dec_state.num_passes > 0) {
768 panic!(
769 "has_data mismatch tile={tile_idx} comp={comp_idx} res={res_idx} sb={sb_idx} cb={cb_idx} rect={:?} enc={:?} dec={:?}",
770 enc_cb.cb_rect, enc, dec_state
771 );
772 }
773 if !enc.has_data {
774 continue;
775 }
776 if enc.pass1_bytes != dec_state.pass1_len
777 || enc.pass2_bytes != dec_state.pass2_len
778 || enc.num_passes != dec_state.num_passes
779 || enc.missing_msbs != dec_state.missing_msbs
780 || enc_cb.coded_data != dec_cb.coded_data
781 {
782 panic!(
783 "packet mismatch tile={tile_idx} comp={comp_idx} res={res_idx} sb={sb_idx} cb={cb_idx} rect={:?} enc={:?} dec={:?} enc_bytes={:02X?} dec_bytes={:02X?}",
784 enc_cb.cb_rect,
785 enc,
786 dec_state,
787 enc_cb.coded_data,
788 dec_cb.coded_data,
789 );
790 }
791 }
792 _ => panic!(
793 "state presence mismatch tile={tile_idx} comp={comp_idx} res={res_idx} sb={sb_idx} cb={cb_idx} rect={:?} enc={:?} dec={:?}",
794 enc_cb.cb_rect,
795 enc_state,
796 dec_state,
797 ),
798 }
799 }
800 }
801 }
802 }
803 }
804 }
805}