Skip to content

Commit ee8d132

Browse files
committed
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.
1 parent 169a896 commit ee8d132

File tree

2 files changed

+124
-2
lines changed

2 files changed

+124
-2
lines changed

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`

0 commit comments

Comments
 (0)