Skip to main content

ebcc/
config.rs

1//! Configuration types for EBCC compression.
2
3use crate::error::{EBCCError, EBCCResult};
4
5/// Residual compression types supported by EBCC.
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub enum EBCCResidualType {
8    /// No residual compression - base JPEG2000 only
9    Jpeg2000Only,
10    /// Residual compression with absolute maximum error bound
11    AbsoluteError(f32),
12    /// Residual compression with relative error bound
13    RelativeError(f32),
14}
15
16impl EBCCResidualType {
17    pub(crate) const fn as_residual(self) -> ebcc_sys::residual_t::Type {
18        match self {
19            Self::Jpeg2000Only => ebcc_sys::residual_t::NONE,
20            Self::AbsoluteError(_) => ebcc_sys::residual_t::MAX_ERROR,
21            Self::RelativeError(_) => ebcc_sys::residual_t::RELATIVE_ERROR,
22        }
23    }
24
25    pub(crate) const fn as_error(self) -> f32 {
26        match self {
27            Self::Jpeg2000Only => 0.0,
28            Self::AbsoluteError(error) | Self::RelativeError(error) => error,
29        }
30    }
31}
32
33/// Configuration for EBCC compression.
34#[derive(Debug, Clone, PartialEq)]
35pub struct EBCCConfig {
36    /// Base compression ratio for JPEG2000 layer
37    pub base_cr: f32,
38
39    /// Type of residual compression to apply
40    pub residual_compression_type: EBCCResidualType,
41}
42
43impl Default for EBCCConfig {
44    fn default() -> Self {
45        Self::new()
46    }
47}
48
49const DEFAULT_BASE_CR: f32 = 100.0;
50
51impl EBCCConfig {
52    /// Create a new EBCC configuration with default values.
53    #[must_use]
54    pub const fn new() -> Self {
55        Self {
56            base_cr: DEFAULT_BASE_CR,
57            residual_compression_type: EBCCResidualType::Jpeg2000Only,
58        }
59    }
60
61    /// Create a configuration for JPEG2000-only compression.
62    #[must_use]
63    pub const fn jpeg2000_only(base_cr: f32) -> Self {
64        Self {
65            base_cr,
66            residual_compression_type: EBCCResidualType::Jpeg2000Only,
67        }
68    }
69
70    /// Create a configuration for maximum error bounded compression.
71    #[must_use]
72    pub const fn max_absolute_error_bounded(error: f32) -> Self {
73        Self {
74            base_cr: DEFAULT_BASE_CR,
75            residual_compression_type: EBCCResidualType::AbsoluteError(error),
76        }
77    }
78
79    /// Create a configuration for relative error bounded compression.
80    #[must_use]
81    pub const fn relative_error_bounded(error: f32) -> Self {
82        Self {
83            base_cr: DEFAULT_BASE_CR,
84            residual_compression_type: EBCCResidualType::RelativeError(error),
85        }
86    }
87
88    /// Change the JPEG2000 layer base compression ratio.
89    #[must_use]
90    pub const fn with_base_cr(mut self, base_cr: f32) -> Self {
91        self.base_cr = base_cr;
92        self
93    }
94
95    /// Validate the configuration parameters.
96    ///
97    /// # Errors
98    ///
99    /// - [`EBCCError::InvalidConfig`] if `base_cr` is non-positive
100    /// - [`EBCCError::InvalidConfig`] if the absolute or relative error bound
101    ///   is non-positive
102    pub fn validate(&self) -> EBCCResult<()> {
103        // Check compression ratio
104        if self.base_cr <= 0.0 {
105            return Err(EBCCError::InvalidConfig(String::from(
106                "Base compression ratio must be positive",
107            )));
108        }
109
110        // Check residual-specific parameters
111        match self.residual_compression_type {
112            EBCCResidualType::AbsoluteError(error) | EBCCResidualType::RelativeError(error) => {
113                if error <= 0.0 {
114                    return Err(EBCCError::InvalidConfig(String::from(
115                        "Error bound must be positive",
116                    )));
117                }
118            }
119            EBCCResidualType::Jpeg2000Only => {
120                // No additional validation needed
121            }
122        }
123
124        Ok(())
125    }
126}