Skip to main content

tiff_writer/
sample.rs

1//! Type-safe sample encoding for TIFF writes.
2
3use tiff_core::ByteOrder;
4
5/// Types that can be written as TIFF samples.
6pub trait TiffWriteSample: tiff_core::TiffSample + Copy + Send + Sync {
7    /// TIFF SampleFormat code (1=uint, 2=int, 3=float).
8    const SAMPLE_FORMAT: u16;
9    /// TIFF BitsPerSample value.
10    const BITS_PER_SAMPLE: u16;
11    /// Bytes per sample.
12    const BYTES_PER_SAMPLE: usize;
13
14    /// Encode a slice of samples into file-order bytes.
15    fn encode_slice(samples: &[Self], byte_order: ByteOrder) -> Vec<u8>;
16
17    /// Encode a block of samples as a LERC2 blob.
18    ///
19    /// For LERC-compatible types (i8, u8, i16, u16, i32, u32, f32, f64) this
20    /// delegates to the `lerc-writer` crate. For types not supported by LERC
21    /// (u64, i64), this returns an error.
22    fn lerc_encode_block(
23        samples: &[Self],
24        width: u32,
25        height: u32,
26        depth: u32,
27        max_z_error: f64,
28        index: usize,
29    ) -> crate::error::Result<Vec<u8>>;
30}
31
32// ---------- 8-bit types (LERC-compatible) ----------
33
34macro_rules! impl_write_sample_8 {
35    ($ty:ty, $format:expr) => {
36        impl TiffWriteSample for $ty {
37            const SAMPLE_FORMAT: u16 = $format;
38            const BITS_PER_SAMPLE: u16 = 8;
39            const BYTES_PER_SAMPLE: usize = 1;
40
41            fn encode_slice(samples: &[Self], _byte_order: ByteOrder) -> Vec<u8> {
42                samples.iter().map(|&v| v as u8).collect()
43            }
44
45            fn lerc_encode_block(
46                samples: &[Self],
47                width: u32,
48                height: u32,
49                depth: u32,
50                max_z_error: f64,
51                index: usize,
52            ) -> crate::error::Result<Vec<u8>> {
53                crate::compress::lerc_encode(samples, width, height, depth, max_z_error, index)
54            }
55        }
56    };
57}
58
59// ---------- Multi-byte types (LERC-compatible) ----------
60
61macro_rules! impl_write_sample {
62    ($ty:ty, $format:expr, $bits:expr, $bytes:expr, $write_fn:ident) => {
63        impl TiffWriteSample for $ty {
64            const SAMPLE_FORMAT: u16 = $format;
65            const BITS_PER_SAMPLE: u16 = $bits;
66            const BYTES_PER_SAMPLE: usize = $bytes;
67
68            fn encode_slice(samples: &[Self], byte_order: ByteOrder) -> Vec<u8> {
69                let mut out = Vec::with_capacity(samples.len() * $bytes);
70                for &v in samples {
71                    out.extend_from_slice(&byte_order.$write_fn(v));
72                }
73                out
74            }
75
76            fn lerc_encode_block(
77                samples: &[Self],
78                width: u32,
79                height: u32,
80                depth: u32,
81                max_z_error: f64,
82                index: usize,
83            ) -> crate::error::Result<Vec<u8>> {
84                crate::compress::lerc_encode(samples, width, height, depth, max_z_error, index)
85            }
86        }
87    };
88}
89
90// ---------- 64-bit integer types (NOT LERC-compatible) ----------
91
92macro_rules! impl_write_sample_no_lerc {
93    ($ty:ty, $format:expr, $bits:expr, $bytes:expr, $write_fn:ident) => {
94        impl TiffWriteSample for $ty {
95            const SAMPLE_FORMAT: u16 = $format;
96            const BITS_PER_SAMPLE: u16 = $bits;
97            const BYTES_PER_SAMPLE: usize = $bytes;
98
99            fn encode_slice(samples: &[Self], byte_order: ByteOrder) -> Vec<u8> {
100                let mut out = Vec::with_capacity(samples.len() * $bytes);
101                for &v in samples {
102                    out.extend_from_slice(&byte_order.$write_fn(v));
103                }
104                out
105            }
106
107            fn lerc_encode_block(
108                _samples: &[Self],
109                _width: u32,
110                _height: u32,
111                _depth: u32,
112                _max_z_error: f64,
113                index: usize,
114            ) -> crate::error::Result<Vec<u8>> {
115                Err(crate::error::Error::CompressionFailed {
116                    index,
117                    reason: "LERC does not support 64-bit integer samples".into(),
118                })
119            }
120        }
121    };
122}
123
124impl_write_sample_8!(u8, 1);
125impl_write_sample_8!(i8, 2);
126impl_write_sample!(u16, 1, 16, 2, write_u16);
127impl_write_sample!(i16, 2, 16, 2, write_i16);
128impl_write_sample!(u32, 1, 32, 4, write_u32);
129impl_write_sample!(i32, 2, 32, 4, write_i32);
130impl_write_sample!(f32, 3, 32, 4, write_f32);
131impl_write_sample!(f64, 3, 64, 8, write_f64);
132impl_write_sample_no_lerc!(u64, 1, 64, 8, write_u64);
133impl_write_sample_no_lerc!(i64, 2, 64, 8, write_i64);