Merge pull request #63 from image-rs/tagged
Replace FromPrimitive with our own tag macro
This commit is contained in:
5 files changed
+163
-77
No files matched your search
@@ -19,8 +19,6 @@ exclude = ["tests/images/*", "tests/fuzz_images/*"]
|
||||
[dependencies]
|
||||
byteorder = "1.2"
|
||||
lzw = "0.10"
|
||||
num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
miniz_oxide = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
+98
-55
@@ -10,27 +10,42 @@ use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
||||
use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational};
|
||||
|
||||
macro_rules! tags {
|
||||
{$(
|
||||
$tag:ident
|
||||
$val:expr;
|
||||
)*} => {
|
||||
|
||||
/// TIFF tag
|
||||
{
|
||||
// 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 Tag {
|
||||
$($tag,)*
|
||||
Unknown(u16)
|
||||
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 Tag {
|
||||
pub fn from_u16(n: u16) -> Tag {
|
||||
$(if n == $val { Tag::$tag } else)* {
|
||||
Tag::Unknown(n)
|
||||
|
||||
impl $name {
|
||||
#[inline(always)]
|
||||
fn __from_inner_type(n: $ty) -> Result<Self, $ty> {
|
||||
match n {
|
||||
$( $val => Ok($name::$tag), )*
|
||||
n => Err(n),
|
||||
}
|
||||
}
|
||||
pub fn to_u16(&self) -> u16 {
|
||||
|
||||
#[inline(always)]
|
||||
fn __to_inner_type(&self) -> $ty {
|
||||
match *self {
|
||||
$( Tag::$tag => $val, )*
|
||||
Tag::Unknown(n) => n,
|
||||
$( $name::$tag => $val, )*
|
||||
$( $name::Unknown(n) => { $unknown_doc; n }, )*
|
||||
$name::__NonExhaustive => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,51 +54,65 @@ macro_rules! tags {
|
||||
|
||||
// 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;
|
||||
Artist = 315,
|
||||
// grayscale images PhotometricInterpretation 1 or 3
|
||||
BitsPerSample 258;
|
||||
CellLength 265; // TODO add support
|
||||
CellWidth 264; // TODO add support
|
||||
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;
|
||||
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;
|
||||
Predictor = 317,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, FromPrimitive)]
|
||||
pub enum Type {
|
||||
impl Tag {
|
||||
pub fn from_u16(val: u16) -> Self {
|
||||
Self::__from_inner_type(val).unwrap_or_else(Tag::Unknown)
|
||||
}
|
||||
|
||||
pub fn to_u16(&self) -> u16 {
|
||||
Self::__to_inner_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
tags! {
|
||||
/// The type of an IFD entry (a 2 byte field).
|
||||
pub enum Type(u16) {
|
||||
BYTE = 1,
|
||||
ASCII = 2,
|
||||
SHORT = 3,
|
||||
@@ -94,6 +123,18 @@ pub enum Type {
|
||||
SLONG = 9,
|
||||
SRATIONAL = 10,
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn from_u16(val: u16) -> Option<Self> {
|
||||
Self::__from_inner_type(val).ok()
|
||||
}
|
||||
|
||||
pub fn to_u16(&self) -> u16 {
|
||||
Self::__to_inner_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[allow(unused_qualifications)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
@@ -104,6 +145,8 @@ pub enum Value {
|
||||
Rational(u32, u32),
|
||||
SRational(i32, i32),
|
||||
Ascii(String),
|
||||
#[doc(hidden)] // Do not match against this.
|
||||
__NonExhaustive,
|
||||
}
|
||||
|
||||
impl Value {
|
||||
|
||||
+63
-15
@@ -1,4 +1,3 @@
|
||||
use num_traits::{FromPrimitive, Num};
|
||||
use std::collections::HashMap;
|
||||
use std::io::{self, Read, Seek};
|
||||
use std::cmp;
|
||||
@@ -9,6 +8,7 @@ use self::ifd::Directory;
|
||||
|
||||
use self::stream::{ByteOrder, EndianReader, LZWReader, DeflateReader, PackBitsReader, SmartReader};
|
||||
|
||||
#[macro_use]
|
||||
pub mod ifd;
|
||||
mod stream;
|
||||
|
||||
@@ -80,8 +80,8 @@ impl<'a> DecodingBuffer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||
pub enum PhotometricInterpretation {
|
||||
tags! {
|
||||
pub enum PhotometricInterpretation(u16) {
|
||||
WhiteIsZero = 0,
|
||||
BlackIsZero = 1,
|
||||
RGB = 2,
|
||||
@@ -91,9 +91,10 @@ pub enum PhotometricInterpretation {
|
||||
YCbCr = 6,
|
||||
CIELab = 8,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||
pub enum CompressionMethod {
|
||||
tags! {
|
||||
pub enum CompressionMethod(u16) {
|
||||
None = 1,
|
||||
Huffman = 2,
|
||||
Fax3 = 3,
|
||||
@@ -104,18 +105,61 @@ pub enum CompressionMethod {
|
||||
OldDeflate = 0x80B2,
|
||||
PackBits = 0x8005,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||
pub enum PlanarConfiguration {
|
||||
tags! {
|
||||
pub enum PlanarConfiguration(u16) {
|
||||
Chunky = 1,
|
||||
Planar = 2,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||
enum Predictor {
|
||||
tags! {
|
||||
enum Predictor(u16) {
|
||||
None = 1,
|
||||
Horizontal = 2,
|
||||
}
|
||||
}
|
||||
|
||||
impl PhotometricInterpretation {
|
||||
pub fn from_u16(val: u16) -> Option<Self> {
|
||||
Self::__from_inner_type(val).ok()
|
||||
}
|
||||
|
||||
pub fn to_u16(&self) -> u16 {
|
||||
Self::__to_inner_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl CompressionMethod {
|
||||
pub fn from_u16(val: u16) -> Option<Self> {
|
||||
Self::__from_inner_type(val).ok()
|
||||
}
|
||||
|
||||
pub fn to_u16(&self) -> u16 {
|
||||
Self::__to_inner_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PlanarConfiguration {
|
||||
pub fn from_u16(val: u16) -> Option<Self> {
|
||||
Self::__from_inner_type(val).ok()
|
||||
}
|
||||
|
||||
pub fn to_u16(&self) -> u16 {
|
||||
Self::__to_inner_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Predictor {
|
||||
pub fn from_u16(val: u16) -> Option<Self> {
|
||||
Self::__from_inner_type(val).ok()
|
||||
}
|
||||
|
||||
pub fn to_u16(&self) -> u16 {
|
||||
Self::__to_inner_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StripDecodeState {
|
||||
@@ -191,7 +235,7 @@ impl Wrapping for u16 {
|
||||
|
||||
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize)
|
||||
where
|
||||
T: Num + Copy + Wrapping,
|
||||
T: Copy + Wrapping,
|
||||
{
|
||||
let width = size.0 as usize;
|
||||
let height = size.1 as usize;
|
||||
@@ -334,8 +378,9 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
self.width = self.get_tag_u32(ifd::Tag::ImageWidth)?;
|
||||
self.height = self.get_tag_u32(ifd::Tag::ImageLength)?;
|
||||
self.strip_decoder = None;
|
||||
self.photometric_interpretation = match FromPrimitive::from_u32(
|
||||
self.get_tag_u32(ifd::Tag::PhotometricInterpretation)?
|
||||
// TODO: error on non-SHORT value.
|
||||
self.photometric_interpretation = match PhotometricInterpretation::from_u16(
|
||||
self.get_tag_u32(ifd::Tag::PhotometricInterpretation)? as u16
|
||||
) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
@@ -344,8 +389,9 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
))
|
||||
}
|
||||
};
|
||||
// TODO: error on non-SHORT value.
|
||||
if let Some(val) = self.find_tag_u32(ifd::Tag::Compression)? {
|
||||
match FromPrimitive::from_u32(val) {
|
||||
match CompressionMethod::from_u16(val as u16) {
|
||||
Some(method) => self.compression_method = method,
|
||||
None => {
|
||||
return Err(TiffError::UnsupportedError(
|
||||
@@ -454,7 +500,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
// 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(self.read_short()?);
|
||||
let type_: ifd::Type = match FromPrimitive::from_u16(self.read_short()?) {
|
||||
let type_ = match ifd::Type::from_u16(self.read_short()?) {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
// Unknown type. Skip this entry according to spec.
|
||||
@@ -720,7 +766,8 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
));
|
||||
}
|
||||
if let Ok(predictor) = self.get_tag_u32(ifd::Tag::Predictor) {
|
||||
match FromPrimitive::from_u32(predictor) {
|
||||
// TODO: error on non-SHORT value.
|
||||
match Predictor::from_u16(predictor as u16) {
|
||||
Some(Predictor::None) => (),
|
||||
Some(Predictor::Horizontal) => {
|
||||
rev_hpredict(
|
||||
@@ -734,6 +781,7 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
predictor,
|
||||
)))
|
||||
}
|
||||
Some(Predictor::__NonExhaustive) => unreachable!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
+2
-2
@@ -441,7 +441,7 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> {
|
||||
}
|
||||
|
||||
self.ifd
|
||||
.insert(tag.to_u16(), (<T>::FIELD_TYPE as u16, value.count(), bytes));
|
||||
.insert(tag.to_u16(), (<T>::FIELD_TYPE.to_u16(), value.count(), bytes));
|
||||
}
|
||||
|
||||
fn write_directory(&mut self) -> TiffResult<u64> {
|
||||
@@ -568,7 +568,7 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
|
||||
encoder.write_tag(Tag::Compression, 1u16);
|
||||
|
||||
encoder.write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE);
|
||||
encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE as u16);
|
||||
encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16());
|
||||
|
||||
encoder.write_tag(Tag::RowsPerStrip, rows_per_strip as u32);
|
||||
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
extern crate byteorder;
|
||||
extern crate lzw;
|
||||
extern crate miniz_oxide;
|
||||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
extern crate num_traits;
|
||||
|
||||
pub mod decoder;
|
||||
pub mod encoder;
|
||||
|
||||
Reference in new issue
Block a user