Skip to content

Commit 855eb4e

Browse files
authored
Merge pull request #323 from image-rs/tiff-value-for-tags
Utils for working with tags
2 parents 169a896 + fee650d commit 855eb4e

File tree

4 files changed

+139
-3
lines changed

4 files changed

+139
-3
lines changed

CHANGES.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# Version 0.11.1 (Unreleased)
2+
3+
Fixes:
4+
- The enumeration types in `tags` are now all marked with a representation of
5+
their underlying TIFF type (e.g. `repr(u16)`) and variants are explicitly
6+
assigned their corresponding values. That is you may _read_ the raw
7+
discriminant and interpret that as the value—except for `Unknown` variants.
8+
9+
Additions:
10+
- Types in `tags` now generally implement `TiffValue` and can be handed to the
11+
`DirectoryEncoder::write_tag` method. Unlike primitive types they do _not_
12+
always implement the trait for slices of themselves.
13+
114
# Version 0.11.0
215

316
- `Directory` now implements `FromIterator<(Tag, Value)>`.

src/encoder/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T,
582582
)?;
583583
encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?;
584584
encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?;
585-
encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None.to_u16())?;
585+
encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None)?;
586586

587587
Ok(ImageEncoder {
588588
encoder,

src/encoder/tiff_value.rs

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{borrow::Cow, io::Write, slice::from_ref};
22

3-
use crate::{bytecast, tags::Type, TiffError, TiffFormatError, TiffResult};
3+
use crate::{bytecast, tags, tags::Type, TiffError, TiffFormatError, TiffResult};
44

55
use super::writer::TiffWriter;
66

@@ -458,6 +458,128 @@ impl TiffValue for str {
458458
}
459459
}
460460

461+
// FIXME: held up on reading the discriminant for all but the unknown variant.
462+
//
463+
// It needs to have `repr(u16)` to have a defined layout and then we may read the tag from its
464+
// value representation by casting a u16 pointer to a pointer to the enum type.
465+
// unsafe { *<*const _>::from(self).cast::<u16>() }
466+
// But that is quite unsafe and needs careful review to maintain the safety requirements. Maybe we
467+
// could get `bytemuck` to add a trait for this (it has `TransparentWrapper`) with a derive for
468+
// enum types that have an explicit repr.
469+
//
470+
// This would allow returning borrowed data in more cases. For all types without an unknown, in all
471+
// cases including as slices, and for all types with and unknown variant when we have a single
472+
// value (either returning a borrowed discriminant or a borrowed value within `Unknown`).
473+
impl TiffValue for tags::CompressionMethod {
474+
const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
475+
const FIELD_TYPE: Type = Type::SHORT;
476+
477+
fn count(&self) -> usize {
478+
1
479+
}
480+
481+
fn data(&self) -> Cow<'_, [u8]> {
482+
let bytes = self.to_u16().to_ne_bytes();
483+
Cow::Owned(bytes.to_vec())
484+
}
485+
}
486+
487+
impl TiffValue for tags::PhotometricInterpretation {
488+
const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
489+
const FIELD_TYPE: Type = Type::SHORT;
490+
491+
fn count(&self) -> usize {
492+
1
493+
}
494+
495+
fn data(&self) -> Cow<'_, [u8]> {
496+
self.to_u16().to_ne_bytes().to_vec().into()
497+
}
498+
}
499+
500+
impl TiffValue for tags::PlanarConfiguration {
501+
const BYTE_LEN: u8 = 2;
502+
const FIELD_TYPE: Type = Type::SHORT;
503+
504+
fn count(&self) -> usize {
505+
1
506+
}
507+
508+
fn data(&self) -> Cow<'_, [u8]> {
509+
self.to_u16().to_ne_bytes().to_vec().into()
510+
}
511+
}
512+
513+
impl TiffValue for tags::Predictor {
514+
const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
515+
const FIELD_TYPE: Type = Type::SHORT;
516+
517+
fn count(&self) -> usize {
518+
1
519+
}
520+
521+
fn data(&self) -> Cow<'_, [u8]> {
522+
self.to_u16().to_ne_bytes().to_vec().into()
523+
}
524+
}
525+
526+
impl TiffValue for tags::ResolutionUnit {
527+
const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
528+
const FIELD_TYPE: Type = Type::SHORT;
529+
530+
fn count(&self) -> usize {
531+
1
532+
}
533+
534+
fn data(&self) -> Cow<'_, [u8]> {
535+
self.to_u16().to_ne_bytes().to_vec().into()
536+
}
537+
}
538+
539+
/// This is implemented for slices as the `SampleFormat` tag takes a count of `N`.
540+
///
541+
/// Use `core::slice::from_ref` if you really need to write a single element.
542+
///
543+
/// See: <https://web.archive.org/web/20191120220815/https://www.awaresystems.be/imaging/tiff/tifftags/sampleformat.html>
544+
impl TiffValue for [tags::SampleFormat] {
545+
const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
546+
const FIELD_TYPE: Type = Type::SHORT;
547+
548+
fn count(&self) -> usize {
549+
self.len()
550+
}
551+
552+
fn data(&self) -> Cow<'_, [u8]> {
553+
let mut buf: Vec<u8> = Vec::with_capacity(self.len() * 2);
554+
for x in self {
555+
buf.extend_from_slice(&x.to_u16().to_ne_bytes());
556+
}
557+
Cow::Owned(buf)
558+
}
559+
}
560+
561+
/// This is implemented for slices as the `ExtraSamples` tag takes a count of `N`.
562+
///
563+
/// Use `core::slice::from_ref` if you really need to write a single element.
564+
///
565+
/// See: <https://web.archive.org/web/20191120220815/https://www.awaresystems.be/imaging/tiff/tifftags/extrasamples.html>
566+
impl TiffValue for [tags::ExtraSamples] {
567+
const BYTE_LEN: u8 = <u16 as TiffValue>::BYTE_LEN;
568+
const FIELD_TYPE: Type = Type::SHORT;
569+
570+
fn count(&self) -> usize {
571+
self.len()
572+
}
573+
574+
fn data(&self) -> Cow<'_, [u8]> {
575+
let mut buf: Vec<u8> = Vec::with_capacity(self.len() * 2);
576+
for x in self {
577+
buf.extend_from_slice(&x.to_u16().to_ne_bytes());
578+
}
579+
Cow::Owned(buf)
580+
}
581+
}
582+
461583
// If you pass `&Vec<_>` then you'd get at first sight the complaint:
462584
//
463585
// `Vec<T>` does not implement `TiffValue`

src/tags.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ macro_rules! tags {
1010
$( #[$enum_attr] )*
1111
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1212
#[non_exhaustive]
13+
#[repr($ty)]
1314
pub enum $name {
14-
$($(#[$ident_attr])* $tag,)*
15+
$($(#[$ident_attr])* $tag = $val,)*
1516
$(
1617
#[$unknown_meta]
1718
Unknown($ty),

0 commit comments

Comments
 (0)