Coverage Report

Created: 2026-06-10 07:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tiff-0.11.3/src/encoder/writer.rs
Line
Count
Source
1
use crate::encoder::compression::*;
2
use crate::error::TiffResult;
3
use std::io::{self, Seek, SeekFrom, Write};
4
5
0
pub fn write_tiff_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
6
    #[cfg(target_endian = "little")]
7
0
    let boi: u8 = 0x49;
8
    #[cfg(not(target_endian = "little"))]
9
    let boi: u8 = 0x4d;
10
11
0
    writer.writer.write_all(&[boi, boi])?;
12
0
    writer.writer.write_all(&42u16.to_ne_bytes())?;
13
0
    writer.offset += 4;
14
15
0
    Ok(())
16
0
}
Unexecuted instantiation: tiff::encoder::writer::write_tiff_header::<_>
Unexecuted instantiation: tiff::encoder::writer::write_tiff_header::<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
17
18
/// Writes a BigTiff header, excluding the IFD offset field.
19
///
20
/// Writes the byte order, version number, offset byte size, and zero constant fields. Does
21
// _not_ write the offset to the first IFD, this should be done by the caller.
22
0
pub fn write_bigtiff_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
23
    #[cfg(target_endian = "little")]
24
0
    let boi: u8 = 0x49;
25
    #[cfg(not(target_endian = "little"))]
26
    let boi: u8 = 0x4d;
27
28
    // byte order indication
29
0
    writer.writer.write_all(&[boi, boi])?;
30
    // version number
31
0
    writer.writer.write_all(&43u16.to_ne_bytes())?;
32
    // bytesize of offsets (pointer size)
33
0
    writer.writer.write_all(&8u16.to_ne_bytes())?;
34
    // always 0
35
0
    writer.writer.write_all(&0u16.to_ne_bytes())?;
36
37
    // we wrote 8 bytes, so set the internal offset accordingly
38
0
    writer.offset += 8;
39
40
0
    Ok(())
41
0
}
42
43
pub struct TiffWriter<W> {
44
    writer: W,
45
    offset: u64,
46
    byte_count: u64,
47
    compressor: Compressor,
48
}
49
50
impl<W: Write> TiffWriter<W> {
51
0
    pub fn new(writer: W) -> Self {
52
0
        Self {
53
0
            writer,
54
0
            offset: 0,
55
0
            byte_count: 0,
56
0
            compressor: Compressor::default(),
57
0
        }
58
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::new
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut alloc::vec::Vec<u8>>>::new
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
59
60
0
    pub fn set_compression(&mut self, compressor: Compressor) {
61
0
        self.compressor = compressor;
62
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::set_compression
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::set_compression
63
64
0
    pub fn reset_compression(&mut self) {
65
0
        self.compressor = Compressor::default();
66
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::reset_compression
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::reset_compression
67
68
0
    pub fn offset(&self) -> u64 {
69
0
        self.offset
70
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::offset
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::offset
71
72
0
    pub(crate) fn previous_ifd_pointer<K: super::TiffKind>(&self) -> u64 {
73
0
        self.offset() - core::mem::size_of::<K::OffsetType>() as u64
74
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::previous_ifd_pointer::<_>
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::previous_ifd_pointer::<tiff::encoder::TiffKindStandard>
75
76
0
    pub fn last_written(&self) -> u64 {
77
0
        self.byte_count
78
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::last_written
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::last_written
79
80
0
    pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), io::Error> {
81
0
        self.byte_count = self.compressor.write_to(&mut self.writer, bytes)?;
82
0
        self.offset += self.byte_count;
83
0
        Ok(())
84
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::write_bytes
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut alloc::vec::Vec<u8>>>::write_bytes
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_bytes
85
86
0
    pub fn write_u8(&mut self, n: u8) -> Result<(), io::Error> {
87
0
        self.byte_count = self
88
0
            .compressor
89
0
            .write_to(&mut self.writer, &n.to_ne_bytes())?;
90
0
        self.offset += self.byte_count;
91
0
        Ok(())
92
0
    }
93
94
0
    pub fn write_i8(&mut self, n: i8) -> Result<(), io::Error> {
95
0
        self.byte_count = self
96
0
            .compressor
97
0
            .write_to(&mut self.writer, &n.to_ne_bytes())?;
98
0
        self.offset += self.byte_count;
99
0
        Ok(())
100
0
    }
101
102
0
    pub fn write_u16(&mut self, n: u16) -> Result<(), io::Error> {
103
0
        self.byte_count = self
104
0
            .compressor
105
0
            .write_to(&mut self.writer, &n.to_ne_bytes())?;
106
0
        self.offset += self.byte_count;
107
108
0
        Ok(())
109
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::write_u16
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut alloc::vec::Vec<u8>>>::write_u16
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_u16
110
111
0
    pub fn write_i16(&mut self, n: i16) -> Result<(), io::Error> {
112
0
        self.byte_count = self
113
0
            .compressor
114
0
            .write_to(&mut self.writer, &n.to_ne_bytes())?;
115
0
        self.offset += self.byte_count;
116
117
0
        Ok(())
118
0
    }
119
120
0
    pub fn write_u32(&mut self, n: u32) -> Result<(), io::Error> {
121
0
        self.byte_count = self
122
0
            .compressor
123
0
            .write_to(&mut self.writer, &n.to_ne_bytes())?;
124
0
        self.offset += self.byte_count;
125
126
0
        Ok(())
127
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::write_u32
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut alloc::vec::Vec<u8>>>::write_u32
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_u32
128
129
0
    pub fn write_i32(&mut self, n: i32) -> Result<(), io::Error> {
130
0
        self.byte_count = self
131
0
            .compressor
132
0
            .write_to(&mut self.writer, &n.to_ne_bytes())?;
133
0
        self.offset += self.byte_count;
134
135
0
        Ok(())
136
0
    }
137
138
0
    pub fn write_u64(&mut self, n: u64) -> Result<(), io::Error> {
139
0
        self.byte_count = self
140
0
            .compressor
141
0
            .write_to(&mut self.writer, &n.to_ne_bytes())?;
142
0
        self.offset += self.byte_count;
143
144
0
        Ok(())
145
0
    }
146
147
0
    pub fn write_i64(&mut self, n: i64) -> Result<(), io::Error> {
148
0
        self.byte_count = self
149
0
            .compressor
150
0
            .write_to(&mut self.writer, &n.to_ne_bytes())?;
151
0
        self.offset += self.byte_count;
152
153
0
        Ok(())
154
0
    }
155
156
0
    pub fn write_f32(&mut self, n: f32) -> Result<(), io::Error> {
157
0
        self.byte_count = self
158
0
            .compressor
159
0
            .write_to(&mut self.writer, &u32::to_ne_bytes(n.to_bits()))?;
160
0
        self.offset += self.byte_count;
161
162
0
        Ok(())
163
0
    }
164
165
0
    pub fn write_f64(&mut self, n: f64) -> Result<(), io::Error> {
166
0
        self.byte_count = self
167
0
            .compressor
168
0
            .write_to(&mut self.writer, &u64::to_ne_bytes(n.to_bits()))?;
169
0
        self.offset += self.byte_count;
170
171
0
        Ok(())
172
0
    }
173
174
0
    pub fn pad_word_boundary(&mut self) -> Result<(), io::Error> {
175
0
        if self.offset % 4 != 0 {
176
0
            let padding = [0, 0, 0];
177
0
            let padd_len = 4 - (self.offset % 4);
178
0
            self.writer.write_all(&padding[..padd_len as usize])?;
179
0
            self.offset += padd_len;
180
0
        }
181
182
0
        Ok(())
183
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::pad_word_boundary
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::pad_word_boundary
184
}
185
186
impl<W: Seek> TiffWriter<W> {
187
0
    pub fn goto_offset(&mut self, offset: u64) -> Result<(), io::Error> {
188
0
        self.offset = offset;
189
0
        self.writer.seek(SeekFrom::Start(offset))?;
190
0
        Ok(())
191
0
    }
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<_>>::goto_offset
Unexecuted instantiation: <tiff::encoder::writer::TiffWriter<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::goto_offset
192
}
193
194
#[test]
195
fn encoder_on_short_writes() {
196
    struct ShortWriter<T> {
197
        inner: T,
198
    }
199
200
    impl<T: std::io::Write> std::io::Write for ShortWriter<T> {
201
        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
202
            let lower_bound = buf.len().min(1);
203
            let lower = buf.len().saturating_sub(1).max(lower_bound);
204
205
            self.inner.write(&buf[..lower])
206
        }
207
208
        fn flush(&mut self) -> std::io::Result<()> {
209
            self.inner.flush()
210
        }
211
    }
212
213
    impl<T: std::io::Seek> std::io::Seek for ShortWriter<T> {
214
        fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
215
            self.inner.seek(pos)
216
        }
217
    }
218
219
    let mut write = ShortWriter {
220
        inner: std::io::Cursor::new(vec![0u8; 0]),
221
    };
222
223
    let imgdata = vec![42u8; 100 * 100];
224
    let mut data = crate::decoder::DecodingResult::U8(vec![]);
225
226
    for comp in [
227
        super::Compression::Uncompressed,
228
        super::Compression::Packbits,
229
    ] {
230
        write.inner.set_position(0);
231
        write.inner.get_mut().clear();
232
233
        {
234
            let mut tiff_writer = super::TiffEncoder::new(&mut write)
235
                .unwrap()
236
                .with_compression(comp);
237
238
            tiff_writer
239
                .write_image::<super::Gray8>(100, 100, &imgdata)
240
                .unwrap();
241
        }
242
243
        write.inner.set_position(0);
244
        let mut tiff_reader = crate::decoder::Decoder::new(&mut write.inner).unwrap();
245
        let _layout = tiff_reader.read_image_to_buffer(&mut data).unwrap();
246
247
        assert!(
248
            matches!(&data, crate::decoder::DecodingResult::U8(v) if *v == imgdata),
249
            "{data:?} @ {}",
250
            data.as_buffer(0).byte_len()
251
        );
252
    }
253
}