From ee8d13249e2f1f9e7b3ec675d39951e092655caf Mon Sep 17 00:00:00 2001 From: "A. Molzer" <5550310+197g@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:19:30 +0100 Subject: [PATCH 1/2] Utils for working with tags Implement the encoder's `TiffValue` trait for the tags commonly defined and represented as separate types in our own code. We don't tie the tag for an entry of these to the value type (yet). This lets us keep the trait exactly as-is and we avoid unnecessary churn. We can always add a separate trait on top. --- src/encoder/mod.rs | 2 +- src/encoder/tiff_value.rs | 124 +++++++++++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index c56c0123..93256d15 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -582,7 +582,7 @@ impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T, )?; encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?; encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?; - encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None.to_u16())?; + encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None)?; Ok(ImageEncoder { encoder, diff --git a/src/encoder/tiff_value.rs b/src/encoder/tiff_value.rs index 16ab2c18..b40d0f42 100644 --- a/src/encoder/tiff_value.rs +++ b/src/encoder/tiff_value.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, io::Write, slice::from_ref}; -use crate::{bytecast, tags::Type, TiffError, TiffFormatError, TiffResult}; +use crate::{bytecast, tags, tags::Type, TiffError, TiffFormatError, TiffResult}; use super::writer::TiffWriter; @@ -458,6 +458,128 @@ impl TiffValue for str { } } +// FIXME: held up on reading the discriminant for all but the unknown variant. +// +// It needs to have `repr(u16)` to have a defined layout and then we may read the tag from its +// value representation by casting a u16 pointer to a pointer to the enum type. +// unsafe { *<*const _>::from(self).cast::() } +// But that is quite unsafe and needs careful review to maintain the safety requirements. Maybe we +// could get `bytemuck` to add a trait for this (it has `TransparentWrapper`) with a derive for +// enum types that have an explicit repr. +// +// This would allow returning borrowed data in more cases. For all types without an unknown, in all +// cases including as slices, and for all types with and unknown variant when we have a single +// value (either returning a borrowed discriminant or a borrowed value within `Unknown`). +impl TiffValue for tags::CompressionMethod { + const BYTE_LEN: u8 = ::BYTE_LEN; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + 1 + } + + fn data(&self) -> Cow<'_, [u8]> { + let bytes = self.to_u16().to_ne_bytes(); + Cow::Owned(bytes.to_vec()) + } +} + +impl TiffValue for tags::PhotometricInterpretation { + const BYTE_LEN: u8 = ::BYTE_LEN; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + 1 + } + + fn data(&self) -> Cow<'_, [u8]> { + self.to_u16().to_ne_bytes().to_vec().into() + } +} + +impl TiffValue for tags::PlanarConfiguration { + const BYTE_LEN: u8 = 2; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + 1 + } + + fn data(&self) -> Cow<'_, [u8]> { + self.to_u16().to_ne_bytes().to_vec().into() + } +} + +impl TiffValue for tags::Predictor { + const BYTE_LEN: u8 = ::BYTE_LEN; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + 1 + } + + fn data(&self) -> Cow<'_, [u8]> { + self.to_u16().to_ne_bytes().to_vec().into() + } +} + +impl TiffValue for tags::ResolutionUnit { + const BYTE_LEN: u8 = ::BYTE_LEN; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + 1 + } + + fn data(&self) -> Cow<'_, [u8]> { + self.to_u16().to_ne_bytes().to_vec().into() + } +} + +/// This is implemented for slices as the `SampleFormat` tag takes a count of `N`. +/// +/// Use `core::slice::from_ref` if you really need to write a single element. +/// +/// See: +impl TiffValue for [tags::SampleFormat] { + const BYTE_LEN: u8 = ::BYTE_LEN; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + self.len() + } + + fn data(&self) -> Cow<'_, [u8]> { + let mut buf: Vec = Vec::with_capacity(self.len() * 2); + for x in self { + buf.extend_from_slice(&x.to_u16().to_ne_bytes()); + } + Cow::Owned(buf) + } +} + +/// This is implemented for slices as the `ExtraSamples` tag takes a count of `N`. +/// +/// Use `core::slice::from_ref` if you really need to write a single element. +/// +/// See: +impl TiffValue for [tags::ExtraSamples] { + const BYTE_LEN: u8 = ::BYTE_LEN; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + self.len() + } + + fn data(&self) -> Cow<'_, [u8]> { + let mut buf: Vec = Vec::with_capacity(self.len() * 2); + for x in self { + buf.extend_from_slice(&x.to_u16().to_ne_bytes()); + } + Cow::Owned(buf) + } +} + // If you pass `&Vec<_>` then you'd get at first sight the complaint: // // `Vec` does not implement `TiffValue` From fee650d7f6b6b47bee379be628fc56ec616b3f34 Mon Sep 17 00:00:00 2001 From: "A. Molzer" <5550310+197g@users.noreply.github.com> Date: Thu, 8 Jan 2026 19:47:05 +0100 Subject: [PATCH 2/2] Ensure repr and values of tags! variants --- CHANGES.md | 13 +++++++++++++ src/tags.rs | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 2074e8f7..cf37b34e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,16 @@ +# Version 0.11.1 (Unreleased) + +Fixes: +- The enumeration types in `tags` are now all marked with a representation of + their underlying TIFF type (e.g. `repr(u16)`) and variants are explicitly + assigned their corresponding values. That is you may _read_ the raw + discriminant and interpret that as the value—except for `Unknown` variants. + +Additions: +- Types in `tags` now generally implement `TiffValue` and can be handed to the + `DirectoryEncoder::write_tag` method. Unlike primitive types they do _not_ + always implement the trait for slices of themselves. + # Version 0.11.0 - `Directory` now implements `FromIterator<(Tag, Value)>`. diff --git a/src/tags.rs b/src/tags.rs index 14cc3837..8dc87169 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -10,8 +10,9 @@ macro_rules! tags { $( #[$enum_attr] )* #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] #[non_exhaustive] + #[repr($ty)] pub enum $name { - $($(#[$ident_attr])* $tag,)* + $($(#[$ident_attr])* $tag = $val,)* $( #[$unknown_meta] Unknown($ty),