/rust/registry/src/index.crates.io-6f17d22bba15001f/tiff-0.10.0/src/encoder/mod.rs
Line | Count | Source (jump to first uncovered line) |
1 | | pub use tiff_value::*; |
2 | | |
3 | | use std::{ |
4 | | cmp, |
5 | | collections::BTreeMap, |
6 | | io::{self, Seek, Write}, |
7 | | marker::PhantomData, |
8 | | mem, |
9 | | num::TryFromIntError, |
10 | | }; |
11 | | |
12 | | use crate::{ |
13 | | error::{TiffResult, UsageError}, |
14 | | tags::{CompressionMethod, ResolutionUnit, SampleFormat, Tag}, |
15 | | TiffError, TiffFormatError, |
16 | | }; |
17 | | |
18 | | pub mod colortype; |
19 | | pub mod compression; |
20 | | mod tiff_value; |
21 | | mod writer; |
22 | | |
23 | | use self::colortype::*; |
24 | | use self::compression::Compression as Comp; |
25 | | use self::compression::*; |
26 | | use self::writer::*; |
27 | | |
28 | | /// Type of prediction to prepare the image with. |
29 | | /// |
30 | | /// Image data can be very unpredictable, and thus very hard to compress. Predictors are simple |
31 | | /// passes ran over the image data to prepare it for compression. This is mostly used for LZW |
32 | | /// compression, where using [Predictor::Horizontal] we see a 35% improvement in compression |
33 | | /// ratio over the unpredicted compression ! |
34 | | /// |
35 | | /// [Predictor::FloatingPoint] is currently not supported. |
36 | | pub type Predictor = crate::tags::Predictor; |
37 | | #[cfg(feature = "deflate")] |
38 | | pub type DeflateLevel = compression::DeflateLevel; |
39 | | |
40 | | #[derive(Clone, Copy, PartialEq)] |
41 | | pub enum Compression { |
42 | | Uncompressed, |
43 | | #[cfg(feature = "lzw")] |
44 | | Lzw, |
45 | | #[cfg(feature = "deflate")] |
46 | | Deflate(DeflateLevel), |
47 | | Packbits, |
48 | | } |
49 | | |
50 | | impl Default for Compression { |
51 | 0 | fn default() -> Self { |
52 | 0 | Self::Uncompressed |
53 | 0 | } |
54 | | } |
55 | | |
56 | | impl Compression { |
57 | 0 | fn tag(&self) -> CompressionMethod { |
58 | 0 | match self { |
59 | 0 | Compression::Uncompressed => CompressionMethod::None, |
60 | | #[cfg(feature = "lzw")] |
61 | 0 | Compression::Lzw => CompressionMethod::LZW, |
62 | | #[cfg(feature = "deflate")] |
63 | 0 | Compression::Deflate(_) => CompressionMethod::Deflate, |
64 | 0 | Compression::Packbits => CompressionMethod::PackBits, |
65 | | } |
66 | 0 | } |
67 | | |
68 | 0 | fn get_algorithm(&self) -> Compressor { |
69 | 0 | match self { |
70 | 0 | Compression::Uncompressed => compression::Uncompressed {}.get_algorithm(), |
71 | | #[cfg(feature = "lzw")] |
72 | 0 | Compression::Lzw => compression::Lzw {}.get_algorithm(), |
73 | | #[cfg(feature = "deflate")] |
74 | 0 | Compression::Deflate(level) => compression::Deflate::with_level(*level).get_algorithm(), |
75 | 0 | Compression::Packbits => compression::Packbits {}.get_algorithm(), |
76 | | } |
77 | 0 | } |
78 | | } |
79 | | |
80 | | /// Encoder for Tiff and BigTiff files. |
81 | | /// |
82 | | /// With this type you can get a `DirectoryEncoder` or a `ImageEncoder` |
83 | | /// to encode Tiff/BigTiff ifd directories with images. |
84 | | /// |
85 | | /// See `DirectoryEncoder` and `ImageEncoder`. |
86 | | /// |
87 | | /// # Examples |
88 | | /// ``` |
89 | | /// # extern crate tiff; |
90 | | /// # fn main() { |
91 | | /// # let mut file = std::io::Cursor::new(Vec::new()); |
92 | | /// # let image_data = vec![0; 100*100*3]; |
93 | | /// use tiff::encoder::*; |
94 | | /// |
95 | | /// // create a standard Tiff file |
96 | | /// let mut tiff = TiffEncoder::new(&mut file).unwrap(); |
97 | | /// tiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap(); |
98 | | /// |
99 | | /// // create a BigTiff file |
100 | | /// let mut bigtiff = TiffEncoder::new_big(&mut file).unwrap(); |
101 | | /// bigtiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap(); |
102 | | /// |
103 | | /// # } |
104 | | /// ``` |
105 | | pub struct TiffEncoder<W, K: TiffKind = TiffKindStandard> { |
106 | | writer: TiffWriter<W>, |
107 | | kind: PhantomData<K>, |
108 | | predictor: Predictor, |
109 | | compression: Compression, |
110 | | } |
111 | | |
112 | | /// Constructor functions to create standard Tiff files. |
113 | | impl<W: Write + Seek> TiffEncoder<W> { |
114 | | /// Creates a new encoder for standard Tiff files. |
115 | | /// |
116 | | /// To create BigTiff files, use [`new_big`][TiffEncoder::new_big] or |
117 | | /// [`new_generic`][TiffEncoder::new_generic]. |
118 | 0 | pub fn new(writer: W) -> TiffResult<TiffEncoder<W, TiffKindStandard>> { |
119 | 0 | TiffEncoder::new_generic(writer) |
120 | 0 | } Unexecuted instantiation: <tiff::encoder::TiffEncoder<_>>::new Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new |
121 | | } |
122 | | |
123 | | /// Constructor functions to create BigTiff files. |
124 | | impl<W: Write + Seek> TiffEncoder<W, TiffKindBig> { |
125 | | /// Creates a new encoder for BigTiff files. |
126 | | /// |
127 | | /// To create standard Tiff files, use [`new`][TiffEncoder::new] or |
128 | | /// [`new_generic`][TiffEncoder::new_generic]. |
129 | 0 | pub fn new_big(writer: W) -> TiffResult<Self> { |
130 | 0 | TiffEncoder::new_generic(writer) |
131 | 0 | } |
132 | | } |
133 | | |
134 | | /// Generic functions that are available for both Tiff and BigTiff encoders. |
135 | | impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> { |
136 | | /// Creates a new Tiff or BigTiff encoder, inferred from the return type. |
137 | 0 | pub fn new_generic(writer: W) -> TiffResult<Self> { |
138 | 0 | let mut encoder = TiffEncoder { |
139 | 0 | writer: TiffWriter::new(writer), |
140 | 0 | kind: PhantomData, |
141 | 0 | predictor: Predictor::None, |
142 | 0 | compression: Compression::Uncompressed, |
143 | 0 | }; |
144 | 0 |
|
145 | 0 | K::write_header(&mut encoder.writer)?; |
146 | | |
147 | 0 | Ok(encoder) |
148 | 0 | } Unexecuted instantiation: <tiff::encoder::TiffEncoder<_, _>>::new_generic Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_generic |
149 | | |
150 | | /// Set the predictor to use |
151 | | /// |
152 | | /// A predictor is used to simplify the file before writing it. This is very |
153 | | /// useful when writing a file compressed using LZW as it can improve efficiency |
154 | 0 | pub fn with_predictor(mut self, predictor: Predictor) -> Self { |
155 | 0 | self.predictor = predictor; |
156 | 0 |
|
157 | 0 | self |
158 | 0 | } |
159 | | |
160 | | /// Set the compression method to use |
161 | 0 | pub fn with_compression(mut self, compression: Compression) -> Self { |
162 | 0 | self.compression = compression; |
163 | 0 |
|
164 | 0 | self |
165 | 0 | } |
166 | | |
167 | | /// Create a [`DirectoryEncoder`] to encode an ifd directory. |
168 | 0 | pub fn new_directory(&mut self) -> TiffResult<DirectoryEncoder<W, K>> { |
169 | 0 | DirectoryEncoder::new(&mut self.writer) |
170 | 0 | } |
171 | | |
172 | | /// Create an [`ImageEncoder`] to encode an image one slice at a time. |
173 | 0 | pub fn new_image<C: ColorType>( |
174 | 0 | &mut self, |
175 | 0 | width: u32, |
176 | 0 | height: u32, |
177 | 0 | ) -> TiffResult<ImageEncoder<W, C, K>> { |
178 | 0 | let encoder = DirectoryEncoder::new(&mut self.writer)?; |
179 | 0 | ImageEncoder::new(encoder, width, height, self.compression, self.predictor) |
180 | 0 | } |
181 | | |
182 | | /// Convenience function to write an entire image from memory. |
183 | 0 | pub fn write_image<C: ColorType>( |
184 | 0 | &mut self, |
185 | 0 | width: u32, |
186 | 0 | height: u32, |
187 | 0 | data: &[C::Inner], |
188 | 0 | ) -> TiffResult<()> |
189 | 0 | where |
190 | 0 | [C::Inner]: TiffValue, |
191 | 0 | { |
192 | 0 | let encoder = DirectoryEncoder::new(&mut self.writer)?; |
193 | 0 | let image: ImageEncoder<W, C, K> = |
194 | 0 | ImageEncoder::new(encoder, width, height, self.compression, self.predictor)?; |
195 | 0 | image.write_data(data) |
196 | 0 | } Unexecuted instantiation: <tiff::encoder::TiffEncoder<_, _>>::write_image::<_> Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGB8> Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::Gray8> Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGB16> Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGBA8> Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::Gray16> Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGBA16> |
197 | | } |
198 | | |
199 | | /// Low level interface to encode ifd directories. |
200 | | /// |
201 | | /// You should call `finish` on this when you are finished with it. |
202 | | /// Encoding can silently fail while this is dropping. |
203 | | pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> { |
204 | | writer: &'a mut TiffWriter<W>, |
205 | | dropped: bool, |
206 | | // We use BTreeMap to make sure tags are written in correct order |
207 | | ifd_pointer_pos: u64, |
208 | | ifd: BTreeMap<u16, DirectoryEntry<K::OffsetType>>, |
209 | | } |
210 | | |
211 | | impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> { |
212 | 0 | fn new(writer: &'a mut TiffWriter<W>) -> TiffResult<Self> { |
213 | 0 | // the previous word is the IFD offset position |
214 | 0 | let ifd_pointer_pos = writer.offset() - mem::size_of::<K::OffsetType>() as u64; |
215 | 0 | writer.pad_word_boundary()?; // TODO: Do we need to adjust this for BigTiff? |
216 | 0 | Ok(DirectoryEncoder { |
217 | 0 | writer, |
218 | 0 | dropped: false, |
219 | 0 | ifd_pointer_pos, |
220 | 0 | ifd: BTreeMap::new(), |
221 | 0 | }) |
222 | 0 | } Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::new Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::new |
223 | | |
224 | | /// Write a single ifd tag. |
225 | 0 | pub fn write_tag<T: TiffValue>(&mut self, tag: Tag, value: T) -> TiffResult<()> { |
226 | 0 | let mut bytes = Vec::with_capacity(value.bytes()); |
227 | 0 | { |
228 | 0 | let mut writer = TiffWriter::new(&mut bytes); |
229 | 0 | value.write(&mut writer)?; |
230 | | } |
231 | | |
232 | 0 | self.ifd.insert( |
233 | 0 | tag.to_u16(), |
234 | 0 | DirectoryEntry { |
235 | 0 | data_type: <T>::FIELD_TYPE.to_u16(), |
236 | 0 | count: value.count().try_into()?, |
237 | 0 | data: bytes, |
238 | 0 | }, |
239 | 0 | ); |
240 | 0 |
|
241 | 0 | Ok(()) |
242 | 0 | } Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::write_tag::<_> Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<tiff::encoder::tiff_value::Rational> Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<&[u32]> Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<&[u16]> Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<u32> Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<u16> |
243 | | |
244 | 0 | fn write_directory(&mut self) -> TiffResult<u64> { |
245 | | // Start by writing out all values |
246 | | for &mut DirectoryEntry { |
247 | 0 | data: ref mut bytes, |
248 | | .. |
249 | 0 | } in self.ifd.values_mut() |
250 | | { |
251 | 0 | let data_bytes = mem::size_of::<K::OffsetType>(); |
252 | 0 |
|
253 | 0 | if bytes.len() > data_bytes { |
254 | 0 | let offset = self.writer.offset(); |
255 | 0 | self.writer.write_bytes(bytes)?; |
256 | 0 | *bytes = vec![0; data_bytes]; |
257 | 0 | let mut writer = TiffWriter::new(bytes as &mut [u8]); |
258 | 0 | K::write_offset(&mut writer, offset)?; |
259 | | } else { |
260 | 0 | while bytes.len() < data_bytes { |
261 | 0 | bytes.push(0); |
262 | 0 | } |
263 | | } |
264 | | } |
265 | | |
266 | 0 | let offset = self.writer.offset(); |
267 | 0 |
|
268 | 0 | K::write_entry_count(self.writer, self.ifd.len())?; |
269 | | for ( |
270 | 0 | tag, |
271 | 0 | DirectoryEntry { |
272 | 0 | data_type: field_type, |
273 | 0 | count, |
274 | 0 | data: offset, |
275 | | }, |
276 | 0 | ) in self.ifd.iter() |
277 | | { |
278 | 0 | self.writer.write_u16(*tag)?; |
279 | 0 | self.writer.write_u16(*field_type)?; |
280 | 0 | (*count).write(self.writer)?; |
281 | 0 | self.writer.write_bytes(offset)?; |
282 | | } |
283 | | |
284 | 0 | Ok(offset) |
285 | 0 | } Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::write_directory Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_directory |
286 | | |
287 | | /// Write some data to the tiff file, the offset of the data is returned. |
288 | | /// |
289 | | /// This could be used to write tiff strips. |
290 | 0 | pub fn write_data<T: TiffValue>(&mut self, value: T) -> TiffResult<u64> { |
291 | 0 | let offset = self.writer.offset(); |
292 | 0 | value.write(self.writer)?; |
293 | 0 | Ok(offset) |
294 | 0 | } Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::write_data::<_> Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_data::<&[u8]> Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_data::<&[u16]> |
295 | | |
296 | | /// Provides the number of bytes written by the underlying TiffWriter during the last call. |
297 | 0 | fn last_written(&self) -> u64 { |
298 | 0 | self.writer.last_written() |
299 | 0 | } Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::last_written Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::last_written |
300 | | |
301 | 0 | fn finish_internal(&mut self) -> TiffResult<()> { |
302 | 0 | let ifd_pointer = self.write_directory()?; |
303 | 0 | let curr_pos = self.writer.offset(); |
304 | 0 |
|
305 | 0 | self.writer.goto_offset(self.ifd_pointer_pos)?; |
306 | 0 | K::write_offset(self.writer, ifd_pointer)?; |
307 | 0 | self.writer.goto_offset(curr_pos)?; |
308 | 0 | K::write_offset(self.writer, 0)?; |
309 | | |
310 | 0 | self.dropped = true; |
311 | 0 |
|
312 | 0 | Ok(()) |
313 | 0 | } Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::finish_internal Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::finish_internal |
314 | | |
315 | | /// Write out the ifd directory. |
316 | 0 | pub fn finish(mut self) -> TiffResult<()> { |
317 | 0 | self.finish_internal() |
318 | 0 | } |
319 | | } |
320 | | |
321 | | impl<'a, W: Write + Seek, K: TiffKind> Drop for DirectoryEncoder<'a, W, K> { |
322 | 0 | fn drop(&mut self) { |
323 | 0 | if !self.dropped { |
324 | 0 | let _ = self.finish_internal(); |
325 | 0 | } |
326 | 0 | } Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _> as core::ops::drop::Drop>::drop Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop |
327 | | } |
328 | | |
329 | | /// Type to encode images strip by strip. |
330 | | /// |
331 | | /// You should call `finish` on this when you are finished with it. |
332 | | /// Encoding can silently fail while this is dropping. |
333 | | /// |
334 | | /// # Examples |
335 | | /// ``` |
336 | | /// # extern crate tiff; |
337 | | /// # fn main() { |
338 | | /// # let mut file = std::io::Cursor::new(Vec::new()); |
339 | | /// # let image_data = vec![0; 100*100*3]; |
340 | | /// use tiff::encoder::*; |
341 | | /// use tiff::tags::Tag; |
342 | | /// |
343 | | /// let mut tiff = TiffEncoder::new(&mut file).unwrap(); |
344 | | /// let mut image = tiff.new_image::<colortype::RGB8>(100, 100).unwrap(); |
345 | | /// |
346 | | /// // You can encode tags here |
347 | | /// image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap(); |
348 | | /// |
349 | | /// // Strip size can be configured before writing data |
350 | | /// image.rows_per_strip(2).unwrap(); |
351 | | /// |
352 | | /// let mut idx = 0; |
353 | | /// while image.next_strip_sample_count() > 0 { |
354 | | /// let sample_count = image.next_strip_sample_count() as usize; |
355 | | /// image.write_strip(&image_data[idx..idx+sample_count]).unwrap(); |
356 | | /// idx += sample_count; |
357 | | /// } |
358 | | /// image.finish().unwrap(); |
359 | | /// # } |
360 | | /// ``` |
361 | | /// You can also call write_data function wich will encode by strip and finish |
362 | | pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType, K: TiffKind> { |
363 | | encoder: DirectoryEncoder<'a, W, K>, |
364 | | strip_idx: u64, |
365 | | strip_count: u64, |
366 | | row_samples: u64, |
367 | | width: u32, |
368 | | height: u32, |
369 | | rows_per_strip: u64, |
370 | | strip_offsets: Vec<K::OffsetType>, |
371 | | strip_byte_count: Vec<K::OffsetType>, |
372 | | dropped: bool, |
373 | | compression: Compression, |
374 | | predictor: Predictor, |
375 | | _phantom: ::std::marker::PhantomData<C>, |
376 | | } |
377 | | |
378 | | impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T, K> { |
379 | 0 | fn sanity_check(compression: Compression, predictor: Predictor) -> TiffResult<()> { |
380 | 0 | match (predictor, compression, T::SAMPLE_FORMAT[0]) { |
381 | | (Predictor::Horizontal, _, SampleFormat::IEEEFP | SampleFormat::Void) => { |
382 | 0 | Err(TiffError::UsageError(UsageError::PredictorIncompatible)) |
383 | | } |
384 | | (Predictor::FloatingPoint, _, _) => { |
385 | 0 | Err(TiffError::UsageError(UsageError::PredictorUnavailable)) |
386 | | } |
387 | 0 | _ => Ok(()), |
388 | | } |
389 | 0 | } Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::sanity_check Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::sanity_check Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::sanity_check Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::sanity_check Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::sanity_check Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::sanity_check Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::sanity_check |
390 | | |
391 | 0 | fn new( |
392 | 0 | mut encoder: DirectoryEncoder<'a, W, K>, |
393 | 0 | width: u32, |
394 | 0 | height: u32, |
395 | 0 | compression: Compression, |
396 | 0 | predictor: Predictor, |
397 | 0 | ) -> TiffResult<Self> { |
398 | 0 | if width == 0 || height == 0 { |
399 | 0 | return Err(TiffError::FormatError(TiffFormatError::InvalidDimensions( |
400 | 0 | width, height, |
401 | 0 | ))); |
402 | 0 | } |
403 | 0 |
|
404 | 0 | Self::sanity_check(compression, predictor)?; |
405 | | |
406 | 0 | let row_samples = u64::from(width) * u64::try_from(<T>::BITS_PER_SAMPLE.len())?; |
407 | 0 | let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN); |
408 | | |
409 | | // Limit the strip size to prevent potential memory and security issues. |
410 | | // Also keep the multiple strip handling 'oiled' |
411 | 0 | let rows_per_strip = { |
412 | 0 | match compression.tag() { |
413 | 0 | CompressionMethod::PackBits => 1, // Each row must be packed separately. Do not compress across row boundaries |
414 | 0 | _ => (1_000_000 + row_bytes - 1) / row_bytes, |
415 | | } |
416 | | }; |
417 | | |
418 | 0 | let strip_count = (u64::from(height) + rows_per_strip - 1) / rows_per_strip; |
419 | 0 |
|
420 | 0 | encoder.write_tag(Tag::ImageWidth, width)?; |
421 | 0 | encoder.write_tag(Tag::ImageLength, height)?; |
422 | 0 | encoder.write_tag(Tag::Compression, compression.tag().to_u16())?; |
423 | 0 | encoder.write_tag(Tag::Predictor, predictor.to_u16())?; |
424 | | |
425 | 0 | encoder.write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE)?; |
426 | 0 | let sample_format: Vec<_> = <T>::SAMPLE_FORMAT.iter().map(|s| s.to_u16()).collect(); Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::new::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::new::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::new::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::new::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::new::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::new::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::new::{closure#0} |
427 | 0 | encoder.write_tag(Tag::SampleFormat, &sample_format[..])?; |
428 | 0 | encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16())?; |
429 | | |
430 | 0 | encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?; |
431 | | |
432 | 0 | encoder.write_tag( |
433 | 0 | Tag::SamplesPerPixel, |
434 | 0 | u16::try_from(<T>::BITS_PER_SAMPLE.len())?, |
435 | 0 | )?; |
436 | 0 | encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?; |
437 | 0 | encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?; |
438 | 0 | encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None.to_u16())?; |
439 | | |
440 | 0 | Ok(ImageEncoder { |
441 | 0 | encoder, |
442 | 0 | strip_count, |
443 | 0 | strip_idx: 0, |
444 | 0 | row_samples, |
445 | 0 | rows_per_strip, |
446 | 0 | width, |
447 | 0 | height, |
448 | 0 | strip_offsets: Vec::new(), |
449 | 0 | strip_byte_count: Vec::new(), |
450 | 0 | dropped: false, |
451 | 0 | compression, |
452 | 0 | predictor, |
453 | 0 | _phantom: ::std::marker::PhantomData, |
454 | 0 | }) |
455 | 0 | } Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::new Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::new Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::new Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::new Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::new Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::new Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::new |
456 | | |
457 | | /// Number of samples the next strip should have. |
458 | 0 | pub fn next_strip_sample_count(&self) -> u64 { |
459 | 0 | if self.strip_idx >= self.strip_count { |
460 | 0 | return 0; |
461 | 0 | } |
462 | 0 |
|
463 | 0 | let raw_start_row = self.strip_idx * self.rows_per_strip; |
464 | 0 | let start_row = cmp::min(u64::from(self.height), raw_start_row); |
465 | 0 | let end_row = cmp::min(u64::from(self.height), raw_start_row + self.rows_per_strip); |
466 | 0 |
|
467 | 0 | (end_row - start_row) * self.row_samples |
468 | 0 | } Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::next_strip_sample_count Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::next_strip_sample_count Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::next_strip_sample_count Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::next_strip_sample_count Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::next_strip_sample_count Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::next_strip_sample_count Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::next_strip_sample_count |
469 | | |
470 | | /// Write a single strip. |
471 | 0 | pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()> |
472 | 0 | where |
473 | 0 | [T::Inner]: TiffValue, |
474 | 0 | { |
475 | 0 | let samples = self.next_strip_sample_count(); |
476 | 0 | if u64::try_from(value.len())? != samples { |
477 | 0 | return Err(io::Error::new( |
478 | 0 | io::ErrorKind::InvalidData, |
479 | 0 | "Slice is wrong size for strip", |
480 | 0 | ) |
481 | 0 | .into()); |
482 | 0 | } |
483 | | |
484 | | // Write the (possible compressed) data to the encoder. |
485 | 0 | let offset = match self.predictor { |
486 | 0 | Predictor::None => self.encoder.write_data(value)?, |
487 | | Predictor::Horizontal => { |
488 | 0 | let mut row_result = Vec::with_capacity(value.len()); |
489 | 0 | for row in value.chunks_exact(self.row_samples as usize) { |
490 | 0 | T::horizontal_predict(row, &mut row_result); |
491 | 0 | } |
492 | 0 | self.encoder.write_data(row_result.as_slice())? |
493 | | } |
494 | 0 | _ => unimplemented!(), |
495 | | }; |
496 | | |
497 | 0 | let byte_count = self.encoder.last_written() as usize; |
498 | 0 |
|
499 | 0 | self.strip_offsets.push(K::convert_offset(offset)?); |
500 | 0 | self.strip_byte_count.push(byte_count.try_into()?); |
501 | | |
502 | 0 | self.strip_idx += 1; |
503 | 0 | Ok(()) |
504 | 0 | } Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::write_strip Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::write_strip Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::write_strip Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::write_strip Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::write_strip Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::write_strip Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::write_strip |
505 | | |
506 | | /// Write strips from data |
507 | 0 | pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()> |
508 | 0 | where |
509 | 0 | [T::Inner]: TiffValue, |
510 | 0 | { |
511 | 0 | let num_pix = usize::try_from(self.width)? |
512 | 0 | .checked_mul(usize::try_from(self.height)?) |
513 | 0 | .ok_or_else(|| { |
514 | 0 | io::Error::new( |
515 | 0 | io::ErrorKind::InvalidInput, |
516 | 0 | "Image width * height exceeds usize", |
517 | 0 | ) |
518 | 0 | })?; Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::write_data::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::write_data::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::write_data::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::write_data::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::write_data::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::write_data::{closure#0} Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::write_data::{closure#0} |
519 | 0 | if data.len() < num_pix { |
520 | 0 | return Err(io::Error::new( |
521 | 0 | io::ErrorKind::InvalidData, |
522 | 0 | "Input data slice is undersized for provided dimensions", |
523 | 0 | ) |
524 | 0 | .into()); |
525 | 0 | } |
526 | 0 |
|
527 | 0 | self.encoder |
528 | 0 | .writer |
529 | 0 | .set_compression(self.compression.get_algorithm()); |
530 | 0 |
|
531 | 0 | let mut idx = 0; |
532 | 0 | while self.next_strip_sample_count() > 0 { |
533 | 0 | let sample_count = usize::try_from(self.next_strip_sample_count())?; |
534 | 0 | self.write_strip(&data[idx..idx + sample_count])?; |
535 | 0 | idx += sample_count; |
536 | | } |
537 | | |
538 | 0 | self.encoder.writer.reset_compression(); |
539 | 0 | self.finish()?; |
540 | 0 | Ok(()) |
541 | 0 | } Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::write_data Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::write_data Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::write_data Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::write_data Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::write_data Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::write_data Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::write_data |
542 | | |
543 | | /// Set image resolution |
544 | 0 | pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) { |
545 | 0 | self.encoder |
546 | 0 | .write_tag(Tag::ResolutionUnit, unit.to_u16()) |
547 | 0 | .unwrap(); |
548 | 0 | self.encoder |
549 | 0 | .write_tag(Tag::XResolution, value.clone()) |
550 | 0 | .unwrap(); |
551 | 0 | self.encoder.write_tag(Tag::YResolution, value).unwrap(); |
552 | 0 | } |
553 | | |
554 | | /// Set image resolution unit |
555 | 0 | pub fn resolution_unit(&mut self, unit: ResolutionUnit) { |
556 | 0 | self.encoder |
557 | 0 | .write_tag(Tag::ResolutionUnit, unit.to_u16()) |
558 | 0 | .unwrap(); |
559 | 0 | } |
560 | | |
561 | | /// Set image x-resolution |
562 | 0 | pub fn x_resolution(&mut self, value: Rational) { |
563 | 0 | self.encoder.write_tag(Tag::XResolution, value).unwrap(); |
564 | 0 | } |
565 | | |
566 | | /// Set image y-resolution |
567 | 0 | pub fn y_resolution(&mut self, value: Rational) { |
568 | 0 | self.encoder.write_tag(Tag::YResolution, value).unwrap(); |
569 | 0 | } |
570 | | |
571 | | /// Set image number of lines per strip |
572 | | /// |
573 | | /// This function needs to be called before any calls to `write_data` or |
574 | | /// `write_strip` and will return an error otherwise. |
575 | 0 | pub fn rows_per_strip(&mut self, value: u32) -> TiffResult<()> { |
576 | 0 | if self.strip_idx != 0 { |
577 | 0 | return Err(io::Error::new( |
578 | 0 | io::ErrorKind::InvalidInput, |
579 | 0 | "Cannot change strip size after data was written", |
580 | 0 | ) |
581 | 0 | .into()); |
582 | 0 | } |
583 | 0 | // Write tag as 32 bits |
584 | 0 | self.encoder.write_tag(Tag::RowsPerStrip, value)?; |
585 | | |
586 | 0 | let value: u64 = value as u64; |
587 | 0 | self.strip_count = (self.height as u64 + value - 1) / value; |
588 | 0 | self.rows_per_strip = value; |
589 | 0 |
|
590 | 0 | Ok(()) |
591 | 0 | } |
592 | | |
593 | 0 | fn finish_internal(&mut self) -> TiffResult<()> { |
594 | 0 | self.encoder |
595 | 0 | .write_tag(Tag::StripOffsets, K::convert_slice(&self.strip_offsets))?; |
596 | 0 | self.encoder.write_tag( |
597 | 0 | Tag::StripByteCounts, |
598 | 0 | K::convert_slice(&self.strip_byte_count), |
599 | 0 | )?; |
600 | 0 | self.dropped = true; |
601 | 0 |
|
602 | 0 | self.encoder.finish_internal() |
603 | 0 | } Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::finish_internal Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::finish_internal Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::finish_internal Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::finish_internal Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::finish_internal Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::finish_internal Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::finish_internal |
604 | | |
605 | | /// Get a reference of the underlying `DirectoryEncoder` |
606 | 0 | pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W, K> { |
607 | 0 | &mut self.encoder |
608 | 0 | } |
609 | | |
610 | | /// Write out image and ifd directory. |
611 | 0 | pub fn finish(mut self) -> TiffResult<()> { |
612 | 0 | self.finish_internal() |
613 | 0 | } Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::finish Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::finish Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::finish Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::finish Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::finish Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::finish Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::finish |
614 | | } |
615 | | |
616 | | impl<'a, W: Write + Seek, C: ColorType, K: TiffKind> Drop for ImageEncoder<'a, W, C, K> { |
617 | 0 | fn drop(&mut self) { |
618 | 0 | if !self.dropped { |
619 | 0 | let _ = self.finish_internal(); |
620 | 0 | } |
621 | 0 | } Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _> as core::ops::drop::Drop>::drop Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop |
622 | | } |
623 | | |
624 | | struct DirectoryEntry<S> { |
625 | | data_type: u16, |
626 | | count: S, |
627 | | data: Vec<u8>, |
628 | | } |
629 | | |
630 | | /// Trait to abstract over Tiff/BigTiff differences. |
631 | | /// |
632 | | /// Implemented for [`TiffKindStandard`] and [`TiffKindBig`]. |
633 | | pub trait TiffKind { |
634 | | /// The type of offset fields, `u32` for normal Tiff, `u64` for BigTiff. |
635 | | type OffsetType: TryFrom<usize, Error = TryFromIntError> + Into<u64> + TiffValue; |
636 | | |
637 | | /// Needed for the `convert_slice` method. |
638 | | type OffsetArrayType: ?Sized + TiffValue; |
639 | | |
640 | | /// Write the (Big)Tiff header. |
641 | | fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>; |
642 | | |
643 | | /// Convert a file offset to `Self::OffsetType`. |
644 | | /// |
645 | | /// This returns an error for normal Tiff if the offset is larger than `u32::MAX`. |
646 | | fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType>; |
647 | | |
648 | | /// Write an offset value to the given writer. |
649 | | /// |
650 | | /// Like `convert_offset`, this errors if `offset > u32::MAX` for normal Tiff. |
651 | | fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()>; |
652 | | |
653 | | /// Write the IFD entry count field with the given `count` value. |
654 | | /// |
655 | | /// The entry count field is an `u16` for normal Tiff and `u64` for BigTiff. Errors |
656 | | /// if the given `usize` is larger than the representable values. |
657 | | fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()>; |
658 | | |
659 | | /// Internal helper method for satisfying Rust's type checker. |
660 | | /// |
661 | | /// The `TiffValue` trait is implemented for both primitive values (e.g. `u8`, `u32`) and |
662 | | /// slices of primitive values (e.g. `[u8]`, `[u32]`). However, this is not represented in |
663 | | /// the type system, so there is no guarantee that that for all `T: TiffValue` there is also |
664 | | /// an implementation of `TiffValue` for `[T]`. This method works around that problem by |
665 | | /// providing a conversion from `[T]` to some value that implements `TiffValue`, thereby |
666 | | /// making all slices of `OffsetType` usable with `write_tag` and similar methods. |
667 | | /// |
668 | | /// Implementations of this trait should always set `OffsetArrayType` to `[OffsetType]`. |
669 | | fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType; |
670 | | } |
671 | | |
672 | | /// Create a standard Tiff file. |
673 | | pub struct TiffKindStandard; |
674 | | |
675 | | impl TiffKind for TiffKindStandard { |
676 | | type OffsetType = u32; |
677 | | type OffsetArrayType = [u32]; |
678 | | |
679 | 0 | fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> { |
680 | 0 | write_tiff_header(writer)?; |
681 | | // blank the IFD offset location |
682 | 0 | writer.write_u32(0)?; |
683 | | |
684 | 0 | Ok(()) |
685 | 0 | } Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_header::<_> Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_header::<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> |
686 | | |
687 | 0 | fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> { |
688 | 0 | Ok(Self::OffsetType::try_from(offset)?) |
689 | 0 | } |
690 | | |
691 | 0 | fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> { |
692 | 0 | writer.write_u32(u32::try_from(offset)?)?; |
693 | 0 | Ok(()) |
694 | 0 | } Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_offset::<_> Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_offset::<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_offset::<&mut [u8]> |
695 | | |
696 | 0 | fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> { |
697 | 0 | writer.write_u16(u16::try_from(count)?)?; |
698 | | |
699 | 0 | Ok(()) |
700 | 0 | } Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_entry_count::<_> Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_entry_count::<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> |
701 | | |
702 | 0 | fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType { |
703 | 0 | slice |
704 | 0 | } |
705 | | } |
706 | | |
707 | | /// Create a BigTiff file. |
708 | | pub struct TiffKindBig; |
709 | | |
710 | | impl TiffKind for TiffKindBig { |
711 | | type OffsetType = u64; |
712 | | type OffsetArrayType = [u64]; |
713 | | |
714 | 0 | fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> { |
715 | 0 | write_bigtiff_header(writer)?; |
716 | | // blank the IFD offset location |
717 | 0 | writer.write_u64(0)?; |
718 | | |
719 | 0 | Ok(()) |
720 | 0 | } |
721 | | |
722 | 0 | fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> { |
723 | 0 | Ok(offset) |
724 | 0 | } |
725 | | |
726 | 0 | fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> { |
727 | 0 | writer.write_u64(offset)?; |
728 | 0 | Ok(()) |
729 | 0 | } |
730 | | |
731 | 0 | fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> { |
732 | 0 | writer.write_u64(u64::try_from(count)?)?; |
733 | 0 | Ok(()) |
734 | 0 | } |
735 | | |
736 | 0 | fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType { |
737 | 0 | slice |
738 | 0 | } |
739 | | } |