Skip to main content

tiff/encoder/
tiff_value.rs

1use std::{borrow::Cow, io::Write, slice::from_ref};
2
3use crate::{bytecast, tags, tags::Type, TiffError, TiffFormatError, TiffResult};
4
5use super::writer::TiffWriter;
6
7/// Trait for types that can be encoded in a tiff file
8#[diagnostic::on_unimplemented(
9    message = "the type `{Self}` does not implement `TiffValue`",
10    note = "the trait is implemented for primitive types (`u8`, `i16`, `f32`, etc.)",
11    note = "the trait is implemented for shared references to values",
12    note = "the trait is implemented for slices, pass them by reference (e.g. `&[u8]`)",
13    note = "the trait is implemented for arrays if it is implemented for a slice",
14    note = "values in a `Vec` or `Box` should be dereferenced, e.g. `&vec[..]`"
15)]
16pub trait TiffValue {
17    const BYTE_LEN: u8;
18    const FIELD_TYPE: Type;
19
20    // FIXME: If we want this to mean 'count' in the sense of `Entry` it should return `u32` or
21    // `u64`, probably the latter with `convert_offset` taking care of the check against `u32::MAX`
22    // for classic tiff.
23    fn count(&self) -> usize;
24
25    fn bytes(&self) -> usize {
26        self.count() * usize::from(Self::BYTE_LEN)
27    }
28
29    /// Access this value as an contiguous sequence of bytes.
30    /// If their is no trivial representation, allocate it on the heap.
31    fn data(&self) -> Cow<'_, [u8]>;
32
33    /// Write this value to a TiffWriter.
34    /// While the default implementation will work in all cases, it may require unnecessary allocations.
35    /// The written bytes of any custom implementation MUST be the same as yielded by `self.data()`.
36    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
37        writer.write_bytes(&self.data())?;
38        Ok(())
39    }
40}
41
42impl TiffValue for [u8] {
43    const BYTE_LEN: u8 = 1;
44    const FIELD_TYPE: Type = Type::BYTE;
45
46    fn count(&self) -> usize {
47        self.len()
48    }
49
50    fn data(&self) -> Cow<'_, [u8]> {
51        Cow::Borrowed(self)
52    }
53}
54
55impl TiffValue for [i8] {
56    const BYTE_LEN: u8 = 1;
57    const FIELD_TYPE: Type = Type::SBYTE;
58
59    fn count(&self) -> usize {
60        self.len()
61    }
62
63    fn data(&self) -> Cow<'_, [u8]> {
64        Cow::Borrowed(bytecast::i8_as_ne_bytes(self))
65    }
66}
67
68impl TiffValue for [u16] {
69    const BYTE_LEN: u8 = 2;
70    const FIELD_TYPE: Type = Type::SHORT;
71
72    fn count(&self) -> usize {
73        self.len()
74    }
75
76    fn data(&self) -> Cow<'_, [u8]> {
77        Cow::Borrowed(bytecast::u16_as_ne_bytes(self))
78    }
79}
80
81impl TiffValue for [i16] {
82    const BYTE_LEN: u8 = 2;
83    const FIELD_TYPE: Type = Type::SSHORT;
84
85    fn count(&self) -> usize {
86        self.len()
87    }
88
89    fn data(&self) -> Cow<'_, [u8]> {
90        Cow::Borrowed(bytecast::i16_as_ne_bytes(self))
91    }
92}
93
94impl TiffValue for [u32] {
95    const BYTE_LEN: u8 = 4;
96    const FIELD_TYPE: Type = Type::LONG;
97
98    fn count(&self) -> usize {
99        self.len()
100    }
101
102    fn data(&self) -> Cow<'_, [u8]> {
103        Cow::Borrowed(bytecast::u32_as_ne_bytes(self))
104    }
105}
106
107impl TiffValue for [i32] {
108    const BYTE_LEN: u8 = 4;
109    const FIELD_TYPE: Type = Type::SLONG;
110
111    fn count(&self) -> usize {
112        self.len()
113    }
114
115    fn data(&self) -> Cow<'_, [u8]> {
116        Cow::Borrowed(bytecast::i32_as_ne_bytes(self))
117    }
118}
119
120impl TiffValue for [u64] {
121    const BYTE_LEN: u8 = 8;
122    const FIELD_TYPE: Type = Type::LONG8;
123
124    fn count(&self) -> usize {
125        self.len()
126    }
127
128    fn data(&self) -> Cow<'_, [u8]> {
129        Cow::Borrowed(bytecast::u64_as_ne_bytes(self))
130    }
131}
132
133impl TiffValue for [i64] {
134    const BYTE_LEN: u8 = 8;
135    const FIELD_TYPE: Type = Type::SLONG8;
136
137    fn count(&self) -> usize {
138        self.len()
139    }
140
141    fn data(&self) -> Cow<'_, [u8]> {
142        Cow::Borrowed(bytecast::i64_as_ne_bytes(self))
143    }
144}
145
146impl TiffValue for [f32] {
147    const BYTE_LEN: u8 = 4;
148    const FIELD_TYPE: Type = Type::FLOAT;
149
150    fn count(&self) -> usize {
151        self.len()
152    }
153
154    fn data(&self) -> Cow<'_, [u8]> {
155        // We write using native endian so this should be safe
156        Cow::Borrowed(bytecast::f32_as_ne_bytes(self))
157    }
158}
159
160impl TiffValue for [f64] {
161    const BYTE_LEN: u8 = 8;
162    const FIELD_TYPE: Type = Type::DOUBLE;
163
164    fn count(&self) -> usize {
165        self.len()
166    }
167
168    fn data(&self) -> Cow<'_, [u8]> {
169        // We write using native endian so this should be safe
170        Cow::Borrowed(bytecast::f64_as_ne_bytes(self))
171    }
172}
173
174impl TiffValue for u8 {
175    const BYTE_LEN: u8 = 1;
176    const FIELD_TYPE: Type = Type::BYTE;
177
178    fn count(&self) -> usize {
179        1
180    }
181
182    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
183        writer.write_u8(*self)?;
184        Ok(())
185    }
186
187    fn data(&self) -> Cow<'_, [u8]> {
188        Cow::Borrowed(from_ref(self))
189    }
190}
191
192impl TiffValue for i8 {
193    const BYTE_LEN: u8 = 1;
194    const FIELD_TYPE: Type = Type::SBYTE;
195
196    fn count(&self) -> usize {
197        1
198    }
199
200    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
201        writer.write_i8(*self)?;
202        Ok(())
203    }
204
205    fn data(&self) -> Cow<'_, [u8]> {
206        Cow::Borrowed(bytecast::i8_as_ne_bytes(from_ref(self)))
207    }
208}
209
210impl TiffValue for u16 {
211    const BYTE_LEN: u8 = 2;
212    const FIELD_TYPE: Type = Type::SHORT;
213
214    fn count(&self) -> usize {
215        1
216    }
217
218    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
219        writer.write_u16(*self)?;
220        Ok(())
221    }
222
223    fn data(&self) -> Cow<'_, [u8]> {
224        Cow::Borrowed(bytecast::u16_as_ne_bytes(from_ref(self)))
225    }
226}
227
228impl TiffValue for i16 {
229    const BYTE_LEN: u8 = 2;
230    const FIELD_TYPE: Type = Type::SSHORT;
231
232    fn count(&self) -> usize {
233        1
234    }
235
236    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
237        writer.write_i16(*self)?;
238        Ok(())
239    }
240
241    fn data(&self) -> Cow<'_, [u8]> {
242        Cow::Borrowed(bytecast::i16_as_ne_bytes(from_ref(self)))
243    }
244}
245
246impl TiffValue for u32 {
247    const BYTE_LEN: u8 = 4;
248    const FIELD_TYPE: Type = Type::LONG;
249
250    fn count(&self) -> usize {
251        1
252    }
253
254    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
255        writer.write_u32(*self)?;
256        Ok(())
257    }
258
259    fn data(&self) -> Cow<'_, [u8]> {
260        Cow::Borrowed(bytecast::u32_as_ne_bytes(from_ref(self)))
261    }
262}
263
264impl TiffValue for i32 {
265    const BYTE_LEN: u8 = 4;
266    const FIELD_TYPE: Type = Type::SLONG;
267
268    fn count(&self) -> usize {
269        1
270    }
271
272    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
273        writer.write_i32(*self)?;
274        Ok(())
275    }
276
277    fn data(&self) -> Cow<'_, [u8]> {
278        Cow::Borrowed(bytecast::i32_as_ne_bytes(from_ref(self)))
279    }
280}
281
282impl TiffValue for u64 {
283    const BYTE_LEN: u8 = 8;
284    const FIELD_TYPE: Type = Type::LONG8;
285
286    fn count(&self) -> usize {
287        1
288    }
289
290    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
291        writer.write_u64(*self)?;
292        Ok(())
293    }
294
295    fn data(&self) -> Cow<'_, [u8]> {
296        Cow::Borrowed(bytecast::u64_as_ne_bytes(from_ref(self)))
297    }
298}
299
300impl TiffValue for i64 {
301    const BYTE_LEN: u8 = 8;
302    const FIELD_TYPE: Type = Type::SLONG8;
303
304    fn count(&self) -> usize {
305        1
306    }
307
308    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
309        writer.write_i64(*self)?;
310        Ok(())
311    }
312
313    fn data(&self) -> Cow<'_, [u8]> {
314        Cow::Borrowed(bytecast::i64_as_ne_bytes(from_ref(self)))
315    }
316}
317
318impl TiffValue for f32 {
319    const BYTE_LEN: u8 = 4;
320    const FIELD_TYPE: Type = Type::FLOAT;
321
322    fn count(&self) -> usize {
323        1
324    }
325
326    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
327        writer.write_f32(*self)?;
328        Ok(())
329    }
330
331    fn data(&self) -> Cow<'_, [u8]> {
332        Cow::Borrowed(bytecast::f32_as_ne_bytes(from_ref(self)))
333    }
334}
335
336impl TiffValue for f64 {
337    const BYTE_LEN: u8 = 8;
338    const FIELD_TYPE: Type = Type::DOUBLE;
339
340    fn count(&self) -> usize {
341        1
342    }
343
344    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
345        writer.write_f64(*self)?;
346        Ok(())
347    }
348
349    fn data(&self) -> Cow<'_, [u8]> {
350        Cow::Borrowed(bytecast::f64_as_ne_bytes(from_ref(self)))
351    }
352}
353
354impl TiffValue for Ifd {
355    const BYTE_LEN: u8 = 4;
356    const FIELD_TYPE: Type = Type::IFD;
357
358    fn count(&self) -> usize {
359        1
360    }
361
362    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
363        writer.write_u32(self.0)?;
364        Ok(())
365    }
366
367    fn data(&self) -> Cow<'_, [u8]> {
368        Cow::Borrowed(bytecast::u32_as_ne_bytes(from_ref(&self.0)))
369    }
370}
371
372impl TiffValue for Ifd8 {
373    const BYTE_LEN: u8 = 8;
374    const FIELD_TYPE: Type = Type::IFD8;
375
376    fn count(&self) -> usize {
377        1
378    }
379
380    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
381        writer.write_u64(self.0)?;
382        Ok(())
383    }
384
385    fn data(&self) -> Cow<'_, [u8]> {
386        Cow::Borrowed(bytecast::u64_as_ne_bytes(from_ref(&self.0)))
387    }
388}
389
390impl TiffValue for Rational {
391    const BYTE_LEN: u8 = 8;
392    const FIELD_TYPE: Type = Type::RATIONAL;
393
394    fn count(&self) -> usize {
395        1
396    }
397
398    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
399        writer.write_u32(self.n)?;
400        writer.write_u32(self.d)?;
401        Ok(())
402    }
403
404    fn data(&self) -> Cow<'_, [u8]> {
405        Cow::Owned({
406            let first_dword = bytecast::u32_as_ne_bytes(from_ref(&self.n));
407            let second_dword = bytecast::u32_as_ne_bytes(from_ref(&self.d));
408            [first_dword, second_dword].concat()
409        })
410    }
411}
412
413impl TiffValue for SRational {
414    const BYTE_LEN: u8 = 8;
415    const FIELD_TYPE: Type = Type::SRATIONAL;
416
417    fn count(&self) -> usize {
418        1
419    }
420
421    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
422        writer.write_i32(self.n)?;
423        writer.write_i32(self.d)?;
424        Ok(())
425    }
426
427    fn data(&self) -> Cow<'_, [u8]> {
428        Cow::Owned({
429            let first_dword = bytecast::i32_as_ne_bytes(from_ref(&self.n));
430            let second_dword = bytecast::i32_as_ne_bytes(from_ref(&self.d));
431            [first_dword, second_dword].concat()
432        })
433    }
434}
435
436impl TiffValue for str {
437    const BYTE_LEN: u8 = 1;
438    const FIELD_TYPE: Type = Type::ASCII;
439
440    fn count(&self) -> usize {
441        self.len() + 1
442    }
443
444    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
445        if self.is_ascii() && !self.bytes().any(|b| b == 0) {
446            writer.write_bytes(self.as_bytes())?;
447            writer.write_u8(0)?;
448            Ok(())
449        } else {
450            Err(TiffError::FormatError(TiffFormatError::InvalidTag))
451        }
452    }
453
454    fn data(&self) -> Cow<'_, [u8]> {
455        Cow::Owned({
456            if self.is_ascii() && !self.bytes().any(|b| b == 0) {
457                let bytes: &[u8] = self.as_bytes();
458                [bytes, &[0]].concat()
459            } else {
460                vec![]
461            }
462        })
463    }
464}
465
466// FIXME: held up on reading the discriminant for all but the unknown variant.
467//
468// It needs to have `repr(u16)` to have a defined layout and then we may read the tag from its
469// value representation by casting a u16 pointer to a pointer to the enum type.
470//     unsafe { *<*const _>::from(self).cast::<u16>() }
471// But that is quite unsafe and needs careful review to maintain the safety requirements. Maybe we
472// could get `bytemuck` to add a trait for this (it has `TransparentWrapper`) with a derive for
473// enum types that have an explicit repr.
474//
475// This would allow returning borrowed data in more cases. For all types without an unknown, in all
476// cases including as slices, and for all types with and unknown variant when we have a single
477// value (either returning a borrowed discriminant or a borrowed value within `Unknown`).
478impl TiffValue for tags::CompressionMethod {
479    const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
480    const FIELD_TYPE: Type = Type::SHORT;
481
482    fn count(&self) -> usize {
483        1
484    }
485
486    fn data(&self) -> Cow<'_, [u8]> {
487        let bytes = self.to_u16().to_ne_bytes();
488        Cow::Owned(bytes.to_vec())
489    }
490}
491
492impl TiffValue for tags::PhotometricInterpretation {
493    const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
494    const FIELD_TYPE: Type = Type::SHORT;
495
496    fn count(&self) -> usize {
497        1
498    }
499
500    fn data(&self) -> Cow<'_, [u8]> {
501        self.to_u16().to_ne_bytes().to_vec().into()
502    }
503}
504
505impl TiffValue for tags::PlanarConfiguration {
506    const BYTE_LEN: u8 = 2;
507    const FIELD_TYPE: Type = Type::SHORT;
508
509    fn count(&self) -> usize {
510        1
511    }
512
513    fn data(&self) -> Cow<'_, [u8]> {
514        self.to_u16().to_ne_bytes().to_vec().into()
515    }
516}
517
518impl TiffValue for tags::Predictor {
519    const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
520    const FIELD_TYPE: Type = Type::SHORT;
521
522    fn count(&self) -> usize {
523        1
524    }
525
526    fn data(&self) -> Cow<'_, [u8]> {
527        self.to_u16().to_ne_bytes().to_vec().into()
528    }
529}
530
531impl TiffValue for tags::ResolutionUnit {
532    const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
533    const FIELD_TYPE: Type = Type::SHORT;
534
535    fn count(&self) -> usize {
536        1
537    }
538
539    fn data(&self) -> Cow<'_, [u8]> {
540        self.to_u16().to_ne_bytes().to_vec().into()
541    }
542}
543
544/// This is implemented for slices as the `SampleFormat` tag takes a count of `N`.
545///
546/// Use `core::slice::from_ref` if you really need to write a single element.
547///
548/// See: <https://web.archive.org/web/20191120220815/https://www.awaresystems.be/imaging/tiff/tifftags/sampleformat.html>
549impl TiffValue for [tags::SampleFormat] {
550    const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
551    const FIELD_TYPE: Type = Type::SHORT;
552
553    fn count(&self) -> usize {
554        self.len()
555    }
556
557    fn data(&self) -> Cow<'_, [u8]> {
558        let mut buf: Vec<u8> = Vec::with_capacity(self.len() * 2);
559        for x in self {
560            buf.extend_from_slice(&x.to_u16().to_ne_bytes());
561        }
562        Cow::Owned(buf)
563    }
564}
565
566/// This is implemented for slices as the `ExtraSamples` tag takes a count of `N`.
567///
568/// Use `core::slice::from_ref` if you really need to write a single element.
569///
570/// See: <https://web.archive.org/web/20191120220815/https://www.awaresystems.be/imaging/tiff/tifftags/extrasamples.html>
571impl TiffValue for [tags::ExtraSamples] {
572    const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
573    const FIELD_TYPE: Type = Type::SHORT;
574
575    fn count(&self) -> usize {
576        self.len()
577    }
578
579    fn data(&self) -> Cow<'_, [u8]> {
580        let mut buf: Vec<u8> = Vec::with_capacity(self.len() * 2);
581        for x in self {
582            buf.extend_from_slice(&x.to_u16().to_ne_bytes());
583        }
584        Cow::Owned(buf)
585    }
586}
587
588// If you pass `&Vec<_>` then you'd get at first sight the  complaint:
589//
590//  `Vec<T>` does not implement `TiffValue`
591//
592// and a list of implementations of `TiffValue` that are quite unrelated. That is not very helpful.
593// We do not *want* `Vec` to implement the trait as an owning type, instead you should pass a
594// reference to a slice. The error message is further customized in the diagnostics of the trait.
595#[diagnostic::do_not_recommend]
596impl<T: TiffValue + ?Sized> TiffValue for &'_ T {
597    const BYTE_LEN: u8 = T::BYTE_LEN;
598    const FIELD_TYPE: Type = T::FIELD_TYPE;
599
600    fn count(&self) -> usize {
601        (*self).count()
602    }
603
604    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
605        (*self).write(writer)
606    }
607
608    fn data(&self) -> Cow<'_, [u8]> {
609        T::data(self)
610    }
611}
612
613/// An array is treated like a slice of the same length.
614impl<T, const N: usize> TiffValue for [T; N]
615where
616    [T]: TiffValue,
617{
618    const BYTE_LEN: u8 = <[T]>::BYTE_LEN;
619    const FIELD_TYPE: Type = <[T]>::FIELD_TYPE;
620
621    fn count(&self) -> usize {
622        self.as_slice().count()
623    }
624
625    fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
626        self.as_slice().write(writer)
627    }
628
629    fn data(&self) -> Cow<'_, [u8]> {
630        self.as_slice().data()
631    }
632}
633
634macro_rules! impl_tiff_value_for_contiguous_sequence {
635    ($inner_type:ty; $bytes:expr; $field_type:expr) => {
636        impl $crate::encoder::TiffValue for [$inner_type] {
637            const BYTE_LEN: u8 = $bytes;
638            const FIELD_TYPE: Type = $field_type;
639
640            fn count(&self) -> usize {
641                self.len()
642            }
643
644            fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
645                for x in self {
646                    x.write(writer)?;
647                }
648                Ok(())
649            }
650
651            fn data(&self) -> Cow<'_, [u8]> {
652                let mut buf: Vec<u8> = Vec::with_capacity(Self::BYTE_LEN as usize * self.len());
653                for x in self {
654                    buf.extend_from_slice(&x.data());
655                }
656                Cow::Owned(buf)
657            }
658        }
659    };
660}
661
662impl_tiff_value_for_contiguous_sequence!(Ifd; 4; Type::IFD);
663impl_tiff_value_for_contiguous_sequence!(Ifd8; 8; Type::IFD8);
664impl_tiff_value_for_contiguous_sequence!(Rational; 8; Type::RATIONAL);
665impl_tiff_value_for_contiguous_sequence!(SRational; 8; Type::SRATIONAL);
666
667/// Type to represent tiff values of type `IFD`
668#[derive(Clone)]
669pub struct Ifd(pub u32);
670
671/// Type to represent tiff values of type `IFD8`
672#[derive(Clone)]
673pub struct Ifd8(pub u64);
674
675/// Type to represent tiff values of type `RATIONAL`
676#[derive(Clone)]
677pub struct Rational {
678    pub n: u32,
679    pub d: u32,
680}
681
682/// Type to represent tiff values of type `SRATIONAL`
683#[derive(Clone)]
684pub struct SRational {
685    pub n: i32,
686    pub d: i32,
687}