Merge pull request #63 from image-rs/tagged
Replace FromPrimitive with our own tag macro
This commit is contained in:
5 files changed
+164
-78
No files matched your search
@@ -19,8 +19,6 @@ exclude = ["tests/images/*", "tests/fuzz_images/*"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.2"
|
byteorder = "1.2"
|
||||||
lzw = "0.10"
|
lzw = "0.10"
|
||||||
num-derive = "0.3"
|
|
||||||
num-traits = "0.2"
|
|
||||||
miniz_oxide = "0.3"
|
miniz_oxide = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
+99
-56
@@ -10,27 +10,42 @@ use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
|||||||
use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational};
|
use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational};
|
||||||
|
|
||||||
macro_rules! tags {
|
macro_rules! tags {
|
||||||
{$(
|
{
|
||||||
$tag:ident
|
// Permit arbitrary meta items, which include documentation.
|
||||||
$val:expr;
|
$( #[$enum_attr:meta] )*
|
||||||
)*} => {
|
$vis:vis enum $name:ident($ty:ty) $(unknown($unknown_doc:literal))* {
|
||||||
|
// Each of the `Name = Val,` permitting documentation.
|
||||||
/// TIFF tag
|
$($(#[$ident_attr:meta])* $tag:ident = $val:expr,)*
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
|
||||||
pub enum Tag {
|
|
||||||
$($tag,)*
|
|
||||||
Unknown(u16)
|
|
||||||
}
|
}
|
||||||
impl Tag {
|
} => {
|
||||||
pub fn from_u16(n: u16) -> Tag {
|
$( #[$enum_attr] )*
|
||||||
$(if n == $val { Tag::$tag } else)* {
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
Tag::Unknown(n)
|
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 $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 {
|
match *self {
|
||||||
$( Tag::$tag => $val, )*
|
$( $name::$tag => $val, )*
|
||||||
Tag::Unknown(n) => n,
|
$( $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
|
// Note: These tags appear in the order they are mentioned in the TIFF reference
|
||||||
tags! {
|
tags! {
|
||||||
|
/// TIFF tags
|
||||||
|
pub enum Tag(u16) unknown("A private or extension tag") {
|
||||||
// Baseline tags:
|
// Baseline tags:
|
||||||
Artist 315;
|
Artist = 315,
|
||||||
// grayscale images PhotometricInterpretation 1 or 3
|
// grayscale images PhotometricInterpretation 1 or 3
|
||||||
BitsPerSample 258;
|
BitsPerSample = 258,
|
||||||
CellLength 265; // TODO add support
|
CellLength = 265, // TODO add support
|
||||||
CellWidth 264; // TODO add support
|
CellWidth = 264, // TODO add support
|
||||||
// palette-color images (PhotometricInterpretation 3)
|
// palette-color images (PhotometricInterpretation 3)
|
||||||
ColorMap 320; // TODO add support
|
ColorMap = 320, // TODO add support
|
||||||
Compression 259; // TODO add support for 2 and 32773
|
Compression = 259, // TODO add support for 2 and 32773
|
||||||
Copyright 33_432;
|
Copyright = 33_432,
|
||||||
DateTime 306;
|
DateTime = 306,
|
||||||
ExtraSamples 338; // TODO add support
|
ExtraSamples = 338, // TODO add support
|
||||||
FillOrder 266; // TODO add support
|
FillOrder = 266, // TODO add support
|
||||||
FreeByteCounts 289; // TODO add support
|
FreeByteCounts = 289, // TODO add support
|
||||||
FreeOffsets 288; // TODO add support
|
FreeOffsets = 288, // TODO add support
|
||||||
GrayResponseCurve 291; // TODO add support
|
GrayResponseCurve = 291, // TODO add support
|
||||||
GrayResponseUnit 290; // TODO add support
|
GrayResponseUnit = 290, // TODO add support
|
||||||
HostComputer 316;
|
HostComputer = 316,
|
||||||
ImageDescription 270;
|
ImageDescription = 270,
|
||||||
ImageLength 257;
|
ImageLength = 257,
|
||||||
ImageWidth 256;
|
ImageWidth = 256,
|
||||||
Make 271;
|
Make = 271,
|
||||||
MaxSampleValue 281; // TODO add support
|
MaxSampleValue = 281, // TODO add support
|
||||||
MinSampleValue 280; // TODO add support
|
MinSampleValue = 280, // TODO add support
|
||||||
Model 272;
|
Model = 272,
|
||||||
NewSubfileType 254; // TODO add support
|
NewSubfileType = 254, // TODO add support
|
||||||
Orientation 274; // TODO add support
|
Orientation = 274, // TODO add support
|
||||||
PhotometricInterpretation 262;
|
PhotometricInterpretation = 262,
|
||||||
PlanarConfiguration 284;
|
PlanarConfiguration = 284,
|
||||||
ResolutionUnit 296; // TODO add support
|
ResolutionUnit = 296, // TODO add support
|
||||||
RowsPerStrip 278;
|
RowsPerStrip = 278,
|
||||||
SamplesPerPixel 277;
|
SamplesPerPixel = 277,
|
||||||
Software 305;
|
Software = 305,
|
||||||
StripByteCounts 279;
|
StripByteCounts = 279,
|
||||||
StripOffsets 273;
|
StripOffsets = 273,
|
||||||
SubfileType 255; // TODO add support
|
SubfileType = 255, // TODO add support
|
||||||
Threshholding 263; // TODO add support
|
Threshholding = 263, // TODO add support
|
||||||
XResolution 282;
|
XResolution = 282,
|
||||||
YResolution 283;
|
YResolution = 283,
|
||||||
// Advanced tags
|
// Advanced tags
|
||||||
Predictor 317;
|
Predictor = 317,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, FromPrimitive)]
|
impl Tag {
|
||||||
pub enum Type {
|
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,
|
BYTE = 1,
|
||||||
ASCII = 2,
|
ASCII = 2,
|
||||||
SHORT = 3,
|
SHORT = 3,
|
||||||
@@ -94,6 +123,18 @@ pub enum Type {
|
|||||||
SLONG = 9,
|
SLONG = 9,
|
||||||
SRATIONAL = 10,
|
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)]
|
#[allow(unused_qualifications)]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
@@ -104,6 +145,8 @@ pub enum Value {
|
|||||||
Rational(u32, u32),
|
Rational(u32, u32),
|
||||||
SRational(i32, i32),
|
SRational(i32, i32),
|
||||||
Ascii(String),
|
Ascii(String),
|
||||||
|
#[doc(hidden)] // Do not match against this.
|
||||||
|
__NonExhaustive,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
|||||||
+63
-15
@@ -1,4 +1,3 @@
|
|||||||
use num_traits::{FromPrimitive, Num};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::{self, Read, Seek};
|
use std::io::{self, Read, Seek};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
@@ -9,6 +8,7 @@ use self::ifd::Directory;
|
|||||||
|
|
||||||
use self::stream::{ByteOrder, EndianReader, LZWReader, DeflateReader, PackBitsReader, SmartReader};
|
use self::stream::{ByteOrder, EndianReader, LZWReader, DeflateReader, PackBitsReader, SmartReader};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
pub mod ifd;
|
pub mod ifd;
|
||||||
mod stream;
|
mod stream;
|
||||||
|
|
||||||
@@ -80,8 +80,8 @@ impl<'a> DecodingBuffer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
tags! {
|
||||||
pub enum PhotometricInterpretation {
|
pub enum PhotometricInterpretation(u16) {
|
||||||
WhiteIsZero = 0,
|
WhiteIsZero = 0,
|
||||||
BlackIsZero = 1,
|
BlackIsZero = 1,
|
||||||
RGB = 2,
|
RGB = 2,
|
||||||
@@ -91,9 +91,10 @@ pub enum PhotometricInterpretation {
|
|||||||
YCbCr = 6,
|
YCbCr = 6,
|
||||||
CIELab = 8,
|
CIELab = 8,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
tags! {
|
||||||
pub enum CompressionMethod {
|
pub enum CompressionMethod(u16) {
|
||||||
None = 1,
|
None = 1,
|
||||||
Huffman = 2,
|
Huffman = 2,
|
||||||
Fax3 = 3,
|
Fax3 = 3,
|
||||||
@@ -104,18 +105,61 @@ pub enum CompressionMethod {
|
|||||||
OldDeflate = 0x80B2,
|
OldDeflate = 0x80B2,
|
||||||
PackBits = 0x8005,
|
PackBits = 0x8005,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
tags! {
|
||||||
pub enum PlanarConfiguration {
|
pub enum PlanarConfiguration(u16) {
|
||||||
Chunky = 1,
|
Chunky = 1,
|
||||||
Planar = 2,
|
Planar = 2,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
tags! {
|
||||||
enum Predictor {
|
enum Predictor(u16) {
|
||||||
None = 1,
|
None = 1,
|
||||||
Horizontal = 2,
|
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)]
|
#[derive(Debug)]
|
||||||
struct StripDecodeState {
|
struct StripDecodeState {
|
||||||
@@ -191,7 +235,7 @@ impl Wrapping for u16 {
|
|||||||
|
|
||||||
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize)
|
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize)
|
||||||
where
|
where
|
||||||
T: Num + Copy + Wrapping,
|
T: Copy + Wrapping,
|
||||||
{
|
{
|
||||||
let width = size.0 as usize;
|
let width = size.0 as usize;
|
||||||
let height = size.1 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.width = self.get_tag_u32(ifd::Tag::ImageWidth)?;
|
||||||
self.height = self.get_tag_u32(ifd::Tag::ImageLength)?;
|
self.height = self.get_tag_u32(ifd::Tag::ImageLength)?;
|
||||||
self.strip_decoder = None;
|
self.strip_decoder = None;
|
||||||
self.photometric_interpretation = match FromPrimitive::from_u32(
|
// TODO: error on non-SHORT value.
|
||||||
self.get_tag_u32(ifd::Tag::PhotometricInterpretation)?
|
self.photometric_interpretation = match PhotometricInterpretation::from_u16(
|
||||||
|
self.get_tag_u32(ifd::Tag::PhotometricInterpretation)? as u16
|
||||||
) {
|
) {
|
||||||
Some(val) => val,
|
Some(val) => val,
|
||||||
None => {
|
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)? {
|
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,
|
Some(method) => self.compression_method = method,
|
||||||
None => {
|
None => {
|
||||||
return Err(TiffError::UnsupportedError(
|
return Err(TiffError::UnsupportedError(
|
||||||
@@ -454,7 +500,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
// Value 4 bytes either a pointer the value itself
|
// Value 4 bytes either a pointer the value itself
|
||||||
fn read_entry(&mut self) -> TiffResult<Option<(ifd::Tag, ifd::Entry)>> {
|
fn read_entry(&mut self) -> TiffResult<Option<(ifd::Tag, ifd::Entry)>> {
|
||||||
let tag = ifd::Tag::from_u16(self.read_short()?);
|
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,
|
Some(t) => t,
|
||||||
None => {
|
None => {
|
||||||
// Unknown type. Skip this entry according to spec.
|
// 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) {
|
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::None) => (),
|
||||||
Some(Predictor::Horizontal) => {
|
Some(Predictor::Horizontal) => {
|
||||||
rev_hpredict(
|
rev_hpredict(
|
||||||
@@ -734,6 +781,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
predictor,
|
predictor,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
Some(Predictor::__NonExhaustive) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
+2
-2
@@ -441,7 +441,7 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.ifd
|
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> {
|
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::Compression, 1u16);
|
||||||
|
|
||||||
encoder.write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE);
|
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);
|
encoder.write_tag(Tag::RowsPerStrip, rows_per_strip as u32);
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,6 @@
|
|||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate lzw;
|
extern crate lzw;
|
||||||
extern crate miniz_oxide;
|
extern crate miniz_oxide;
|
||||||
#[macro_use]
|
|
||||||
extern crate num_derive;
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
pub mod decoder;
|
pub mod decoder;
|
||||||
pub mod encoder;
|
pub mod encoder;
|
||||||
|
|||||||
Reference in new issue
Block a user