Factor tags into own module
Tag representations are not decoder- or encoder-specific, so should live in their own module accessible to both for reuse. The decoder::ifd module remains since this module is mainly dedicated to decoding the IFD.
This commit is contained in:
1 parent
f9cace84da
commit
f92be13f6c
9 files changed
+242
-238
No files matched your search
+1
-138
@@ -5,148 +5,11 @@ use std::io::{self, Read, Seek};
|
||||
use std::mem;
|
||||
|
||||
use super::stream::{ByteOrder, EndianReader, SmartReader};
|
||||
use tags::{Tag, Type};
|
||||
use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
||||
|
||||
use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational};
|
||||
|
||||
pub(crate) mod seals {
|
||||
pub trait TagConversion<T>: Sized {
|
||||
fn __from_inner_type(T) -> Result<Self, T>;
|
||||
|
||||
fn __to_inner_type(&self) -> T;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait U16Tag: Sized {
|
||||
fn from_u16(val: u16) -> Option<Self>;
|
||||
|
||||
fn to_u16(&self) -> u16;
|
||||
}
|
||||
|
||||
impl<T: seals::TagConversion<u16>> U16Tag for T {
|
||||
fn from_u16(val: u16) -> Option<Self> {
|
||||
Self::__from_inner_type(val).ok()
|
||||
}
|
||||
|
||||
fn to_u16(&self) -> u16 {
|
||||
Self::__to_inner_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tags {
|
||||
{
|
||||
// Permit arbitrary meta items, which include documentation.
|
||||
$( #[$enum_attr:meta] )*
|
||||
$vis:vis enum $name:ident($ty:ty) $(unknown($unknown_doc:literal))* {
|
||||
// Each of the `Name = Val,` permitting documentation.
|
||||
$($(#[$ident_attr:meta])* $tag:ident = $val:expr,)*
|
||||
}
|
||||
} => {
|
||||
$( #[$enum_attr] )*
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum $name {
|
||||
$($(#[$ident_attr])* $tag,)*
|
||||
// FIXME: switch to non_exhaustive once stabilized and compiler requirement new enough
|
||||
#[doc(hidden)]
|
||||
__NonExhaustive,
|
||||
$(
|
||||
#[doc = $unknown_doc]
|
||||
Unknown($ty),
|
||||
)*
|
||||
}
|
||||
|
||||
impl ::decoder::ifd::seals::TagConversion<$ty> for $name {
|
||||
#[inline(always)]
|
||||
fn __from_inner_type(n: $ty) -> Result<Self, $ty> {
|
||||
match n {
|
||||
$( $val => Ok($name::$tag), )*
|
||||
n => Err(n),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn __to_inner_type(&self) -> $ty {
|
||||
match *self {
|
||||
$( $name::$tag => $val, )*
|
||||
$( $name::Unknown(n) => { $unknown_doc; n }, )*
|
||||
$name::__NonExhaustive => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: These tags appear in the order they are mentioned in the TIFF reference
|
||||
tags! {
|
||||
/// TIFF tags
|
||||
pub enum Tag(u16) unknown("A private or extension tag") {
|
||||
// Baseline tags:
|
||||
Artist = 315,
|
||||
// grayscale images PhotometricInterpretation 1 or 3
|
||||
BitsPerSample = 258,
|
||||
CellLength = 265, // TODO add support
|
||||
CellWidth = 264, // TODO add support
|
||||
// palette-color images (PhotometricInterpretation 3)
|
||||
ColorMap = 320, // TODO add support
|
||||
Compression = 259, // TODO add support for 2 and 32773
|
||||
Copyright = 33_432,
|
||||
DateTime = 306,
|
||||
ExtraSamples = 338, // TODO add support
|
||||
FillOrder = 266, // TODO add support
|
||||
FreeByteCounts = 289, // TODO add support
|
||||
FreeOffsets = 288, // TODO add support
|
||||
GrayResponseCurve = 291, // TODO add support
|
||||
GrayResponseUnit = 290, // TODO add support
|
||||
HostComputer = 316,
|
||||
ImageDescription = 270,
|
||||
ImageLength = 257,
|
||||
ImageWidth = 256,
|
||||
Make = 271,
|
||||
MaxSampleValue = 281, // TODO add support
|
||||
MinSampleValue = 280, // TODO add support
|
||||
Model = 272,
|
||||
NewSubfileType = 254, // TODO add support
|
||||
Orientation = 274, // TODO add support
|
||||
PhotometricInterpretation = 262,
|
||||
PlanarConfiguration = 284,
|
||||
ResolutionUnit = 296, // TODO add support
|
||||
RowsPerStrip = 278,
|
||||
SamplesPerPixel = 277,
|
||||
Software = 305,
|
||||
StripByteCounts = 279,
|
||||
StripOffsets = 273,
|
||||
SubfileType = 255, // TODO add support
|
||||
Threshholding = 263, // TODO add support
|
||||
XResolution = 282,
|
||||
YResolution = 283,
|
||||
// Advanced tags
|
||||
Predictor = 317,
|
||||
}
|
||||
}
|
||||
|
||||
impl Tag {
|
||||
pub fn from_u16_exhaustive(val: u16) -> Self {
|
||||
Self::from_u16(val).unwrap_or_else(|| Tag::Unknown(val))
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
/// The type of an IFD entry (a 2 byte field).
|
||||
pub enum Type(u16) {
|
||||
BYTE = 1,
|
||||
ASCII = 2,
|
||||
SHORT = 3,
|
||||
LONG = 4,
|
||||
RATIONAL = 5,
|
||||
SBYTE = 6,
|
||||
SSHORT = 8,
|
||||
SLONG = 9,
|
||||
SRATIONAL = 10,
|
||||
/// BigTIFF 64-bit unsigned integer
|
||||
LONG8 = 16,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[allow(unused_qualifications)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
||||
+25
-66
@@ -5,11 +5,11 @@ use std::cmp;
|
||||
|
||||
use {ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
||||
|
||||
use self::ifd::{Directory, U16Tag};
|
||||
use self::ifd::Directory;
|
||||
use tags::{CompressionMethod, PhotometricInterpretation, Predictor, Tag, Type, U16Tag};
|
||||
|
||||
use self::stream::{ByteOrder, EndianReader, LZWReader, DeflateReader, PackBitsReader, SmartReader};
|
||||
|
||||
#[macro_use]
|
||||
pub mod ifd;
|
||||
mod stream;
|
||||
|
||||
@@ -113,47 +113,6 @@ impl<'a> DecodingBuffer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
pub enum PhotometricInterpretation(u16) {
|
||||
WhiteIsZero = 0,
|
||||
BlackIsZero = 1,
|
||||
RGB = 2,
|
||||
RGBPalette = 3,
|
||||
TransparencyMask = 4,
|
||||
CMYK = 5,
|
||||
YCbCr = 6,
|
||||
CIELab = 8,
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
pub enum CompressionMethod(u16) {
|
||||
None = 1,
|
||||
Huffman = 2,
|
||||
Fax3 = 3,
|
||||
Fax4 = 4,
|
||||
LZW = 5,
|
||||
JPEG = 6,
|
||||
Deflate = 8,
|
||||
OldDeflate = 0x80B2,
|
||||
PackBits = 0x8005,
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
pub enum PlanarConfiguration(u16) {
|
||||
Chunky = 1,
|
||||
Planar = 2,
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
enum Predictor(u16) {
|
||||
None = 1,
|
||||
Horizontal = 2,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StripDecodeState {
|
||||
strip_index: usize,
|
||||
@@ -385,24 +344,24 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
/// To determine whether there are more images call `TIFFDecoder::more_images` instead.
|
||||
pub fn next_image(&mut self) -> TiffResult<()> {
|
||||
self.ifd = Some(self.read_ifd()?);
|
||||
self.width = self.get_tag_u32(ifd::Tag::ImageWidth)?;
|
||||
self.height = self.get_tag_u32(ifd::Tag::ImageLength)?;
|
||||
self.width = self.get_tag_u32(Tag::ImageWidth)?;
|
||||
self.height = self.get_tag_u32(Tag::ImageLength)?;
|
||||
self.strip_decoder = None;
|
||||
|
||||
self.photometric_interpretation = self
|
||||
.find_tag_unsigned(ifd::Tag::PhotometricInterpretation)?
|
||||
.find_tag_unsigned(Tag::PhotometricInterpretation)?
|
||||
.and_then(PhotometricInterpretation::from_u16)
|
||||
.ok_or(TiffUnsupportedError::UnknownInterpretation)?;
|
||||
|
||||
if let Some(val) = self.find_tag_unsigned(ifd::Tag::Compression)? {
|
||||
if let Some(val) = self.find_tag_unsigned(Tag::Compression)? {
|
||||
self.compression_method = CompressionMethod::from_u16(val)
|
||||
.ok_or(TiffUnsupportedError::UnknownCompressionMethod)?;
|
||||
}
|
||||
if let Some(val) = self.find_tag_unsigned(ifd::Tag::SamplesPerPixel)? {
|
||||
if let Some(val) = self.find_tag_unsigned(Tag::SamplesPerPixel)? {
|
||||
self.samples = val;
|
||||
}
|
||||
match self.samples {
|
||||
1 | 3 | 4 => if let Some(val) = self.find_tag_unsigned_vec(ifd::Tag::BitsPerSample)? {
|
||||
1 | 3 | 4 => if let Some(val) = self.find_tag_unsigned_vec(Tag::BitsPerSample)? {
|
||||
self.bits_per_sample = val;
|
||||
},
|
||||
_ => return Err(TiffUnsupportedError::UnsupportedSampleDepth(self.samples).into()),
|
||||
@@ -485,9 +444,9 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
// Type 2 bytes
|
||||
// Count 4 bytes
|
||||
// Value 4 bytes either a pointer the value itself
|
||||
fn read_entry(&mut self) -> TiffResult<Option<(ifd::Tag, ifd::Entry)>> {
|
||||
let tag = ifd::Tag::from_u16_exhaustive(self.read_short()?);
|
||||
let type_ = match ifd::Type::from_u16(self.read_short()?) {
|
||||
fn read_entry(&mut self) -> TiffResult<Option<(Tag, ifd::Entry)>> {
|
||||
let tag = Tag::from_u16_exhaustive(self.read_short()?);
|
||||
let type_ = match Type::from_u16(self.read_short()?) {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
// Unknown type. Skip this entry according to spec.
|
||||
@@ -533,7 +492,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
|
||||
/// Tries to retrieve a tag.
|
||||
/// Return `Ok(None)` if the tag is not present.
|
||||
pub fn find_tag(&mut self, tag: ifd::Tag) -> TiffResult<Option<ifd::Value>> {
|
||||
pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> {
|
||||
let entry = match self.ifd.as_ref().unwrap().get(&tag) {
|
||||
None => return Ok(None),
|
||||
Some(entry) => entry.clone(),
|
||||
@@ -545,7 +504,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
}
|
||||
|
||||
/// Tries to retrieve a tag and convert it to the desired unsigned type.
|
||||
pub fn find_tag_unsigned<T: TryFrom<u32>>(&mut self, tag: ifd::Tag) -> TiffResult<Option<T>> {
|
||||
pub fn find_tag_unsigned<T: TryFrom<u32>>(&mut self, tag: Tag) -> TiffResult<Option<T>> {
|
||||
self.find_tag(tag)?
|
||||
.map(|v| v.into_u32()).transpose()?
|
||||
.map(|value| T::try_from(value)
|
||||
@@ -555,7 +514,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
|
||||
/// Tries to retrieve a vector of all a tag's values and convert them to
|
||||
/// the desired unsigned type.
|
||||
pub fn find_tag_unsigned_vec<T: TryFrom<u32>>(&mut self, tag: ifd::Tag) -> TiffResult<Option<Vec<T>>> {
|
||||
pub fn find_tag_unsigned_vec<T: TryFrom<u32>>(&mut self, tag: Tag) -> TiffResult<Option<Vec<T>>> {
|
||||
self.find_tag(tag)?
|
||||
.map(|v| v.into_u32_vec()).transpose()?
|
||||
.map(|v| v.into_iter()
|
||||
@@ -566,14 +525,14 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
|
||||
/// Tries to retrieve a tag and convert it to the desired unsigned type.
|
||||
/// Returns an error if the tag is not present.
|
||||
pub fn get_tag_unsigned<T: TryFrom<u32>>(&mut self, tag: ifd::Tag) -> TiffResult<T> {
|
||||
pub fn get_tag_unsigned<T: TryFrom<u32>>(&mut self, tag: Tag) -> TiffResult<T> {
|
||||
self.find_tag_unsigned(tag)?
|
||||
.ok_or_else(|| TiffFormatError::RequiredTagNotFound(tag).into())
|
||||
}
|
||||
|
||||
/// Tries to retrieve a tag.
|
||||
/// Returns an error if the tag is not present
|
||||
pub fn get_tag(&mut self, tag: ifd::Tag) -> TiffResult<ifd::Value> {
|
||||
pub fn get_tag(&mut self, tag: Tag) -> TiffResult<ifd::Value> {
|
||||
match self.find_tag(tag)? {
|
||||
Some(val) => Ok(val),
|
||||
None => Err(TiffError::FormatError(
|
||||
@@ -583,12 +542,12 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
}
|
||||
|
||||
/// Tries to retrieve a tag and convert it to the desired type.
|
||||
pub fn get_tag_u32(&mut self, tag: ifd::Tag) -> TiffResult<u32> {
|
||||
pub fn get_tag_u32(&mut self, tag: Tag) -> TiffResult<u32> {
|
||||
self.get_tag(tag)?.into_u32()
|
||||
}
|
||||
|
||||
/// Tries to retrieve a tag and convert it to the desired type.
|
||||
pub fn get_tag_u32_vec(&mut self, tag: ifd::Tag) -> TiffResult<Vec<u32>> {
|
||||
pub fn get_tag_u32_vec(&mut self, tag: Tag) -> TiffResult<Vec<u32>> {
|
||||
self.get_tag(tag)?.into_u32_vec()
|
||||
}
|
||||
|
||||
@@ -714,7 +673,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
/// Number of strips in image
|
||||
pub fn strip_count(&mut self) -> TiffResult<u32> {
|
||||
let rows_per_strip = self
|
||||
.get_tag_u32(ifd::Tag::RowsPerStrip)
|
||||
.get_tag_u32(Tag::RowsPerStrip)
|
||||
.unwrap_or(self.height);
|
||||
|
||||
if rows_per_strip == 0 {
|
||||
@@ -726,8 +685,8 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
|
||||
fn initialize_strip_decoder(&mut self) -> TiffResult<()> {
|
||||
if self.strip_decoder.is_none() {
|
||||
let strip_offsets = self.get_tag_u32_vec(ifd::Tag::StripOffsets)?;
|
||||
let strip_bytes = self.get_tag_u32_vec(ifd::Tag::StripByteCounts)?;
|
||||
let strip_offsets = self.get_tag_u32_vec(Tag::StripOffsets)?;
|
||||
let strip_bytes = self.get_tag_u32_vec(Tag::StripByteCounts)?;
|
||||
|
||||
self.strip_decoder = Some(StripDecodeState {
|
||||
strip_index: 0,
|
||||
@@ -762,7 +721,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
))?;
|
||||
|
||||
let rows_per_strip = self
|
||||
.get_tag_u32(ifd::Tag::RowsPerStrip)
|
||||
.get_tag_u32(Tag::RowsPerStrip)
|
||||
.unwrap_or(self.height) as usize;
|
||||
|
||||
let strip_height = cmp::min(
|
||||
@@ -791,7 +750,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
TiffFormatError::InconsistentSizesEncountered,
|
||||
));
|
||||
}
|
||||
if let Ok(predictor) = self.get_tag_unsigned(ifd::Tag::Predictor) {
|
||||
if let Ok(predictor) = self.get_tag_unsigned(Tag::Predictor) {
|
||||
match Predictor::from_u16(predictor) {
|
||||
Some(Predictor::None) => (),
|
||||
Some(Predictor::Horizontal) => {
|
||||
@@ -834,7 +793,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
let index = self.strip_decoder.as_ref().unwrap().strip_index;
|
||||
|
||||
let rows_per_strip = self
|
||||
.get_tag_u32(ifd::Tag::RowsPerStrip)
|
||||
.get_tag_u32(Tag::RowsPerStrip)
|
||||
.unwrap_or(self.height) as usize;
|
||||
|
||||
let strip_height = cmp::min(
|
||||
@@ -853,7 +812,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
pub fn read_image(&mut self) -> TiffResult<DecodingResult> {
|
||||
self.initialize_strip_decoder()?;
|
||||
let rows_per_strip = self
|
||||
.get_tag_u32(ifd::Tag::RowsPerStrip)
|
||||
.get_tag_u32(Tag::RowsPerStrip)
|
||||
.unwrap_or(self.height) as usize;
|
||||
|
||||
let samples_per_strip =
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use decoder::PhotometricInterpretation;
|
||||
use tags::PhotometricInterpretation;
|
||||
|
||||
/// Trait for different colortypes that can be encoded.
|
||||
pub trait ColorType {
|
||||
|
||||
+22
-29
@@ -3,7 +3,7 @@ use std::collections::BTreeMap;
|
||||
use std::io::{Seek, Write};
|
||||
use std::mem;
|
||||
|
||||
use decoder::ifd::{self, Tag, U16Tag};
|
||||
use tags::{self, ResolutionUnit, Tag, Type, U16Tag};
|
||||
use error::{TiffError, TiffFormatError, TiffResult};
|
||||
|
||||
pub mod colortype;
|
||||
@@ -25,17 +25,10 @@ pub struct SRational {
|
||||
pub d: i32,
|
||||
}
|
||||
|
||||
/// Type to represent resolution units
|
||||
pub enum ResolutionUnit {
|
||||
None = 1,
|
||||
Inch = 2,
|
||||
Centimeter = 3,
|
||||
}
|
||||
|
||||
/// Trait for types that can be encoded in a tiff file
|
||||
pub trait TiffValue {
|
||||
const BYTE_LEN: u32;
|
||||
const FIELD_TYPE: ifd::Type;
|
||||
const FIELD_TYPE: Type;
|
||||
fn count(&self) -> u32;
|
||||
fn bytes(&self) -> u32 {
|
||||
self.count() * Self::BYTE_LEN
|
||||
@@ -45,7 +38,7 @@ pub trait TiffValue {
|
||||
|
||||
impl TiffValue for [u8] {
|
||||
const BYTE_LEN: u32 = 1;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::BYTE;
|
||||
const FIELD_TYPE: Type = Type::BYTE;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -59,7 +52,7 @@ impl TiffValue for [u8] {
|
||||
|
||||
impl TiffValue for [i8] {
|
||||
const BYTE_LEN: u32 = 1;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SBYTE;
|
||||
const FIELD_TYPE: Type = Type::SBYTE;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -76,7 +69,7 @@ impl TiffValue for [i8] {
|
||||
|
||||
impl TiffValue for [u16] {
|
||||
const BYTE_LEN: u32 = 2;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SHORT;
|
||||
const FIELD_TYPE: Type = Type::SHORT;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -93,7 +86,7 @@ impl TiffValue for [u16] {
|
||||
|
||||
impl TiffValue for [i16] {
|
||||
const BYTE_LEN: u32 = 2;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SSHORT;
|
||||
const FIELD_TYPE: Type = Type::SSHORT;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -110,7 +103,7 @@ impl TiffValue for [i16] {
|
||||
|
||||
impl TiffValue for [u32] {
|
||||
const BYTE_LEN: u32 = 4;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::LONG;
|
||||
const FIELD_TYPE: Type = Type::LONG;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -127,7 +120,7 @@ impl TiffValue for [u32] {
|
||||
|
||||
impl TiffValue for [i32] {
|
||||
const BYTE_LEN: u32 = 4;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SLONG;
|
||||
const FIELD_TYPE: Type = Type::SLONG;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -144,7 +137,7 @@ impl TiffValue for [i32] {
|
||||
|
||||
impl TiffValue for [u64] {
|
||||
const BYTE_LEN: u32 = 8;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::LONG8;
|
||||
const FIELD_TYPE: Type = Type::LONG8;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -161,7 +154,7 @@ impl TiffValue for [u64] {
|
||||
|
||||
impl TiffValue for [Rational] {
|
||||
const BYTE_LEN: u32 = 8;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL;
|
||||
const FIELD_TYPE: Type = Type::RATIONAL;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -177,7 +170,7 @@ impl TiffValue for [Rational] {
|
||||
|
||||
impl TiffValue for [SRational] {
|
||||
const BYTE_LEN: u32 = 8;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SRATIONAL;
|
||||
const FIELD_TYPE: Type = Type::SRATIONAL;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32
|
||||
@@ -193,7 +186,7 @@ impl TiffValue for [SRational] {
|
||||
|
||||
impl TiffValue for u8 {
|
||||
const BYTE_LEN: u32 = 1;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::BYTE;
|
||||
const FIELD_TYPE: Type = Type::BYTE;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -207,7 +200,7 @@ impl TiffValue for u8 {
|
||||
|
||||
impl TiffValue for i8 {
|
||||
const BYTE_LEN: u32 = 1;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SBYTE;
|
||||
const FIELD_TYPE: Type = Type::SBYTE;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -221,7 +214,7 @@ impl TiffValue for i8 {
|
||||
|
||||
impl TiffValue for u16 {
|
||||
const BYTE_LEN: u32 = 2;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SHORT;
|
||||
const FIELD_TYPE: Type = Type::SHORT;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -235,7 +228,7 @@ impl TiffValue for u16 {
|
||||
|
||||
impl TiffValue for i16 {
|
||||
const BYTE_LEN: u32 = 2;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SSHORT;
|
||||
const FIELD_TYPE: Type = Type::SSHORT;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -249,7 +242,7 @@ impl TiffValue for i16 {
|
||||
|
||||
impl TiffValue for u32 {
|
||||
const BYTE_LEN: u32 = 4;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::LONG;
|
||||
const FIELD_TYPE: Type = Type::LONG;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -263,7 +256,7 @@ impl TiffValue for u32 {
|
||||
|
||||
impl TiffValue for i32 {
|
||||
const BYTE_LEN: u32 = 4;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SLONG;
|
||||
const FIELD_TYPE: Type = Type::SLONG;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -277,7 +270,7 @@ impl TiffValue for i32 {
|
||||
|
||||
impl TiffValue for u64 {
|
||||
const BYTE_LEN: u32 = 8;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::LONG8;
|
||||
const FIELD_TYPE: Type = Type::LONG8;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -291,7 +284,7 @@ impl TiffValue for u64 {
|
||||
|
||||
impl TiffValue for Rational {
|
||||
const BYTE_LEN: u32 = 8;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL;
|
||||
const FIELD_TYPE: Type = Type::RATIONAL;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -306,7 +299,7 @@ impl TiffValue for Rational {
|
||||
|
||||
impl TiffValue for SRational {
|
||||
const BYTE_LEN: u32 = 8;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::SRATIONAL;
|
||||
const FIELD_TYPE: Type = Type::SRATIONAL;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
1
|
||||
@@ -321,7 +314,7 @@ impl TiffValue for SRational {
|
||||
|
||||
impl TiffValue for str {
|
||||
const BYTE_LEN: u32 = 1;
|
||||
const FIELD_TYPE: ifd::Type = ifd::Type::ASCII;
|
||||
const FIELD_TYPE: Type = Type::ASCII;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
self.len() as u32 + 1
|
||||
@@ -340,7 +333,7 @@ impl TiffValue for str {
|
||||
|
||||
impl<'a, T: TiffValue + ?Sized> TiffValue for &'a T {
|
||||
const BYTE_LEN: u32 = T::BYTE_LEN;
|
||||
const FIELD_TYPE: ifd::Type = T::FIELD_TYPE;
|
||||
const FIELD_TYPE: Type = T::FIELD_TYPE;
|
||||
|
||||
fn count(&self) -> u32 {
|
||||
(*self).count()
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@ use std::fmt;
|
||||
use std::io;
|
||||
use std::string;
|
||||
|
||||
use decoder::ifd::{Tag, Value};
|
||||
use decoder::{CompressionMethod, PhotometricInterpretation, PlanarConfiguration};
|
||||
use decoder::ifd::{Value};
|
||||
use tags::{CompressionMethod, PhotometricInterpretation, PlanarConfiguration, Tag};
|
||||
use miniz_oxide::inflate::TINFLStatus;
|
||||
use ColorType;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ extern crate miniz_oxide;
|
||||
pub mod decoder;
|
||||
pub mod encoder;
|
||||
mod error;
|
||||
pub mod tags;
|
||||
|
||||
pub use self::error::{InflateError, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
||||
|
||||
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
mod seals {
|
||||
pub trait TagConversion<T>: Sized {
|
||||
fn __from_inner_type(T) -> Result<Self, T>;
|
||||
|
||||
fn __to_inner_type(&self) -> T;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait U16Tag: Sized {
|
||||
fn from_u16(val: u16) -> Option<Self>;
|
||||
|
||||
fn to_u16(&self) -> u16;
|
||||
}
|
||||
|
||||
impl<T: seals::TagConversion<u16>> U16Tag for T {
|
||||
fn from_u16(val: u16) -> Option<Self> {
|
||||
Self::__from_inner_type(val).ok()
|
||||
}
|
||||
|
||||
fn to_u16(&self) -> u16 {
|
||||
Self::__to_inner_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tags {
|
||||
{
|
||||
// Permit arbitrary meta items, which include documentation.
|
||||
$( #[$enum_attr:meta] )*
|
||||
$vis:vis enum $name:ident($ty:ty) $(unknown($unknown_doc:literal))* {
|
||||
// Each of the `Name = Val,` permitting documentation.
|
||||
$($(#[$ident_attr:meta])* $tag:ident = $val:expr,)*
|
||||
}
|
||||
} => {
|
||||
$( #[$enum_attr] )*
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum $name {
|
||||
$($(#[$ident_attr])* $tag,)*
|
||||
// FIXME: switch to non_exhaustive once stabilized and compiler requirement new enough
|
||||
#[doc(hidden)]
|
||||
__NonExhaustive,
|
||||
$(
|
||||
#[doc = $unknown_doc]
|
||||
Unknown($ty),
|
||||
)*
|
||||
}
|
||||
|
||||
impl ::tags::seals::TagConversion<$ty> for $name {
|
||||
#[inline(always)]
|
||||
fn __from_inner_type(n: $ty) -> Result<Self, $ty> {
|
||||
match n {
|
||||
$( $val => Ok($name::$tag), )*
|
||||
n => Err(n),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn __to_inner_type(&self) -> $ty {
|
||||
match *self {
|
||||
$( $name::$tag => $val, )*
|
||||
$( $name::Unknown(n) => { $unknown_doc; n }, )*
|
||||
$name::__NonExhaustive => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: These tags appear in the order they are mentioned in the TIFF reference
|
||||
tags! {
|
||||
/// TIFF tags
|
||||
pub enum Tag(u16) unknown("A private or extension tag") {
|
||||
// Baseline tags:
|
||||
Artist = 315,
|
||||
// grayscale images PhotometricInterpretation 1 or 3
|
||||
BitsPerSample = 258,
|
||||
CellLength = 265, // TODO add support
|
||||
CellWidth = 264, // TODO add support
|
||||
// palette-color images (PhotometricInterpretation 3)
|
||||
ColorMap = 320, // TODO add support
|
||||
Compression = 259, // TODO add support for 2 and 32773
|
||||
Copyright = 33_432,
|
||||
DateTime = 306,
|
||||
ExtraSamples = 338, // TODO add support
|
||||
FillOrder = 266, // TODO add support
|
||||
FreeByteCounts = 289, // TODO add support
|
||||
FreeOffsets = 288, // TODO add support
|
||||
GrayResponseCurve = 291, // TODO add support
|
||||
GrayResponseUnit = 290, // TODO add support
|
||||
HostComputer = 316,
|
||||
ImageDescription = 270,
|
||||
ImageLength = 257,
|
||||
ImageWidth = 256,
|
||||
Make = 271,
|
||||
MaxSampleValue = 281, // TODO add support
|
||||
MinSampleValue = 280, // TODO add support
|
||||
Model = 272,
|
||||
NewSubfileType = 254, // TODO add support
|
||||
Orientation = 274, // TODO add support
|
||||
PhotometricInterpretation = 262,
|
||||
PlanarConfiguration = 284,
|
||||
ResolutionUnit = 296, // TODO add support
|
||||
RowsPerStrip = 278,
|
||||
SamplesPerPixel = 277,
|
||||
Software = 305,
|
||||
StripByteCounts = 279,
|
||||
StripOffsets = 273,
|
||||
SubfileType = 255, // TODO add support
|
||||
Threshholding = 263, // TODO add support
|
||||
XResolution = 282,
|
||||
YResolution = 283,
|
||||
// Advanced tags
|
||||
Predictor = 317,
|
||||
}
|
||||
}
|
||||
|
||||
impl Tag {
|
||||
pub fn from_u16_exhaustive(val: u16) -> Self {
|
||||
Self::from_u16(val).unwrap_or_else(|| Tag::Unknown(val))
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
/// The type of an IFD entry (a 2 byte field).
|
||||
pub enum Type(u16) {
|
||||
BYTE = 1,
|
||||
ASCII = 2,
|
||||
SHORT = 3,
|
||||
LONG = 4,
|
||||
RATIONAL = 5,
|
||||
SBYTE = 6,
|
||||
SSHORT = 8,
|
||||
SLONG = 9,
|
||||
SRATIONAL = 10,
|
||||
/// BigTIFF 64-bit unsigned integer
|
||||
LONG8 = 16,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tags! {
|
||||
pub enum CompressionMethod(u16) {
|
||||
None = 1,
|
||||
Huffman = 2,
|
||||
Fax3 = 3,
|
||||
Fax4 = 4,
|
||||
LZW = 5,
|
||||
JPEG = 6,
|
||||
Deflate = 8,
|
||||
OldDeflate = 0x80B2,
|
||||
PackBits = 0x8005,
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
pub enum PhotometricInterpretation(u16) {
|
||||
WhiteIsZero = 0,
|
||||
BlackIsZero = 1,
|
||||
RGB = 2,
|
||||
RGBPalette = 3,
|
||||
TransparencyMask = 4,
|
||||
CMYK = 5,
|
||||
YCbCr = 6,
|
||||
CIELab = 8,
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
pub enum PlanarConfiguration(u16) {
|
||||
Chunky = 1,
|
||||
Planar = 2,
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
pub enum Predictor(u16) {
|
||||
None = 1,
|
||||
Horizontal = 2,
|
||||
}
|
||||
}
|
||||
|
||||
tags!{
|
||||
/// Type to represent resolution units
|
||||
pub enum ResolutionUnit(u16) {
|
||||
None = 1,
|
||||
Inch = 2,
|
||||
Centimeter = 3,
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ fn test_string_tags() {
|
||||
let path = PathBuf::from(TEST_IMAGE_DIR).join(filename);
|
||||
let img_file = File::open(path).expect("Cannot find test image!");
|
||||
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
let software = decoder.get_tag(ifd::Tag::Software).unwrap();
|
||||
let software = decoder.get_tag(tiff::tags::Tag::Software).unwrap();
|
||||
match software {
|
||||
ifd::Value::Ascii(s) => assert_eq!(
|
||||
&s,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
extern crate tiff;
|
||||
|
||||
use tiff::decoder::{Decoder, DecodingResult};
|
||||
use tiff::decoder::ifd::Tag;
|
||||
use tiff::encoder::{colortype, TiffEncoder, SRational};
|
||||
use tiff::ColorType;
|
||||
use tiff::tags::Tag;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Cursor, Seek, SeekFrom};
|
||||
|
||||
Reference in new issue
Block a user