1use std::f64::consts::LN_2;
6
7use crate::arch::population_count;
8use crate::error::{OjphError, Result};
9use crate::file::{InfileBase, OutfileBase};
10use crate::types::*;
11
12#[allow(dead_code)]
17pub(crate) mod markers {
18 pub const SOC: u16 = 0xFF4F;
19 pub const CAP: u16 = 0xFF50;
20 pub const SIZ: u16 = 0xFF51;
21 pub const COD: u16 = 0xFF52;
22 pub const COC: u16 = 0xFF53;
23 pub const TLM: u16 = 0xFF55;
24 pub const PRF: u16 = 0xFF56;
25 pub const PLM: u16 = 0xFF57;
26 pub const PLT: u16 = 0xFF58;
27 pub const CPF: u16 = 0xFF59;
28 pub const QCD: u16 = 0xFF5C;
29 pub const QCC: u16 = 0xFF5D;
30 pub const RGN: u16 = 0xFF5E;
31 pub const POC: u16 = 0xFF5F;
32 pub const PPM: u16 = 0xFF60;
33 pub const PPT: u16 = 0xFF61;
34 pub const CRG: u16 = 0xFF63;
35 pub const COM: u16 = 0xFF64;
36 pub const DFS: u16 = 0xFF72;
37 pub const ADS: u16 = 0xFF73;
38 pub const NLT: u16 = 0xFF76;
39 pub const ATK: u16 = 0xFF79;
40 pub const SOT: u16 = 0xFF90;
41 pub const SOP: u16 = 0xFF91;
42 pub const EPH: u16 = 0xFF92;
43 pub const SOD: u16 = 0xFF93;
44 pub const EOC: u16 = 0xFFD9;
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56#[repr(i32)]
57pub enum ProgressionOrder {
58 LRCP = 0,
60 RLCP = 1,
62 RPCL = 2,
64 PCRL = 3,
66 CPRL = 4,
68}
69
70impl ProgressionOrder {
71 pub fn from_i32(v: i32) -> Option<Self> {
73 match v {
74 0 => Some(Self::LRCP),
75 1 => Some(Self::RLCP),
76 2 => Some(Self::RPCL),
77 3 => Some(Self::PCRL),
78 4 => Some(Self::CPRL),
79 _ => None,
80 }
81 }
82
83 pub fn as_str(&self) -> &'static str {
85 match self {
86 Self::LRCP => "LRCP",
87 Self::RLCP => "RLCP",
88 Self::RPCL => "RPCL",
89 Self::PCRL => "PCRL",
90 Self::CPRL => "CPRL",
91 }
92 }
93
94 #[allow(clippy::should_implement_trait)]
96 pub fn from_str(s: &str) -> Option<Self> {
97 match s.to_uppercase().as_str() {
98 "LRCP" => Some(Self::LRCP),
99 "RLCP" => Some(Self::RLCP),
100 "RPCL" => Some(Self::RPCL),
101 "PCRL" => Some(Self::PCRL),
102 "CPRL" => Some(Self::CPRL),
103 _ => None,
104 }
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[repr(i32)]
118#[allow(dead_code)]
119pub enum ProfileNum {
120 Undefined = 0,
122 Profile0 = 1,
124 Profile1 = 2,
126 Cinema2K = 3,
128 Cinema4K = 4,
130 CinemaS2K = 5,
132 CinemaS4K = 6,
134 Broadcast = 7,
136 Imf = 8,
138}
139
140impl ProfileNum {
141 #[allow(clippy::should_implement_trait)]
143 pub fn from_str(s: &str) -> Option<Self> {
144 match s.to_uppercase().as_str() {
145 "PROFILE0" => Some(Self::Profile0),
146 "PROFILE1" => Some(Self::Profile1),
147 "CINEMA2K" => Some(Self::Cinema2K),
148 "CINEMA4K" => Some(Self::Cinema4K),
149 "CINEMAS2K" => Some(Self::CinemaS2K),
150 "CINEMAS4K" => Some(Self::CinemaS4K),
151 "BROADCAST" => Some(Self::Broadcast),
152 "IMF" => Some(Self::Imf),
153 _ => None,
154 }
155 }
156}
157
158#[allow(dead_code)]
163pub(crate) const TILEPART_NO_DIVISIONS: u32 = 0x0;
164pub(crate) const TILEPART_RESOLUTIONS: u32 = 0x1;
165pub(crate) const TILEPART_COMPONENTS: u32 = 0x2;
166#[allow(dead_code)]
167pub(crate) const TILEPART_LAYERS: u32 = 0x4;
168#[allow(dead_code)]
169pub(crate) const TILEPART_MASK: u32 = 0x3;
170
171#[inline]
176#[allow(dead_code)]
177pub(crate) fn swap_byte_u16(v: u16) -> u16 {
178 v.swap_bytes()
179}
180
181#[inline]
182#[allow(dead_code)]
183pub(crate) fn swap_byte_u32(v: u32) -> u32 {
184 v.swap_bytes()
185}
186
187#[inline]
188#[allow(dead_code)]
189pub(crate) fn swap_byte_u64(v: u64) -> u64 {
190 v.swap_bytes()
191}
192
193fn read_u8(file: &mut dyn InfileBase) -> Result<u8> {
195 let mut buf = [0u8; 1];
196 if file.read(&mut buf)? != 1 {
197 return Err(OjphError::Codec {
198 code: 0,
199 message: "unexpected EOF reading u8".into(),
200 });
201 }
202 Ok(buf[0])
203}
204
205fn read_u16_be(file: &mut dyn InfileBase) -> Result<u16> {
206 let mut buf = [0u8; 2];
207 if file.read(&mut buf)? != 2 {
208 return Err(OjphError::Codec {
209 code: 0,
210 message: "unexpected EOF reading u16".into(),
211 });
212 }
213 Ok(u16::from_be_bytes(buf))
214}
215
216fn read_u32_be(file: &mut dyn InfileBase) -> Result<u32> {
217 let mut buf = [0u8; 4];
218 if file.read(&mut buf)? != 4 {
219 return Err(OjphError::Codec {
220 code: 0,
221 message: "unexpected EOF reading u32".into(),
222 });
223 }
224 Ok(u32::from_be_bytes(buf))
225}
226
227fn write_u8(file: &mut dyn OutfileBase, v: u8) -> Result<bool> {
228 Ok(file.write(&[v])? == 1)
229}
230
231fn write_u16_be(file: &mut dyn OutfileBase, v: u16) -> Result<bool> {
232 Ok(file.write(&v.to_be_bytes())? == 2)
233}
234
235fn write_u32_be(file: &mut dyn OutfileBase, v: u32) -> Result<bool> {
236 Ok(file.write(&v.to_be_bytes())? == 4)
237}
238
239#[derive(Debug, Clone, Copy, Default)]
244pub(crate) struct SizCompInfo {
245 pub ssiz: u8,
246 pub xr_siz: u8,
247 pub yr_siz: u8,
248}
249
250#[allow(dead_code)]
255pub(crate) const RSIZ_NLT_FLAG: u16 = 0x200;
256pub(crate) const RSIZ_HT_FLAG: u16 = 0x4000;
257#[allow(dead_code)]
258pub(crate) const RSIZ_EXT_FLAG: u16 = 0x8000;
259
260#[derive(Debug)]
283pub struct ParamSiz {
284 pub(crate) lsiz: u16,
285 pub(crate) rsiz: u16,
286 pub(crate) xsiz: u32,
287 pub(crate) ysiz: u32,
288 pub(crate) xo_siz: u32,
289 pub(crate) yo_siz: u32,
290 pub(crate) xt_siz: u32,
291 pub(crate) yt_siz: u32,
292 pub(crate) xto_siz: u32,
293 pub(crate) yto_siz: u32,
294 pub(crate) csiz: u16,
295 pub(crate) components: Vec<SizCompInfo>,
296 pub(crate) skipped_resolutions: u32,
297}
298
299impl Default for ParamSiz {
300 fn default() -> Self {
301 Self {
302 lsiz: 0,
303 rsiz: RSIZ_HT_FLAG,
304 xsiz: 0,
305 ysiz: 0,
306 xo_siz: 0,
307 yo_siz: 0,
308 xt_siz: 0,
309 yt_siz: 0,
310 xto_siz: 0,
311 yto_siz: 0,
312 csiz: 0,
313 components: Vec::new(),
314 skipped_resolutions: 0,
315 }
316 }
317}
318
319impl ParamSiz {
320 pub fn set_image_extent(&mut self, extent: Point) {
322 self.xsiz = extent.x;
323 self.ysiz = extent.y;
324 }
325
326 pub fn get_image_extent(&self) -> Point {
328 Point::new(self.xsiz, self.ysiz)
329 }
330
331 pub fn set_tile_size(&mut self, s: Size) {
333 self.xt_siz = s.w;
334 self.yt_siz = s.h;
335 }
336
337 pub fn get_tile_size(&self) -> Size {
339 Size::new(self.xt_siz, self.yt_siz)
340 }
341
342 pub fn set_image_offset(&mut self, offset: Point) {
344 self.xo_siz = offset.x;
345 self.yo_siz = offset.y;
346 }
347
348 pub fn get_image_offset(&self) -> Point {
350 Point::new(self.xo_siz, self.yo_siz)
351 }
352
353 pub fn set_tile_offset(&mut self, offset: Point) {
355 self.xto_siz = offset.x;
356 self.yto_siz = offset.y;
357 }
358
359 pub fn get_tile_offset(&self) -> Point {
361 Point::new(self.xto_siz, self.yto_siz)
362 }
363
364 pub fn set_num_components(&mut self, num_comps: u32) {
366 self.csiz = num_comps as u16;
367 self.components
368 .resize(num_comps as usize, SizCompInfo::default());
369 }
370
371 pub fn get_num_components(&self) -> u16 {
373 self.csiz
374 }
375
376 pub fn set_comp_info(
384 &mut self,
385 comp_num: u32,
386 downsampling: Point,
387 bit_depth: u32,
388 is_signed: bool,
389 ) {
390 debug_assert!(comp_num < self.csiz as u32);
391 debug_assert!(downsampling.x != 0 && downsampling.y != 0);
392 let c = &mut self.components[comp_num as usize];
393 c.ssiz = (bit_depth - 1) as u8 + if is_signed { 0x80 } else { 0 };
394 c.xr_siz = downsampling.x as u8;
395 c.yr_siz = downsampling.y as u8;
396 }
397
398 pub fn get_bit_depth(&self, comp_num: u32) -> u32 {
400 debug_assert!(comp_num < self.csiz as u32);
401 ((self.components[comp_num as usize].ssiz & 0x7F) + 1) as u32
402 }
403
404 pub fn is_signed(&self, comp_num: u32) -> bool {
406 debug_assert!(comp_num < self.csiz as u32);
407 (self.components[comp_num as usize].ssiz & 0x80) != 0
408 }
409
410 pub fn get_downsampling(&self, comp_num: u32) -> Point {
412 debug_assert!(comp_num < self.csiz as u32);
413 let c = &self.components[comp_num as usize];
414 Point::new(c.xr_siz as u32, c.yr_siz as u32)
415 }
416
417 pub fn get_width(&self, comp_num: u32) -> u32 {
420 let ds = self.components[comp_num as usize].xr_siz as u32;
421 div_ceil(self.xsiz, ds) - div_ceil(self.xo_siz, ds)
422 }
423
424 pub fn get_height(&self, comp_num: u32) -> u32 {
427 let ds = self.components[comp_num as usize].yr_siz as u32;
428 div_ceil(self.ysiz, ds) - div_ceil(self.yo_siz, ds)
429 }
430
431 pub fn get_recon_width(&self, comp_num: u32) -> u32 {
433 let factor = self.get_recon_downsampling(comp_num);
434 div_ceil(self.xsiz, factor.x) - div_ceil(self.xo_siz, factor.x)
435 }
436
437 pub fn get_recon_height(&self, comp_num: u32) -> u32 {
439 let factor = self.get_recon_downsampling(comp_num);
440 div_ceil(self.ysiz, factor.y) - div_ceil(self.yo_siz, factor.y)
441 }
442
443 pub fn get_recon_downsampling(&self, comp_num: u32) -> Point {
446 let sr = self.skipped_resolutions;
447 let mut factor = Point::new(1u32 << sr, 1u32 << sr);
448 factor.x *= self.components[comp_num as usize].xr_siz as u32;
449 factor.y *= self.components[comp_num as usize].yr_siz as u32;
450 factor
451 }
452
453 pub fn set_rsiz_flag(&mut self, flag: u16) {
455 self.rsiz |= flag;
456 }
457
458 #[allow(dead_code)]
460 pub fn reset_rsiz_flag(&mut self, flag: u16) {
461 self.rsiz &= !flag;
462 }
463
464 pub fn set_skipped_resolutions(&mut self, sr: u32) {
466 self.skipped_resolutions = sr;
467 }
468
469 pub fn check_validity(&self) -> Result<()> {
476 if self.xsiz == 0 || self.ysiz == 0 || self.xt_siz == 0 || self.yt_siz == 0 {
477 return Err(OjphError::Codec {
478 code: 0x00040001,
479 message: "Image extent and/or tile size cannot be zero".into(),
480 });
481 }
482 if self.xto_siz > self.xo_siz || self.yto_siz > self.yo_siz {
483 return Err(OjphError::Codec {
484 code: 0x00040002,
485 message: "Tile offset has to be smaller than the image offset".into(),
486 });
487 }
488 if self.xt_siz + self.xto_siz <= self.xo_siz || self.yt_siz + self.yto_siz <= self.yo_siz {
489 return Err(OjphError::Codec {
490 code: 0x00040003,
491 message: "The top left tile must intersect with the image".into(),
492 });
493 }
494 if self.xsiz <= self.xo_siz || self.ysiz <= self.yo_siz {
495 return Err(OjphError::Codec {
496 code: 0x00040004,
497 message: "Image extent must be larger than image offset".into(),
498 });
499 }
500 Ok(())
501 }
502
503 pub fn write(&mut self, file: &mut dyn OutfileBase) -> Result<bool> {
504 self.lsiz = 38 + 3 * self.csiz;
505 let mut ok = true;
506 ok &= write_u16_be(file, markers::SIZ)?;
507 ok &= write_u16_be(file, self.lsiz)?;
508 ok &= write_u16_be(file, self.rsiz)?;
509 ok &= write_u32_be(file, self.xsiz)?;
510 ok &= write_u32_be(file, self.ysiz)?;
511 ok &= write_u32_be(file, self.xo_siz)?;
512 ok &= write_u32_be(file, self.yo_siz)?;
513 ok &= write_u32_be(file, self.xt_siz)?;
514 ok &= write_u32_be(file, self.yt_siz)?;
515 ok &= write_u32_be(file, self.xto_siz)?;
516 ok &= write_u32_be(file, self.yto_siz)?;
517 ok &= write_u16_be(file, self.csiz)?;
518 for c in &self.components {
519 ok &= write_u8(file, c.ssiz)?;
520 ok &= write_u8(file, c.xr_siz)?;
521 ok &= write_u8(file, c.yr_siz)?;
522 }
523 Ok(ok)
524 }
525
526 pub fn read(&mut self, file: &mut dyn InfileBase) -> Result<()> {
527 self.lsiz = read_u16_be(file).map_err(|_| OjphError::Codec {
528 code: 0x00050041,
529 message: "error reading SIZ marker".into(),
530 })?;
531 if self.lsiz < 38 {
532 return Err(OjphError::Codec {
533 code: 0x00050042,
534 message: "error in SIZ marker length".into(),
535 });
536 }
537 let num_comps = ((self.lsiz - 38) / 3) as i32;
538 if self.lsiz != 38 + 3 * num_comps as u16 {
539 return Err(OjphError::Codec {
540 code: 0x00050042,
541 message: "error in SIZ marker length".into(),
542 });
543 }
544 self.rsiz = read_u16_be(file).map_err(|_| OjphError::Codec {
545 code: 0x00050043,
546 message: "error reading SIZ marker".into(),
547 })?;
548 if (self.rsiz & 0x4000) == 0 {
549 return Err(OjphError::Codec {
550 code: 0x00050044,
551 message: "Rsiz bit 14 is not set (this is not a JPH file)".into(),
552 });
553 }
554 self.xsiz = read_u32_be(file).map_err(|_| OjphError::Codec {
555 code: 0x00050045,
556 message: "error reading SIZ marker".into(),
557 })?;
558 self.ysiz = read_u32_be(file).map_err(|_| OjphError::Codec {
559 code: 0x00050046,
560 message: "error reading SIZ marker".into(),
561 })?;
562 let xo = read_u32_be(file).map_err(|_| OjphError::Codec {
563 code: 0x00050047,
564 message: "error reading SIZ marker".into(),
565 })?;
566 let yo = read_u32_be(file).map_err(|_| OjphError::Codec {
567 code: 0x00050048,
568 message: "error reading SIZ marker".into(),
569 })?;
570 self.set_image_offset(Point::new(xo, yo));
571 let xtw = read_u32_be(file).map_err(|_| OjphError::Codec {
572 code: 0x00050049,
573 message: "error reading SIZ marker".into(),
574 })?;
575 let yth = read_u32_be(file).map_err(|_| OjphError::Codec {
576 code: 0x0005004A,
577 message: "error reading SIZ marker".into(),
578 })?;
579 self.set_tile_size(Size::new(xtw, yth));
580 let xto = read_u32_be(file).map_err(|_| OjphError::Codec {
581 code: 0x0005004B,
582 message: "error reading SIZ marker".into(),
583 })?;
584 let yto = read_u32_be(file).map_err(|_| OjphError::Codec {
585 code: 0x0005004C,
586 message: "error reading SIZ marker".into(),
587 })?;
588 self.set_tile_offset(Point::new(xto, yto));
589 self.csiz = read_u16_be(file).map_err(|_| OjphError::Codec {
590 code: 0x0005004D,
591 message: "error reading SIZ marker".into(),
592 })?;
593 if self.csiz as i32 != num_comps {
594 return Err(OjphError::Codec {
595 code: 0x0005004E,
596 message: "Csiz does not match the SIZ marker size".into(),
597 });
598 }
599 self.set_num_components(self.csiz as u32);
600 for c in 0..self.csiz as usize {
601 self.components[c].ssiz = read_u8(file).map_err(|_| OjphError::Codec {
602 code: 0x00050051,
603 message: "error reading SIZ marker".into(),
604 })?;
605 self.components[c].xr_siz = read_u8(file).map_err(|_| OjphError::Codec {
606 code: 0x00050052,
607 message: "error reading SIZ marker".into(),
608 })?;
609 self.components[c].yr_siz = read_u8(file).map_err(|_| OjphError::Codec {
610 code: 0x00050053,
611 message: "error reading SIZ marker".into(),
612 })?;
613 if (self.components[c].ssiz & 0x7F) > 37 {
614 return Err(OjphError::Codec {
615 code: 0x00050054,
616 message: format!("Wrong SIZ-SSiz value of {}", self.components[c].ssiz),
617 });
618 }
619 if self.components[c].xr_siz == 0 {
620 return Err(OjphError::Codec {
621 code: 0x00050055,
622 message: format!("Wrong SIZ-XRsiz value of {}", self.components[c].xr_siz),
623 });
624 }
625 if self.components[c].yr_siz == 0 {
626 return Err(OjphError::Codec {
627 code: 0x00050056,
628 message: format!("Wrong SIZ-YRsiz value of {}", self.components[c].yr_siz),
629 });
630 }
631 }
632 self.check_validity()?;
633 Ok(())
634 }
635}
636
637#[derive(Debug, Clone)]
642pub(crate) struct CodSPcod {
643 pub num_decomp: u8,
644 pub block_width: u8,
645 pub block_height: u8,
646 pub block_style: u8,
647 pub wavelet_trans: u8,
648 pub precinct_size: [u8; 33],
649}
650
651impl Default for CodSPcod {
652 fn default() -> Self {
653 Self {
654 num_decomp: 5,
655 block_width: 4, block_height: 4, block_style: 0x40, wavelet_trans: 0, precinct_size: [0; 33],
660 }
661 }
662}
663
664impl CodSPcod {
665 pub fn get_log_block_dims(&self) -> Size {
666 Size::new(
667 (self.block_width + 2) as u32,
668 (self.block_height + 2) as u32,
669 )
670 }
671
672 pub fn get_block_dims(&self) -> Size {
673 let t = self.get_log_block_dims();
674 Size::new(1 << t.w, 1 << t.h)
675 }
676
677 pub fn get_log_precinct_size(&self, res_num: u32) -> Size {
678 let p = self.precinct_size[res_num as usize];
679 Size::new((p & 0xF) as u32, (p >> 4) as u32)
680 }
681}
682
683#[derive(Debug, Clone)]
685pub(crate) struct CodSGcod {
686 pub prog_order: u8,
687 pub num_layers: u16,
688 pub mc_trans: u8,
689}
690
691impl Default for CodSGcod {
692 fn default() -> Self {
693 Self {
694 prog_order: ProgressionOrder::RPCL as u8,
695 num_layers: 1,
696 mc_trans: 0,
697 }
698 }
699}
700
701#[allow(dead_code)]
706pub(crate) const VERT_CAUSAL_MODE: u8 = 0x8;
707pub(crate) const HT_MODE: u8 = 0x40;
708
709pub(crate) const DWT_IRV97: u8 = 0;
711pub(crate) const DWT_REV53: u8 = 1;
712
713#[derive(Debug, Clone, Copy, PartialEq, Eq)]
715pub(crate) enum CodType {
716 #[allow(dead_code)]
717 Undefined,
718 CodMain,
719 CocMain,
720}
721
722pub(crate) const COD_DEFAULT_COMP: u16 = 65535;
727#[allow(dead_code)]
728pub(crate) const COD_UNKNOWN_COMP: u16 = 65534;
729
730#[derive(Debug, Clone)]
736pub struct ParamCod {
737 pub(crate) cod_type: CodType,
738 pub(crate) lcod: u16,
739 pub(crate) scod: u8,
740 pub(crate) sg_cod: CodSGcod,
741 pub(crate) sp_cod: CodSPcod,
742 pub(crate) comp_idx: u16,
743 pub(crate) children: Vec<ParamCod>,
745}
746
747impl Default for ParamCod {
748 fn default() -> Self {
749 Self {
750 cod_type: CodType::CodMain,
751 lcod: 0,
752 scod: 0,
753 sg_cod: CodSGcod::default(),
754 sp_cod: CodSPcod::default(),
755 comp_idx: COD_DEFAULT_COMP,
756 children: Vec::new(),
757 }
758 }
759}
760
761impl ParamCod {
762 pub fn new_coc(comp_idx: u16) -> Self {
765 Self {
766 cod_type: CodType::CocMain,
767 lcod: 0,
768 scod: 0,
769 sg_cod: CodSGcod::default(),
770 sp_cod: CodSPcod::default(),
771 comp_idx,
772 children: Vec::new(),
773 }
774 }
775
776 pub fn set_reversible(&mut self, reversible: bool) {
779 self.sp_cod.wavelet_trans = if reversible { DWT_REV53 } else { DWT_IRV97 };
780 }
781
782 pub fn set_color_transform(&mut self, ct: bool) {
787 self.sg_cod.mc_trans = if ct { 1 } else { 0 };
788 }
789
790 pub fn set_num_decomposition(&mut self, num: u32) {
792 self.sp_cod.num_decomp = num as u8;
793 }
794
795 pub fn set_block_dims(&mut self, width: u32, height: u32) {
798 self.sp_cod.block_width = (width as f64).log2() as u8 - 2;
799 self.sp_cod.block_height = (height as f64).log2() as u8 - 2;
800 }
801
802 pub fn set_precinct_size(&mut self, num_levels: i32, sizes: &[Size]) {
804 if num_levels > 0 && !sizes.is_empty() {
805 self.scod |= 1;
806 for i in 0..=self.sp_cod.num_decomp as usize {
807 let idx = i.min(sizes.len() - 1);
808 let w = (sizes[idx].w as f64).log2() as u8;
809 let h = (sizes[idx].h as f64).log2() as u8;
810 self.sp_cod.precinct_size[i] = w | (h << 4);
811 }
812 }
813 }
814
815 pub fn set_progression_order(&mut self, name: &str) -> Result<()> {
822 match ProgressionOrder::from_str(name) {
823 Some(po) => {
824 self.sg_cod.prog_order = po as u8;
825 Ok(())
826 }
827 None => Err(OjphError::InvalidParam(format!(
828 "unknown progression order: {}",
829 name
830 ))),
831 }
832 }
833
834 pub fn get_num_decompositions(&self) -> u8 {
836 if self.cod_type == CodType::CocMain && self.is_dfs_defined() {
837 self.sp_cod.num_decomp & 0x7F
838 } else {
839 self.sp_cod.num_decomp
840 }
841 }
842
843 pub fn get_block_dims(&self) -> Size {
845 self.sp_cod.get_block_dims()
846 }
847
848 pub fn get_log_block_dims(&self) -> Size {
850 self.sp_cod.get_log_block_dims()
851 }
852
853 pub fn get_wavelet_kern(&self) -> u8 {
855 self.sp_cod.wavelet_trans
856 }
857
858 pub fn is_reversible(&self) -> bool {
860 self.sp_cod.wavelet_trans == DWT_REV53
861 }
862
863 pub fn is_employing_color_transform(&self) -> bool {
865 self.sg_cod.mc_trans == 1
866 }
867
868 pub fn get_precinct_size(&self, res_num: u32) -> Size {
870 let t = self.get_log_precinct_size(res_num);
871 Size::new(1 << t.w, 1 << t.h)
872 }
873
874 pub fn get_log_precinct_size(&self, res_num: u32) -> Size {
876 if self.scod & 1 != 0 {
877 self.sp_cod.get_log_precinct_size(res_num)
878 } else {
879 Size::new(15, 15)
880 }
881 }
882
883 pub fn packets_may_use_sop(&self) -> bool {
885 if self.cod_type == CodType::CodMain {
886 (self.scod & 2) == 2
887 } else {
888 false
889 }
890 }
891
892 pub fn packets_use_eph(&self) -> bool {
894 if self.cod_type == CodType::CodMain {
895 (self.scod & 4) == 4
896 } else {
897 false
898 }
899 }
900
901 pub fn get_block_vertical_causality(&self) -> bool {
903 (self.sp_cod.block_style & VERT_CAUSAL_MODE) != 0
904 }
905
906 pub fn get_progression_order(&self) -> i32 {
908 self.sg_cod.prog_order as i32
909 }
910
911 pub fn get_progression_order_as_string(&self) -> &'static str {
913 ProgressionOrder::from_i32(self.sg_cod.prog_order as i32)
914 .unwrap_or(ProgressionOrder::LRCP)
915 .as_str()
916 }
917
918 pub fn get_num_layers(&self) -> i32 {
920 self.sg_cod.num_layers as i32
921 }
922
923 pub fn is_dfs_defined(&self) -> bool {
925 (self.sp_cod.num_decomp & 0x80) != 0
926 }
927
928 #[allow(dead_code)]
930 pub fn get_dfs_index(&self) -> u16 {
931 (self.sp_cod.num_decomp & 0xF) as u16
932 }
933
934 pub fn get_comp_idx(&self) -> u16 {
936 self.comp_idx
937 }
938
939 pub fn get_coc(&self, comp_idx: u32) -> &ParamCod {
942 for child in &self.children {
943 if child.comp_idx == comp_idx as u16 {
944 return child;
945 }
946 }
947 self
948 }
949
950 pub fn get_coc_mut(&mut self, comp_idx: u32) -> &mut ParamCod {
952 for i in 0..self.children.len() {
953 if self.children[i].comp_idx == comp_idx as u16 {
954 return &mut self.children[i];
955 }
956 }
957 self
958 }
959
960 pub fn add_coc(&mut self, comp_idx: u32) -> &mut ParamCod {
962 let coc = ParamCod::new_coc(comp_idx as u16);
963 self.children.push(coc);
964 self.children.last_mut().unwrap()
965 }
966
967 pub fn check_validity(&self, siz: &ParamSiz) -> Result<()> {
968 debug_assert!(self.cod_type == CodType::CodMain);
969 let num_comps = siz.get_num_components();
970 if self.sg_cod.mc_trans == 1 && num_comps < 3 {
971 return Err(OjphError::Codec {
972 code: 0x00040011,
973 message: "color transform needs 3+ components".into(),
974 });
975 }
976 if self.sg_cod.mc_trans == 1 {
977 let p = siz.get_downsampling(0);
978 let bd = siz.get_bit_depth(0);
979 let s = siz.is_signed(0);
980 for i in 1..3u32 {
981 let pi = siz.get_downsampling(i);
982 if p.x != pi.x || p.y != pi.y {
983 return Err(OjphError::Codec {
984 code: 0x00040012,
985 message:
986 "color transform requires same downsampling for first 3 components"
987 .into(),
988 });
989 }
990 if bd != siz.get_bit_depth(i) {
991 return Err(OjphError::Codec {
992 code: 0x00040014,
993 message: "color transform requires same bit depth for first 3 components"
994 .into(),
995 });
996 }
997 if s != siz.is_signed(i) {
998 return Err(OjphError::Codec {
999 code: 0x00040015,
1000 message: "color transform requires same signedness for first 3 components"
1001 .into(),
1002 });
1003 }
1004 }
1005 }
1006 Ok(())
1007 }
1008
1009 pub fn write(&mut self, file: &mut dyn OutfileBase) -> Result<bool> {
1010 debug_assert!(self.cod_type == CodType::CodMain);
1011 self.lcod = 12;
1012 if self.scod & 1 != 0 {
1013 self.lcod += 1 + self.sp_cod.num_decomp as u16;
1014 }
1015 let mut ok = true;
1016 ok &= write_u16_be(file, markers::COD)?;
1017 ok &= write_u16_be(file, self.lcod)?;
1018 ok &= write_u8(file, self.scod)?;
1019 ok &= write_u8(file, self.sg_cod.prog_order)?;
1020 ok &= write_u16_be(file, self.sg_cod.num_layers)?;
1021 ok &= write_u8(file, self.sg_cod.mc_trans)?;
1022 ok &= write_u8(file, self.sp_cod.num_decomp)?;
1023 ok &= write_u8(file, self.sp_cod.block_width)?;
1024 ok &= write_u8(file, self.sp_cod.block_height)?;
1025 ok &= write_u8(file, self.sp_cod.block_style)?;
1026 ok &= write_u8(file, self.sp_cod.wavelet_trans)?;
1027 if self.scod & 1 != 0 {
1028 for i in 0..=self.sp_cod.num_decomp as usize {
1029 ok &= write_u8(file, self.sp_cod.precinct_size[i])?;
1030 }
1031 }
1032 Ok(ok)
1033 }
1034
1035 pub fn write_coc(&self, file: &mut dyn OutfileBase, num_comps: u32) -> Result<bool> {
1036 let mut ok = true;
1037 for child in &self.children {
1038 if (child.comp_idx as u32) < num_comps {
1039 ok &= child.internal_write_coc(file, num_comps)?;
1040 }
1041 }
1042 Ok(ok)
1043 }
1044
1045 fn internal_write_coc(&self, file: &mut dyn OutfileBase, num_comps: u32) -> Result<bool> {
1046 let lcod: u16 = if num_comps < 257 { 9 } else { 10 }
1047 + if self.scod & 1 != 0 {
1048 1 + self.sp_cod.num_decomp as u16
1049 } else {
1050 0
1051 };
1052 let mut ok = true;
1053 ok &= write_u16_be(file, markers::COC)?;
1054 ok &= write_u16_be(file, lcod)?;
1055 if num_comps < 257 {
1056 ok &= write_u8(file, self.comp_idx as u8)?;
1057 } else {
1058 ok &= write_u16_be(file, self.comp_idx)?;
1059 }
1060 ok &= write_u8(file, self.scod)?;
1061 ok &= write_u8(file, self.sp_cod.num_decomp)?;
1062 ok &= write_u8(file, self.sp_cod.block_width)?;
1063 ok &= write_u8(file, self.sp_cod.block_height)?;
1064 ok &= write_u8(file, self.sp_cod.block_style)?;
1065 ok &= write_u8(file, self.sp_cod.wavelet_trans)?;
1066 if self.scod & 1 != 0 {
1067 for i in 0..=self.sp_cod.num_decomp as usize {
1068 ok &= write_u8(file, self.sp_cod.precinct_size[i])?;
1069 }
1070 }
1071 Ok(ok)
1072 }
1073
1074 pub fn read(&mut self, file: &mut dyn InfileBase) -> Result<()> {
1075 self.lcod = read_u16_be(file).map_err(|_| OjphError::Codec {
1076 code: 0x00050071,
1077 message: "error reading COD segment".into(),
1078 })?;
1079 self.scod = read_u8(file).map_err(|_| OjphError::Codec {
1080 code: 0x00050072,
1081 message: "error reading COD segment".into(),
1082 })?;
1083 self.sg_cod.prog_order = read_u8(file).map_err(|_| OjphError::Codec {
1084 code: 0x00050073,
1085 message: "error reading COD segment".into(),
1086 })?;
1087 self.sg_cod.num_layers = read_u16_be(file).map_err(|_| OjphError::Codec {
1088 code: 0x00050074,
1089 message: "error reading COD segment".into(),
1090 })?;
1091 self.sg_cod.mc_trans = read_u8(file).map_err(|_| OjphError::Codec {
1092 code: 0x00050075,
1093 message: "error reading COD segment".into(),
1094 })?;
1095 self.sp_cod.num_decomp = read_u8(file).map_err(|_| OjphError::Codec {
1096 code: 0x00050076,
1097 message: "error reading COD segment".into(),
1098 })?;
1099 self.sp_cod.block_width = read_u8(file).map_err(|_| OjphError::Codec {
1100 code: 0x00050077,
1101 message: "error reading COD segment".into(),
1102 })?;
1103 self.sp_cod.block_height = read_u8(file).map_err(|_| OjphError::Codec {
1104 code: 0x00050078,
1105 message: "error reading COD segment".into(),
1106 })?;
1107 self.sp_cod.block_style = read_u8(file).map_err(|_| OjphError::Codec {
1108 code: 0x00050079,
1109 message: "error reading COD segment".into(),
1110 })?;
1111 self.sp_cod.wavelet_trans = read_u8(file).map_err(|_| OjphError::Codec {
1112 code: 0x0005007A,
1113 message: "error reading COD segment".into(),
1114 })?;
1115
1116 if self.get_num_decompositions() > 32
1117 || self.sp_cod.block_width > 8
1118 || self.sp_cod.block_height > 8
1119 || self.sp_cod.block_width + self.sp_cod.block_height > 8
1120 || (self.sp_cod.block_style & HT_MODE) != HT_MODE
1121 || (self.sp_cod.block_style & 0xB7) != 0x00
1122 {
1123 return Err(OjphError::Codec {
1124 code: 0x0005007D,
1125 message: "wrong settings in COD-SPcod parameter".into(),
1126 });
1127 }
1128
1129 let nd = self.get_num_decompositions();
1130 if self.scod & 1 != 0 {
1131 for i in 0..=nd as usize {
1132 self.sp_cod.precinct_size[i] = read_u8(file).map_err(|_| OjphError::Codec {
1133 code: 0x0005007B,
1134 message: "error reading COD segment".into(),
1135 })?;
1136 }
1137 }
1138 let expected = 12
1139 + if self.scod & 1 != 0 {
1140 1 + self.sp_cod.num_decomp as u16
1141 } else {
1142 0
1143 };
1144 if self.lcod != expected {
1145 return Err(OjphError::Codec {
1146 code: 0x0005007C,
1147 message: "error in COD segment length".into(),
1148 });
1149 }
1150 Ok(())
1151 }
1152
1153 pub fn read_coc(&mut self, file: &mut dyn InfileBase, num_comps: u32) -> Result<()> {
1154 self.cod_type = CodType::CocMain;
1155 self.lcod = read_u16_be(file).map_err(|_| OjphError::Codec {
1156 code: 0x00050121,
1157 message: "error reading COC segment".into(),
1158 })?;
1159 if num_comps < 257 {
1160 self.comp_idx = read_u8(file).map_err(|_| OjphError::Codec {
1161 code: 0x00050122,
1162 message: "error reading COC segment".into(),
1163 })? as u16;
1164 } else {
1165 self.comp_idx = read_u16_be(file).map_err(|_| OjphError::Codec {
1166 code: 0x00050123,
1167 message: "error reading COC segment".into(),
1168 })?;
1169 }
1170 self.scod = read_u8(file).map_err(|_| OjphError::Codec {
1171 code: 0x00050124,
1172 message: "error reading COC segment".into(),
1173 })?;
1174 self.sp_cod.num_decomp = read_u8(file).map_err(|_| OjphError::Codec {
1175 code: 0x00050125,
1176 message: "error reading COC segment".into(),
1177 })?;
1178 self.sp_cod.block_width = read_u8(file).map_err(|_| OjphError::Codec {
1179 code: 0x00050126,
1180 message: "error reading COC segment".into(),
1181 })?;
1182 self.sp_cod.block_height = read_u8(file).map_err(|_| OjphError::Codec {
1183 code: 0x00050127,
1184 message: "error reading COC segment".into(),
1185 })?;
1186 self.sp_cod.block_style = read_u8(file).map_err(|_| OjphError::Codec {
1187 code: 0x00050128,
1188 message: "error reading COC segment".into(),
1189 })?;
1190 self.sp_cod.wavelet_trans = read_u8(file).map_err(|_| OjphError::Codec {
1191 code: 0x00050129,
1192 message: "error reading COC segment".into(),
1193 })?;
1194
1195 if self.get_num_decompositions() > 32
1196 || self.sp_cod.block_width > 8
1197 || self.sp_cod.block_height > 8
1198 || (self.sp_cod.block_style & HT_MODE) != HT_MODE
1199 || (self.sp_cod.block_style & 0xB7) != 0x00
1200 {
1201 return Err(OjphError::Codec {
1202 code: 0x0005012C,
1203 message: "wrong settings in COC-SPcoc parameter".into(),
1204 });
1205 }
1206
1207 let nd = self.get_num_decompositions();
1208 if self.scod & 1 != 0 {
1209 for i in 0..=nd as usize {
1210 self.sp_cod.precinct_size[i] = read_u8(file).map_err(|_| OjphError::Codec {
1211 code: 0x0005012A,
1212 message: "error reading COC segment".into(),
1213 })?;
1214 }
1215 }
1216 let mut expected: u32 = 9 + if num_comps < 257 { 0 } else { 1 };
1217 expected += if self.scod & 1 != 0 { 1 + nd as u32 } else { 0 };
1218 if self.lcod as u32 != expected {
1219 return Err(OjphError::Codec {
1220 code: 0x0005012B,
1221 message: "error in COC segment length".into(),
1222 });
1223 }
1224 Ok(())
1225 }
1226}
1227
1228pub(crate) const QCD_DEFAULT_COMP: u16 = 65535;
1233
1234#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1235pub(crate) enum QcdType {
1236 QcdMain,
1237 QccMain,
1238}
1239
1240#[derive(Debug, Clone)]
1242pub(crate) enum SpqcdData {
1243 Reversible(Vec<u8>),
1244 Irreversible(Vec<u16>),
1245}
1246
1247impl Default for SpqcdData {
1248 fn default() -> Self {
1249 SpqcdData::Reversible(Vec::new())
1250 }
1251}
1252
1253#[derive(Debug, Clone)]
1260pub struct ParamQcd {
1261 pub(crate) qcd_type: QcdType,
1262 pub(crate) lqcd: u16,
1263 pub(crate) sqcd: u8,
1264 pub(crate) sp_qcd: SpqcdData,
1265 pub(crate) num_subbands: u32,
1266 pub(crate) base_delta: f32,
1267 pub(crate) enabled: bool,
1268 pub(crate) comp_idx: u16,
1269 pub(crate) children: Vec<ParamQcd>,
1271}
1272
1273impl Default for ParamQcd {
1274 fn default() -> Self {
1275 Self {
1276 qcd_type: QcdType::QcdMain,
1277 lqcd: 0,
1278 sqcd: 0,
1279 sp_qcd: SpqcdData::default(),
1280 num_subbands: 0,
1281 base_delta: -1.0,
1282 enabled: true,
1283 comp_idx: QCD_DEFAULT_COMP,
1284 children: Vec::new(),
1285 }
1286 }
1287}
1288
1289mod bibo_gains {
1291 pub fn get_bibo_gain_l(num_decomps: u32, _rev: bool) -> f64 {
1292 static GAINS_L: [f64; 34] = [
1293 1.0,
1294 1.5,
1295 2.0,
1296 2.75,
1297 3.6875,
1298 4.96875,
1299 6.671875,
1300 8.953125,
1301 12.015625,
1302 16.125,
1303 21.65625,
1304 29.078125,
1305 39.046875,
1306 52.4375,
1307 70.421875,
1308 94.578125,
1309 127.015625,
1310 170.53125,
1311 229.015625,
1312 307.578125,
1313 413.015625,
1314 554.578125,
1315 744.734375,
1316 1000.234375,
1317 1343.015625,
1318 1803.234375,
1319 2420.734375,
1320 3250.734375,
1321 4365.234375,
1322 5862.234375,
1323 7871.234375,
1324 10571.234375,
1325 14198.734375,
1326 19066.734375,
1327 ];
1328 GAINS_L[num_decomps.min(33) as usize]
1329 }
1330
1331 pub fn get_bibo_gain_h(num_decomps: u32, _rev: bool) -> f64 {
1332 static GAINS_H: [f64; 34] = [
1333 2.0,
1334 2.75,
1335 3.6875,
1336 4.96875,
1337 6.671875,
1338 8.953125,
1339 12.015625,
1340 16.125,
1341 21.65625,
1342 29.078125,
1343 39.046875,
1344 52.4375,
1345 70.421875,
1346 94.578125,
1347 127.015625,
1348 170.53125,
1349 229.015625,
1350 307.578125,
1351 413.015625,
1352 554.578125,
1353 744.734375,
1354 1000.234375,
1355 1343.015625,
1356 1803.234375,
1357 2420.734375,
1358 3250.734375,
1359 4365.234375,
1360 5862.234375,
1361 7871.234375,
1362 10571.234375,
1363 14198.734375,
1364 19066.734375,
1365 25606.234375,
1366 34394.234375,
1367 ];
1368 GAINS_H[num_decomps.min(33) as usize]
1369 }
1370}
1371
1372#[allow(clippy::excessive_precision)]
1374mod sqrt_energy_gains {
1375 pub fn get_gain_l(num_decomps: u32, _rev: bool) -> f32 {
1376 static GAINS_L: [f32; 34] = [
1377 1.0, 1.4021, 1.9692, 2.7665, 3.8873, 5.4645, 7.6816, 10.7968, 15.1781, 21.3348,
1378 29.9852, 42.1538, 59.2485, 83.2750, 117.0424, 164.4989, 231.2285, 325.0069, 456.8019,
1379 641.9960, 902.5009, 1268.6768, 1783.6345, 2506.8855, 3522.8044, 4952.2319, 6960.2544,
1380 9781.8203, 13748.4473, 19325.1445, 27167.4688, 38181.2344, 53668.6953, 75428.9531,
1381 ];
1382 GAINS_L[num_decomps.min(33) as usize]
1383 }
1384
1385 pub fn get_gain_h(num_decomps: u32, _rev: bool) -> f32 {
1386 static GAINS_H: [f32; 34] = [
1387 1.0, 1.4425, 2.0286, 2.8525, 4.0104, 5.6381, 7.9270, 11.1440, 15.6658, 22.0236,
1388 30.9537, 43.5079, 61.1495, 85.9350, 120.8194, 169.8440, 238.7607, 335.6575, 471.8611,
1389 663.2765, 932.3842, 1310.5906, 1842.0957, 2589.3047, 3639.6855, 5116.5957, 7193.1211,
1390 10112.9805, 14213.5547, 19979.6094, 28089.3984, 39483.7109, 55517.6484, 78048.0000,
1391 ];
1392 GAINS_H[num_decomps.min(33) as usize]
1393 }
1394}
1395
1396impl ParamQcd {
1397 pub fn new_qcc(comp_idx: u16) -> Self {
1399 Self {
1400 qcd_type: QcdType::QccMain,
1401 comp_idx,
1402 ..Default::default()
1403 }
1404 }
1405
1406 pub fn set_delta(&mut self, delta: f32) {
1411 self.base_delta = delta;
1412 }
1413
1414 pub fn set_delta_for_comp(&mut self, comp_idx: u32, delta: f32) {
1416 let qcc = self.get_or_add_qcc(comp_idx);
1417 qcc.base_delta = delta;
1418 }
1419
1420 pub fn get_num_guard_bits(&self) -> u32 {
1422 (self.sqcd >> 5) as u32
1423 }
1424
1425 fn decode_spqcd(&self, v: u8) -> u8 {
1426 v >> 3
1427 }
1428
1429 fn encode_spqcd(&self, v: u8) -> u8 {
1430 v << 3
1431 }
1432
1433 pub fn get_magb(&self) -> u32 {
1434 let mut b = 0u32;
1435 self.compute_magb_for(&mut b);
1436 for child in &self.children {
1437 child.compute_magb_for(&mut b);
1438 }
1439 b
1440 }
1441
1442 fn compute_magb_for(&self, b: &mut u32) {
1443 let num_decomps = (self.num_subbands.saturating_sub(1)) / 3;
1444 let irrev = self.sqcd & 0x1F;
1445 if irrev == 0 {
1446 if let SpqcdData::Reversible(ref data) = self.sp_qcd {
1447 for i in 0..self.num_subbands.min(data.len() as u32) {
1448 let t =
1449 self.decode_spqcd(data[i as usize]) as u32 + self.get_num_guard_bits() - 1;
1450 *b = (*b).max(t);
1451 }
1452 }
1453 } else if irrev == 2 {
1454 if let SpqcdData::Irreversible(ref data) = self.sp_qcd {
1455 for i in 0..self.num_subbands.min(data.len() as u32) {
1456 let nb = num_decomps - if i > 0 { (i - 1) / 3 } else { 0 };
1457 let t = (data[i as usize] >> 11) as u32 + self.get_num_guard_bits() - nb;
1458 *b = (*b).max(t);
1459 }
1460 }
1461 }
1462 }
1463
1464 pub fn get_kmax(&self, _num_decompositions: u32, resolution: u32, subband: u32) -> u32 {
1465 let idx = if resolution > 0 {
1466 (resolution - 1) * 3 + subband
1467 } else {
1468 0
1469 };
1470 let idx = idx.min(self.num_subbands.saturating_sub(1));
1471 let irrev = self.sqcd & 0x1F;
1472 let num_bits = if irrev == 0 {
1473 if let SpqcdData::Reversible(ref data) = self.sp_qcd {
1474 let v = self.decode_spqcd(data[idx as usize]);
1475 if v == 0 {
1476 0u32
1477 } else {
1478 v as u32 - 1
1479 }
1480 } else {
1481 0
1482 }
1483 } else if irrev == 2 {
1484 if let SpqcdData::Irreversible(ref data) = self.sp_qcd {
1485 (data[idx as usize] >> 11) as u32 - 1
1486 } else {
1487 0
1488 }
1489 } else {
1490 0
1491 };
1492 num_bits + self.get_num_guard_bits()
1493 }
1494
1495 pub fn get_irrev_delta(&self, _num_decompositions: u32, resolution: u32, subband: u32) -> f32 {
1496 let arr: [f32; 4] = [1.0, 2.0, 2.0, 4.0];
1497 let idx = if resolution > 0 {
1498 (resolution - 1) * 3 + subband
1499 } else {
1500 0
1501 };
1502 let idx = idx.min(self.num_subbands.saturating_sub(1));
1503 if let SpqcdData::Irreversible(ref data) = self.sp_qcd {
1504 let eps = data[idx as usize] >> 11;
1505 let mut mantissa =
1506 ((data[idx as usize] & 0x7FF) | 0x800) as f32 * arr[subband as usize];
1507 mantissa /= (1u32 << 11) as f32;
1508 mantissa /= (1u32 << eps) as f32;
1509 mantissa
1510 } else {
1511 1.0
1512 }
1513 }
1514
1515 fn set_rev_quant(&mut self, num_decomps: u32, bit_depth: u32, employing_ct: bool) {
1516 let b = bit_depth + if employing_ct { 1 } else { 0 } + 1;
1520 let ns = 1 + 3 * num_decomps;
1521 let mut sp = vec![0u8; ns as usize];
1522 let mut s = 0usize;
1523 let bibo_l = bibo_gains::get_bibo_gain_l(num_decomps, true);
1524 let x = (bibo_l * bibo_l).ln() / LN_2;
1525 let x = x.ceil() as u32;
1526 sp[s] = (b + x) as u8;
1527 let mut max_bpx = b + x;
1528 s += 1;
1529 for d in (1..=num_decomps).rev() {
1530 let bl = bibo_gains::get_bibo_gain_l(d, true);
1531 let bh = bibo_gains::get_bibo_gain_h(d - 1, true);
1532 let x = ((bh * bl).ln() / LN_2).ceil() as u32;
1533 sp[s] = (b + x) as u8;
1534 max_bpx = max_bpx.max(b + x);
1535 s += 1;
1536 sp[s] = (b + x) as u8;
1537 max_bpx = max_bpx.max(b + x);
1538 s += 1;
1539 let x = ((bh * bh).ln() / LN_2).ceil() as u32;
1540 sp[s] = (b + x) as u8;
1541 max_bpx = max_bpx.max(b + x);
1542 s += 1;
1543 }
1544 let guard_bits = 1i32.max(max_bpx as i32 - 31);
1545 self.sqcd = (guard_bits as u8) << 5;
1546 for v in sp.iter_mut() {
1547 *v = self.encode_spqcd((*v as i32 - guard_bits) as u8);
1548 }
1549 self.sp_qcd = SpqcdData::Reversible(sp);
1550 self.num_subbands = ns;
1551 }
1552
1553 fn set_irrev_quant(&mut self, num_decomps: u32) {
1554 let guard_bits = 1u8;
1555 self.sqcd = (guard_bits << 5) | 0x2;
1556 let ns = 1 + 3 * num_decomps;
1557 let mut sp = vec![0u16; ns as usize];
1558 let mut s = 0usize;
1559
1560 let gain_l = sqrt_energy_gains::get_gain_l(num_decomps, false);
1561 let delta_b = self.base_delta / (gain_l * gain_l);
1562 let (exp, mantissa) = quantize_delta(delta_b);
1563 sp[s] = (exp << 11) | mantissa;
1564 s += 1;
1565
1566 for d in (1..=num_decomps).rev() {
1567 let gl = sqrt_energy_gains::get_gain_l(d, false);
1568 let gh = sqrt_energy_gains::get_gain_h(d - 1, false);
1569
1570 let delta_b = self.base_delta / (gl * gh);
1571 let (exp, mantissa) = quantize_delta(delta_b);
1572 sp[s] = (exp << 11) | mantissa;
1573 s += 1;
1574 sp[s] = (exp << 11) | mantissa;
1575 s += 1;
1576
1577 let delta_b = self.base_delta / (gh * gh);
1578 let (exp, mantissa) = quantize_delta(delta_b);
1579 sp[s] = (exp << 11) | mantissa;
1580 s += 1;
1581 }
1582 self.sp_qcd = SpqcdData::Irreversible(sp);
1583 self.num_subbands = ns;
1584 }
1585
1586 pub fn check_validity(&mut self, siz: &ParamSiz, cod: &ParamCod) -> Result<()> {
1587 let num_comps = siz.get_num_components() as u32;
1588
1589 let qcd_num_decomps = cod.get_num_decompositions() as u32;
1590 let qcd_bit_depth = siz.get_bit_depth(0);
1591 let qcd_wavelet_kern = cod.get_wavelet_kern();
1592 let employing_ct = cod.is_employing_color_transform();
1593
1594 self.num_subbands = 1 + 3 * qcd_num_decomps;
1595 if qcd_wavelet_kern == DWT_REV53 {
1596 self.set_rev_quant(qcd_num_decomps, qcd_bit_depth, employing_ct);
1597 } else {
1598 if self.base_delta < 0.0 {
1599 self.base_delta = 1.0 / (1u32 << qcd_bit_depth) as f32;
1600 }
1601 self.set_irrev_quant(qcd_num_decomps);
1602 }
1603
1604 for child in &mut self.children {
1606 if child.comp_idx >= num_comps as u16 {
1607 child.enabled = false;
1608 continue;
1609 }
1610 let c = child.comp_idx as u32;
1611 let cp = cod.get_coc(c);
1612 let nd = cp.get_num_decompositions() as u32;
1613 child.num_subbands = 1 + 3 * nd;
1614 let bd = siz.get_bit_depth(c);
1615 if cp.get_wavelet_kern() == DWT_REV53 {
1616 child.set_rev_quant(nd, bd, if c < 3 { employing_ct } else { false });
1617 } else {
1618 if child.base_delta < 0.0 {
1619 child.base_delta = 1.0 / (1u32 << bd) as f32;
1620 }
1621 child.set_irrev_quant(nd);
1622 }
1623 }
1624 Ok(())
1625 }
1626
1627 pub fn get_qcc(&self, comp_idx: u32) -> &ParamQcd {
1629 for child in &self.children {
1630 if child.comp_idx == comp_idx as u16 {
1631 return child;
1632 }
1633 }
1634 self
1635 }
1636
1637 pub fn get_or_add_qcc(&mut self, comp_idx: u32) -> &mut ParamQcd {
1638 for i in 0..self.children.len() {
1639 if self.children[i].comp_idx == comp_idx as u16 {
1640 return &mut self.children[i];
1641 }
1642 }
1643 let qcc = ParamQcd::new_qcc(comp_idx as u16);
1644 self.children.push(qcc);
1645 self.children.last_mut().unwrap()
1646 }
1647
1648 pub fn write(&mut self, file: &mut dyn OutfileBase) -> Result<bool> {
1649 let irrev = self.sqcd & 0x1F;
1650 self.lqcd = 3;
1651 if irrev == 0 {
1652 self.lqcd += self.num_subbands as u16;
1653 } else if irrev == 2 {
1654 self.lqcd += 2 * self.num_subbands as u16;
1655 }
1656 let mut ok = true;
1657 ok &= write_u16_be(file, markers::QCD)?;
1658 ok &= write_u16_be(file, self.lqcd)?;
1659 ok &= write_u8(file, self.sqcd)?;
1660 match &self.sp_qcd {
1661 SpqcdData::Reversible(data) => {
1662 for item in data.iter().take(self.num_subbands as usize) {
1663 ok &= write_u8(file, *item)?;
1664 }
1665 }
1666 SpqcdData::Irreversible(data) => {
1667 for item in data.iter().take(self.num_subbands as usize) {
1668 ok &= write_u16_be(file, *item)?;
1669 }
1670 }
1671 }
1672 Ok(ok)
1673 }
1674
1675 pub fn write_qcc(&self, file: &mut dyn OutfileBase, num_comps: u32) -> Result<bool> {
1676 let mut ok = true;
1677 for child in &self.children {
1678 if child.enabled {
1679 ok &= child.internal_write_qcc(file, num_comps)?;
1680 }
1681 }
1682 Ok(ok)
1683 }
1684
1685 fn internal_write_qcc(&self, file: &mut dyn OutfileBase, num_comps: u32) -> Result<bool> {
1686 let irrev = self.sqcd & 0x1F;
1687 let mut lqcd: u16 = 4 + if num_comps < 257 { 0 } else { 1 };
1688 if irrev == 0 {
1689 lqcd += self.num_subbands as u16;
1690 } else if irrev == 2 {
1691 lqcd += 2 * self.num_subbands as u16;
1692 }
1693 let mut ok = true;
1694 ok &= write_u16_be(file, markers::QCC)?;
1695 ok &= write_u16_be(file, lqcd)?;
1696 if num_comps < 257 {
1697 ok &= write_u8(file, self.comp_idx as u8)?;
1698 } else {
1699 ok &= write_u16_be(file, self.comp_idx)?;
1700 }
1701 ok &= write_u8(file, self.sqcd)?;
1702 match &self.sp_qcd {
1703 SpqcdData::Reversible(data) => {
1704 for item in data.iter().take(self.num_subbands as usize) {
1705 ok &= write_u8(file, *item)?;
1706 }
1707 }
1708 SpqcdData::Irreversible(data) => {
1709 for item in data.iter().take(self.num_subbands as usize) {
1710 ok &= write_u16_be(file, *item)?;
1711 }
1712 }
1713 }
1714 Ok(ok)
1715 }
1716
1717 pub fn read(&mut self, file: &mut dyn InfileBase) -> Result<()> {
1718 self.lqcd = read_u16_be(file).map_err(|_| OjphError::Codec {
1719 code: 0x00050081,
1720 message: "error reading QCD marker".into(),
1721 })?;
1722 self.sqcd = read_u8(file).map_err(|_| OjphError::Codec {
1723 code: 0x00050082,
1724 message: "error reading QCD marker".into(),
1725 })?;
1726 let irrev = self.sqcd & 0x1F;
1727 if irrev == 0 {
1728 self.num_subbands = (self.lqcd - 3) as u32;
1729 if self.num_subbands > 97 || self.lqcd != 3 + self.num_subbands as u16 {
1730 return Err(OjphError::Codec {
1731 code: 0x00050083,
1732 message: format!("wrong Lqcd value of {} in QCD marker", self.lqcd),
1733 });
1734 }
1735 let mut data = vec![0u8; self.num_subbands as usize];
1736 for item in data.iter_mut().take(self.num_subbands as usize) {
1737 *item = read_u8(file).map_err(|_| OjphError::Codec {
1738 code: 0x00050084,
1739 message: "error reading QCD marker".into(),
1740 })?;
1741 }
1742 self.sp_qcd = SpqcdData::Reversible(data);
1743 } else if irrev == 2 {
1744 self.num_subbands = ((self.lqcd - 3) / 2) as u32;
1745 if self.num_subbands > 97 || self.lqcd != 3 + 2 * self.num_subbands as u16 {
1746 return Err(OjphError::Codec {
1747 code: 0x00050086,
1748 message: format!("wrong Lqcd value of {} in QCD marker", self.lqcd),
1749 });
1750 }
1751 let mut data = vec![0u16; self.num_subbands as usize];
1752 for item in data.iter_mut().take(self.num_subbands as usize) {
1753 *item = read_u16_be(file).map_err(|_| OjphError::Codec {
1754 code: 0x00050087,
1755 message: "error reading QCD marker".into(),
1756 })?;
1757 }
1758 self.sp_qcd = SpqcdData::Irreversible(data);
1759 } else {
1760 return Err(OjphError::Codec {
1761 code: 0x00050088,
1762 message: "wrong Sqcd value in QCD marker".into(),
1763 });
1764 }
1765 Ok(())
1766 }
1767
1768 pub fn read_qcc(&mut self, file: &mut dyn InfileBase, num_comps: u32) -> Result<()> {
1769 self.qcd_type = QcdType::QccMain;
1770 self.lqcd = read_u16_be(file).map_err(|_| OjphError::Codec {
1771 code: 0x000500A1,
1772 message: "error reading QCC marker".into(),
1773 })?;
1774 if num_comps < 257 {
1775 self.comp_idx = read_u8(file).map_err(|_| OjphError::Codec {
1776 code: 0x000500A2,
1777 message: "error reading QCC marker".into(),
1778 })? as u16;
1779 } else {
1780 self.comp_idx = read_u16_be(file).map_err(|_| OjphError::Codec {
1781 code: 0x000500A3,
1782 message: "error reading QCC marker".into(),
1783 })?;
1784 }
1785 self.sqcd = read_u8(file).map_err(|_| OjphError::Codec {
1786 code: 0x000500A4,
1787 message: "error reading QCC marker".into(),
1788 })?;
1789 let offset: u32 = if num_comps < 257 { 4 } else { 5 };
1790 let irrev = self.sqcd & 0x1F;
1791 if irrev == 0 {
1792 self.num_subbands = (self.lqcd as u32).saturating_sub(offset);
1793 let mut data = vec![0u8; self.num_subbands as usize];
1794 for item in data.iter_mut().take(self.num_subbands as usize) {
1795 *item = read_u8(file).map_err(|_| OjphError::Codec {
1796 code: 0x000500A6,
1797 message: "error reading QCC marker".into(),
1798 })?;
1799 }
1800 self.sp_qcd = SpqcdData::Reversible(data);
1801 } else if irrev == 2 {
1802 self.num_subbands = ((self.lqcd as u32).saturating_sub(offset)) / 2;
1803 let mut data = vec![0u16; self.num_subbands as usize];
1804 for item in data.iter_mut().take(self.num_subbands as usize) {
1805 *item = read_u16_be(file).map_err(|_| OjphError::Codec {
1806 code: 0x000500A9,
1807 message: "error reading QCC marker".into(),
1808 })?;
1809 }
1810 self.sp_qcd = SpqcdData::Irreversible(data);
1811 } else {
1812 return Err(OjphError::Codec {
1813 code: 0x000500AA,
1814 message: "wrong Sqcc value in QCC marker".into(),
1815 });
1816 }
1817 Ok(())
1818 }
1819}
1820
1821fn quantize_delta(mut delta_b: f32) -> (u16, u16) {
1822 let mut exp: u16 = 0;
1823 while delta_b < 1.0 {
1824 exp += 1;
1825 delta_b *= 2.0;
1826 }
1827 let mut mantissa = (delta_b * (1u32 << 11) as f32).round() as i32 - (1i32 << 11);
1828 mantissa = mantissa.min(0x7FF);
1829 (exp, mantissa as u16)
1830}
1831
1832#[derive(Debug, Clone)]
1841pub struct ParamCap {
1842 pub(crate) lcap: u16,
1843 pub(crate) pcap: u32,
1844 pub(crate) ccap: [u16; 32],
1845}
1846
1847impl Default for ParamCap {
1848 fn default() -> Self {
1849 let mut cap = Self {
1850 lcap: 8,
1851 pcap: 0x00020000,
1852 ccap: [0u16; 32],
1853 };
1854 cap.ccap[0] = 0;
1855 cap
1856 }
1857}
1858
1859impl ParamCap {
1860 pub fn check_validity(&mut self, cod: &ParamCod, qcd: &ParamQcd) {
1861 if cod.get_wavelet_kern() == DWT_REV53 {
1862 self.ccap[0] &= 0xFFDF;
1863 } else {
1864 self.ccap[0] |= 0x0020;
1865 }
1866 self.ccap[0] &= 0xFFE0;
1867 let b = qcd.get_magb();
1868 let bp = if b <= 8 {
1869 0
1870 } else if b < 28 {
1871 b - 8
1872 } else {
1873 13 + (b >> 2)
1874 };
1875 self.ccap[0] |= bp as u16;
1876 }
1877
1878 pub fn write(&self, file: &mut dyn OutfileBase) -> Result<bool> {
1879 let mut ok = true;
1880 ok &= write_u16_be(file, markers::CAP)?;
1881 ok &= write_u16_be(file, self.lcap)?;
1882 ok &= write_u32_be(file, self.pcap)?;
1883 ok &= write_u16_be(file, self.ccap[0])?;
1884 Ok(ok)
1885 }
1886
1887 pub fn read(&mut self, file: &mut dyn InfileBase) -> Result<()> {
1888 self.lcap = read_u16_be(file).map_err(|_| OjphError::Codec {
1889 code: 0x00050061,
1890 message: "error reading CAP marker".into(),
1891 })?;
1892 self.pcap = read_u32_be(file).map_err(|_| OjphError::Codec {
1893 code: 0x00050062,
1894 message: "error reading CAP marker".into(),
1895 })?;
1896 let count = population_count(self.pcap);
1897 if (self.pcap & 0x00020000) == 0 {
1898 return Err(OjphError::Codec {
1899 code: 0x00050064,
1900 message: "Pcap should have its 15th MSB set. Not a JPH file".into(),
1901 });
1902 }
1903 for i in 0..count as usize {
1904 self.ccap[i] = read_u16_be(file).map_err(|_| OjphError::Codec {
1905 code: 0x00050065,
1906 message: "error reading CAP marker".into(),
1907 })?;
1908 }
1909 if self.lcap != 6 + 2 * count as u16 {
1910 return Err(OjphError::Codec {
1911 code: 0x00050066,
1912 message: "error in CAP marker length".into(),
1913 });
1914 }
1915 Ok(())
1916 }
1917}
1918
1919#[derive(Debug, Clone, Default)]
1928pub struct ParamSot {
1929 pub(crate) isot: u16,
1930 pub(crate) psot: u32,
1931 pub(crate) tp_sot: u8,
1932 pub(crate) tn_sot: u8,
1933}
1934
1935impl ParamSot {
1936 pub fn init(
1937 &mut self,
1938 payload_length: u32,
1939 tile_idx: u16,
1940 tile_part_index: u8,
1941 num_tile_parts: u8,
1942 ) {
1943 self.psot = payload_length + 12;
1944 self.isot = tile_idx;
1945 self.tp_sot = tile_part_index;
1946 self.tn_sot = num_tile_parts;
1947 }
1948
1949 pub fn get_tile_index(&self) -> u16 {
1950 self.isot
1951 }
1952 pub fn get_payload_length(&self) -> u32 {
1953 if self.psot > 0 {
1954 self.psot - 12
1955 } else {
1956 0
1957 }
1958 }
1959 pub fn get_tile_part_index(&self) -> u8 {
1960 self.tp_sot
1961 }
1962 #[allow(dead_code)]
1963 pub fn get_num_tile_parts(&self) -> u8 {
1964 self.tn_sot
1965 }
1966
1967 pub fn write(&mut self, file: &mut dyn OutfileBase, payload_len: u32) -> Result<bool> {
1968 self.psot = payload_len + 14;
1969 let mut ok = true;
1970 ok &= write_u16_be(file, markers::SOT)?;
1971 ok &= write_u16_be(file, 10)?; ok &= write_u16_be(file, self.isot)?;
1973 ok &= write_u32_be(file, self.psot)?;
1974 ok &= write_u8(file, self.tp_sot)?;
1975 ok &= write_u8(file, self.tn_sot)?;
1976 Ok(ok)
1977 }
1978
1979 pub fn read(&mut self, file: &mut dyn InfileBase, resilient: bool) -> Result<bool> {
1980 if resilient {
1981 let lsot = match read_u16_be(file) {
1982 Ok(v) => v,
1983 Err(_) => {
1984 self.clear();
1985 return Ok(false);
1986 }
1987 };
1988 if lsot != 10 {
1989 self.clear();
1990 return Ok(false);
1991 }
1992 self.isot = match read_u16_be(file) {
1993 Ok(v) => v,
1994 Err(_) => {
1995 self.clear();
1996 return Ok(false);
1997 }
1998 };
1999 if self.isot == 0xFFFF {
2000 self.clear();
2001 return Ok(false);
2002 }
2003 self.psot = match read_u32_be(file) {
2004 Ok(v) => v,
2005 Err(_) => {
2006 self.clear();
2007 return Ok(false);
2008 }
2009 };
2010 self.tp_sot = match read_u8(file) {
2011 Ok(v) => v,
2012 Err(_) => {
2013 self.clear();
2014 return Ok(false);
2015 }
2016 };
2017 self.tn_sot = match read_u8(file) {
2018 Ok(v) => v,
2019 Err(_) => {
2020 self.clear();
2021 return Ok(false);
2022 }
2023 };
2024 } else {
2025 let lsot = read_u16_be(file).map_err(|_| OjphError::Codec {
2026 code: 0x00050091,
2027 message: "error reading SOT marker".into(),
2028 })?;
2029 if lsot != 10 {
2030 return Err(OjphError::Codec {
2031 code: 0x00050092,
2032 message: "error in SOT length".into(),
2033 });
2034 }
2035 self.isot = read_u16_be(file).map_err(|_| OjphError::Codec {
2036 code: 0x00050093,
2037 message: "error reading SOT marker".into(),
2038 })?;
2039 if self.isot == 0xFFFF {
2040 return Err(OjphError::Codec {
2041 code: 0x00050094,
2042 message: "tile index in SOT marker cannot be 0xFFFF".into(),
2043 });
2044 }
2045 self.psot = read_u32_be(file).map_err(|_| OjphError::Codec {
2046 code: 0x00050095,
2047 message: "error reading SOT marker".into(),
2048 })?;
2049 self.tp_sot = read_u8(file).map_err(|_| OjphError::Codec {
2050 code: 0x00050096,
2051 message: "error reading SOT marker".into(),
2052 })?;
2053 self.tn_sot = read_u8(file).map_err(|_| OjphError::Codec {
2054 code: 0x00050097,
2055 message: "error reading SOT marker".into(),
2056 })?;
2057 }
2058 Ok(true)
2059 }
2060
2061 fn clear(&mut self) {
2062 self.isot = 0;
2063 self.psot = 0;
2064 self.tp_sot = 0;
2065 self.tn_sot = 0;
2066 }
2067}
2068
2069#[derive(Debug, Clone, Default)]
2075pub struct TtlmPtlmPair {
2076 pub ttlm: u16,
2078 pub ptlm: u32,
2080}
2081
2082#[derive(Debug, Clone, Default)]
2087pub struct ParamTlm {
2088 pub(crate) ltlm: u16,
2089 pub(crate) ztlm: u8,
2090 pub(crate) stlm: u8,
2091 pub(crate) pairs: Vec<TtlmPtlmPair>,
2092 pub(crate) next_pair_index: u32,
2093}
2094
2095impl ParamTlm {
2096 pub fn init(&mut self, num_pairs: u32) {
2097 self.pairs
2098 .resize(num_pairs as usize, TtlmPtlmPair::default());
2099 self.ltlm = 4 + 6 * num_pairs as u16;
2100 self.ztlm = 0;
2101 self.stlm = 0x60;
2102 self.next_pair_index = 0;
2103 }
2104
2105 pub fn set_next_pair(&mut self, ttlm: u16, ptlm: u32) {
2106 let idx = self.next_pair_index as usize;
2107 self.pairs[idx].ttlm = ttlm;
2108 self.pairs[idx].ptlm = ptlm + 14;
2109 self.next_pair_index += 1;
2110 }
2111
2112 pub fn write(&self, file: &mut dyn OutfileBase) -> Result<bool> {
2113 let mut ok = true;
2114 ok &= write_u16_be(file, markers::TLM)?;
2115 ok &= write_u16_be(file, self.ltlm)?;
2116 ok &= write_u8(file, self.ztlm)?;
2117 ok &= write_u8(file, self.stlm)?;
2118 for pair in &self.pairs {
2119 ok &= write_u16_be(file, pair.ttlm)?;
2120 ok &= write_u32_be(file, pair.ptlm)?;
2121 }
2122 Ok(ok)
2123 }
2124}
2125
2126pub(crate) const NLT_ALL_COMPS: u16 = 65535;
2131pub(crate) const NLT_NO_NLT: u8 = 0;
2132#[allow(dead_code)]
2133pub(crate) const NLT_BINARY_COMPLEMENT: u8 = 3;
2134pub(crate) const NLT_UNDEFINED: u8 = 255;
2135
2136#[derive(Debug, Clone)]
2141pub struct ParamNlt {
2142 pub(crate) lnlt: u16,
2143 pub(crate) cnlt: u16,
2144 pub(crate) bd_nlt: u8,
2145 pub(crate) tnlt: u8,
2146 pub(crate) enabled: bool,
2147 pub(crate) children: Vec<ParamNlt>,
2148}
2149
2150impl Default for ParamNlt {
2151 fn default() -> Self {
2152 Self {
2153 lnlt: 6,
2154 cnlt: NLT_ALL_COMPS,
2155 bd_nlt: 0,
2156 tnlt: NLT_UNDEFINED,
2157 enabled: false,
2158 children: Vec::new(),
2159 }
2160 }
2161}
2162
2163impl ParamNlt {
2164 pub fn set_nonlinear_transform(&mut self, comp_num: u32, nl_type: u8) -> Result<()> {
2173 if nl_type != NLT_NO_NLT && nl_type != NLT_BINARY_COMPLEMENT {
2174 return Err(OjphError::Unsupported(
2175 "only NLT types 0 and 3 are supported".into(),
2176 ));
2177 }
2178 let child = self.get_or_add_child(comp_num);
2179 child.tnlt = nl_type;
2180 child.enabled = true;
2181 Ok(())
2182 }
2183
2184 pub fn get_nonlinear_transform(&self, comp_num: u32) -> Option<(u8, bool, u8)> {
2187 for child in &self.children {
2188 if child.cnlt == comp_num as u16 && child.enabled {
2189 let bd = (child.bd_nlt & 0x7F) + 1;
2190 let is_signed = (child.bd_nlt & 0x80) == 0x80;
2191 return Some((bd.min(38), is_signed, child.tnlt));
2192 }
2193 }
2194 if self.enabled {
2195 let bd = (self.bd_nlt & 0x7F) + 1;
2196 let is_signed = (self.bd_nlt & 0x80) == 0x80;
2197 return Some((bd.min(38), is_signed, self.tnlt));
2198 }
2199 None
2200 }
2201
2202 pub fn is_any_enabled(&self) -> bool {
2204 if self.enabled {
2205 return true;
2206 }
2207 self.children.iter().any(|c| c.enabled)
2208 }
2209
2210 fn get_or_add_child(&mut self, comp_num: u32) -> &mut ParamNlt {
2211 for i in 0..self.children.len() {
2212 if self.children[i].cnlt == comp_num as u16 {
2213 return &mut self.children[i];
2214 }
2215 }
2216 let child = ParamNlt {
2217 cnlt: comp_num as u16,
2218 ..Default::default()
2219 };
2220 self.children.push(child);
2221 self.children.last_mut().unwrap()
2222 }
2223
2224 pub fn write(&self, file: &mut dyn OutfileBase) -> Result<bool> {
2225 if !self.is_any_enabled() {
2226 return Ok(true);
2227 }
2228 let mut ok = true;
2229 if self.enabled {
2230 ok &= write_u16_be(file, markers::NLT)?;
2231 ok &= write_u16_be(file, self.lnlt)?;
2232 ok &= write_u16_be(file, self.cnlt)?;
2233 ok &= write_u8(file, self.bd_nlt)?;
2234 ok &= write_u8(file, self.tnlt)?;
2235 }
2236 for child in &self.children {
2237 if child.enabled {
2238 ok &= write_u16_be(file, markers::NLT)?;
2239 ok &= write_u16_be(file, child.lnlt)?;
2240 ok &= write_u16_be(file, child.cnlt)?;
2241 ok &= write_u8(file, child.bd_nlt)?;
2242 ok &= write_u8(file, child.tnlt)?;
2243 }
2244 }
2245 Ok(ok)
2246 }
2247
2248 pub fn read(&mut self, file: &mut dyn InfileBase) -> Result<()> {
2249 let mut buf = [0u8; 6];
2250 let mut offset = 0;
2251 while offset < 6 {
2252 let n = file.read(&mut buf[offset..])?;
2253 if n == 0 {
2254 return Err(OjphError::Codec {
2255 code: 0x00050141,
2256 message: "error reading NLT marker".into(),
2257 });
2258 }
2259 offset += n;
2260 }
2261 let length = u16::from_be_bytes([buf[0], buf[1]]);
2262 if length != 6 || (buf[5] != 3 && buf[5] != 0) {
2263 return Err(OjphError::Codec {
2264 code: 0x00050142,
2265 message: format!("Unsupported NLT type {}", buf[5]),
2266 });
2267 }
2268 let comp = u16::from_be_bytes([buf[2], buf[3]]);
2269 let child = self.get_or_add_child(comp as u32);
2270 child.enabled = true;
2271 child.cnlt = comp;
2272 child.bd_nlt = buf[4];
2273 child.tnlt = buf[5];
2274 Ok(())
2275 }
2276}
2277
2278#[allow(clippy::enum_variant_names)]
2283#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2284#[repr(u8)]
2285pub enum DfsDwtType {
2286 NoDwt = 0,
2287 BidirDwt = 1,
2288 HorzDwt = 2,
2289 VertDwt = 3,
2290}
2291
2292#[derive(Debug, Clone, Default)]
2297pub struct ParamDfs {
2298 pub(crate) ldfs: u16,
2299 pub(crate) sdfs: u16,
2300 pub(crate) ids: u8,
2301 pub(crate) ddfs: [u8; 8],
2302 pub(crate) children: Vec<ParamDfs>,
2303}
2304
2305impl ParamDfs {
2306 pub fn exists(&self) -> bool {
2307 self.ldfs != 0
2308 }
2309
2310 #[allow(dead_code)]
2311 pub fn get_dfs(&self, index: i32) -> Option<&ParamDfs> {
2312 if self.sdfs == index as u16 {
2313 return Some(self);
2314 }
2315 self.children
2316 .iter()
2317 .find(|child| child.sdfs == index as u16)
2318 }
2319
2320 pub fn get_dwt_type(&self, decomp_level: u32) -> DfsDwtType {
2321 let dl = decomp_level.min(self.ids as u32);
2322 let d = dl - 1;
2323 let idx = d >> 2;
2324 let bits = d & 0x3;
2325 let val = (self.ddfs[idx as usize] >> (6 - 2 * bits)) & 0x3;
2326 match val {
2327 0 => DfsDwtType::NoDwt,
2328 1 => DfsDwtType::BidirDwt,
2329 2 => DfsDwtType::HorzDwt,
2330 3 => DfsDwtType::VertDwt,
2331 _ => DfsDwtType::BidirDwt,
2332 }
2333 }
2334
2335 pub fn read(&mut self, file: &mut dyn InfileBase) -> Result<bool> {
2336 if self.ldfs != 0 {
2337 let mut child = ParamDfs::default();
2338 let ok = child.read(file)?;
2339 self.children.push(child);
2340 return Ok(ok);
2341 }
2342 self.ldfs = read_u16_be(file).map_err(|_| OjphError::Codec {
2343 code: 0x000500D1,
2344 message: "error reading DFS-Ldfs".into(),
2345 })?;
2346 self.sdfs = read_u16_be(file).map_err(|_| OjphError::Codec {
2347 code: 0x000500D2,
2348 message: "error reading DFS-Sdfs".into(),
2349 })?;
2350 let l_ids = read_u8(file).map_err(|_| OjphError::Codec {
2351 code: 0x000500D4,
2352 message: "error reading DFS-Ids".into(),
2353 })?;
2354 let max_ddfs = (self.ddfs.len() * 4) as u8;
2355 self.ids = l_ids.min(max_ddfs);
2356 for i in (0..self.ids).step_by(4) {
2357 self.ddfs[(i / 4) as usize] = read_u8(file).map_err(|_| OjphError::Codec {
2358 code: 0x000500D6,
2359 message: "error reading DFS-Ddfs".into(),
2360 })?;
2361 }
2362 for _ in (self.ids..l_ids).step_by(4) {
2363 let _ = read_u8(file);
2364 }
2365 Ok(true)
2366 }
2367}
2368
2369#[derive(Debug, Clone, Default)]
2379pub struct CommentExchange {
2380 pub data: Vec<u8>,
2382 pub rcom: u16,
2384}
2385
2386impl CommentExchange {
2387 pub fn set_string(&mut self, s: &str) {
2389 self.data = s.as_bytes().to_vec();
2390 self.rcom = 1; }
2392
2393 pub fn set_data(&mut self, data: &[u8]) {
2395 self.data = data.to_vec();
2396 self.rcom = 0; }
2398}
2399
2400#[cfg(test)]
2405mod tests {
2406 use super::*;
2407 use crate::file::{MemInfile, MemOutfile};
2408 use crate::types::{Point, Size};
2409
2410 #[test]
2415 fn param_siz_set_get() {
2416 let mut siz = ParamSiz::default();
2417 siz.set_image_extent(Point::new(1920, 1080));
2418 siz.set_tile_size(Size::new(512, 512));
2419 siz.set_image_offset(Point::new(10, 20));
2420 siz.set_tile_offset(Point::new(5, 10));
2421
2422 assert_eq!(siz.get_image_extent(), Point::new(1920, 1080));
2423 assert_eq!(siz.get_tile_size(), Size::new(512, 512));
2424 assert_eq!(siz.get_image_offset(), Point::new(10, 20));
2425 assert_eq!(siz.get_tile_offset(), Point::new(5, 10));
2426 }
2427
2428 #[test]
2429 fn param_siz_components() {
2430 let mut siz = ParamSiz::default();
2431 siz.set_num_components(3);
2432 assert_eq!(siz.get_num_components(), 3);
2433
2434 siz.set_comp_info(0, Point::new(1, 1), 8, false);
2436 siz.set_comp_info(1, Point::new(2, 2), 12, true);
2438 siz.set_comp_info(2, Point::new(1, 2), 16, false);
2440
2441 assert_eq!(siz.get_bit_depth(0), 8);
2442 assert!(!siz.is_signed(0));
2443 assert_eq!(siz.get_downsampling(0), Point::new(1, 1));
2444
2445 assert_eq!(siz.get_bit_depth(1), 12);
2446 assert!(siz.is_signed(1));
2447 assert_eq!(siz.get_downsampling(1), Point::new(2, 2));
2448
2449 assert_eq!(siz.get_bit_depth(2), 16);
2450 assert!(!siz.is_signed(2));
2451 assert_eq!(siz.get_downsampling(2), Point::new(1, 2));
2452 }
2453
2454 #[test]
2455 fn param_siz_validity_ok() {
2456 let mut siz = ParamSiz::default();
2457 siz.set_image_extent(Point::new(1920, 1080));
2458 siz.set_tile_size(Size::new(512, 512));
2459 siz.set_image_offset(Point::new(0, 0));
2460 siz.set_tile_offset(Point::new(0, 0));
2461 assert!(siz.check_validity().is_ok());
2462 }
2463
2464 #[test]
2465 fn param_siz_validity_zero_extent() {
2466 let mut siz = ParamSiz::default();
2467 siz.set_image_extent(Point::new(0, 0));
2468 siz.set_tile_size(Size::new(512, 512));
2469 assert!(siz.check_validity().is_err());
2470 }
2471
2472 #[test]
2473 fn param_siz_validity_bad_offset() {
2474 let mut siz = ParamSiz::default();
2475 siz.set_image_extent(Point::new(1920, 1080));
2476 siz.set_tile_size(Size::new(512, 512));
2477 siz.set_image_offset(Point::new(10, 10));
2479 siz.set_tile_offset(Point::new(20, 20));
2480 assert!(siz.check_validity().is_err());
2481 }
2482
2483 #[test]
2484 fn param_siz_write_read_roundtrip() {
2485 let mut siz = ParamSiz::default();
2486 siz.set_image_extent(Point::new(1920, 1080));
2487 siz.set_tile_size(Size::new(512, 512));
2488 siz.set_num_components(3);
2489 for i in 0..3u32 {
2490 siz.set_comp_info(i, Point::new(1, 1), 8, false);
2491 }
2492
2493 let mut out = MemOutfile::new();
2494 siz.write(&mut out).expect("write failed");
2495
2496 let data = out.get_data();
2498 let mut inp = MemInfile::new(&data[2..]);
2499 let mut siz2 = ParamSiz::default();
2500 siz2.read(&mut inp).expect("read failed");
2501
2502 assert_eq!(siz2.xsiz, 1920);
2503 assert_eq!(siz2.ysiz, 1080);
2504 assert_eq!(siz2.xt_siz, 512);
2505 assert_eq!(siz2.yt_siz, 512);
2506 assert_eq!(siz2.csiz, 3);
2507 assert_eq!(siz2.get_bit_depth(0), 8);
2508 assert_eq!(siz2.get_bit_depth(1), 8);
2509 assert_eq!(siz2.get_bit_depth(2), 8);
2510 assert!(!siz2.is_signed(0));
2511 assert_eq!(siz2.get_downsampling(0), Point::new(1, 1));
2512 }
2513
2514 #[test]
2515 fn param_siz_get_width_height() {
2516 let mut siz = ParamSiz::default();
2517 siz.set_image_extent(Point::new(1920, 1080));
2518 siz.set_image_offset(Point::new(100, 50));
2519 siz.set_tile_size(Size::new(1920, 1080));
2520 siz.set_num_components(2);
2521 siz.set_comp_info(0, Point::new(1, 1), 8, false);
2523 siz.set_comp_info(1, Point::new(2, 2), 8, false);
2525
2526 assert_eq!(siz.get_width(0), 1820);
2528 assert_eq!(siz.get_height(0), 1030);
2530
2531 assert_eq!(siz.get_width(1), 910);
2533 assert_eq!(siz.get_height(1), 515);
2535 }
2536
2537 #[test]
2542 fn param_cod_set_get() {
2543 let mut cod = ParamCod::default();
2544 cod.set_reversible(true);
2545 assert!(cod.is_reversible());
2546 assert_eq!(cod.get_wavelet_kern(), DWT_REV53);
2547
2548 cod.set_reversible(false);
2549 assert!(!cod.is_reversible());
2550 assert_eq!(cod.get_wavelet_kern(), DWT_IRV97);
2551
2552 cod.set_num_decomposition(5);
2553 assert_eq!(cod.get_num_decompositions(), 5);
2554
2555 cod.set_color_transform(true);
2556 assert!(cod.is_employing_color_transform());
2557 cod.set_color_transform(false);
2558 assert!(!cod.is_employing_color_transform());
2559 }
2560
2561 #[test]
2562 fn param_cod_progression_order() {
2563 let mut cod = ParamCod::default();
2564 cod.set_progression_order("CPRL")
2565 .expect("valid progression");
2566 assert_eq!(cod.get_progression_order_as_string(), "CPRL");
2567
2568 cod.set_progression_order("lrcp").expect("case-insensitive");
2569 assert_eq!(cod.get_progression_order_as_string(), "LRCP");
2570 }
2571
2572 #[test]
2573 fn param_cod_invalid_progression() {
2574 let mut cod = ParamCod::default();
2575 assert!(cod.set_progression_order("INVALID").is_err());
2576 }
2577
2578 #[test]
2579 fn param_cod_block_dims() {
2580 let mut cod = ParamCod::default();
2581 cod.set_block_dims(32, 32);
2582 assert_eq!(cod.get_block_dims(), Size::new(32, 32));
2583
2584 cod.set_block_dims(64, 64);
2585 assert_eq!(cod.get_block_dims(), Size::new(64, 64));
2586
2587 cod.set_block_dims(32, 64);
2588 assert_eq!(cod.get_block_dims(), Size::new(32, 64));
2589 }
2590
2591 #[test]
2592 fn param_cod_write_read_roundtrip() {
2593 let mut cod = ParamCod::default();
2594 cod.set_reversible(true);
2595 cod.set_num_decomposition(5);
2596 cod.set_block_dims(64, 64);
2597
2598 let mut out = MemOutfile::new();
2599 cod.write(&mut out).expect("write failed");
2600
2601 let data = out.get_data();
2602 let mut inp = MemInfile::new(&data[2..]); let mut cod2 = ParamCod::default();
2604 cod2.read(&mut inp).expect("read failed");
2605
2606 assert_eq!(cod2.get_num_decompositions(), 5);
2607 assert!(cod2.is_reversible());
2608 assert_eq!(cod2.get_block_dims(), Size::new(64, 64));
2609 }
2610
2611 #[test]
2616 fn param_qcd_reversible() {
2617 let mut siz = ParamSiz::default();
2618 siz.set_image_extent(Point::new(256, 256));
2619 siz.set_tile_size(Size::new(256, 256));
2620 siz.set_num_components(1);
2621 siz.set_comp_info(0, Point::new(1, 1), 8, false);
2622
2623 let mut cod = ParamCod::default();
2624 cod.set_reversible(true);
2625 cod.set_num_decomposition(5);
2626
2627 let mut qcd = ParamQcd::default();
2628 qcd.check_validity(&siz, &cod)
2629 .expect("check_validity failed");
2630
2631 assert_eq!(qcd.sqcd & 0x1F, 0);
2633 assert!(qcd.get_num_guard_bits() >= 1);
2634 assert_eq!(qcd.num_subbands, 1 + 3 * 5);
2635 }
2636
2637 #[test]
2638 fn param_qcd_reversible_no_dwt_8bit_uses_kmax_8() {
2639 let mut siz = ParamSiz::default();
2640 siz.set_image_extent(Point::new(33, 33));
2641 siz.set_tile_size(Size::new(33, 33));
2642 siz.set_num_components(1);
2643 siz.set_comp_info(0, Point::new(1, 1), 8, false);
2644
2645 let mut cod = ParamCod::default();
2646 cod.set_reversible(true);
2647 cod.set_num_decomposition(0);
2648
2649 let mut qcd = ParamQcd::default();
2650 qcd.check_validity(&siz, &cod)
2651 .expect("check_validity failed");
2652
2653 assert_eq!(qcd.get_kmax(0, 0, 0), 8);
2654 assert_eq!(qcd.get_magb(), 8);
2655 }
2656
2657 #[test]
2658 fn param_qcd_write_read_roundtrip() {
2659 let mut siz = ParamSiz::default();
2660 siz.set_image_extent(Point::new(256, 256));
2661 siz.set_tile_size(Size::new(256, 256));
2662 siz.set_num_components(1);
2663 siz.set_comp_info(0, Point::new(1, 1), 8, false);
2664
2665 let mut cod = ParamCod::default();
2666 cod.set_reversible(true);
2667 cod.set_num_decomposition(5);
2668
2669 let mut qcd = ParamQcd::default();
2670 qcd.check_validity(&siz, &cod)
2671 .expect("check_validity failed");
2672
2673 let mut out = MemOutfile::new();
2674 qcd.write(&mut out).expect("write failed");
2675
2676 let data = out.get_data();
2677 let mut inp = MemInfile::new(&data[2..]); let mut qcd2 = ParamQcd::default();
2679 qcd2.read(&mut inp).expect("read failed");
2680
2681 assert_eq!(qcd2.sqcd, qcd.sqcd);
2682 assert_eq!(qcd2.num_subbands, qcd.num_subbands);
2683 assert_eq!(qcd2.get_num_guard_bits(), qcd.get_num_guard_bits());
2684
2685 match (&qcd.sp_qcd, &qcd2.sp_qcd) {
2687 (SpqcdData::Reversible(a), SpqcdData::Reversible(b)) => {
2688 assert_eq!(a, b);
2689 }
2690 _ => panic!("expected reversible quantization data"),
2691 }
2692 }
2693
2694 #[test]
2699 fn progression_order_from_str() {
2700 assert_eq!(
2701 ProgressionOrder::from_str("LRCP"),
2702 Some(ProgressionOrder::LRCP)
2703 );
2704 assert_eq!(
2705 ProgressionOrder::from_str("RLCP"),
2706 Some(ProgressionOrder::RLCP)
2707 );
2708 assert_eq!(
2709 ProgressionOrder::from_str("RPCL"),
2710 Some(ProgressionOrder::RPCL)
2711 );
2712 assert_eq!(
2713 ProgressionOrder::from_str("PCRL"),
2714 Some(ProgressionOrder::PCRL)
2715 );
2716 assert_eq!(
2717 ProgressionOrder::from_str("CPRL"),
2718 Some(ProgressionOrder::CPRL)
2719 );
2720 assert_eq!(
2722 ProgressionOrder::from_str("lrcp"),
2723 Some(ProgressionOrder::LRCP)
2724 );
2725 assert_eq!(ProgressionOrder::from_str("INVALID"), None);
2727 }
2728
2729 #[test]
2730 fn progression_order_as_str() {
2731 assert_eq!(ProgressionOrder::LRCP.as_str(), "LRCP");
2732 assert_eq!(ProgressionOrder::RLCP.as_str(), "RLCP");
2733 assert_eq!(ProgressionOrder::RPCL.as_str(), "RPCL");
2734 assert_eq!(ProgressionOrder::PCRL.as_str(), "PCRL");
2735 assert_eq!(ProgressionOrder::CPRL.as_str(), "CPRL");
2736 }
2737
2738 #[test]
2739 fn progression_order_from_i32() {
2740 assert_eq!(ProgressionOrder::from_i32(0), Some(ProgressionOrder::LRCP));
2741 assert_eq!(ProgressionOrder::from_i32(1), Some(ProgressionOrder::RLCP));
2742 assert_eq!(ProgressionOrder::from_i32(2), Some(ProgressionOrder::RPCL));
2743 assert_eq!(ProgressionOrder::from_i32(3), Some(ProgressionOrder::PCRL));
2744 assert_eq!(ProgressionOrder::from_i32(4), Some(ProgressionOrder::CPRL));
2745 assert_eq!(ProgressionOrder::from_i32(5), None);
2746 assert_eq!(ProgressionOrder::from_i32(-1), None);
2747 }
2748}