1use binrw::{BinRead, BinWrite};
10use std::fmt;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, BinRead, BinWrite)]
16pub enum ByteOrder {
17 #[brw(magic = b"II")]
19 LittleEndian,
20 #[brw(magic = b"MM")]
22 BigEndian,
23}
24
25impl ByteOrder {
26 pub fn from_bytes(bytes: [u8; 2]) -> Option<Self> {
28 match &bytes {
29 b"II" => Some(ByteOrder::LittleEndian),
30 b"MM" => Some(ByteOrder::BigEndian),
31 _ => None,
32 }
33 }
34
35 pub fn to_bytes(self) -> [u8; 2] {
37 match self {
38 ByteOrder::LittleEndian => *b"II",
39 ByteOrder::BigEndian => *b"MM",
40 }
41 }
42
43 pub fn as_str(&self) -> &'static str {
45 match self {
46 ByteOrder::LittleEndian => "LE",
47 ByteOrder::BigEndian => "BE",
48 }
49 }
50}
51
52impl fmt::Display for ByteOrder {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 ByteOrder::LittleEndian => write!(f, "Little-Endian (II)"),
56 ByteOrder::BigEndian => write!(f, "Big-Endian (MM)"),
57 }
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, BinRead, BinWrite)]
66#[brw(repr = u16)]
67#[repr(u16)]
68pub enum TiffType {
69 Byte = 1,
71 Ascii = 2,
73 Short = 3,
75 Long = 4,
77 Rational = 5,
79 SByte = 6,
81 Undefined = 7,
83 SShort = 8,
85 SLong = 9,
87 SRational = 10,
89 Float = 11,
91 Double = 12,
93 Ifd = 13,
95 Long8 = 16,
97 SLong8 = 17,
99 Ifd8 = 18,
101}
102
103impl TiffType {
104 pub fn from_u16(value: u16) -> Option<Self> {
106 match value {
107 1 => Some(TiffType::Byte),
108 2 => Some(TiffType::Ascii),
109 3 => Some(TiffType::Short),
110 4 => Some(TiffType::Long),
111 5 => Some(TiffType::Rational),
112 6 => Some(TiffType::SByte),
113 7 => Some(TiffType::Undefined),
114 8 => Some(TiffType::SShort),
115 9 => Some(TiffType::SLong),
116 10 => Some(TiffType::SRational),
117 11 => Some(TiffType::Float),
118 12 => Some(TiffType::Double),
119 13 => Some(TiffType::Ifd),
120 16 => Some(TiffType::Long8),
121 17 => Some(TiffType::SLong8),
122 18 => Some(TiffType::Ifd8),
123 _ => None,
124 }
125 }
126
127 pub fn size(&self) -> usize {
129 match self {
130 TiffType::Byte | TiffType::Ascii | TiffType::SByte | TiffType::Undefined => 1,
131 TiffType::Short | TiffType::SShort => 2,
132 TiffType::Long | TiffType::SLong | TiffType::Float | TiffType::Ifd => 4,
133 TiffType::Rational
134 | TiffType::SRational
135 | TiffType::Double
136 | TiffType::Long8
137 | TiffType::SLong8
138 | TiffType::Ifd8 => 8,
139 }
140 }
141
142 pub fn fits_inline(&self, count: u32) -> bool {
147 self.size() * (count as usize) <= 4
148 }
149
150 pub fn fits_inline_bigtiff(&self, count: u64) -> bool {
154 self.size() * (count as usize) <= 8
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, BinRead, BinWrite)]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161pub struct Rational {
162 pub numerator: u32,
164 pub denominator: u32,
166}
167
168impl Rational {
169 pub fn new(numerator: u32, denominator: u32) -> Self {
171 Self {
172 numerator,
173 denominator,
174 }
175 }
176
177 pub fn to_f64(&self) -> f64 {
179 if self.denominator == 0 {
180 if self.numerator == 0 {
181 f64::NAN
182 } else {
183 f64::INFINITY
184 }
185 } else {
186 self.numerator as f64 / self.denominator as f64
187 }
188 }
189}
190
191impl From<(u32, u32)> for Rational {
192 fn from((numerator, denominator): (u32, u32)) -> Self {
193 Self {
194 numerator,
195 denominator,
196 }
197 }
198}
199
200impl fmt::Display for Rational {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 write!(f, "{}/{}", self.numerator, self.denominator)
203 }
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq, BinRead, BinWrite)]
208#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
209pub struct SRational {
210 pub numerator: i32,
212 pub denominator: i32,
214}
215
216impl SRational {
217 pub fn new(numerator: i32, denominator: i32) -> Self {
219 Self {
220 numerator,
221 denominator,
222 }
223 }
224
225 pub fn to_f64(&self) -> f64 {
227 if self.denominator == 0 {
228 if self.numerator == 0 {
229 f64::NAN
230 } else if self.numerator > 0 {
231 f64::INFINITY
232 } else {
233 f64::NEG_INFINITY
234 }
235 } else {
236 self.numerator as f64 / self.denominator as f64
237 }
238 }
239}
240
241impl From<(i32, i32)> for SRational {
242 fn from((numerator, denominator): (i32, i32)) -> Self {
243 Self {
244 numerator,
245 denominator,
246 }
247 }
248}
249
250impl fmt::Display for SRational {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 write!(f, "{}/{}", self.numerator, self.denominator)
253 }
254}
255
256impl From<Rational> for rawshift_core::metadata::URational {
261 fn from(r: Rational) -> Self {
262 Self::new(r.numerator, r.denominator)
263 }
264}
265
266impl From<SRational> for rawshift_core::metadata::SRational {
267 fn from(r: SRational) -> Self {
268 Self::new(r.numerator, r.denominator)
269 }
270}
271
272#[derive(Debug, Clone, PartialEq)]
277pub enum TiffValue {
278 Bytes(Vec<u8>),
280 Ascii(String),
282 Shorts(Vec<u16>),
284 Longs(Vec<u32>),
286 Rationals(Vec<Rational>),
288 SBytes(Vec<i8>),
290 Undefined(Vec<u8>),
292 SShorts(Vec<i16>),
294 SLongs(Vec<i32>),
296 SRationals(Vec<SRational>),
298 Floats(Vec<f32>),
300 Doubles(Vec<f64>),
302 Long8s(Vec<u64>),
304 SLong8s(Vec<i64>),
306}
307
308impl TiffValue {
309 pub fn as_u32(&self) -> Option<u32> {
311 match self {
312 TiffValue::Bytes(v) if v.len() == 1 => Some(v[0] as u32),
313 TiffValue::Shorts(v) if v.len() == 1 => Some(v[0] as u32),
314 TiffValue::Longs(v) if v.len() == 1 => Some(v[0]),
315 _ => None,
316 }
317 }
318
319 pub fn first_u32(&self) -> Option<u32> {
321 match self {
322 TiffValue::Bytes(v) if !v.is_empty() => Some(v[0] as u32),
323 TiffValue::Shorts(v) if !v.is_empty() => Some(v[0] as u32),
324 TiffValue::Longs(v) if !v.is_empty() => Some(v[0]),
325 _ => None,
326 }
327 }
328
329 pub fn as_u32_vec(&self) -> Option<Vec<u32>> {
331 match self {
332 TiffValue::Bytes(v) => Some(v.iter().map(|&x| x as u32).collect()),
333 TiffValue::Shorts(v) => Some(v.iter().map(|&x| x as u32).collect()),
334 TiffValue::Longs(v) => Some(v.clone()),
335 _ => None,
336 }
337 }
338
339 pub fn as_u64(&self) -> Option<u64> {
341 match self {
342 TiffValue::Bytes(v) if v.len() == 1 => Some(v[0] as u64),
343 TiffValue::Shorts(v) if v.len() == 1 => Some(v[0] as u64),
344 TiffValue::Longs(v) if v.len() == 1 => Some(v[0] as u64),
345 TiffValue::Long8s(v) if v.len() == 1 => Some(v[0]),
346 _ => None,
347 }
348 }
349
350 pub fn as_u64_vec(&self) -> Option<Vec<u64>> {
352 match self {
353 TiffValue::Bytes(v) => Some(v.iter().map(|&x| x as u64).collect()),
354 TiffValue::Shorts(v) => Some(v.iter().map(|&x| x as u64).collect()),
355 TiffValue::Longs(v) => Some(v.iter().map(|&x| x as u64).collect()),
356 TiffValue::Long8s(v) => Some(v.clone()),
357 _ => None,
358 }
359 }
360
361 pub fn as_f64_vec(&self) -> Option<Vec<f64>> {
364 match self {
365 TiffValue::Bytes(v) => Some(v.iter().map(|&x| x as f64).collect()),
366 TiffValue::Shorts(v) => Some(v.iter().map(|&x| x as f64).collect()),
367 TiffValue::Longs(v) => Some(v.iter().map(|&x| x as f64).collect()),
368 TiffValue::Rationals(v) => Some(v.iter().map(|r| r.to_f64()).collect()),
369 TiffValue::SRationals(v) => Some(v.iter().map(|r| r.to_f64()).collect()),
370 TiffValue::Floats(v) => Some(v.iter().map(|&x| x as f64).collect()),
371 TiffValue::Doubles(v) => Some(v.clone()),
372 _ => None,
373 }
374 }
375
376 pub fn as_str(&self) -> Option<&str> {
378 match self {
379 TiffValue::Ascii(s) => Some(s.as_str()),
380 _ => None,
381 }
382 }
383
384 pub fn len(&self) -> usize {
386 match self {
387 TiffValue::Bytes(v) | TiffValue::Undefined(v) => v.len(),
388 TiffValue::Ascii(s) => s.len() + 1, TiffValue::Shorts(v) => v.len(),
390 TiffValue::Longs(v) => v.len(),
391 TiffValue::Rationals(v) => v.len(),
392 TiffValue::SBytes(v) => v.len(),
393 TiffValue::SShorts(v) => v.len(),
394 TiffValue::SLongs(v) => v.len(),
395 TiffValue::SRationals(v) => v.len(),
396 TiffValue::Floats(v) => v.len(),
397 TiffValue::Doubles(v) => v.len(),
398 TiffValue::Long8s(v) => v.len(),
399 TiffValue::SLong8s(v) => v.len(),
400 }
401 }
402
403 pub fn is_empty(&self) -> bool {
405 self.len() == 0
406 }
407}
408
409#[cfg(test)]
410mod tests {
411 use super::*;
412
413 #[test]
414 fn test_byte_order_from_bytes() {
415 assert_eq!(ByteOrder::from_bytes(*b"II"), Some(ByteOrder::LittleEndian));
416 assert_eq!(ByteOrder::from_bytes(*b"MM"), Some(ByteOrder::BigEndian));
417 assert_eq!(ByteOrder::from_bytes(*b"XX"), None);
418 }
419
420 #[test]
421 fn test_byte_order_to_bytes() {
422 assert_eq!(ByteOrder::LittleEndian.to_bytes(), *b"II");
423 assert_eq!(ByteOrder::BigEndian.to_bytes(), *b"MM");
424 }
425
426 #[test]
427 fn test_byte_order_as_str() {
428 assert_eq!(ByteOrder::LittleEndian.as_str(), "LE");
429 assert_eq!(ByteOrder::BigEndian.as_str(), "BE");
430 }
431
432 #[test]
433 fn test_tiff_type_size() {
434 assert_eq!(TiffType::Byte.size(), 1);
435 assert_eq!(TiffType::Ascii.size(), 1);
436 assert_eq!(TiffType::Short.size(), 2);
437 assert_eq!(TiffType::Long.size(), 4);
438 assert_eq!(TiffType::Rational.size(), 8);
439 assert_eq!(TiffType::Double.size(), 8);
440 assert_eq!(TiffType::Long8.size(), 8);
441 }
442
443 #[test]
444 fn test_tiff_type_fits_inline() {
445 assert!(TiffType::Byte.fits_inline(4));
447 assert!(TiffType::Byte.fits_inline(1));
448 assert!(!TiffType::Byte.fits_inline(5));
449
450 assert!(TiffType::Short.fits_inline(2));
451 assert!(!TiffType::Short.fits_inline(3));
452
453 assert!(TiffType::Long.fits_inline(1));
454 assert!(!TiffType::Long.fits_inline(2));
455
456 assert!(!TiffType::Rational.fits_inline(1));
458 }
459
460 #[test]
461 fn test_rational_to_f64() {
462 let r = Rational::new(1, 2);
463 assert_eq!(r.to_f64(), 0.5);
464
465 let r = Rational::new(0, 0);
466 assert!(r.to_f64().is_nan());
467
468 let r = Rational::new(1, 0);
469 assert!(r.to_f64().is_infinite());
470 }
471
472 #[test]
473 fn test_srational_to_f64() {
474 let r = SRational::new(-1, 2);
475 assert_eq!(r.to_f64(), -0.5);
476
477 let r = SRational::new(-1, 0);
478 assert_eq!(r.to_f64(), f64::NEG_INFINITY);
479 }
480
481 #[test]
482 fn test_tiff_value_as_u32() {
483 let v = TiffValue::Shorts(vec![42]);
484 assert_eq!(v.as_u32(), Some(42));
485
486 let v = TiffValue::Longs(vec![1000]);
487 assert_eq!(v.as_u32(), Some(1000));
488
489 let v = TiffValue::Longs(vec![1, 2]);
490 assert_eq!(v.as_u32(), None); }
492
493 #[test]
494 fn test_tiff_value_as_u64() {
495 let v = TiffValue::Shorts(vec![255]);
497 assert_eq!(v.as_u64(), Some(255u64));
498
499 let v = TiffValue::Longs(vec![100_000]);
501 assert_eq!(v.as_u64(), Some(100_000u64));
502
503 let v = TiffValue::Long8s(vec![u64::MAX]);
505 assert_eq!(v.as_u64(), Some(u64::MAX));
506
507 let v = TiffValue::Shorts(vec![1, 2]);
509 assert_eq!(v.as_u64(), None);
510
511 let v = TiffValue::Ascii("hello".to_string());
513 assert_eq!(v.as_u64(), None);
514 }
515
516 #[test]
517 fn test_tiff_value_as_string() {
518 let v = TiffValue::Ascii("Canon".to_string());
519 assert_eq!(v.as_str(), Some("Canon"));
520
521 let v = TiffValue::Shorts(vec![1]);
523 assert_eq!(v.as_str(), None);
524
525 let v = TiffValue::Bytes(vec![65, 66]);
526 assert_eq!(v.as_str(), None);
527 }
528}