/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tiff-0.11.3/src/decoder/mod.rs
Line | Count | Source |
1 | | use std::alloc::{Layout, LayoutError}; |
2 | | use std::collections::BTreeMap; |
3 | | use std::io::{self, Read, Seek}; |
4 | | use std::num::NonZeroUsize; |
5 | | |
6 | | use crate::tags::{ |
7 | | CompressionMethod, IfdPointer, PhotometricInterpretation, PlanarConfiguration, Predictor, |
8 | | SampleFormat, Tag, Type, ValueBuffer, |
9 | | }; |
10 | | use crate::{ |
11 | | bytecast, ColorType, Directory, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, |
12 | | UsageError, |
13 | | }; |
14 | | use half::f16; |
15 | | |
16 | | use self::image::Image; |
17 | | use self::stream::{ByteOrder, EndianReader}; |
18 | | |
19 | | mod cycles; |
20 | | pub mod ifd; |
21 | | mod image; |
22 | | mod stream; |
23 | | mod tag_reader; |
24 | | |
25 | | /// An index referring to a (rectangular) region of an image. |
26 | | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
27 | | pub struct TiffCodingUnit(pub u32); |
28 | | |
29 | | /// Result of a decoding process |
30 | | #[derive(Debug)] |
31 | | pub enum DecodingResult { |
32 | | /// A vector of unsigned bytes |
33 | | U8(Vec<u8>), |
34 | | /// A vector of unsigned words |
35 | | U16(Vec<u16>), |
36 | | /// A vector of 32 bit unsigned ints |
37 | | U32(Vec<u32>), |
38 | | /// A vector of 64 bit unsigned ints |
39 | | U64(Vec<u64>), |
40 | | /// A vector of 16 bit IEEE floats (held in u16) |
41 | | F16(Vec<f16>), |
42 | | /// A vector of 32 bit IEEE floats |
43 | | F32(Vec<f32>), |
44 | | /// A vector of 64 bit IEEE floats |
45 | | F64(Vec<f64>), |
46 | | /// A vector of 8 bit signed ints |
47 | | I8(Vec<i8>), |
48 | | /// A vector of 16 bit signed ints |
49 | | I16(Vec<i16>), |
50 | | /// A vector of 32 bit signed ints |
51 | | I32(Vec<i32>), |
52 | | /// A vector of 64 bit signed ints |
53 | | I64(Vec<i64>), |
54 | | } |
55 | | |
56 | | impl DecodingResult { |
57 | | /// Reallocate the buffer to decode all planes of the indicated layout. |
58 | 0 | pub fn resize_to( |
59 | 0 | &mut self, |
60 | 0 | buffer: &BufferLayoutPreference, |
61 | 0 | limits: &Limits, |
62 | 0 | ) -> Result<(), TiffError> { |
63 | 0 | let sample_type = buffer.sample_type.ok_or(TiffError::UnsupportedError( |
64 | 0 | TiffUnsupportedError::UnknownInterpretation, |
65 | 0 | ))?; |
66 | | |
67 | 0 | let extent = sample_type.extent_for_bytes(buffer.complete_len); |
68 | 0 | self.resize_to_extent(extent, limits) |
69 | 0 | } |
70 | | |
71 | 13.7k | fn resize_to_extent( |
72 | 13.7k | &mut self, |
73 | 13.7k | extent: DecodingExtent, |
74 | 13.7k | limits: &Limits, |
75 | 13.7k | ) -> Result<(), TiffError> { |
76 | | // FIXME: we *can* reuse the allocation sometimes. |
77 | 13.7k | *self = extent.to_result_buffer(limits)?; |
78 | 13.7k | Ok(()) |
79 | 13.7k | } |
80 | | |
81 | 13.7k | fn new<T: Default + Copy>( |
82 | 13.7k | size: usize, |
83 | 13.7k | limits: &Limits, |
84 | 13.7k | from_fn: fn(Vec<T>) -> Self, |
85 | 13.7k | ) -> TiffResult<DecodingResult> { |
86 | 13.7k | if size > limits.decoding_buffer_size / core::mem::size_of::<T>() { |
87 | 37 | Err(TiffError::LimitsExceeded) |
88 | | } else { |
89 | 13.7k | Ok(from_fn(vec![T::default(); size])) |
90 | | } |
91 | 13.7k | } Unexecuted instantiation: <tiff::decoder::DecodingResult>::new::<half::binary16::f16> Unexecuted instantiation: <tiff::decoder::DecodingResult>::new::<i8> Unexecuted instantiation: <tiff::decoder::DecodingResult>::new::<f64> <tiff::decoder::DecodingResult>::new::<f32> Line | Count | Source | 81 | 64 | fn new<T: Default + Copy>( | 82 | 64 | size: usize, | 83 | 64 | limits: &Limits, | 84 | 64 | from_fn: fn(Vec<T>) -> Self, | 85 | 64 | ) -> TiffResult<DecodingResult> { | 86 | 64 | if size > limits.decoding_buffer_size / core::mem::size_of::<T>() { | 87 | 0 | Err(TiffError::LimitsExceeded) | 88 | | } else { | 89 | 64 | Ok(from_fn(vec![T::default(); size])) | 90 | | } | 91 | 64 | } |
<tiff::decoder::DecodingResult>::new::<u8> Line | Count | Source | 81 | 11.6k | fn new<T: Default + Copy>( | 82 | 11.6k | size: usize, | 83 | 11.6k | limits: &Limits, | 84 | 11.6k | from_fn: fn(Vec<T>) -> Self, | 85 | 11.6k | ) -> TiffResult<DecodingResult> { | 86 | 11.6k | if size > limits.decoding_buffer_size / core::mem::size_of::<T>() { | 87 | 18 | Err(TiffError::LimitsExceeded) | 88 | | } else { | 89 | 11.5k | Ok(from_fn(vec![T::default(); size])) | 90 | | } | 91 | 11.6k | } |
Unexecuted instantiation: <tiff::decoder::DecodingResult>::new::<i32> <tiff::decoder::DecodingResult>::new::<u32> Line | Count | Source | 81 | 18 | fn new<T: Default + Copy>( | 82 | 18 | size: usize, | 83 | 18 | limits: &Limits, | 84 | 18 | from_fn: fn(Vec<T>) -> Self, | 85 | 18 | ) -> TiffResult<DecodingResult> { | 86 | 18 | if size > limits.decoding_buffer_size / core::mem::size_of::<T>() { | 87 | 0 | Err(TiffError::LimitsExceeded) | 88 | | } else { | 89 | 18 | Ok(from_fn(vec![T::default(); size])) | 90 | | } | 91 | 18 | } |
Unexecuted instantiation: <tiff::decoder::DecodingResult>::new::<i16> <tiff::decoder::DecodingResult>::new::<u16> Line | Count | Source | 81 | 2.08k | fn new<T: Default + Copy>( | 82 | 2.08k | size: usize, | 83 | 2.08k | limits: &Limits, | 84 | 2.08k | from_fn: fn(Vec<T>) -> Self, | 85 | 2.08k | ) -> TiffResult<DecodingResult> { | 86 | 2.08k | if size > limits.decoding_buffer_size / core::mem::size_of::<T>() { | 87 | 19 | Err(TiffError::LimitsExceeded) | 88 | | } else { | 89 | 2.07k | Ok(from_fn(vec![T::default(); size])) | 90 | | } | 91 | 2.08k | } |
Unexecuted instantiation: <tiff::decoder::DecodingResult>::new::<i64> Unexecuted instantiation: <tiff::decoder::DecodingResult>::new::<u64> |
92 | | |
93 | 11.6k | fn new_u8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
94 | 11.6k | Self::new(size, limits, DecodingResult::U8) |
95 | 11.6k | } |
96 | | |
97 | 2.08k | fn new_u16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
98 | 2.08k | Self::new(size, limits, DecodingResult::U16) |
99 | 2.08k | } |
100 | | |
101 | 18 | fn new_u32(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
102 | 18 | Self::new(size, limits, DecodingResult::U32) |
103 | 18 | } |
104 | | |
105 | 0 | fn new_u64(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
106 | 0 | Self::new(size, limits, DecodingResult::U64) |
107 | 0 | } |
108 | | |
109 | 64 | fn new_f32(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
110 | 64 | Self::new(size, limits, DecodingResult::F32) |
111 | 64 | } |
112 | | |
113 | 0 | fn new_f64(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
114 | 0 | Self::new(size, limits, DecodingResult::F64) |
115 | 0 | } |
116 | | |
117 | 0 | fn new_f16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
118 | 0 | Self::new(size, limits, DecodingResult::F16) |
119 | 0 | } |
120 | | |
121 | 0 | fn new_i8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
122 | 0 | Self::new(size, limits, DecodingResult::I8) |
123 | 0 | } |
124 | | |
125 | 0 | fn new_i16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
126 | 0 | Self::new(size, limits, DecodingResult::I16) |
127 | 0 | } |
128 | | |
129 | 0 | fn new_i32(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
130 | 0 | Self::new(size, limits, DecodingResult::I32) |
131 | 0 | } |
132 | | |
133 | 0 | fn new_i64(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { |
134 | 0 | Self::new(size, limits, DecodingResult::I64) |
135 | 0 | } |
136 | | |
137 | | /// Get a view of this buffer starting from the nth _sample_ of the current type. |
138 | 17.5k | pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer<'_> { |
139 | 17.5k | match *self { |
140 | 15.2k | DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]), |
141 | 2.12k | DecodingResult::U16(ref mut buf) => DecodingBuffer::U16(&mut buf[start..]), |
142 | 23 | DecodingResult::U32(ref mut buf) => DecodingBuffer::U32(&mut buf[start..]), |
143 | 0 | DecodingResult::U64(ref mut buf) => DecodingBuffer::U64(&mut buf[start..]), |
144 | 0 | DecodingResult::F16(ref mut buf) => DecodingBuffer::F16(&mut buf[start..]), |
145 | 91 | DecodingResult::F32(ref mut buf) => DecodingBuffer::F32(&mut buf[start..]), |
146 | 0 | DecodingResult::F64(ref mut buf) => DecodingBuffer::F64(&mut buf[start..]), |
147 | 0 | DecodingResult::I8(ref mut buf) => DecodingBuffer::I8(&mut buf[start..]), |
148 | 0 | DecodingResult::I16(ref mut buf) => DecodingBuffer::I16(&mut buf[start..]), |
149 | 0 | DecodingResult::I32(ref mut buf) => DecodingBuffer::I32(&mut buf[start..]), |
150 | 0 | DecodingResult::I64(ref mut buf) => DecodingBuffer::I64(&mut buf[start..]), |
151 | | } |
152 | 17.5k | } |
153 | | } |
154 | | |
155 | | // A buffer for image decoding |
156 | | pub enum DecodingBuffer<'a> { |
157 | | /// A slice of unsigned bytes |
158 | | U8(&'a mut [u8]), |
159 | | /// A slice of unsigned words |
160 | | U16(&'a mut [u16]), |
161 | | /// A slice of 32 bit unsigned ints |
162 | | U32(&'a mut [u32]), |
163 | | /// A slice of 64 bit unsigned ints |
164 | | U64(&'a mut [u64]), |
165 | | /// A slice of 16 bit IEEE floats |
166 | | F16(&'a mut [f16]), |
167 | | /// A slice of 32 bit IEEE floats |
168 | | F32(&'a mut [f32]), |
169 | | /// A slice of 64 bit IEEE floats |
170 | | F64(&'a mut [f64]), |
171 | | /// A slice of 8 bits signed ints |
172 | | I8(&'a mut [i8]), |
173 | | /// A slice of 16 bits signed ints |
174 | | I16(&'a mut [i16]), |
175 | | /// A slice of 32 bits signed ints |
176 | | I32(&'a mut [i32]), |
177 | | /// A slice of 64 bits signed ints |
178 | | I64(&'a mut [i64]), |
179 | | } |
180 | | |
181 | | impl<'a> DecodingBuffer<'a> { |
182 | 3.78k | pub fn as_bytes(&self) -> &[u8] { |
183 | 3.78k | match self { |
184 | 3.69k | DecodingBuffer::U8(buf) => buf, |
185 | 0 | DecodingBuffer::I8(buf) => bytecast::i8_as_ne_bytes(buf), |
186 | 56 | DecodingBuffer::U16(buf) => bytecast::u16_as_ne_bytes(buf), |
187 | 0 | DecodingBuffer::I16(buf) => bytecast::i16_as_ne_bytes(buf), |
188 | 5 | DecodingBuffer::U32(buf) => bytecast::u32_as_ne_bytes(buf), |
189 | 0 | DecodingBuffer::I32(buf) => bytecast::i32_as_ne_bytes(buf), |
190 | 0 | DecodingBuffer::U64(buf) => bytecast::u64_as_ne_bytes(buf), |
191 | 0 | DecodingBuffer::I64(buf) => bytecast::i64_as_ne_bytes(buf), |
192 | 0 | DecodingBuffer::F16(buf) => bytecast::f16_as_ne_bytes(buf), |
193 | 27 | DecodingBuffer::F32(buf) => bytecast::f32_as_ne_bytes(buf), |
194 | 0 | DecodingBuffer::F64(buf) => bytecast::f64_as_ne_bytes(buf), |
195 | | } |
196 | 3.78k | } |
197 | | |
198 | 13.7k | pub fn as_bytes_mut(&mut self) -> &mut [u8] { |
199 | 13.7k | match self { |
200 | 11.5k | DecodingBuffer::U8(buf) => buf, |
201 | 0 | DecodingBuffer::I8(buf) => bytecast::i8_as_ne_mut_bytes(buf), |
202 | 2.07k | DecodingBuffer::U16(buf) => bytecast::u16_as_ne_mut_bytes(buf), |
203 | 0 | DecodingBuffer::I16(buf) => bytecast::i16_as_ne_mut_bytes(buf), |
204 | 18 | DecodingBuffer::U32(buf) => bytecast::u32_as_ne_mut_bytes(buf), |
205 | 0 | DecodingBuffer::I32(buf) => bytecast::i32_as_ne_mut_bytes(buf), |
206 | 0 | DecodingBuffer::U64(buf) => bytecast::u64_as_ne_mut_bytes(buf), |
207 | 0 | DecodingBuffer::I64(buf) => bytecast::i64_as_ne_mut_bytes(buf), |
208 | 0 | DecodingBuffer::F16(buf) => bytecast::f16_as_ne_mut_bytes(buf), |
209 | 64 | DecodingBuffer::F32(buf) => bytecast::f32_as_ne_mut_bytes(buf), |
210 | 0 | DecodingBuffer::F64(buf) => bytecast::f64_as_ne_mut_bytes(buf), |
211 | | } |
212 | 13.7k | } |
213 | | |
214 | 0 | pub fn byte_len(&self) -> usize { |
215 | 0 | self.as_bytes().len() |
216 | 0 | } |
217 | | } |
218 | | |
219 | | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
220 | | pub enum DecodingSampleType { |
221 | | U8, |
222 | | U16, |
223 | | U32, |
224 | | U64, |
225 | | F16, |
226 | | F32, |
227 | | F64, |
228 | | I8, |
229 | | I16, |
230 | | I32, |
231 | | I64, |
232 | | } |
233 | | |
234 | | impl DecodingSampleType { |
235 | 13.7k | fn extent_for_bytes(self, bytes: usize) -> DecodingExtent { |
236 | 13.7k | match self { |
237 | 11.6k | DecodingSampleType::U8 => DecodingExtent::U8(bytes), |
238 | 2.08k | DecodingSampleType::U16 => DecodingExtent::U16(bytes.div_ceil(2)), |
239 | 18 | DecodingSampleType::U32 => DecodingExtent::U32(bytes.div_ceil(4)), |
240 | 0 | DecodingSampleType::U64 => DecodingExtent::U64(bytes.div_ceil(8)), |
241 | 0 | DecodingSampleType::I8 => DecodingExtent::I8(bytes), |
242 | 0 | DecodingSampleType::I16 => DecodingExtent::I16(bytes.div_ceil(2)), |
243 | 0 | DecodingSampleType::I32 => DecodingExtent::I32(bytes.div_ceil(4)), |
244 | 0 | DecodingSampleType::I64 => DecodingExtent::I64(bytes.div_ceil(8)), |
245 | 0 | DecodingSampleType::F16 => DecodingExtent::F16(bytes.div_ceil(2)), |
246 | 64 | DecodingSampleType::F32 => DecodingExtent::F32(bytes.div_ceil(4)), |
247 | 0 | DecodingSampleType::F64 => DecodingExtent::F64(bytes.div_ceil(8)), |
248 | | } |
249 | 13.7k | } |
250 | | } |
251 | | |
252 | | /// Information on the byte buffer that should be supplied to the decoder. |
253 | | /// |
254 | | /// This is relevant for [`Decoder::read_image_bytes`] and [`Decoder::read_chunk_bytes`] where the |
255 | | /// caller provided buffer must fit the expectations of the decoder to be filled with data from the |
256 | | /// current image. |
257 | | #[non_exhaustive] |
258 | | #[derive(Debug, Clone)] |
259 | | pub struct BufferLayoutPreference { |
260 | | /// Minimum byte size of the buffer to read image data. |
261 | | pub len: usize, |
262 | | /// The interpretation of each sample in the image. |
263 | | /// |
264 | | /// We only support a uniform sample layout. Detailed information for mixed colors may be added |
265 | | /// in the future and will become available by explicit query. The same goes for the bit-depth |
266 | | /// of samples that must also be uniform. |
267 | | pub sample_format: SampleFormat, |
268 | | /// The type representation for each sample. Only available for depths and formats which the |
269 | | /// library can describe. |
270 | | pub sample_type: Option<DecodingSampleType>, |
271 | | /// Minimum number of bytes to represent a row of image data of the requested content. |
272 | | pub row_stride: Option<NonZeroUsize>, |
273 | | /// Number of planes in the image. |
274 | | pub planes: usize, |
275 | | /// Number of bytes used to represent one plane. |
276 | | pub plane_stride: Option<NonZeroUsize>, |
277 | | /// Number of bytes of data when reading all planes. |
278 | | pub complete_len: usize, |
279 | | } |
280 | | |
281 | | impl BufferLayoutPreference { |
282 | 13.7k | fn from_planes(layout: &image::PlaneLayout) -> Self { |
283 | 13.7k | BufferLayoutPreference { |
284 | 13.7k | len: layout.readout.plane_stride, |
285 | 13.7k | row_stride: core::num::NonZeroUsize::new(layout.readout.row_stride), |
286 | 13.7k | planes: layout.plane_offsets.len(), |
287 | 13.7k | plane_stride: core::num::NonZeroUsize::new(layout.readout.plane_stride), |
288 | 13.7k | complete_len: layout.total_bytes, |
289 | 13.7k | sample_format: layout.readout.sample_format, |
290 | 13.7k | sample_type: Self::sample_type(layout.readout.sample_format, layout.readout.color), |
291 | 13.7k | } |
292 | 13.7k | } |
293 | | |
294 | 27.5k | fn sample_type(sample_format: SampleFormat, color: ColorType) -> Option<DecodingSampleType> { |
295 | 27.5k | Some(match sample_format { |
296 | 27.4k | SampleFormat::Uint => match color.bit_depth() { |
297 | 27.4k | n if n <= 8 => DecodingSampleType::U8, |
298 | 4.21k | n if n <= 16 => DecodingSampleType::U16, |
299 | 36 | n if n <= 32 => DecodingSampleType::U32, |
300 | 0 | n if n <= 64 => DecodingSampleType::U64, |
301 | 0 | _ => return None, |
302 | | }, |
303 | 128 | SampleFormat::IEEEFP => match color.bit_depth() { |
304 | 0 | 16 => DecodingSampleType::F16, |
305 | 128 | 32 => DecodingSampleType::F32, |
306 | 0 | 64 => DecodingSampleType::F64, |
307 | 0 | _ => return None, |
308 | | }, |
309 | 0 | SampleFormat::Int => match color.bit_depth() { |
310 | 0 | n if n <= 8 => DecodingSampleType::I8, |
311 | 0 | n if n <= 16 => DecodingSampleType::I16, |
312 | 0 | n if n <= 32 => DecodingSampleType::I32, |
313 | 0 | n if n <= 64 => DecodingSampleType::I64, |
314 | 0 | _ => return None, |
315 | | }, |
316 | 0 | _other => { |
317 | 0 | return None; |
318 | | } |
319 | | }) |
320 | 27.5k | } |
321 | | } |
322 | | |
323 | | impl image::ReadoutLayout { |
324 | | // FIXME: when planes are not homogenous (i.e. subsampled or differing depths) then the |
325 | | // `readout_for_size` or `to_plane_layout` needs a parameter to determine the planes being |
326 | | // read instead of assuming a constant repeated size for them. |
327 | 13.7k | fn result_extent_for_planes( |
328 | 13.7k | self: &image::ReadoutLayout, |
329 | 13.7k | planes: core::ops::Range<u16>, |
330 | 13.7k | ) -> TiffResult<DecodingExtent> { |
331 | 13.7k | let buffer = self.to_plane_layout()?; |
332 | | |
333 | | // The layout is for all planes. So restrict ourselves to the planes that were requested. |
334 | 13.7k | let offset = match buffer.plane_offsets.get(usize::from(planes.start)) { |
335 | 13.7k | Some(n) => *n, |
336 | | None => { |
337 | 0 | return Err(TiffError::UsageError(UsageError::InvalidPlaneIndex( |
338 | 0 | planes.start, |
339 | 0 | ))) |
340 | | } |
341 | | }; |
342 | | |
343 | 13.7k | let end = match buffer.plane_offsets.get(usize::from(planes.end)) { |
344 | 0 | Some(n) => *n, |
345 | 13.7k | None => buffer.total_bytes, |
346 | | }; |
347 | | |
348 | 13.7k | let buffer_bytes = end - offset; |
349 | 13.7k | let bits_per_sample = self.color.bit_depth(); |
350 | | |
351 | 13.7k | let Some(sample_type) = BufferLayoutPreference::sample_type(self.sample_format, self.color) |
352 | | else { |
353 | 0 | if matches!( |
354 | 0 | self.sample_format, |
355 | | SampleFormat::Uint | SampleFormat::Int | SampleFormat::IEEEFP |
356 | | ) { |
357 | 0 | return Err(TiffError::UnsupportedError( |
358 | 0 | TiffUnsupportedError::UnsupportedSampleDepth(bits_per_sample), |
359 | 0 | )); |
360 | | } else { |
361 | 0 | return Err(TiffError::UnsupportedError( |
362 | 0 | TiffUnsupportedError::UnsupportedSampleFormat(vec![self.sample_format]), |
363 | 0 | )); |
364 | | } |
365 | | }; |
366 | | |
367 | 13.7k | Ok(sample_type.extent_for_bytes(buffer_bytes)) |
368 | 13.7k | } |
369 | | |
370 | | #[inline(always)] |
371 | 13.7k | fn assert_min_layout<T>(&self, buffer: &[T]) -> TiffResult<()> { |
372 | 13.7k | if core::mem::size_of_val(buffer) < self.plane_stride { |
373 | 0 | Err(TiffError::UsageError( |
374 | 0 | UsageError::InsufficientOutputBufferSize { |
375 | 0 | needed: self.plane_stride, |
376 | 0 | provided: buffer.len(), |
377 | 0 | }, |
378 | 0 | )) |
379 | | } else { |
380 | 13.7k | Ok(()) |
381 | | } |
382 | 13.7k | } <tiff::decoder::image::ReadoutLayout>::assert_min_layout::<u8> Line | Count | Source | 371 | 13.7k | fn assert_min_layout<T>(&self, buffer: &[T]) -> TiffResult<()> { | 372 | 13.7k | if core::mem::size_of_val(buffer) < self.plane_stride { | 373 | 0 | Err(TiffError::UsageError( | 374 | 0 | UsageError::InsufficientOutputBufferSize { | 375 | 0 | needed: self.plane_stride, | 376 | 0 | provided: buffer.len(), | 377 | 0 | }, | 378 | 0 | )) | 379 | | } else { | 380 | 13.7k | Ok(()) | 381 | | } | 382 | 13.7k | } |
Unexecuted instantiation: <tiff::decoder::image::ReadoutLayout>::assert_min_layout::<_> |
383 | | } |
384 | | |
385 | | /// The count and matching discriminant for a `DecodingBuffer`. |
386 | | #[derive(Clone)] |
387 | | enum DecodingExtent { |
388 | | U8(usize), |
389 | | U16(usize), |
390 | | U32(usize), |
391 | | U64(usize), |
392 | | F16(usize), |
393 | | F32(usize), |
394 | | F64(usize), |
395 | | I8(usize), |
396 | | I16(usize), |
397 | | I32(usize), |
398 | | I64(usize), |
399 | | } |
400 | | |
401 | | impl DecodingExtent { |
402 | 13.7k | fn to_result_buffer(&self, limits: &Limits) -> TiffResult<DecodingResult> { |
403 | 13.7k | match *self { |
404 | 11.6k | DecodingExtent::U8(count) => DecodingResult::new_u8(count, limits), |
405 | 2.08k | DecodingExtent::U16(count) => DecodingResult::new_u16(count, limits), |
406 | 18 | DecodingExtent::U32(count) => DecodingResult::new_u32(count, limits), |
407 | 0 | DecodingExtent::U64(count) => DecodingResult::new_u64(count, limits), |
408 | 0 | DecodingExtent::F16(count) => DecodingResult::new_f16(count, limits), |
409 | 64 | DecodingExtent::F32(count) => DecodingResult::new_f32(count, limits), |
410 | 0 | DecodingExtent::F64(count) => DecodingResult::new_f64(count, limits), |
411 | 0 | DecodingExtent::I8(count) => DecodingResult::new_i8(count, limits), |
412 | 0 | DecodingExtent::I16(count) => DecodingResult::new_i16(count, limits), |
413 | 0 | DecodingExtent::I32(count) => DecodingResult::new_i32(count, limits), |
414 | 0 | DecodingExtent::I64(count) => DecodingResult::new_i64(count, limits), |
415 | | } |
416 | 13.7k | } |
417 | | |
418 | 0 | fn preferred_layout(self) -> TiffResult<Layout> { |
419 | 0 | fn overflow(_: LayoutError) -> TiffError { |
420 | 0 | TiffError::LimitsExceeded |
421 | 0 | } |
422 | | |
423 | 0 | match self { |
424 | 0 | DecodingExtent::U8(count) => Layout::array::<u8>(count), |
425 | 0 | DecodingExtent::U16(count) => Layout::array::<u16>(count), |
426 | 0 | DecodingExtent::U32(count) => Layout::array::<u32>(count), |
427 | 0 | DecodingExtent::U64(count) => Layout::array::<u64>(count), |
428 | 0 | DecodingExtent::F16(count) => Layout::array::<f16>(count), |
429 | 0 | DecodingExtent::F32(count) => Layout::array::<f32>(count), |
430 | 0 | DecodingExtent::F64(count) => Layout::array::<f64>(count), |
431 | 0 | DecodingExtent::I8(count) => Layout::array::<i8>(count), |
432 | 0 | DecodingExtent::I16(count) => Layout::array::<i16>(count), |
433 | 0 | DecodingExtent::I32(count) => Layout::array::<i32>(count), |
434 | 0 | DecodingExtent::I64(count) => Layout::array::<i64>(count), |
435 | | } |
436 | 0 | .map_err(overflow) |
437 | 0 | } |
438 | | |
439 | 0 | fn sample_type(&self) -> DecodingSampleType { |
440 | 0 | match *self { |
441 | 0 | DecodingExtent::U8(_) => DecodingSampleType::U8, |
442 | 0 | DecodingExtent::U16(_) => DecodingSampleType::U16, |
443 | 0 | DecodingExtent::U32(_) => DecodingSampleType::U32, |
444 | 0 | DecodingExtent::U64(_) => DecodingSampleType::U64, |
445 | 0 | DecodingExtent::F16(_) => DecodingSampleType::F16, |
446 | 0 | DecodingExtent::F32(_) => DecodingSampleType::F32, |
447 | 0 | DecodingExtent::F64(_) => DecodingSampleType::F64, |
448 | 0 | DecodingExtent::I8(_) => DecodingSampleType::I8, |
449 | 0 | DecodingExtent::I16(_) => DecodingSampleType::I16, |
450 | 0 | DecodingExtent::I32(_) => DecodingSampleType::I32, |
451 | 0 | DecodingExtent::I64(_) => DecodingSampleType::I64, |
452 | | } |
453 | 0 | } |
454 | | } |
455 | | |
456 | | #[derive(Debug, Copy, Clone, PartialEq)] |
457 | | /// Chunk type of the internal representation |
458 | | pub enum ChunkType { |
459 | | Strip, |
460 | | Tile, |
461 | | } |
462 | | |
463 | | /// Decoding limits |
464 | | #[derive(Clone, Debug)] |
465 | | #[non_exhaustive] |
466 | | pub struct Limits { |
467 | | /// The maximum size of any `DecodingResult` in bytes, the default is |
468 | | /// 256MiB. If the entire image is decoded at once, then this will |
469 | | /// be the maximum size of the image. If it is decoded one strip at a |
470 | | /// time, this will be the maximum size of a strip. |
471 | | pub decoding_buffer_size: usize, |
472 | | /// The maximum size of any ifd value in bytes, the default is |
473 | | /// 1MiB. |
474 | | pub ifd_value_size: usize, |
475 | | /// Maximum size for intermediate buffer which may be used to limit the amount of data read per |
476 | | /// segment even if the entire image is decoded at once. |
477 | | pub intermediate_buffer_size: usize, |
478 | | } |
479 | | |
480 | | impl Limits { |
481 | | /// A configuration that does not impose any limits. |
482 | | /// |
483 | | /// This is a good start if the caller only wants to impose selective limits, contrary to the |
484 | | /// default limits which allows selectively disabling limits. |
485 | | /// |
486 | | /// Note that this configuration is likely to crash on excessively large images since, |
487 | | /// naturally, the machine running the program does not have infinite memory. |
488 | 0 | pub fn unlimited() -> Limits { |
489 | 0 | Limits { |
490 | 0 | decoding_buffer_size: usize::MAX, |
491 | 0 | ifd_value_size: usize::MAX, |
492 | 0 | intermediate_buffer_size: usize::MAX, |
493 | 0 | } |
494 | 0 | } |
495 | | } |
496 | | |
497 | | impl Default for Limits { |
498 | 33.5k | fn default() -> Limits { |
499 | 33.5k | Limits { |
500 | 33.5k | decoding_buffer_size: 256 * 1024 * 1024, |
501 | 33.5k | intermediate_buffer_size: 128 * 1024 * 1024, |
502 | 33.5k | ifd_value_size: 1024 * 1024, |
503 | 33.5k | } |
504 | 33.5k | } |
505 | | } |
506 | | |
507 | | /// The representation of a TIFF decoder |
508 | | /// |
509 | | /// Currently does not support decoding of interlaced images |
510 | | #[derive(Debug)] |
511 | | pub struct Decoder<R> |
512 | | where |
513 | | R: Read + Seek, |
514 | | { |
515 | | /// There are grouped for borrow checker reasons. This allows us to implement methods that |
516 | | /// borrow the stream access and the other fields mutably at the same time. |
517 | | value_reader: ValueReader<R>, |
518 | | current_ifd: Option<IfdPointer>, |
519 | | next_ifd: Option<IfdPointer>, |
520 | | /// The IFDs we visited already in this chain of IFDs. |
521 | | ifd_offsets: Vec<IfdPointer>, |
522 | | /// Map from the ifd into the `ifd_offsets` ordered list. |
523 | | seen_ifds: cycles::IfdCycles, |
524 | | image: Image, |
525 | | } |
526 | | |
527 | | /// All the information needed to read and interpret byte slices from the underlying file, i.e. to |
528 | | /// turn an entry of a tag into an `ifd::Value` or otherwise fetch arrays of similar types. Used |
529 | | /// only as the type of the field [`Decoder::value_reader`] and passed to submodules. |
530 | | #[derive(Debug)] |
531 | | struct ValueReader<R> { |
532 | | reader: EndianReader<R>, |
533 | | bigtiff: bool, |
534 | | limits: Limits, |
535 | | } |
536 | | |
537 | | /// Reads a directory's tag values from an underlying stream. |
538 | | pub struct IfdDecoder<'lt> { |
539 | | inner: tag_reader::TagReader<'lt, dyn tag_reader::EntryDecoder + 'lt>, |
540 | | } |
541 | | |
542 | 43.7k | fn rev_hpredict_nsamp(buf: &mut [u8], bit_depth: u8, samples: u16) { |
543 | 41.2k | fn one_byte_predict<const N: usize>(buf: &mut [u8]) { |
544 | 25.8M | for i in N..buf.len() { |
545 | 25.8M | buf[i] = buf[i].wrapping_add(buf[i - N]); |
546 | 25.8M | } |
547 | 41.2k | } tiff::decoder::rev_hpredict_nsamp::one_byte_predict::<1> Line | Count | Source | 543 | 36.8k | fn one_byte_predict<const N: usize>(buf: &mut [u8]) { | 544 | 19.0M | for i in N..buf.len() { | 545 | 19.0M | buf[i] = buf[i].wrapping_add(buf[i - N]); | 546 | 19.0M | } | 547 | 36.8k | } |
Unexecuted instantiation: tiff::decoder::rev_hpredict_nsamp::one_byte_predict::<2> tiff::decoder::rev_hpredict_nsamp::one_byte_predict::<3> Line | Count | Source | 543 | 3.11k | fn one_byte_predict<const N: usize>(buf: &mut [u8]) { | 544 | 4.86M | for i in N..buf.len() { | 545 | 4.86M | buf[i] = buf[i].wrapping_add(buf[i - N]); | 546 | 4.86M | } | 547 | 3.11k | } |
tiff::decoder::rev_hpredict_nsamp::one_byte_predict::<4> Line | Count | Source | 543 | 1.29k | fn one_byte_predict<const N: usize>(buf: &mut [u8]) { | 544 | 1.92M | for i in N..buf.len() { | 545 | 1.92M | buf[i] = buf[i].wrapping_add(buf[i - N]); | 546 | 1.92M | } | 547 | 1.29k | } |
|
548 | | |
549 | 2.02k | fn two_bytes_predict<const N: usize>(buf: &mut [u8]) { |
550 | 251k | for i in (2 * N..buf.len()).step_by(2) { |
551 | 251k | let v = u16::from_ne_bytes(buf[i..][..2].try_into().unwrap()); |
552 | 251k | let p = u16::from_ne_bytes(buf[i - 2 * N..][..2].try_into().unwrap()); |
553 | 251k | buf[i..][..2].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); |
554 | 251k | } |
555 | 2.02k | } tiff::decoder::rev_hpredict_nsamp::two_bytes_predict::<1> Line | Count | Source | 549 | 1.50k | fn two_bytes_predict<const N: usize>(buf: &mut [u8]) { | 550 | 151k | for i in (2 * N..buf.len()).step_by(2) { | 551 | 151k | let v = u16::from_ne_bytes(buf[i..][..2].try_into().unwrap()); | 552 | 151k | let p = u16::from_ne_bytes(buf[i - 2 * N..][..2].try_into().unwrap()); | 553 | 151k | buf[i..][..2].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); | 554 | 151k | } | 555 | 1.50k | } |
Unexecuted instantiation: tiff::decoder::rev_hpredict_nsamp::two_bytes_predict::<2> tiff::decoder::rev_hpredict_nsamp::two_bytes_predict::<3> Line | Count | Source | 549 | 526 | fn two_bytes_predict<const N: usize>(buf: &mut [u8]) { | 550 | 99.9k | for i in (2 * N..buf.len()).step_by(2) { | 551 | 99.9k | let v = u16::from_ne_bytes(buf[i..][..2].try_into().unwrap()); | 552 | 99.9k | let p = u16::from_ne_bytes(buf[i - 2 * N..][..2].try_into().unwrap()); | 553 | 99.9k | buf[i..][..2].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); | 554 | 99.9k | } | 555 | 526 | } |
Unexecuted instantiation: tiff::decoder::rev_hpredict_nsamp::two_bytes_predict::<4> |
556 | | |
557 | 180 | fn four_bytes_predict<const N: usize>(buf: &mut [u8]) { |
558 | 252k | for i in (N * 4..buf.len()).step_by(4) { |
559 | 252k | let v = u32::from_ne_bytes(buf[i..][..4].try_into().unwrap()); |
560 | 252k | let p = u32::from_ne_bytes(buf[i - 4 * N..][..4].try_into().unwrap()); |
561 | 252k | buf[i..][..4].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); |
562 | 252k | } |
563 | 180 | } Unexecuted instantiation: tiff::decoder::rev_hpredict_nsamp::four_bytes_predict::<1> Unexecuted instantiation: tiff::decoder::rev_hpredict_nsamp::four_bytes_predict::<2> tiff::decoder::rev_hpredict_nsamp::four_bytes_predict::<3> Line | Count | Source | 557 | 164 | fn four_bytes_predict<const N: usize>(buf: &mut [u8]) { | 558 | 252k | for i in (N * 4..buf.len()).step_by(4) { | 559 | 252k | let v = u32::from_ne_bytes(buf[i..][..4].try_into().unwrap()); | 560 | 252k | let p = u32::from_ne_bytes(buf[i - 4 * N..][..4].try_into().unwrap()); | 561 | 252k | buf[i..][..4].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); | 562 | 252k | } | 563 | 164 | } |
tiff::decoder::rev_hpredict_nsamp::four_bytes_predict::<4> Line | Count | Source | 557 | 16 | fn four_bytes_predict<const N: usize>(buf: &mut [u8]) { | 558 | 320 | for i in (N * 4..buf.len()).step_by(4) { | 559 | 320 | let v = u32::from_ne_bytes(buf[i..][..4].try_into().unwrap()); | 560 | 320 | let p = u32::from_ne_bytes(buf[i - 4 * N..][..4].try_into().unwrap()); | 561 | 320 | buf[i..][..4].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); | 562 | 320 | } | 563 | 16 | } |
|
564 | | |
565 | 43.7k | let samples = usize::from(samples); |
566 | | |
567 | 43.7k | match (bit_depth, samples) { |
568 | | // Note we can't use `windows` or so due to the overlap between each iteration. We split |
569 | | // the cases by the samples / lookback constant so that each is optimized individually. |
570 | | // This is more code generated but each loop can then have a different vectorization |
571 | | // strategy. |
572 | 43.7k | (0..=8, 1) => one_byte_predict::<1>(buf), |
573 | 0 | (0..=8, 2) => one_byte_predict::<2>(buf), |
574 | 3.11k | (0..=8, 3) => one_byte_predict::<3>(buf), |
575 | 1.29k | (0..=8, 4) => one_byte_predict::<4>(buf), |
576 | | // The generic, sub-optimal case for the above. |
577 | | (0..=8, _) => { |
578 | 24.2k | for i in samples..buf.len() { |
579 | 24.2k | buf[i] = buf[i].wrapping_add(buf[i - samples]); |
580 | 24.2k | } |
581 | | } |
582 | 2.20k | (9..=16, 1) => { |
583 | 1.50k | two_bytes_predict::<1>(buf); |
584 | 1.50k | } |
585 | 0 | (9..=16, 2) => { |
586 | 0 | two_bytes_predict::<2>(buf); |
587 | 0 | } |
588 | 526 | (9..=16, 3) => { |
589 | 526 | two_bytes_predict::<3>(buf); |
590 | 526 | } |
591 | 0 | (9..=16, 4) => { |
592 | 0 | two_bytes_predict::<4>(buf); |
593 | 0 | } |
594 | | (9..=16, _) => { |
595 | 0 | for i in (samples * 2..buf.len()).step_by(2) { |
596 | 0 | let v = u16::from_ne_bytes(buf[i..][..2].try_into().unwrap()); |
597 | 0 | let p = u16::from_ne_bytes(buf[i - 2 * samples..][..2].try_into().unwrap()); |
598 | 0 | buf[i..][..2].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); |
599 | 0 | } |
600 | | } |
601 | 180 | (17..=32, 1) => { |
602 | 0 | four_bytes_predict::<1>(buf); |
603 | 0 | } |
604 | 0 | (17..=32, 2) => { |
605 | 0 | four_bytes_predict::<2>(buf); |
606 | 0 | } |
607 | 164 | (17..=32, 3) => { |
608 | 164 | four_bytes_predict::<3>(buf); |
609 | 164 | } |
610 | 16 | (17..=32, 4) => { |
611 | 16 | four_bytes_predict::<4>(buf); |
612 | 16 | } |
613 | | (17..=32, _) => { |
614 | 0 | for i in (samples * 4..buf.len()).step_by(4) { |
615 | 0 | let v = u32::from_ne_bytes(buf[i..][..4].try_into().unwrap()); |
616 | 0 | let p = u32::from_ne_bytes(buf[i - 4 * samples..][..4].try_into().unwrap()); |
617 | 0 | buf[i..][..4].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); |
618 | 0 | } |
619 | | } |
620 | 0 | (33..=64, _) => { |
621 | 0 | for i in (samples * 8..buf.len()).step_by(8) { |
622 | 0 | let v = u64::from_ne_bytes(buf[i..][..8].try_into().unwrap()); |
623 | 0 | let p = u64::from_ne_bytes(buf[i - 8 * samples..][..8].try_into().unwrap()); |
624 | 0 | buf[i..][..8].copy_from_slice(&(v.wrapping_add(p)).to_ne_bytes()); |
625 | 0 | } |
626 | | } |
627 | | _ => { |
628 | 0 | unreachable!("Caller should have validated arguments. Please file a bug.") |
629 | | } |
630 | | } |
631 | 43.7k | } |
632 | | |
633 | 1.26k | fn predict_f32(input: &mut [u8], output: &mut [u8], samples: u16) { |
634 | 1.26k | let samples = usize::from(samples); |
635 | | |
636 | 3.83M | for i in samples..input.len() { |
637 | 3.83M | input[i] = input[i].wrapping_add(input[i - samples]); |
638 | 3.83M | } |
639 | | |
640 | 960k | for (i, chunk) in output.chunks_mut(4).enumerate() { |
641 | 960k | chunk.copy_from_slice(&u32::to_ne_bytes(u32::from_be_bytes([ |
642 | 960k | input[i], |
643 | 960k | input[input.len() / 4 + i], |
644 | 960k | input[input.len() / 4 * 2 + i], |
645 | 960k | input[input.len() / 4 * 3 + i], |
646 | 960k | ]))); |
647 | 960k | } |
648 | 1.26k | } |
649 | | |
650 | 0 | fn predict_f16(input: &mut [u8], output: &mut [u8], samples: u16) { |
651 | 0 | let samples = usize::from(samples); |
652 | | |
653 | 0 | for i in samples..input.len() { |
654 | 0 | input[i] = input[i].wrapping_add(input[i - samples]); |
655 | 0 | } |
656 | | |
657 | 0 | for (i, chunk) in output.chunks_mut(2).enumerate() { |
658 | 0 | chunk.copy_from_slice(&u16::to_ne_bytes(u16::from_be_bytes([ |
659 | 0 | input[i], |
660 | 0 | input[input.len() / 2 + i], |
661 | 0 | ]))); |
662 | 0 | } |
663 | 0 | } |
664 | | |
665 | 0 | fn predict_f64(input: &mut [u8], output: &mut [u8], samples: u16) { |
666 | 0 | let samples = usize::from(samples); |
667 | | |
668 | 0 | for i in samples..input.len() { |
669 | 0 | input[i] = input[i].wrapping_add(input[i - samples]); |
670 | 0 | } |
671 | | |
672 | 0 | for (i, chunk) in output.chunks_mut(8).enumerate() { |
673 | 0 | chunk.copy_from_slice(&u64::to_ne_bytes(u64::from_be_bytes([ |
674 | 0 | input[i], |
675 | 0 | input[input.len() / 8 + i], |
676 | 0 | input[input.len() / 8 * 2 + i], |
677 | 0 | input[input.len() / 8 * 3 + i], |
678 | 0 | input[input.len() / 8 * 4 + i], |
679 | 0 | input[input.len() / 8 * 5 + i], |
680 | 0 | input[input.len() / 8 * 6 + i], |
681 | 0 | input[input.len() / 8 * 7 + i], |
682 | 0 | ]))); |
683 | 0 | } |
684 | 0 | } |
685 | | |
686 | 7.36M | fn fix_endianness_and_predict( |
687 | 7.36M | buf: &mut [u8], |
688 | 7.36M | bit_depth: u8, |
689 | 7.36M | samples: u16, |
690 | 7.36M | byte_order: ByteOrder, |
691 | 7.36M | predictor: Predictor, |
692 | 7.36M | ) { |
693 | 7.36M | match predictor { |
694 | 7.31M | Predictor::None => { |
695 | 7.31M | fix_endianness(buf, byte_order, bit_depth); |
696 | 7.31M | } |
697 | 43.7k | Predictor::Horizontal => { |
698 | 43.7k | fix_endianness(buf, byte_order, bit_depth); |
699 | 43.7k | rev_hpredict_nsamp(buf, bit_depth, samples); |
700 | 43.7k | } |
701 | | Predictor::FloatingPoint => { |
702 | 1.24k | let mut buffer_copy = buf.to_vec(); |
703 | 1.24k | match bit_depth { |
704 | 0 | 16 => predict_f16(&mut buffer_copy, buf, samples), |
705 | 1.24k | 32 => predict_f32(&mut buffer_copy, buf, samples), |
706 | 0 | 64 => predict_f64(&mut buffer_copy, buf, samples), |
707 | 0 | _ => unreachable!("Caller should have validated arguments. Please file a bug."), |
708 | | } |
709 | | } |
710 | | } |
711 | 7.36M | } |
712 | | |
713 | 49.1k | fn invert_colors( |
714 | 49.1k | buf: &mut [u8], |
715 | 49.1k | color_type: ColorType, |
716 | 49.1k | sample_format: SampleFormat, |
717 | 49.1k | ) -> TiffResult<()> { |
718 | 49.1k | match (color_type, sample_format) { |
719 | | // Where pixels do not cross a byte boundary |
720 | | (ColorType::Gray(1 | 2 | 4 | 8), SampleFormat::Uint) => { |
721 | 55.6M | for x in buf { |
722 | 55.5M | // Equivalent to both of the following: |
723 | 55.5M | // |
724 | 55.5M | // *x = 0xff - *x |
725 | 55.5M | // *x = !*x |
726 | 55.5M | // |
727 | 55.5M | // since -x = !x+1 |
728 | 55.5M | *x = !*x; |
729 | 55.5M | } |
730 | | } |
731 | | (ColorType::Gray(16), SampleFormat::Uint) => { |
732 | 598k | for x in buf.chunks_mut(2) { |
733 | 598k | let v = u16::from_ne_bytes(x.try_into().unwrap()); |
734 | 598k | x.copy_from_slice(&(0xffff - v).to_ne_bytes()); |
735 | 598k | } |
736 | | } |
737 | | (ColorType::Gray(32), SampleFormat::Uint) => { |
738 | 0 | for x in buf.chunks_mut(4) { |
739 | 0 | let v = u32::from_ne_bytes(x.try_into().unwrap()); |
740 | 0 | x.copy_from_slice(&(0xffff_ffff - v).to_ne_bytes()); |
741 | 0 | } |
742 | | } |
743 | | (ColorType::Gray(64), SampleFormat::Uint) => { |
744 | 0 | for x in buf.chunks_mut(8) { |
745 | 0 | let v = u64::from_ne_bytes(x.try_into().unwrap()); |
746 | 0 | x.copy_from_slice(&(0xffff_ffff_ffff_ffff - v).to_ne_bytes()); |
747 | 0 | } |
748 | | } |
749 | | (ColorType::Gray(32), SampleFormat::IEEEFP) => { |
750 | 0 | for x in buf.chunks_mut(4) { |
751 | 0 | let v = f32::from_ne_bytes(x.try_into().unwrap()); |
752 | 0 | x.copy_from_slice(&(1.0 - v).to_ne_bytes()); |
753 | 0 | } |
754 | | } |
755 | | (ColorType::Gray(64), SampleFormat::IEEEFP) => { |
756 | 0 | for x in buf.chunks_mut(8) { |
757 | 0 | let v = f64::from_ne_bytes(x.try_into().unwrap()); |
758 | 0 | x.copy_from_slice(&(1.0 - v).to_ne_bytes()); |
759 | 0 | } |
760 | | } |
761 | | _ => { |
762 | 0 | return Err(TiffError::UnsupportedError( |
763 | 0 | TiffUnsupportedError::UnknownInterpretation, |
764 | 0 | )) |
765 | | } |
766 | | } |
767 | | |
768 | 49.1k | Ok(()) |
769 | 49.1k | } |
770 | | |
771 | | /// Fix endianness. If `byte_order` matches the host, then conversion is a no-op. |
772 | 7.36M | fn fix_endianness(buf: &mut [u8], byte_order: ByteOrder, bit_depth: u8) { |
773 | 7.36M | let host = ByteOrder::native(); |
774 | | |
775 | 7.36M | let class = match bit_depth { |
776 | 7.36M | 0..=8 => crate::tags::EndianBytes::One, |
777 | 30.4k | 9..=16 => crate::tags::EndianBytes::Two, |
778 | 773 | 17..=32 => crate::tags::EndianBytes::Four, |
779 | 0 | _ => crate::tags::EndianBytes::Eight, |
780 | | }; |
781 | | |
782 | 7.36M | host.convert_endian_bytes(class, buf, byte_order); |
783 | 7.36M | } |
784 | | |
785 | | impl<R: Read + Seek> Decoder<R> { |
786 | 19.8k | pub fn new(mut r: R) -> TiffResult<Decoder<R>> { |
787 | 19.8k | let mut endianess = Vec::with_capacity(2); |
788 | 19.8k | (&mut r).take(2).read_to_end(&mut endianess)?; |
789 | 19.8k | let byte_order = match &*endianess { |
790 | 19.8k | b"II" => ByteOrder::LittleEndian, |
791 | 1.42k | b"MM" => ByteOrder::BigEndian, |
792 | | _ => { |
793 | 20 | return Err(TiffError::FormatError( |
794 | 20 | TiffFormatError::TiffSignatureNotFound, |
795 | 20 | )) |
796 | | } |
797 | | }; |
798 | 19.8k | let mut reader = EndianReader::new(r, byte_order); |
799 | | |
800 | 19.8k | let bigtiff = match reader.read_u16()? { |
801 | 19.3k | 42 => false, |
802 | | 43 => { |
803 | | // Read bytesize of offsets (in bigtiff it's alway 8 but provide a way to move to 16 some day) |
804 | 518 | if reader.read_u16()? != 8 { |
805 | 16 | return Err(TiffError::FormatError( |
806 | 16 | TiffFormatError::TiffSignatureNotFound, |
807 | 16 | )); |
808 | 499 | } |
809 | | // This constant should always be 0 |
810 | 499 | if reader.read_u16()? != 0 { |
811 | 16 | return Err(TiffError::FormatError( |
812 | 16 | TiffFormatError::TiffSignatureNotFound, |
813 | 16 | )); |
814 | 481 | } |
815 | 481 | true |
816 | | } |
817 | | _ => { |
818 | 1 | return Err(TiffError::FormatError( |
819 | 1 | TiffFormatError::TiffSignatureInvalid, |
820 | 1 | )) |
821 | | } |
822 | | }; |
823 | | |
824 | 19.7k | let next_ifd = if bigtiff { |
825 | 481 | Some(reader.read_u64()?) |
826 | | } else { |
827 | 19.3k | Some(u64::from(reader.read_u32()?)) |
828 | | } |
829 | 19.7k | .map(IfdPointer); |
830 | | |
831 | 19.7k | let current_ifd = *next_ifd.as_ref().unwrap(); |
832 | 19.7k | let ifd_offsets = vec![current_ifd]; |
833 | | |
834 | 19.7k | let mut decoder = Decoder { |
835 | 19.7k | value_reader: ValueReader { |
836 | 19.7k | reader, |
837 | 19.7k | bigtiff, |
838 | 19.7k | limits: Default::default(), |
839 | 19.7k | }, |
840 | 19.7k | next_ifd, |
841 | 19.7k | ifd_offsets, |
842 | 19.7k | current_ifd: None, |
843 | 19.7k | seen_ifds: cycles::IfdCycles::new(), |
844 | 19.7k | image: Image { |
845 | 19.7k | ifd: None, |
846 | 19.7k | width: 0, |
847 | 19.7k | height: 0, |
848 | 19.7k | bits_per_sample: 1, |
849 | 19.7k | samples: 1, |
850 | 19.7k | extra_samples: vec![], |
851 | 19.7k | photometric_samples: 1, |
852 | 19.7k | sample_format: SampleFormat::Uint, |
853 | 19.7k | photometric_interpretation: PhotometricInterpretation::BlackIsZero, |
854 | 19.7k | compression_method: CompressionMethod::None, |
855 | 19.7k | jpeg_tables: None, |
856 | 19.7k | predictor: Predictor::None, |
857 | 19.7k | chunk_type: ChunkType::Strip, |
858 | 19.7k | planar_config: PlanarConfiguration::Chunky, |
859 | 19.7k | strip_decoder: None, |
860 | 19.7k | tile_attributes: None, |
861 | 19.7k | chunk_offsets: Vec::new(), |
862 | 19.7k | chunk_bytes: Vec::new(), |
863 | 19.7k | chroma_subsampling: (2, 2), |
864 | 19.7k | }, |
865 | 19.7k | }; |
866 | 19.7k | decoder.next_image()?; |
867 | 14.0k | Ok(decoder) |
868 | 19.8k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::new Line | Count | Source | 786 | 19.8k | pub fn new(mut r: R) -> TiffResult<Decoder<R>> { | 787 | 19.8k | let mut endianess = Vec::with_capacity(2); | 788 | 19.8k | (&mut r).take(2).read_to_end(&mut endianess)?; | 789 | 19.8k | let byte_order = match &*endianess { | 790 | 19.8k | b"II" => ByteOrder::LittleEndian, | 791 | 1.42k | b"MM" => ByteOrder::BigEndian, | 792 | | _ => { | 793 | 20 | return Err(TiffError::FormatError( | 794 | 20 | TiffFormatError::TiffSignatureNotFound, | 795 | 20 | )) | 796 | | } | 797 | | }; | 798 | 19.8k | let mut reader = EndianReader::new(r, byte_order); | 799 | | | 800 | 19.8k | let bigtiff = match reader.read_u16()? { | 801 | 19.3k | 42 => false, | 802 | | 43 => { | 803 | | // Read bytesize of offsets (in bigtiff it's alway 8 but provide a way to move to 16 some day) | 804 | 518 | if reader.read_u16()? != 8 { | 805 | 16 | return Err(TiffError::FormatError( | 806 | 16 | TiffFormatError::TiffSignatureNotFound, | 807 | 16 | )); | 808 | 499 | } | 809 | | // This constant should always be 0 | 810 | 499 | if reader.read_u16()? != 0 { | 811 | 16 | return Err(TiffError::FormatError( | 812 | 16 | TiffFormatError::TiffSignatureNotFound, | 813 | 16 | )); | 814 | 481 | } | 815 | 481 | true | 816 | | } | 817 | | _ => { | 818 | 1 | return Err(TiffError::FormatError( | 819 | 1 | TiffFormatError::TiffSignatureInvalid, | 820 | 1 | )) | 821 | | } | 822 | | }; | 823 | | | 824 | 19.7k | let next_ifd = if bigtiff { | 825 | 481 | Some(reader.read_u64()?) | 826 | | } else { | 827 | 19.3k | Some(u64::from(reader.read_u32()?)) | 828 | | } | 829 | 19.7k | .map(IfdPointer); | 830 | | | 831 | 19.7k | let current_ifd = *next_ifd.as_ref().unwrap(); | 832 | 19.7k | let ifd_offsets = vec![current_ifd]; | 833 | | | 834 | 19.7k | let mut decoder = Decoder { | 835 | 19.7k | value_reader: ValueReader { | 836 | 19.7k | reader, | 837 | 19.7k | bigtiff, | 838 | 19.7k | limits: Default::default(), | 839 | 19.7k | }, | 840 | 19.7k | next_ifd, | 841 | 19.7k | ifd_offsets, | 842 | 19.7k | current_ifd: None, | 843 | 19.7k | seen_ifds: cycles::IfdCycles::new(), | 844 | 19.7k | image: Image { | 845 | 19.7k | ifd: None, | 846 | 19.7k | width: 0, | 847 | 19.7k | height: 0, | 848 | 19.7k | bits_per_sample: 1, | 849 | 19.7k | samples: 1, | 850 | 19.7k | extra_samples: vec![], | 851 | 19.7k | photometric_samples: 1, | 852 | 19.7k | sample_format: SampleFormat::Uint, | 853 | 19.7k | photometric_interpretation: PhotometricInterpretation::BlackIsZero, | 854 | 19.7k | compression_method: CompressionMethod::None, | 855 | 19.7k | jpeg_tables: None, | 856 | 19.7k | predictor: Predictor::None, | 857 | 19.7k | chunk_type: ChunkType::Strip, | 858 | 19.7k | planar_config: PlanarConfiguration::Chunky, | 859 | 19.7k | strip_decoder: None, | 860 | 19.7k | tile_attributes: None, | 861 | 19.7k | chunk_offsets: Vec::new(), | 862 | 19.7k | chunk_bytes: Vec::new(), | 863 | 19.7k | chroma_subsampling: (2, 2), | 864 | 19.7k | }, | 865 | 19.7k | }; | 866 | 19.7k | decoder.next_image()?; | 867 | 14.0k | Ok(decoder) | 868 | 19.8k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::new |
869 | | |
870 | 13.7k | pub fn with_limits(mut self, limits: Limits) -> Decoder<R> { |
871 | 13.7k | self.value_reader.limits = limits; |
872 | 13.7k | self |
873 | 13.7k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::with_limits Line | Count | Source | 870 | 13.7k | pub fn with_limits(mut self, limits: Limits) -> Decoder<R> { | 871 | 13.7k | self.value_reader.limits = limits; | 872 | 13.7k | self | 873 | 13.7k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::with_limits |
874 | | |
875 | 14.0k | pub fn dimensions(&mut self) -> TiffResult<(u32, u32)> { |
876 | 14.0k | Ok((self.image().width, self.image().height)) |
877 | 14.0k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::dimensions Line | Count | Source | 875 | 14.0k | pub fn dimensions(&mut self) -> TiffResult<(u32, u32)> { | 876 | 14.0k | Ok((self.image().width, self.image().height)) | 877 | 14.0k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::dimensions |
878 | | |
879 | 14.0k | pub fn colortype(&mut self) -> TiffResult<ColorType> { |
880 | 14.0k | self.image().colortype() |
881 | 14.0k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::colortype Line | Count | Source | 879 | 14.0k | pub fn colortype(&mut self) -> TiffResult<ColorType> { | 880 | 14.0k | self.image().colortype() | 881 | 14.0k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::colortype |
882 | | |
883 | | /// The offset of the directory representing the current image. |
884 | 0 | pub fn ifd_pointer(&mut self) -> Option<IfdPointer> { |
885 | 0 | self.current_ifd |
886 | 0 | } |
887 | | |
888 | 104k | fn image(&self) -> &Image { |
889 | 104k | &self.image |
890 | 104k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::image Line | Count | Source | 888 | 104k | fn image(&self) -> &Image { | 889 | 104k | &self.image | 890 | 104k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::image |
891 | | |
892 | | /// Loads the IFD at the specified index in the list, if one exists |
893 | 0 | pub fn seek_to_image(&mut self, ifd_index: usize) -> TiffResult<()> { |
894 | | // Check whether we have seen this IFD before, if so then the index will be less than the length of the list of ifd offsets |
895 | 0 | if ifd_index >= self.ifd_offsets.len() { |
896 | | // We possibly need to load in the next IFD |
897 | 0 | if self.next_ifd.is_none() { |
898 | 0 | self.current_ifd = None; |
899 | | |
900 | 0 | return Err(TiffError::FormatError( |
901 | 0 | TiffFormatError::ImageFileDirectoryNotFound, |
902 | 0 | )); |
903 | 0 | } |
904 | | |
905 | | loop { |
906 | | // Follow the list until we find the one we want, or we reach the end, whichever happens first |
907 | 0 | let ifd = self.next_ifd()?; |
908 | | |
909 | 0 | if ifd.next().is_none() { |
910 | 0 | break; |
911 | 0 | } |
912 | | |
913 | 0 | if ifd_index < self.ifd_offsets.len() { |
914 | 0 | break; |
915 | 0 | } |
916 | | } |
917 | 0 | } |
918 | | |
919 | | // If the index is within the list of ifds then we can load the selected image/IFD |
920 | 0 | if let Some(ifd_offset) = self.ifd_offsets.get(ifd_index) { |
921 | 0 | let ifd = self.value_reader.read_directory(*ifd_offset)?; |
922 | 0 | self.next_ifd = ifd.next(); |
923 | 0 | self.current_ifd = Some(*ifd_offset); |
924 | 0 | self.image = Image::from_reader(&mut self.value_reader, ifd)?; |
925 | | |
926 | 0 | Ok(()) |
927 | | } else { |
928 | 0 | Err(TiffError::FormatError( |
929 | 0 | TiffFormatError::ImageFileDirectoryNotFound, |
930 | 0 | )) |
931 | | } |
932 | 0 | } |
933 | | |
934 | 19.7k | fn next_ifd(&mut self) -> TiffResult<Directory> { |
935 | 19.7k | let Some(next_ifd) = self.next_ifd.take() else { |
936 | 0 | return Err(TiffError::FormatError( |
937 | 0 | TiffFormatError::ImageFileDirectoryNotFound, |
938 | 0 | )); |
939 | | }; |
940 | | |
941 | 19.7k | let ifd = self.value_reader.read_directory(next_ifd)?; |
942 | | |
943 | | // Ensure this walk does not get us into a cycle. |
944 | 17.7k | self.seen_ifds.insert_next(next_ifd, ifd.next())?; |
945 | | |
946 | | // Extend the list of known IFD offsets in this chain, if needed. |
947 | 17.6k | if self.ifd_offsets.last().copied() == self.current_ifd { |
948 | 0 | self.ifd_offsets.push(next_ifd); |
949 | 17.6k | } |
950 | | |
951 | 17.6k | self.current_ifd = Some(next_ifd); |
952 | 17.6k | self.next_ifd = ifd.next(); |
953 | | |
954 | 17.6k | Ok(ifd) |
955 | 19.7k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_ifd Line | Count | Source | 934 | 19.7k | fn next_ifd(&mut self) -> TiffResult<Directory> { | 935 | 19.7k | let Some(next_ifd) = self.next_ifd.take() else { | 936 | 0 | return Err(TiffError::FormatError( | 937 | 0 | TiffFormatError::ImageFileDirectoryNotFound, | 938 | 0 | )); | 939 | | }; | 940 | | | 941 | 19.7k | let ifd = self.value_reader.read_directory(next_ifd)?; | 942 | | | 943 | | // Ensure this walk does not get us into a cycle. | 944 | 17.7k | self.seen_ifds.insert_next(next_ifd, ifd.next())?; | 945 | | | 946 | | // Extend the list of known IFD offsets in this chain, if needed. | 947 | 17.6k | if self.ifd_offsets.last().copied() == self.current_ifd { | 948 | 0 | self.ifd_offsets.push(next_ifd); | 949 | 17.6k | } | 950 | | | 951 | 17.6k | self.current_ifd = Some(next_ifd); | 952 | 17.6k | self.next_ifd = ifd.next(); | 953 | | | 954 | 17.6k | Ok(ifd) | 955 | 19.7k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::next_ifd |
956 | | |
957 | | /// Reads in the next image. |
958 | | /// If there is no further image in the TIFF file a format error is returned. |
959 | | /// To determine whether there are more images call `TIFFDecoder::more_images` instead. |
960 | 19.7k | pub fn next_image(&mut self) -> TiffResult<()> { |
961 | 19.7k | let ifd = self.next_ifd()?; |
962 | 17.6k | self.image = Image::from_reader(&mut self.value_reader, ifd)?; |
963 | 14.0k | Ok(()) |
964 | 19.7k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::next_image Line | Count | Source | 960 | 19.7k | pub fn next_image(&mut self) -> TiffResult<()> { | 961 | 19.7k | let ifd = self.next_ifd()?; | 962 | 17.6k | self.image = Image::from_reader(&mut self.value_reader, ifd)?; | 963 | 14.0k | Ok(()) | 964 | 19.7k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::next_image |
965 | | |
966 | | /// Returns `true` if there is at least one more image available. |
967 | 0 | pub fn more_images(&self) -> bool { |
968 | 0 | self.next_ifd.is_some() |
969 | 0 | } |
970 | | |
971 | | /// Returns the byte_order of the file. |
972 | | /// |
973 | | /// # Usage |
974 | | /// |
975 | | /// This is only relevant to interpreting raw bytes read from tags. The image decoding methods |
976 | | /// will correct to the host byte order automatically. |
977 | 0 | pub fn byte_order(&self) -> ByteOrder { |
978 | 0 | self.value_reader.reader.byte_order |
979 | 0 | } |
980 | | |
981 | | #[inline] |
982 | 0 | pub fn read_ifd_offset(&mut self) -> Result<u64, io::Error> { |
983 | 0 | if self.value_reader.bigtiff { |
984 | 0 | self.read_long8() |
985 | | } else { |
986 | 0 | self.read_long().map(u64::from) |
987 | | } |
988 | 0 | } |
989 | | |
990 | | /// Returns a mutable reference to the stream being decoded. |
991 | 0 | pub fn inner(&mut self) -> &mut R { |
992 | 0 | self.value_reader.reader.inner() |
993 | 0 | } |
994 | | |
995 | | /// Reads a TIFF byte value |
996 | | #[inline] |
997 | 0 | pub fn read_byte(&mut self) -> Result<u8, io::Error> { |
998 | 0 | let mut buf = [0; 1]; |
999 | 0 | self.value_reader.reader.inner().read_exact(&mut buf)?; |
1000 | 0 | Ok(buf[0]) |
1001 | 0 | } |
1002 | | |
1003 | | /// Reads a TIFF short value |
1004 | | #[inline] |
1005 | 0 | pub fn read_short(&mut self) -> Result<u16, io::Error> { |
1006 | 0 | self.value_reader.reader.read_u16() |
1007 | 0 | } |
1008 | | |
1009 | | /// Reads a TIFF sshort value |
1010 | | #[inline] |
1011 | 0 | pub fn read_sshort(&mut self) -> Result<i16, io::Error> { |
1012 | 0 | self.value_reader.reader.read_i16() |
1013 | 0 | } |
1014 | | |
1015 | | /// Reads a TIFF long value |
1016 | | #[inline] |
1017 | 0 | pub fn read_long(&mut self) -> Result<u32, io::Error> { |
1018 | 0 | self.value_reader.reader.read_u32() |
1019 | 0 | } |
1020 | | |
1021 | | /// Reads a TIFF slong value |
1022 | | #[inline] |
1023 | 0 | pub fn read_slong(&mut self) -> Result<i32, io::Error> { |
1024 | 0 | self.value_reader.reader.read_i32() |
1025 | 0 | } |
1026 | | |
1027 | | /// Reads a TIFF float value |
1028 | | #[inline] |
1029 | 0 | pub fn read_float(&mut self) -> Result<f32, io::Error> { |
1030 | 0 | self.value_reader.reader.read_f32() |
1031 | 0 | } |
1032 | | |
1033 | | /// Reads a TIFF double value |
1034 | | #[inline] |
1035 | 0 | pub fn read_double(&mut self) -> Result<f64, io::Error> { |
1036 | 0 | self.value_reader.reader.read_f64() |
1037 | 0 | } |
1038 | | |
1039 | | #[inline] |
1040 | 0 | pub fn read_long8(&mut self) -> Result<u64, io::Error> { |
1041 | 0 | self.value_reader.reader.read_u64() |
1042 | 0 | } |
1043 | | |
1044 | | #[inline] |
1045 | 0 | pub fn read_slong8(&mut self) -> Result<i64, io::Error> { |
1046 | 0 | self.value_reader.reader.read_i64() |
1047 | 0 | } |
1048 | | |
1049 | | /// Reads a string |
1050 | | #[inline] |
1051 | 0 | pub fn read_string(&mut self, length: usize) -> TiffResult<String> { |
1052 | 0 | let mut out = vec![0; length]; |
1053 | 0 | self.value_reader.reader.inner().read_exact(&mut out)?; |
1054 | | // Strings may be null-terminated, so we trim anything downstream of the null byte |
1055 | 0 | if let Some(first) = out.iter().position(|&b| b == 0) { |
1056 | 0 | out.truncate(first); |
1057 | 0 | } |
1058 | 0 | Ok(String::from_utf8(out)?) |
1059 | 0 | } |
1060 | | |
1061 | | /// Reads a TIFF IFA offset/value field |
1062 | | #[inline] |
1063 | 0 | pub fn read_offset(&mut self) -> TiffResult<[u8; 4]> { |
1064 | 0 | if self.value_reader.bigtiff { |
1065 | 0 | return Err(TiffError::FormatError( |
1066 | 0 | TiffFormatError::InconsistentSizesEncountered, |
1067 | 0 | )); |
1068 | 0 | } |
1069 | 0 | let mut val = [0; 4]; |
1070 | 0 | self.value_reader.reader.inner().read_exact(&mut val)?; |
1071 | 0 | Ok(val) |
1072 | 0 | } |
1073 | | |
1074 | | /// Reads a TIFF IFA offset/value field |
1075 | | #[inline] |
1076 | 0 | pub fn read_offset_u64(&mut self) -> Result<[u8; 8], io::Error> { |
1077 | 0 | let mut val = [0; 8]; |
1078 | 0 | self.value_reader.reader.inner().read_exact(&mut val)?; |
1079 | 0 | Ok(val) |
1080 | 0 | } |
1081 | | |
1082 | | /// Moves the cursor to the specified offset |
1083 | | #[inline] |
1084 | 0 | pub fn goto_offset(&mut self, offset: u32) -> io::Result<()> { |
1085 | 0 | self.goto_offset_u64(offset.into()) |
1086 | 0 | } |
1087 | | |
1088 | | #[inline] |
1089 | 35.1k | pub fn goto_offset_u64(&mut self, offset: u64) -> io::Result<()> { |
1090 | 35.1k | self.value_reader.reader.goto_offset(offset) |
1091 | 35.1k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::goto_offset_u64 Line | Count | Source | 1089 | 35.1k | pub fn goto_offset_u64(&mut self, offset: u64) -> io::Result<()> { | 1090 | 35.1k | self.value_reader.reader.goto_offset(offset) | 1091 | 35.1k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::goto_offset_u64 |
1092 | | |
1093 | | /// Read a tag-entry map from a known offset. |
1094 | | /// |
1095 | | /// A TIFF [`Directory`], aka. image file directory aka. IFD, refers to a map from |
1096 | | /// tags–identified by a `u16`–to a typed vector of elements. It is encoded as a list |
1097 | | /// of ascending tag values with the offset and type of their corresponding values. The |
1098 | | /// semantic interpretations of a tag and its type requirements depend on the context of the |
1099 | | /// directory. The main image directories, those iterated over by the `Decoder` after |
1100 | | /// construction, are represented by [`Tag`] and [`ifd::Value`]. Other forms are EXIF and GPS |
1101 | | /// data as well as thumbnail Sub-IFD representations associated with each image file. |
1102 | | /// |
1103 | | /// This method allows the decoding of a directory from an arbitrary offset in the image file |
1104 | | /// with no specific semantic interpretation. Such an offset is usually found as the value of |
1105 | | /// a tag, e.g. [`Tag::SubIfd`], [`Tag::ExifDirectory`], [`Tag::GpsDirectory`] and recovered |
1106 | | /// from the associated value by [`ifd::Value::into_ifd_pointer`]. |
1107 | | /// |
1108 | | /// The library will not verify whether the offset overlaps any other directory or would form a |
1109 | | /// cycle with any other directory when calling this method. This will modify the position of |
1110 | | /// the reader, i.e. continuing with direct reads at a later point will require going back with |
1111 | | /// [`Self::goto_offset`]. |
1112 | 0 | pub fn read_directory(&mut self, ptr: IfdPointer) -> TiffResult<Directory> { |
1113 | 0 | self.value_reader.read_directory(ptr) |
1114 | 0 | } |
1115 | | |
1116 | 0 | fn check_chunk_type(&self, expected: ChunkType) -> TiffResult<()> { |
1117 | 0 | if expected != self.image().chunk_type { |
1118 | 0 | return Err(TiffError::UsageError(UsageError::InvalidChunkType( |
1119 | 0 | expected, |
1120 | 0 | self.image().chunk_type, |
1121 | 0 | ))); |
1122 | 0 | } |
1123 | | |
1124 | 0 | Ok(()) |
1125 | 0 | } |
1126 | | |
1127 | | /// The chunk type (Strips / Tiles) of the image |
1128 | 0 | pub fn get_chunk_type(&self) -> ChunkType { |
1129 | 0 | self.image().chunk_type |
1130 | 0 | } |
1131 | | |
1132 | | /// Number of strips in image |
1133 | 0 | pub fn strip_count(&mut self) -> TiffResult<u32> { |
1134 | 0 | self.check_chunk_type(ChunkType::Strip)?; |
1135 | 0 | let rows_per_strip = self.image().strip_decoder.as_ref().unwrap().rows_per_strip; |
1136 | | |
1137 | 0 | if rows_per_strip == 0 { |
1138 | 0 | return Ok(0); |
1139 | 0 | } |
1140 | | |
1141 | | // rows_per_strip - 1 can never fail since we know it's at least 1 |
1142 | 0 | let height = match self.image().height.checked_add(rows_per_strip - 1) { |
1143 | 0 | Some(h) => h, |
1144 | 0 | None => return Err(TiffError::IntSizeError), |
1145 | | }; |
1146 | | |
1147 | 0 | let strips = match self.image().planar_config { |
1148 | 0 | PlanarConfiguration::Chunky => height / rows_per_strip, |
1149 | 0 | PlanarConfiguration::Planar => height / rows_per_strip * self.image().samples as u32, |
1150 | | }; |
1151 | | |
1152 | 0 | Ok(strips) |
1153 | 0 | } |
1154 | | |
1155 | | /// Number of tiles in image |
1156 | 0 | pub fn tile_count(&mut self) -> TiffResult<u32> { |
1157 | 0 | self.check_chunk_type(ChunkType::Tile)?; |
1158 | 0 | Ok(u32::try_from(self.image().chunk_offsets.len())?) |
1159 | 0 | } |
1160 | | |
1161 | 0 | fn read_chunk_to_bytes( |
1162 | 0 | &mut self, |
1163 | 0 | buffer: &mut [u8], |
1164 | 0 | chunk_index: u32, |
1165 | 0 | layout: &image::ReadoutLayout, |
1166 | 0 | ) -> TiffResult<()> { |
1167 | 0 | let offset = self.image.chunk_file_range(chunk_index)?.0; |
1168 | 0 | self.goto_offset_u64(offset)?; |
1169 | | |
1170 | 0 | self.image |
1171 | 0 | .expand_chunk(&mut self.value_reader, buffer, layout, chunk_index)?; |
1172 | | |
1173 | 0 | Ok(()) |
1174 | 0 | } |
1175 | | |
1176 | | /// Returns the layout preferred to read the specified chunk with [`Self::read_chunk_bytes`]. |
1177 | | /// |
1178 | | /// Returns the layout without being specific as to the underlying type for forward |
1179 | | /// compatibility. Note that, in general, a TIFF may contain an almost arbitrary number of |
1180 | | /// channels of individual *bit* length and format each. |
1181 | | /// |
1182 | | /// See [`Self::colortype`] to describe the sample types. |
1183 | 0 | pub fn image_chunk_buffer_layout( |
1184 | 0 | &mut self, |
1185 | 0 | chunk_index: u32, |
1186 | 0 | ) -> TiffResult<BufferLayoutPreference> { |
1187 | 0 | let data_dims = self.image().chunk_data_dimensions(chunk_index)?; |
1188 | 0 | let readout = self.image().readout_for_size(data_dims.0, data_dims.1)?; |
1189 | | |
1190 | 0 | let extent = readout.result_extent_for_planes(0..1)?; |
1191 | 0 | let sample_type = extent.sample_type(); |
1192 | 0 | let layout = extent.preferred_layout()?; |
1193 | | |
1194 | 0 | let row_stride = core::num::NonZeroUsize::new(readout.minimum_row_stride); |
1195 | 0 | let plane_stride = core::num::NonZeroUsize::new(readout.plane_stride); |
1196 | | |
1197 | 0 | Ok(BufferLayoutPreference { |
1198 | 0 | len: layout.size(), |
1199 | 0 | row_stride, |
1200 | 0 | planes: 1, |
1201 | 0 | plane_stride, |
1202 | 0 | complete_len: layout.size(), |
1203 | 0 | sample_format: self.image().sample_format, |
1204 | 0 | sample_type: Some(sample_type), |
1205 | 0 | }) |
1206 | 0 | } |
1207 | | |
1208 | | /// Return the layout preferred to read several planes corresponding to the specified region. |
1209 | | /// |
1210 | | /// This is similar to [`Self::image_chunk_buffer_layout`] but can read chunks from all planes |
1211 | | /// at the corresponding coordinates of the image. |
1212 | | /// |
1213 | | /// # Bugs |
1214 | | /// |
1215 | | /// Sub-sampled images are not yet supported properly. |
1216 | 0 | pub fn image_coding_unit_layout( |
1217 | 0 | &mut self, |
1218 | 0 | code_unit: TiffCodingUnit, |
1219 | 0 | ) -> TiffResult<BufferLayoutPreference> { |
1220 | 0 | match self.image().planar_config { |
1221 | 0 | PlanarConfiguration::Chunky => return self.image_chunk_buffer_layout(code_unit.0), |
1222 | 0 | PlanarConfiguration::Planar => {} |
1223 | | } |
1224 | | |
1225 | 0 | let (width, height) = self.image().chunk_data_dimensions(code_unit.0)?; |
1226 | | |
1227 | 0 | let layout = self |
1228 | 0 | .image() |
1229 | 0 | .readout_for_size(width, height)? |
1230 | 0 | .to_plane_layout()?; |
1231 | | |
1232 | 0 | if code_unit.0 >= layout.readout.chunks_per_plane { |
1233 | 0 | return Err(TiffError::UsageError(UsageError::InvalidCodingUnit( |
1234 | 0 | code_unit.0, |
1235 | 0 | layout.readout.chunks_per_plane, |
1236 | 0 | ))); |
1237 | 0 | } |
1238 | | |
1239 | 0 | Ok(BufferLayoutPreference::from_planes(&layout)) |
1240 | 0 | } |
1241 | | |
1242 | | /// Read the specified chunk (at index `chunk_index`) and return the binary data as a Vector. |
1243 | | /// |
1244 | | /// Note that for planar images each chunk contains only one sample of the underlying data. |
1245 | 0 | pub fn read_chunk(&mut self, chunk_index: u32) -> TiffResult<DecodingResult> { |
1246 | 0 | let (width, height) = self.image().chunk_data_dimensions(chunk_index)?; |
1247 | | |
1248 | 0 | let readout = self.image().readout_for_size(width, height)?; |
1249 | | |
1250 | 0 | let mut result = readout |
1251 | 0 | .result_extent_for_planes(0..1)? |
1252 | 0 | .to_result_buffer(&self.value_reader.limits)?; |
1253 | | |
1254 | 0 | self.read_chunk_to_bytes(result.as_buffer(0).as_bytes_mut(), chunk_index, &readout)?; |
1255 | | |
1256 | 0 | Ok(result) |
1257 | 0 | } |
1258 | | |
1259 | | /// Read the specified chunk (at index `chunk_index`) into an allocated buffer. |
1260 | | /// |
1261 | | /// Returns a [`TiffError::UsageError`] if the chunk is smaller than the size indicated with a |
1262 | | /// call to [`Self::image_chunk_buffer_layout`]. Note that the alignment may be arbitrary, but |
1263 | | /// an alignment smaller than the preferred alignment may perform worse. |
1264 | | /// |
1265 | | /// Note that for planar images each chunk contains only one sample of the underlying data. |
1266 | 0 | pub fn read_chunk_bytes(&mut self, chunk_index: u32, buffer: &mut [u8]) -> TiffResult<()> { |
1267 | 0 | let (width, height) = self.image().chunk_data_dimensions(chunk_index)?; |
1268 | | |
1269 | 0 | let layout = self.image().readout_for_size(width, height)?; |
1270 | 0 | layout.assert_min_layout(buffer)?; |
1271 | | |
1272 | 0 | self.read_chunk_to_bytes(buffer, chunk_index, &layout)?; |
1273 | | |
1274 | 0 | Ok(()) |
1275 | 0 | } |
1276 | | |
1277 | | /// Read the specified chunk (at index `chunk_index`) into a provide buffer. |
1278 | | /// |
1279 | | /// It will re-allocate the buffer into the correct type and size, within the decoder's |
1280 | | /// configured limits, and then pass it to the underlying method. This is essentially a |
1281 | | /// type-safe wrapper around the raw [`Self::read_chunk_bytes`] method. |
1282 | | /// |
1283 | | /// Note that for planar images each chunk contains only one sample of the underlying data. |
1284 | 0 | pub fn read_chunk_to_buffer( |
1285 | 0 | &mut self, |
1286 | 0 | buffer: &mut DecodingResult, |
1287 | 0 | chunk_index: u32, |
1288 | 0 | output_width: usize, |
1289 | 0 | ) -> TiffResult<()> { |
1290 | 0 | let (width, height) = self.image().chunk_data_dimensions(chunk_index)?; |
1291 | | |
1292 | 0 | let mut layout = self.image().readout_for_size(width, height)?; |
1293 | 0 | layout.set_row_stride(output_width)?; |
1294 | | |
1295 | 0 | let extent = layout.result_extent_for_planes(0..1)?; |
1296 | 0 | buffer.resize_to_extent(extent, &self.value_reader.limits)?; |
1297 | | |
1298 | 0 | self.read_chunk_to_bytes(buffer.as_buffer(0).as_bytes_mut(), chunk_index, &layout)?; |
1299 | | |
1300 | 0 | Ok(()) |
1301 | 0 | } |
1302 | | |
1303 | | /// Read chunks corresponding to several planes of a region of pixels. |
1304 | | /// |
1305 | | /// For non planar images this is equivalent to [`Self::read_chunk_bytes`] as there is only one |
1306 | | /// plane in the image. For planar images the planes are stored consecutively into the output |
1307 | | /// buffer. Returns an error if not enough space for at least one plane is provided. Otherwise |
1308 | | /// reads all planes that can be stored completely in the provided output buffer. |
1309 | | /// |
1310 | | /// A region is a rectangular assortment of pixels in the image, depending on the chunk type |
1311 | | /// either strips or tiles. Borrowing terminology from JPEG we call the collection of all |
1312 | | /// chunks from all planes that encode samples from the same region a "coding unit". |
1313 | | /// |
1314 | | /// # Bugs |
1315 | | /// |
1316 | | /// Sub-sampled images are not yet supported properly. |
1317 | 0 | pub fn read_coding_unit_bytes( |
1318 | 0 | &mut self, |
1319 | 0 | slice: TiffCodingUnit, |
1320 | 0 | buffer: &mut [u8], |
1321 | 0 | ) -> TiffResult<()> { |
1322 | 0 | let (width, height) = self.image().chunk_data_dimensions(slice.0)?; |
1323 | 0 | let readout = self.image().readout_for_size(width, height)?; |
1324 | | |
1325 | 0 | let ref layout @ image::PlaneLayout { |
1326 | 0 | ref plane_offsets, |
1327 | | // We assume that is correct, so really it can be ignored. |
1328 | | total_bytes: _, |
1329 | 0 | ref readout, |
1330 | 0 | } = readout.to_plane_layout()?; |
1331 | | |
1332 | 0 | if slice.0 >= readout.chunks_per_plane { |
1333 | 0 | return Err(TiffError::UsageError(UsageError::InvalidCodingUnit( |
1334 | 0 | slice.0, |
1335 | 0 | readout.chunks_per_plane, |
1336 | 0 | ))); |
1337 | 0 | } |
1338 | | |
1339 | | // No subsamples planes support, for now. |
1340 | 0 | let used_plane_offsets = usize::from(layout.used_planes(buffer)?); |
1341 | 0 | debug_assert!(used_plane_offsets >= 1, "Should have errored"); |
1342 | | |
1343 | 0 | for (idx, &plane_offset) in plane_offsets[..used_plane_offsets].iter().enumerate() { |
1344 | 0 | let chunk = slice.0 + idx as u32 * readout.chunks_per_plane; |
1345 | 0 | self.goto_offset_u64(self.image().chunk_offsets[chunk as usize])?; |
1346 | | |
1347 | 0 | self.image.expand_chunk( |
1348 | 0 | &mut self.value_reader, |
1349 | 0 | &mut buffer[plane_offset..], |
1350 | 0 | readout, |
1351 | 0 | chunk, |
1352 | 0 | )?; |
1353 | | } |
1354 | | |
1355 | 0 | Ok(()) |
1356 | 0 | } |
1357 | | |
1358 | | /// Returns the default chunk size for the current image. Any given chunk in the image is at most as large as |
1359 | | /// the value returned here. For the size of the data (chunk minus padding), use `chunk_data_dimensions`. |
1360 | 0 | pub fn chunk_dimensions(&self) -> (u32, u32) { |
1361 | 0 | self.image().chunk_dimensions().unwrap() |
1362 | 0 | } |
1363 | | |
1364 | | /// Returns the size of the data in the chunk with the specified index. This is the default size of the chunk, |
1365 | | /// minus any padding. |
1366 | 0 | pub fn chunk_data_dimensions(&self, chunk_index: u32) -> (u32, u32) { |
1367 | 0 | self.image() |
1368 | 0 | .chunk_data_dimensions(chunk_index) |
1369 | 0 | .expect("invalid chunk_index") |
1370 | 0 | } |
1371 | | |
1372 | | /// Returns the preferred buffer required to read the whole image with [`Self::read_image_bytes`]. |
1373 | | /// |
1374 | | /// Returns the layout without being specific as to the underlying type for forward |
1375 | | /// compatibility. Note that, in general, a TIFF may contain an almost arbitrary number of |
1376 | | /// channels of individual *bit* length and format each. |
1377 | | /// |
1378 | | /// See [`Self::colortype`] to describe the sample types. |
1379 | | /// |
1380 | | /// # Bugs |
1381 | | /// |
1382 | | /// When the image is stored as a planar configuration, this method will currently only |
1383 | | /// indicate the layout needed to read the first data plane. This will be fixed in a future |
1384 | | /// major version of `tiff`. |
1385 | 0 | pub fn image_buffer_layout(&mut self) -> TiffResult<BufferLayoutPreference> { |
1386 | 0 | let layout = self.image().readout_for_image()?.to_plane_layout()?; |
1387 | 0 | Ok(BufferLayoutPreference::from_planes(&layout)) |
1388 | 0 | } |
1389 | | |
1390 | | /// Decodes the entire image and return it as a Vector |
1391 | | /// |
1392 | | /// # Examples |
1393 | | /// |
1394 | | /// This method is deprecated. For replacement usage see `examples/decode.rs`. |
1395 | | /// |
1396 | | /// # Bugs |
1397 | | /// |
1398 | | /// When the image is stored as a planar configuration, this method will currently only read |
1399 | | /// the first sample's plane. This will be fixed in a future major version of `tiff`. To read |
1400 | | /// multiple planes, [`Self::read_image_to_buffer`] can be used instead. |
1401 | | /// |
1402 | | /// # Intent to deprecate |
1403 | | /// |
1404 | | /// Use [`Self::read_image_to_buffer`] or a combination of [`DecodingResult::resize_to`] and |
1405 | | /// [`Self::read_image_bytes`] instead where possible, preserving the buffer across multiple |
1406 | | /// calls. This old method will likely keep its bugged planar behavior until it is fully |
1407 | | /// replaced, to ensure that existing code will not run into unexpectedly large allocations |
1408 | | /// that will error on limits instead. |
1409 | 0 | pub fn read_image(&mut self) -> TiffResult<DecodingResult> { |
1410 | 0 | let readout = self.image().readout_for_image()?; |
1411 | | |
1412 | 0 | let mut result = readout |
1413 | 0 | .result_extent_for_planes(0..1)? |
1414 | 0 | .to_result_buffer(&self.value_reader.limits)?; |
1415 | | |
1416 | 0 | self.read_image_bytes(result.as_buffer(0).as_bytes_mut())?; |
1417 | | |
1418 | 0 | Ok(result) |
1419 | 0 | } |
1420 | | |
1421 | | /// Decodes the entire image into a provided buffer. |
1422 | | /// |
1423 | | /// It will re-allocate the buffer into the correct type and size, within the decoder's |
1424 | | /// configured limits, and then pass it to the underlying method. This is essentially a |
1425 | | /// type-safe wrapper around the raw [`Self::read_image_bytes`] method. |
1426 | | /// |
1427 | | /// ## Planar behavior |
1428 | | /// |
1429 | | /// If the image is stored as a planar configuration, an attempt is made to resize the buffer |
1430 | | /// to hold all planes. If that does not fit then only the first plane is read. Check the |
1431 | | /// buffer size against [`BufferLayoutPreference::complete_len`] to ensure that all planes were |
1432 | | /// read: |
1433 | | /// |
1434 | | /// ``` |
1435 | | /// use tiff::decoder::{Decoder, DecodingResult}; |
1436 | | /// let mut result = DecodingResult::U8(vec![]); |
1437 | | /// |
1438 | | /// let mut reader = /* */ |
1439 | | /// # Decoder::new(std::io::Cursor::new(include_bytes!(concat!( |
1440 | | /// # env!("CARGO_MANIFEST_DIR"), "/tests/images/tiled-gray-i1.tif" |
1441 | | /// # )))).unwrap(); |
1442 | | /// let layout = reader.read_image_to_buffer(&mut result)?; |
1443 | | /// |
1444 | | /// if result.as_buffer(0).as_bytes().len() < layout.complete_len { |
1445 | | /// println!("Only the first plane was read"); |
1446 | | /// } |
1447 | | /// |
1448 | | /// # Ok::<_, tiff::TiffError>(()) |
1449 | | /// ``` |
1450 | | /// |
1451 | | /// # Examples |
1452 | | /// |
1453 | | /// ``` |
1454 | | /// use tiff::decoder::{Decoder, DecodingResult, Limits}; |
1455 | | /// |
1456 | | /// let mut result = DecodingResult::I8(vec![]); |
1457 | | /// |
1458 | | /// let mut reader = /* */ |
1459 | | /// # Decoder::new(std::io::Cursor::new(include_bytes!(concat!( |
1460 | | /// # env!("CARGO_MANIFEST_DIR"), "/tests/images/tiled-gray-i1.tif" |
1461 | | /// # )))).unwrap(); |
1462 | | /// |
1463 | | /// reader.read_image_to_buffer(&mut result)?; |
1464 | | /// |
1465 | | /// # Ok::<_, tiff::TiffError>(()) |
1466 | | /// ``` |
1467 | 13.7k | pub fn read_image_to_buffer( |
1468 | 13.7k | &mut self, |
1469 | 13.7k | result: &mut DecodingResult, |
1470 | 13.7k | ) -> TiffResult<BufferLayoutPreference> { |
1471 | 13.7k | let readout = self.image().readout_for_image()?; |
1472 | 13.7k | let planes = readout.to_plane_layout()?; |
1473 | | |
1474 | 13.7k | let num_planes = if planes.total_bytes <= self.value_reader.limits.decoding_buffer_size { |
1475 | 13.7k | planes.plane_offsets.len() as u16 |
1476 | | } else { |
1477 | 37 | 1 |
1478 | | }; |
1479 | | |
1480 | 13.7k | let layout = BufferLayoutPreference::from_planes(&planes); |
1481 | 13.7k | let extent = readout.result_extent_for_planes(0..num_planes)?; |
1482 | | // Compatibility: if this extent is too large our configured limits we will fall back to |
1483 | | // reading only the first plane. |
1484 | 13.7k | result.resize_to_extent(extent, &self.value_reader.limits)?; |
1485 | | |
1486 | 13.7k | self.read_image_bytes(result.as_buffer(0).as_bytes_mut())?; |
1487 | | |
1488 | 3.77k | Ok(layout) |
1489 | 13.7k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_image_to_buffer Line | Count | Source | 1467 | 13.7k | pub fn read_image_to_buffer( | 1468 | 13.7k | &mut self, | 1469 | 13.7k | result: &mut DecodingResult, | 1470 | 13.7k | ) -> TiffResult<BufferLayoutPreference> { | 1471 | 13.7k | let readout = self.image().readout_for_image()?; | 1472 | 13.7k | let planes = readout.to_plane_layout()?; | 1473 | | | 1474 | 13.7k | let num_planes = if planes.total_bytes <= self.value_reader.limits.decoding_buffer_size { | 1475 | 13.7k | planes.plane_offsets.len() as u16 | 1476 | | } else { | 1477 | 37 | 1 | 1478 | | }; | 1479 | | | 1480 | 13.7k | let layout = BufferLayoutPreference::from_planes(&planes); | 1481 | 13.7k | let extent = readout.result_extent_for_planes(0..num_planes)?; | 1482 | | // Compatibility: if this extent is too large our configured limits we will fall back to | 1483 | | // reading only the first plane. | 1484 | 13.7k | result.resize_to_extent(extent, &self.value_reader.limits)?; | 1485 | | | 1486 | 13.7k | self.read_image_bytes(result.as_buffer(0).as_bytes_mut())?; | 1487 | | | 1488 | 3.77k | Ok(layout) | 1489 | 13.7k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::read_image_to_buffer |
1490 | | |
1491 | | /// Decodes the entire image into a provided buffer. |
1492 | | /// |
1493 | | /// Returns a [`TiffError::UsageError`] if the chunk is smaller than the size indicated with a |
1494 | | /// call to [`Self::image_buffer_layout`]. Note that the alignment may be arbitrary, but an |
1495 | | /// alignment smaller than the preferred alignment may perform worse. |
1496 | | /// |
1497 | | /// # Error |
1498 | | /// |
1499 | | /// Returns an error if the buffer fits less than one plane. In particular, for non-planar |
1500 | | /// images returns an error if the buffer does not fit the required size. |
1501 | 13.7k | pub fn read_image_bytes(&mut self, buffer: &mut [u8]) -> TiffResult<()> { |
1502 | 13.7k | let readout = self.image().readout_for_image()?; |
1503 | | |
1504 | 13.7k | let ref layout @ image::PlaneLayout { |
1505 | 13.7k | ref plane_offsets, |
1506 | | // We assume that is correct, so really it can be ignored. |
1507 | | total_bytes: _, |
1508 | 13.7k | ref readout, |
1509 | 13.7k | } = readout.to_plane_layout()?; |
1510 | | |
1511 | 13.7k | let used_plane_offsets = usize::from(layout.used_planes(buffer)?); |
1512 | 13.7k | debug_assert!(used_plane_offsets >= 1, "Should have errored"); |
1513 | | |
1514 | | // For multi-band images, only the first band is read. |
1515 | | // Possible improvements: |
1516 | | // * pass requested band as parameter |
1517 | | // * collect bands to a RGB encoding result in case of RGB bands |
1518 | 34.7k | for chunk in 0..readout.chunks_per_plane { |
1519 | 34.7k | let x = (chunk % readout.chunks_across) as usize; |
1520 | 34.7k | let y = (chunk / readout.chunks_across) as usize; |
1521 | | |
1522 | 34.7k | let buffer_offset = y * readout.chunk_col_stride + x * readout.chunk_row_stride; |
1523 | | |
1524 | 35.1k | for (idx, &plane_offset) in plane_offsets[..used_plane_offsets].iter().enumerate() { |
1525 | 35.1k | let chunk = chunk + idx as u32 * readout.chunks_per_plane; |
1526 | 35.1k | self.goto_offset_u64(self.image().chunk_offsets[chunk as usize])?; |
1527 | | |
1528 | 35.1k | self.image.expand_chunk( |
1529 | 35.1k | &mut self.value_reader, |
1530 | 35.1k | &mut buffer[plane_offset..][buffer_offset..], |
1531 | 35.1k | readout, |
1532 | 35.1k | chunk, |
1533 | 9.96k | )?; |
1534 | | } |
1535 | | } |
1536 | | |
1537 | 3.77k | Ok(()) |
1538 | 13.7k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::read_image_bytes Line | Count | Source | 1501 | 13.7k | pub fn read_image_bytes(&mut self, buffer: &mut [u8]) -> TiffResult<()> { | 1502 | 13.7k | let readout = self.image().readout_for_image()?; | 1503 | | | 1504 | 13.7k | let ref layout @ image::PlaneLayout { | 1505 | 13.7k | ref plane_offsets, | 1506 | | // We assume that is correct, so really it can be ignored. | 1507 | | total_bytes: _, | 1508 | 13.7k | ref readout, | 1509 | 13.7k | } = readout.to_plane_layout()?; | 1510 | | | 1511 | 13.7k | let used_plane_offsets = usize::from(layout.used_planes(buffer)?); | 1512 | 13.7k | debug_assert!(used_plane_offsets >= 1, "Should have errored"); | 1513 | | | 1514 | | // For multi-band images, only the first band is read. | 1515 | | // Possible improvements: | 1516 | | // * pass requested band as parameter | 1517 | | // * collect bands to a RGB encoding result in case of RGB bands | 1518 | 34.7k | for chunk in 0..readout.chunks_per_plane { | 1519 | 34.7k | let x = (chunk % readout.chunks_across) as usize; | 1520 | 34.7k | let y = (chunk / readout.chunks_across) as usize; | 1521 | | | 1522 | 34.7k | let buffer_offset = y * readout.chunk_col_stride + x * readout.chunk_row_stride; | 1523 | | | 1524 | 35.1k | for (idx, &plane_offset) in plane_offsets[..used_plane_offsets].iter().enumerate() { | 1525 | 35.1k | let chunk = chunk + idx as u32 * readout.chunks_per_plane; | 1526 | 35.1k | self.goto_offset_u64(self.image().chunk_offsets[chunk as usize])?; | 1527 | | | 1528 | 35.1k | self.image.expand_chunk( | 1529 | 35.1k | &mut self.value_reader, | 1530 | 35.1k | &mut buffer[plane_offset..][buffer_offset..], | 1531 | 35.1k | readout, | 1532 | 35.1k | chunk, | 1533 | 9.96k | )?; | 1534 | | } | 1535 | | } | 1536 | | | 1537 | 3.77k | Ok(()) | 1538 | 13.7k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::read_image_bytes |
1539 | | |
1540 | | /// Get the IFD decoder for our current image IFD. |
1541 | 13.9k | pub fn image_ifd(&mut self) -> IfdDecoder<'_> { |
1542 | 13.9k | IfdDecoder { |
1543 | 13.9k | inner: tag_reader::TagReader { |
1544 | 13.9k | decoder: &mut self.value_reader, |
1545 | 13.9k | ifd: self.image.ifd.as_ref().unwrap(), |
1546 | 13.9k | }, |
1547 | 13.9k | } |
1548 | 13.9k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::image_ifd Line | Count | Source | 1541 | 13.9k | pub fn image_ifd(&mut self) -> IfdDecoder<'_> { | 1542 | 13.9k | IfdDecoder { | 1543 | 13.9k | inner: tag_reader::TagReader { | 1544 | 13.9k | decoder: &mut self.value_reader, | 1545 | 13.9k | ifd: self.image.ifd.as_ref().unwrap(), | 1546 | 13.9k | }, | 1547 | 13.9k | } | 1548 | 13.9k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::image_ifd |
1549 | | |
1550 | | /// Prepare reading values for tags of a given directory. |
1551 | | /// |
1552 | | /// # Examples |
1553 | | /// |
1554 | | /// This method may be used to read the values of tags in directories that have been previously |
1555 | | /// read with [`Decoder::read_directory`]. |
1556 | | /// |
1557 | | /// ```no_run |
1558 | | /// use tiff::decoder::Decoder; |
1559 | | /// use tiff::tags::Tag; |
1560 | | /// |
1561 | | /// # use std::io::Cursor; |
1562 | | /// # let mut data = Cursor::new(vec![0]); |
1563 | | /// let mut decoder = Decoder::new(&mut data).unwrap(); |
1564 | | /// let sub_ifds = decoder.get_tag(Tag::SubIfd)?.into_ifd_vec()?; |
1565 | | /// |
1566 | | /// for ifd in sub_ifds { |
1567 | | /// let subdir = decoder.read_directory(ifd)?; |
1568 | | /// let subfile = decoder.read_directory_tags(&subdir).find_tag(Tag::SubfileType)?; |
1569 | | /// // omitted: handle the subfiles, e.g. thumbnails |
1570 | | /// } |
1571 | | /// |
1572 | | /// # Ok::<_, tiff::TiffError>(()) |
1573 | | /// ``` |
1574 | 0 | pub fn read_directory_tags<'ifd>(&'ifd mut self, ifd: &'ifd Directory) -> IfdDecoder<'ifd> { |
1575 | 0 | IfdDecoder { |
1576 | 0 | inner: tag_reader::TagReader { |
1577 | 0 | decoder: &mut self.value_reader, |
1578 | 0 | ifd, |
1579 | 0 | }, |
1580 | 0 | } |
1581 | 0 | } |
1582 | | |
1583 | | /// Tries to retrieve a tag from the current image directory. |
1584 | | /// Return `Ok(None)` if the tag is not present. |
1585 | 0 | pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> { |
1586 | 0 | self.image_ifd().find_tag(tag) |
1587 | 0 | } Unexecuted instantiation: <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::find_tag Unexecuted instantiation: <tiff::decoder::Decoder<_>>::find_tag |
1588 | | |
1589 | | /// Tries to retrieve a tag in the current image directory and convert it to the desired |
1590 | | /// unsigned type. |
1591 | 0 | pub fn find_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<T>> { |
1592 | 0 | self.image_ifd().find_tag_unsigned(tag) |
1593 | 0 | } |
1594 | | |
1595 | | /// Tries to retrieve a vector of all a tag's values and convert them to the desired unsigned |
1596 | | /// type. |
1597 | 13.9k | pub fn find_tag_unsigned_vec<T: TryFrom<u64>>( |
1598 | 13.9k | &mut self, |
1599 | 13.9k | tag: Tag, |
1600 | 13.9k | ) -> TiffResult<Option<Vec<T>>> { |
1601 | 13.9k | self.image_ifd().find_tag_unsigned_vec(tag) |
1602 | 13.9k | } <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::find_tag_unsigned_vec::<u16> Line | Count | Source | 1597 | 13.9k | pub fn find_tag_unsigned_vec<T: TryFrom<u64>>( | 1598 | 13.9k | &mut self, | 1599 | 13.9k | tag: Tag, | 1600 | 13.9k | ) -> TiffResult<Option<Vec<T>>> { | 1601 | 13.9k | self.image_ifd().find_tag_unsigned_vec(tag) | 1602 | 13.9k | } |
Unexecuted instantiation: <tiff::decoder::Decoder<_>>::find_tag_unsigned_vec::<_> |
1603 | | |
1604 | | /// Tries to retrieve a tag from the current image directory and convert it to the desired |
1605 | | /// unsigned type. Returns an error if the tag is not present. |
1606 | 0 | pub fn get_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<T> { |
1607 | 0 | self.image_ifd().get_tag_unsigned(tag) |
1608 | 0 | } |
1609 | | |
1610 | | /// Tries to retrieve a tag from the current image directory. |
1611 | | /// Returns an error if the tag is not present |
1612 | 0 | pub fn get_tag(&mut self, tag: Tag) -> TiffResult<ifd::Value> { |
1613 | 0 | self.image_ifd().get_tag(tag) |
1614 | 0 | } Unexecuted instantiation: <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::get_tag Unexecuted instantiation: <tiff::decoder::Decoder<_>>::get_tag |
1615 | | |
1616 | 0 | pub fn get_tag_u32(&mut self, tag: Tag) -> TiffResult<u32> { |
1617 | 0 | self.get_tag(tag)?.into_u32() |
1618 | 0 | } |
1619 | | |
1620 | 0 | pub fn get_tag_u64(&mut self, tag: Tag) -> TiffResult<u64> { |
1621 | 0 | self.get_tag(tag)?.into_u64() |
1622 | 0 | } |
1623 | | |
1624 | | /// Tries to retrieve a tag and convert it to the desired type. |
1625 | 0 | pub fn get_tag_f32(&mut self, tag: Tag) -> TiffResult<f32> { |
1626 | 0 | self.get_tag(tag)?.into_f32() |
1627 | 0 | } |
1628 | | |
1629 | | /// Tries to retrieve a tag and convert it to the desired type. |
1630 | 0 | pub fn get_tag_f64(&mut self, tag: Tag) -> TiffResult<f64> { |
1631 | 0 | self.get_tag(tag)?.into_f64() |
1632 | 0 | } |
1633 | | |
1634 | | /// Tries to retrieve a tag and convert it to the desired type. |
1635 | 0 | pub fn get_tag_u32_vec(&mut self, tag: Tag) -> TiffResult<Vec<u32>> { |
1636 | 0 | self.get_tag(tag)?.into_u32_vec() |
1637 | 0 | } |
1638 | | |
1639 | 0 | pub fn get_tag_u16_vec(&mut self, tag: Tag) -> TiffResult<Vec<u16>> { |
1640 | 0 | self.get_tag(tag)?.into_u16_vec() |
1641 | 0 | } |
1642 | | |
1643 | 0 | pub fn get_tag_u64_vec(&mut self, tag: Tag) -> TiffResult<Vec<u64>> { |
1644 | 0 | self.get_tag(tag)?.into_u64_vec() |
1645 | 0 | } |
1646 | | |
1647 | | /// Tries to retrieve a tag and convert it to the desired type. |
1648 | 0 | pub fn get_tag_f32_vec(&mut self, tag: Tag) -> TiffResult<Vec<f32>> { |
1649 | 0 | self.get_tag(tag)?.into_f32_vec() |
1650 | 0 | } |
1651 | | |
1652 | | /// Tries to retrieve a tag and convert it to the desired type. |
1653 | 0 | pub fn get_tag_f64_vec(&mut self, tag: Tag) -> TiffResult<Vec<f64>> { |
1654 | 0 | self.get_tag(tag)?.into_f64_vec() |
1655 | 0 | } |
1656 | | |
1657 | | /// Tries to retrieve a tag and convert it to a 8bit vector. |
1658 | 0 | pub fn get_tag_u8_vec(&mut self, tag: Tag) -> TiffResult<Vec<u8>> { |
1659 | 0 | self.get_tag(tag)?.into_u8_vec() |
1660 | 0 | } Unexecuted instantiation: <tiff::decoder::Decoder<std::io::cursor::Cursor<&[u8]>>>::get_tag_u8_vec Unexecuted instantiation: <tiff::decoder::Decoder<_>>::get_tag_u8_vec |
1661 | | |
1662 | | /// Tries to retrieve a tag and convert it to a ascii vector. |
1663 | 0 | pub fn get_tag_ascii_string(&mut self, tag: Tag) -> TiffResult<String> { |
1664 | 0 | self.get_tag(tag)?.into_string() |
1665 | 0 | } |
1666 | | |
1667 | 0 | pub fn tag_iter(&mut self) -> impl Iterator<Item = TiffResult<(Tag, ifd::Value)>> + '_ { |
1668 | 0 | self.image_ifd().tag_iter() |
1669 | 0 | } |
1670 | | } |
1671 | | |
1672 | | impl<R: Seek + Read> ValueReader<R> { |
1673 | 19.7k | pub(crate) fn read_directory(&mut self, ptr: IfdPointer) -> Result<Directory, TiffError> { |
1674 | 19.7k | Self::read_ifd(&mut self.reader, self.bigtiff, ptr) |
1675 | 19.7k | } <tiff::decoder::ValueReader<std::io::cursor::Cursor<&[u8]>>>::read_directory Line | Count | Source | 1673 | 19.7k | pub(crate) fn read_directory(&mut self, ptr: IfdPointer) -> Result<Directory, TiffError> { | 1674 | 19.7k | Self::read_ifd(&mut self.reader, self.bigtiff, ptr) | 1675 | 19.7k | } |
Unexecuted instantiation: <tiff::decoder::ValueReader<_>>::read_directory |
1676 | | |
1677 | | /// Reads a IFD entry. |
1678 | | // An IFD entry has four fields: |
1679 | | // |
1680 | | // Tag 2 bytes |
1681 | | // Type 2 bytes |
1682 | | // Count 4 bytes |
1683 | | // Value 4 bytes either a pointer the value itself |
1684 | 1.73M | fn read_entry( |
1685 | 1.73M | reader: &mut EndianReader<R>, |
1686 | 1.73M | bigtiff: bool, |
1687 | 1.73M | ) -> TiffResult<Option<(Tag, ifd::Entry)>> { |
1688 | 1.73M | let tag = Tag::from_u16_exhaustive(reader.read_u16()?); |
1689 | 1.73M | let type_ = match Type::from_u16(reader.read_u16()?) { |
1690 | 445k | Some(t) => t, |
1691 | | None => { |
1692 | | // Unknown type. Skip this entry according to spec. |
1693 | 1.29M | reader.read_u32()?; |
1694 | 1.29M | reader.read_u32()?; |
1695 | 1.29M | return Ok(None); |
1696 | | } |
1697 | | }; |
1698 | 445k | let entry = if bigtiff { |
1699 | 9.87k | let mut offset = [0; 8]; |
1700 | | |
1701 | 9.87k | let count = reader.read_u64()?; |
1702 | 9.86k | reader.inner().read_exact(&mut offset)?; |
1703 | 9.85k | ifd::Entry::new_u64(type_, count, offset) |
1704 | | } else { |
1705 | 436k | let mut offset = [0; 4]; |
1706 | | |
1707 | 436k | let count = reader.read_u32()?; |
1708 | 435k | reader.inner().read_exact(&mut offset)?; |
1709 | 435k | ifd::Entry::new(type_, count, offset) |
1710 | | }; |
1711 | 445k | Ok(Some((tag, entry))) |
1712 | 1.73M | } <tiff::decoder::ValueReader<std::io::cursor::Cursor<&[u8]>>>::read_entry Line | Count | Source | 1684 | 1.73M | fn read_entry( | 1685 | 1.73M | reader: &mut EndianReader<R>, | 1686 | 1.73M | bigtiff: bool, | 1687 | 1.73M | ) -> TiffResult<Option<(Tag, ifd::Entry)>> { | 1688 | 1.73M | let tag = Tag::from_u16_exhaustive(reader.read_u16()?); | 1689 | 1.73M | let type_ = match Type::from_u16(reader.read_u16()?) { | 1690 | 445k | Some(t) => t, | 1691 | | None => { | 1692 | | // Unknown type. Skip this entry according to spec. | 1693 | 1.29M | reader.read_u32()?; | 1694 | 1.29M | reader.read_u32()?; | 1695 | 1.29M | return Ok(None); | 1696 | | } | 1697 | | }; | 1698 | 445k | let entry = if bigtiff { | 1699 | 9.87k | let mut offset = [0; 8]; | 1700 | | | 1701 | 9.87k | let count = reader.read_u64()?; | 1702 | 9.86k | reader.inner().read_exact(&mut offset)?; | 1703 | 9.85k | ifd::Entry::new_u64(type_, count, offset) | 1704 | | } else { | 1705 | 436k | let mut offset = [0; 4]; | 1706 | | | 1707 | 436k | let count = reader.read_u32()?; | 1708 | 435k | reader.inner().read_exact(&mut offset)?; | 1709 | 435k | ifd::Entry::new(type_, count, offset) | 1710 | | }; | 1711 | 445k | Ok(Some((tag, entry))) | 1712 | 1.73M | } |
Unexecuted instantiation: <tiff::decoder::ValueReader<_>>::read_entry |
1713 | | |
1714 | | /// Reads the IFD starting at the indicated location. |
1715 | 19.7k | fn read_ifd( |
1716 | 19.7k | reader: &mut EndianReader<R>, |
1717 | 19.7k | bigtiff: bool, |
1718 | 19.7k | ifd_location: IfdPointer, |
1719 | 19.7k | ) -> TiffResult<Directory> { |
1720 | 19.7k | reader.goto_offset(ifd_location.0)?; |
1721 | | |
1722 | 19.7k | let mut entries: BTreeMap<_, _> = BTreeMap::new(); |
1723 | | |
1724 | 19.7k | let num_tags = if bigtiff { |
1725 | 476 | reader.read_u64()? |
1726 | | } else { |
1727 | 19.2k | reader.read_u16()?.into() |
1728 | | }; |
1729 | | |
1730 | 19.7k | for _ in 0..num_tags { |
1731 | 1.73M | let (tag, entry) = match Self::read_entry(reader, bigtiff)? { |
1732 | 445k | Some(val) => val, |
1733 | | None => { |
1734 | 1.29M | continue; |
1735 | | } // Unknown data type in tag, skip |
1736 | | }; |
1737 | | |
1738 | 445k | entries.insert(tag.to_u16(), entry); |
1739 | | } |
1740 | | |
1741 | 17.7k | let next_ifd = if bigtiff { |
1742 | 337 | reader.read_u64()? |
1743 | | } else { |
1744 | 17.3k | reader.read_u32()?.into() |
1745 | | }; |
1746 | | |
1747 | 17.7k | let next_ifd = core::num::NonZeroU64::new(next_ifd); |
1748 | | |
1749 | 17.7k | Ok(Directory { entries, next_ifd }) |
1750 | 19.7k | } <tiff::decoder::ValueReader<std::io::cursor::Cursor<&[u8]>>>::read_ifd Line | Count | Source | 1715 | 19.7k | fn read_ifd( | 1716 | 19.7k | reader: &mut EndianReader<R>, | 1717 | 19.7k | bigtiff: bool, | 1718 | 19.7k | ifd_location: IfdPointer, | 1719 | 19.7k | ) -> TiffResult<Directory> { | 1720 | 19.7k | reader.goto_offset(ifd_location.0)?; | 1721 | | | 1722 | 19.7k | let mut entries: BTreeMap<_, _> = BTreeMap::new(); | 1723 | | | 1724 | 19.7k | let num_tags = if bigtiff { | 1725 | 476 | reader.read_u64()? | 1726 | | } else { | 1727 | 19.2k | reader.read_u16()?.into() | 1728 | | }; | 1729 | | | 1730 | 19.7k | for _ in 0..num_tags { | 1731 | 1.73M | let (tag, entry) = match Self::read_entry(reader, bigtiff)? { | 1732 | 445k | Some(val) => val, | 1733 | | None => { | 1734 | 1.29M | continue; | 1735 | | } // Unknown data type in tag, skip | 1736 | | }; | 1737 | | | 1738 | 445k | entries.insert(tag.to_u16(), entry); | 1739 | | } | 1740 | | | 1741 | 17.7k | let next_ifd = if bigtiff { | 1742 | 337 | reader.read_u64()? | 1743 | | } else { | 1744 | 17.3k | reader.read_u32()?.into() | 1745 | | }; | 1746 | | | 1747 | 17.7k | let next_ifd = core::num::NonZeroU64::new(next_ifd); | 1748 | | | 1749 | 17.7k | Ok(Directory { entries, next_ifd }) | 1750 | 19.7k | } |
Unexecuted instantiation: <tiff::decoder::ValueReader<_>>::read_ifd |
1751 | | } |
1752 | | |
1753 | | impl IfdDecoder<'_> { |
1754 | | /// Retrieve the IFD entry for a given tag, if it exists. |
1755 | | /// |
1756 | | /// The entry contains the metadata of the value, that is its type and count from which we can |
1757 | | /// calculate a total byte size. |
1758 | 0 | pub fn find_entry(&self, tag: Tag) -> Option<ifd::Entry> { |
1759 | 0 | self.inner.ifd.get(tag).cloned() |
1760 | 0 | } |
1761 | | |
1762 | | /// Tries to retrieve a tag. |
1763 | | /// Return `Ok(None)` if the tag is not present. |
1764 | 13.9k | pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> { |
1765 | 13.9k | self.inner.find_tag(tag) |
1766 | 13.9k | } |
1767 | | |
1768 | | /// Retrieve a tag and reproduce its bytes into the provided buffer. |
1769 | | /// |
1770 | | /// The buffer is unmodified if the tag is not present. |
1771 | 0 | pub fn find_tag_buf( |
1772 | 0 | &mut self, |
1773 | 0 | tag: Tag, |
1774 | 0 | buf: &mut ValueBuffer, |
1775 | 0 | ) -> TiffResult<Option<ifd::Entry>> { |
1776 | 0 | self.inner.find_tag_buf(tag, buf) |
1777 | 0 | } |
1778 | | |
1779 | | /// Read bytes of a tag's value into a byte buffer. |
1780 | 0 | pub fn find_tag_bytes( |
1781 | 0 | &mut self, |
1782 | 0 | tag: Tag, |
1783 | 0 | buf: &mut [u8], |
1784 | 0 | offset: u64, |
1785 | 0 | ) -> TiffResult<Option<usize>> { |
1786 | 0 | self.inner.find_tag_raw(tag, buf, offset) |
1787 | 0 | } |
1788 | | |
1789 | | /// Tries to retrieve a tag and convert it to the desired unsigned type. |
1790 | 0 | pub fn find_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<T>> { |
1791 | 0 | self.find_tag(tag)? |
1792 | 0 | .map(|v| v.into_u64()) |
1793 | 0 | .transpose()? |
1794 | 0 | .map(|value| { |
1795 | 0 | T::try_from(value).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()) |
1796 | 0 | }) |
1797 | 0 | .transpose() |
1798 | 0 | } |
1799 | | |
1800 | | /// Tries to retrieve a vector of all a tag's values and convert them to |
1801 | | /// the desired unsigned type. |
1802 | 13.9k | pub fn find_tag_unsigned_vec<T: TryFrom<u64>>( |
1803 | 13.9k | &mut self, |
1804 | 13.9k | tag: Tag, |
1805 | 13.9k | ) -> TiffResult<Option<Vec<T>>> { |
1806 | 13.9k | self.find_tag(tag)? |
1807 | 13.9k | .map(|v| v.into_u64_vec()) <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<u16>::{closure#0}Line | Count | Source | 1807 | 2.23k | .map(|v| v.into_u64_vec()) |
Unexecuted instantiation: <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<_>::{closure#0} |
1808 | 13.9k | .transpose()? |
1809 | 13.9k | .map(|v| { |
1810 | 2.23k | v.into_iter() |
1811 | 71.5k | .map(|u| { |
1812 | 71.5k | T::try_from(u).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()) Unexecuted instantiation: <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<u16>::{closure#1}::{closure#0}::{closure#0}Unexecuted instantiation: <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<_>::{closure#1}::{closure#0}::{closure#0} |
1813 | 71.5k | }) <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<u16>::{closure#1}::{closure#0}Line | Count | Source | 1811 | 71.5k | .map(|u| { | 1812 | 71.5k | T::try_from(u).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()) | 1813 | 71.5k | }) |
Unexecuted instantiation: <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<_>::{closure#1}::{closure#0} |
1814 | 2.23k | .collect() |
1815 | 2.23k | }) <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<u16>::{closure#1}Line | Count | Source | 1809 | 2.23k | .map(|v| { | 1810 | 2.23k | v.into_iter() | 1811 | 2.23k | .map(|u| { | 1812 | | T::try_from(u).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()) | 1813 | | }) | 1814 | 2.23k | .collect() | 1815 | 2.23k | }) |
Unexecuted instantiation: <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<_>::{closure#1} |
1816 | 13.9k | .transpose() |
1817 | 13.9k | } <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<u16> Line | Count | Source | 1802 | 13.9k | pub fn find_tag_unsigned_vec<T: TryFrom<u64>>( | 1803 | 13.9k | &mut self, | 1804 | 13.9k | tag: Tag, | 1805 | 13.9k | ) -> TiffResult<Option<Vec<T>>> { | 1806 | 13.9k | self.find_tag(tag)? | 1807 | 13.9k | .map(|v| v.into_u64_vec()) | 1808 | 13.9k | .transpose()? | 1809 | 13.9k | .map(|v| { | 1810 | | v.into_iter() | 1811 | | .map(|u| { | 1812 | | T::try_from(u).map_err(|_| TiffFormatError::InvalidTagValueType(tag).into()) | 1813 | | }) | 1814 | | .collect() | 1815 | | }) | 1816 | 13.9k | .transpose() | 1817 | 13.9k | } |
Unexecuted instantiation: <tiff::decoder::IfdDecoder>::find_tag_unsigned_vec::<_> |
1818 | | |
1819 | | /// Tries to retrieve a tag and convert it to the desired unsigned type. |
1820 | | /// Returns an error if the tag is not present. |
1821 | 0 | pub fn get_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<T> { |
1822 | 0 | self.find_tag_unsigned(tag)? |
1823 | 0 | .ok_or_else(|| TiffFormatError::RequiredTagNotFound(tag).into()) |
1824 | 0 | } |
1825 | | |
1826 | | /// Tries to retrieve a tag. |
1827 | | /// Returns an error if the tag is not present |
1828 | 0 | pub fn get_tag(&mut self, tag: Tag) -> TiffResult<ifd::Value> { |
1829 | 0 | match self.find_tag(tag)? { |
1830 | 0 | Some(val) => Ok(val), |
1831 | 0 | None => Err(TiffError::FormatError( |
1832 | 0 | TiffFormatError::RequiredTagNotFound(tag), |
1833 | 0 | )), |
1834 | | } |
1835 | 0 | } |
1836 | | |
1837 | | /// Tries to retrieve a tag and convert it to the desired type. |
1838 | 0 | pub fn get_tag_u32(&mut self, tag: Tag) -> TiffResult<u32> { |
1839 | 0 | self.get_tag(tag)?.into_u32() |
1840 | 0 | } |
1841 | | |
1842 | 0 | pub fn get_tag_u64(&mut self, tag: Tag) -> TiffResult<u64> { |
1843 | 0 | self.get_tag(tag)?.into_u64() |
1844 | 0 | } |
1845 | | |
1846 | | /// Tries to retrieve a tag and convert it to the desired type. |
1847 | 0 | pub fn get_tag_f32(&mut self, tag: Tag) -> TiffResult<f32> { |
1848 | 0 | self.get_tag(tag)?.into_f32() |
1849 | 0 | } |
1850 | | |
1851 | | /// Tries to retrieve a tag and convert it to the desired type. |
1852 | 0 | pub fn get_tag_f64(&mut self, tag: Tag) -> TiffResult<f64> { |
1853 | 0 | self.get_tag(tag)?.into_f64() |
1854 | 0 | } |
1855 | | |
1856 | | /// Tries to retrieve a tag and convert it to the desired type. |
1857 | 0 | pub fn get_tag_u32_vec(&mut self, tag: Tag) -> TiffResult<Vec<u32>> { |
1858 | 0 | self.get_tag(tag)?.into_u32_vec() |
1859 | 0 | } |
1860 | | |
1861 | 0 | pub fn get_tag_u16_vec(&mut self, tag: Tag) -> TiffResult<Vec<u16>> { |
1862 | 0 | self.get_tag(tag)?.into_u16_vec() |
1863 | 0 | } |
1864 | | |
1865 | 0 | pub fn get_tag_u64_vec(&mut self, tag: Tag) -> TiffResult<Vec<u64>> { |
1866 | 0 | self.get_tag(tag)?.into_u64_vec() |
1867 | 0 | } |
1868 | | |
1869 | | /// Tries to retrieve a tag and convert it to the desired type. |
1870 | 0 | pub fn get_tag_f32_vec(&mut self, tag: Tag) -> TiffResult<Vec<f32>> { |
1871 | 0 | self.get_tag(tag)?.into_f32_vec() |
1872 | 0 | } |
1873 | | |
1874 | | /// Tries to retrieve a tag and convert it to the desired type. |
1875 | 0 | pub fn get_tag_f64_vec(&mut self, tag: Tag) -> TiffResult<Vec<f64>> { |
1876 | 0 | self.get_tag(tag)?.into_f64_vec() |
1877 | 0 | } |
1878 | | |
1879 | | /// Tries to retrieve a tag and convert it to a 8bit vector. |
1880 | 0 | pub fn get_tag_u8_vec(&mut self, tag: Tag) -> TiffResult<Vec<u8>> { |
1881 | 0 | self.get_tag(tag)?.into_u8_vec() |
1882 | 0 | } |
1883 | | |
1884 | | /// Tries to retrieve a tag and convert it to a ascii vector. |
1885 | 0 | pub fn get_tag_ascii_string(&mut self, tag: Tag) -> TiffResult<String> { |
1886 | 0 | self.get_tag(tag)?.into_string() |
1887 | 0 | } |
1888 | | |
1889 | | /// Inspect the raw underlying directory. |
1890 | 0 | pub fn directory(&self) -> &Directory { |
1891 | 0 | self.inner.ifd |
1892 | 0 | } |
1893 | | } |
1894 | | |
1895 | | impl<'l> IfdDecoder<'l> { |
1896 | | /// Returns an iterator over all tags in the current image, along with their values. |
1897 | 0 | pub fn tag_iter(self) -> impl Iterator<Item = TiffResult<(Tag, ifd::Value)>> + 'l { |
1898 | 0 | self.inner |
1899 | 0 | .ifd |
1900 | 0 | .iter() |
1901 | 0 | .map(|(tag, entry)| match self.inner.decoder.entry_val(entry) { |
1902 | 0 | Ok(value) => Ok((tag, value)), |
1903 | 0 | Err(err) => Err(err), |
1904 | 0 | }) |
1905 | 0 | } |
1906 | | } |
1907 | | |
1908 | | #[cfg(test)] |
1909 | | mod tests { |
1910 | | use super::Decoder; |
1911 | | use crate::{ |
1912 | | bytecast, |
1913 | | tags::{ByteOrder, Tag, ValueBuffer}, |
1914 | | }; |
1915 | | |
1916 | | #[test] |
1917 | | fn equivalence_of_tag_readers() { |
1918 | | let file = std::fs::File::open(concat!( |
1919 | | env!("CARGO_MANIFEST_DIR"), |
1920 | | "/tests/images/int8_rgb.tif" |
1921 | | )) |
1922 | | .unwrap(); |
1923 | | |
1924 | | let mut decoder = Decoder::new(file).unwrap(); |
1925 | | let file_bo = decoder.byte_order(); |
1926 | | let mut ifd = decoder.image_ifd(); |
1927 | | |
1928 | | { |
1929 | | let value = ifd |
1930 | | .find_tag(Tag::BitsPerSample) |
1931 | | .unwrap() |
1932 | | .expect("must have BitsPerSample"); |
1933 | | |
1934 | | let samples = value.into_u16_vec().unwrap(); |
1935 | | assert_eq!(samples.as_slice(), [8, 8, 8]); |
1936 | | } |
1937 | | |
1938 | | { |
1939 | | let mut value = ValueBuffer::from_value(&[0u16; 4]); |
1940 | | let _entry = ifd |
1941 | | .find_tag_buf(Tag::BitsPerSample, &mut value) |
1942 | | .unwrap() |
1943 | | .expect("must have BitsPerSample"); |
1944 | | |
1945 | | value.set_byte_order(ByteOrder::native()); |
1946 | | assert_eq!(value.as_bytes(), bytecast::u16_as_ne_bytes(&[8, 8, 8])); |
1947 | | } |
1948 | | |
1949 | | { |
1950 | | let mut by_bytes = [0u16; 4]; |
1951 | | let entry = ifd |
1952 | | .find_entry(Tag::BitsPerSample) |
1953 | | .expect("must have BitsPerSample"); |
1954 | | |
1955 | | let byte_len = ifd |
1956 | | .find_tag_bytes( |
1957 | | Tag::BitsPerSample, |
1958 | | bytecast::u16_as_ne_mut_bytes(&mut by_bytes), |
1959 | | 0, |
1960 | | ) |
1961 | | .unwrap() |
1962 | | .expect("must have BitsPerSample"); |
1963 | | assert_eq!(byte_len, 3 * std::mem::size_of::<u16>()); |
1964 | | |
1965 | | file_bo.convert( |
1966 | | entry.field_type(), |
1967 | | bytecast::u16_as_ne_mut_bytes(&mut by_bytes[..3]), |
1968 | | ByteOrder::native(), |
1969 | | ); |
1970 | | assert_eq!(&by_bytes[..3], &[8, 8, 8]); |
1971 | | } |
1972 | | } |
1973 | | } |