Skip to main content

tiff_core/
constants.rs

1// Well-known TIFF tag codes.
2pub const TAG_NEW_SUBFILE_TYPE: u16 = 254;
3pub const TAG_SUBFILE_TYPE: u16 = 255;
4pub const TAG_IMAGE_WIDTH: u16 = 256;
5pub const TAG_IMAGE_LENGTH: u16 = 257;
6pub const TAG_BITS_PER_SAMPLE: u16 = 258;
7pub const TAG_COMPRESSION: u16 = 259;
8pub const TAG_PHOTOMETRIC_INTERPRETATION: u16 = 262;
9pub const TAG_STRIP_OFFSETS: u16 = 273;
10pub const TAG_SAMPLES_PER_PIXEL: u16 = 277;
11pub const TAG_ROWS_PER_STRIP: u16 = 278;
12pub const TAG_STRIP_BYTE_COUNTS: u16 = 279;
13pub const TAG_PLANAR_CONFIGURATION: u16 = 284;
14pub const TAG_PREDICTOR: u16 = 317;
15pub const TAG_TILE_WIDTH: u16 = 322;
16pub const TAG_TILE_LENGTH: u16 = 323;
17pub const TAG_TILE_OFFSETS: u16 = 324;
18pub const TAG_TILE_BYTE_COUNTS: u16 = 325;
19pub const TAG_SAMPLE_FORMAT: u16 = 339;
20pub const TAG_JPEG_TABLES: u16 = 347;
21pub const TAG_LERC_PARAMETERS: u16 = 50674;
22
23/// TIFF compression scheme.
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub enum Compression {
26    None,
27    Lzw,
28    OldJpeg,
29    Jpeg,
30    Deflate,
31    PackBits,
32    DeflateOld,
33    Lerc,
34    Zstd,
35}
36
37impl Compression {
38    pub fn from_code(code: u16) -> Option<Self> {
39        match code {
40            1 => Some(Self::None),
41            5 => Some(Self::Lzw),
42            6 => Some(Self::OldJpeg),
43            7 => Some(Self::Jpeg),
44            8 => Some(Self::Deflate),
45            32773 => Some(Self::PackBits),
46            32946 => Some(Self::DeflateOld),
47            34887 => Some(Self::Lerc),
48            50000 => Some(Self::Zstd),
49            _ => None,
50        }
51    }
52
53    pub fn to_code(self) -> u16 {
54        match self {
55            Self::None => 1,
56            Self::Lzw => 5,
57            Self::OldJpeg => 6,
58            Self::Jpeg => 7,
59            Self::Deflate => 8,
60            Self::PackBits => 32773,
61            Self::DeflateOld => 32946,
62            Self::Lerc => 34887,
63            Self::Zstd => 50000,
64        }
65    }
66
67    pub fn name(self) -> &'static str {
68        match self {
69            Self::None => "None",
70            Self::Lzw => "LZW",
71            Self::OldJpeg => "OldJpeg",
72            Self::Jpeg => "JPEG",
73            Self::Deflate => "Deflate",
74            Self::PackBits => "PackBits",
75            Self::DeflateOld => "DeflateOld",
76            Self::Lerc => "LERC",
77            Self::Zstd => "ZSTD",
78        }
79    }
80}
81
82/// TIFF predictor scheme.
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
84pub enum Predictor {
85    None,
86    Horizontal,
87    FloatingPoint,
88}
89
90impl Predictor {
91    pub fn from_code(code: u16) -> Option<Self> {
92        match code {
93            1 => Some(Self::None),
94            2 => Some(Self::Horizontal),
95            3 => Some(Self::FloatingPoint),
96            _ => None,
97        }
98    }
99
100    pub fn to_code(self) -> u16 {
101        match self {
102            Self::None => 1,
103            Self::Horizontal => 2,
104            Self::FloatingPoint => 3,
105        }
106    }
107}
108
109/// TIFF sample format.
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub enum SampleFormat {
112    Uint,
113    Int,
114    Float,
115}
116
117impl SampleFormat {
118    pub fn from_code(code: u16) -> Option<Self> {
119        match code {
120            1 => Some(Self::Uint),
121            2 => Some(Self::Int),
122            3 => Some(Self::Float),
123            _ => None,
124        }
125    }
126
127    pub fn to_code(self) -> u16 {
128        match self {
129            Self::Uint => 1,
130            Self::Int => 2,
131            Self::Float => 3,
132        }
133    }
134}
135
136/// TIFF photometric interpretation.
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
138pub enum PhotometricInterpretation {
139    MinIsWhite,
140    MinIsBlack,
141    Rgb,
142    Palette,
143    Mask,
144}
145
146impl PhotometricInterpretation {
147    pub fn from_code(code: u16) -> Option<Self> {
148        match code {
149            0 => Some(Self::MinIsWhite),
150            1 => Some(Self::MinIsBlack),
151            2 => Some(Self::Rgb),
152            3 => Some(Self::Palette),
153            4 => Some(Self::Mask),
154            _ => None,
155        }
156    }
157
158    pub fn to_code(self) -> u16 {
159        match self {
160            Self::MinIsWhite => 0,
161            Self::MinIsBlack => 1,
162            Self::Rgb => 2,
163            Self::Palette => 3,
164            Self::Mask => 4,
165        }
166    }
167}
168
169/// TIFF planar configuration.
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
171pub enum PlanarConfiguration {
172    Chunky,
173    Planar,
174}
175
176impl PlanarConfiguration {
177    pub fn from_code(code: u16) -> Option<Self> {
178        match code {
179            1 => Some(Self::Chunky),
180            2 => Some(Self::Planar),
181            _ => None,
182        }
183    }
184
185    pub fn to_code(self) -> u16 {
186        match self {
187            Self::Chunky => 1,
188            Self::Planar => 2,
189        }
190    }
191}
192
193/// TIFF-side LERC additional compression mode.
194///
195/// When LERC is the primary compression (tag 259 = 34887), the LERC blob
196/// may optionally be wrapped in an additional compression layer. The mode
197/// is recorded in the `LercParameters` tag (50674).
198#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
199pub enum LercAdditionalCompression {
200    None,
201    Deflate,
202    Zstd,
203}
204
205impl LercAdditionalCompression {
206    pub fn from_code(code: u32) -> Option<Self> {
207        match code {
208            0 => Some(Self::None),
209            1 => Some(Self::Deflate),
210            2 => Some(Self::Zstd),
211            _ => None,
212        }
213    }
214
215    pub fn to_code(self) -> u32 {
216        match self {
217            Self::None => 0,
218            Self::Deflate => 1,
219            Self::Zstd => 2,
220        }
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    #[test]
229    fn compression_roundtrips_lerc() {
230        assert_eq!(Compression::from_code(34887), Some(Compression::Lerc));
231        assert_eq!(Compression::Lerc.to_code(), 34887);
232        assert_eq!(Compression::Lerc.name(), "LERC");
233    }
234
235    #[test]
236    fn lerc_parameters_tag_matches_registered_value() {
237        assert_eq!(TAG_LERC_PARAMETERS, 50674);
238    }
239
240    #[test]
241    fn lerc_additional_compression_roundtrips() {
242        for (code, expected) in [
243            (0, LercAdditionalCompression::None),
244            (1, LercAdditionalCompression::Deflate),
245            (2, LercAdditionalCompression::Zstd),
246        ] {
247            assert_eq!(LercAdditionalCompression::from_code(code), Some(expected));
248            assert_eq!(expected.to_code(), code);
249        }
250        assert_eq!(LercAdditionalCompression::from_code(99), None);
251    }
252}