Skip to content

Commit 8e1c67e

Browse files
author
HeroicKatora
authored
Merge pull request #63 from image-rs/tagged
Replace FromPrimitive with our own tag macro
2 parents 62fee10 + 7b67299 commit 8e1c67e

File tree

5 files changed

+163
-77
lines changed

5 files changed

+163
-77
lines changed

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ exclude = ["tests/images/*", "tests/fuzz_images/*"]
1919
[dependencies]
2020
byteorder = "1.2"
2121
lzw = "0.10"
22-
num-derive = "0.3"
23-
num-traits = "0.2"
2422
miniz_oxide = "0.3"
2523

2624
[dev-dependencies]

src/decoder/ifd.rs

Lines changed: 98 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,42 @@ use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
1010
use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational};
1111

1212
macro_rules! tags {
13-
{$(
14-
$tag:ident
15-
$val:expr;
16-
)*} => {
17-
18-
/// TIFF tag
13+
{
14+
// Permit arbitrary meta items, which include documentation.
15+
$( #[$enum_attr:meta] )*
16+
$vis:vis enum $name:ident($ty:ty) $(unknown($unknown_doc:literal))* {
17+
// Each of the `Name = Val,` permitting documentation.
18+
$($(#[$ident_attr:meta])* $tag:ident = $val:expr,)*
19+
}
20+
} => {
21+
$( #[$enum_attr] )*
1922
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
20-
pub enum Tag {
21-
$($tag,)*
22-
Unknown(u16)
23+
pub enum $name {
24+
$($(#[$ident_attr])* $tag,)*
25+
// FIXME: switch to non_exhaustive once stabilized and compiler requirement new enough
26+
#[doc(hidden)]
27+
__NonExhaustive,
28+
$(
29+
#[doc = $unknown_doc]
30+
Unknown($ty),
31+
)*
2332
}
24-
impl Tag {
25-
pub fn from_u16(n: u16) -> Tag {
26-
$(if n == $val { Tag::$tag } else)* {
27-
Tag::Unknown(n)
33+
34+
impl $name {
35+
#[inline(always)]
36+
fn __from_inner_type(n: $ty) -> Result<Self, $ty> {
37+
match n {
38+
$( $val => Ok($name::$tag), )*
39+
n => Err(n),
2840
}
2941
}
30-
pub fn to_u16(&self) -> u16 {
42+
43+
#[inline(always)]
44+
fn __to_inner_type(&self) -> $ty {
3145
match *self {
32-
$( Tag::$tag => $val, )*
33-
Tag::Unknown(n) => n,
46+
$( $name::$tag => $val, )*
47+
$( $name::Unknown(n) => { $unknown_doc; n }, )*
48+
$name::__NonExhaustive => unreachable!(),
3449
}
3550
}
3651
}
@@ -39,51 +54,65 @@ macro_rules! tags {
3954

4055
// Note: These tags appear in the order they are mentioned in the TIFF reference
4156
tags! {
57+
/// TIFF tags
58+
pub enum Tag(u16) unknown("A private or extension tag") {
4259
// Baseline tags:
43-
Artist 315;
60+
Artist = 315,
4461
// grayscale images PhotometricInterpretation 1 or 3
45-
BitsPerSample 258;
46-
CellLength 265; // TODO add support
47-
CellWidth 264; // TODO add support
62+
BitsPerSample = 258,
63+
CellLength = 265, // TODO add support
64+
CellWidth = 264, // TODO add support
4865
// palette-color images (PhotometricInterpretation 3)
49-
ColorMap 320; // TODO add support
50-
Compression 259; // TODO add support for 2 and 32773
51-
Copyright 33_432;
52-
DateTime 306;
53-
ExtraSamples 338; // TODO add support
54-
FillOrder 266; // TODO add support
55-
FreeByteCounts 289; // TODO add support
56-
FreeOffsets 288; // TODO add support
57-
GrayResponseCurve 291; // TODO add support
58-
GrayResponseUnit 290; // TODO add support
59-
HostComputer 316;
60-
ImageDescription 270;
61-
ImageLength 257;
62-
ImageWidth 256;
63-
Make 271;
64-
MaxSampleValue 281; // TODO add support
65-
MinSampleValue 280; // TODO add support
66-
Model 272;
67-
NewSubfileType 254; // TODO add support
68-
Orientation 274; // TODO add support
69-
PhotometricInterpretation 262;
70-
PlanarConfiguration 284;
71-
ResolutionUnit 296; // TODO add support
72-
RowsPerStrip 278;
73-
SamplesPerPixel 277;
74-
Software 305;
75-
StripByteCounts 279;
76-
StripOffsets 273;
77-
SubfileType 255; // TODO add support
78-
Threshholding 263; // TODO add support
79-
XResolution 282;
80-
YResolution 283;
66+
ColorMap = 320, // TODO add support
67+
Compression = 259, // TODO add support for 2 and 32773
68+
Copyright = 33_432,
69+
DateTime = 306,
70+
ExtraSamples = 338, // TODO add support
71+
FillOrder = 266, // TODO add support
72+
FreeByteCounts = 289, // TODO add support
73+
FreeOffsets = 288, // TODO add support
74+
GrayResponseCurve = 291, // TODO add support
75+
GrayResponseUnit = 290, // TODO add support
76+
HostComputer = 316,
77+
ImageDescription = 270,
78+
ImageLength = 257,
79+
ImageWidth = 256,
80+
Make = 271,
81+
MaxSampleValue = 281, // TODO add support
82+
MinSampleValue = 280, // TODO add support
83+
Model = 272,
84+
NewSubfileType = 254, // TODO add support
85+
Orientation = 274, // TODO add support
86+
PhotometricInterpretation = 262,
87+
PlanarConfiguration = 284,
88+
ResolutionUnit = 296, // TODO add support
89+
RowsPerStrip = 278,
90+
SamplesPerPixel = 277,
91+
Software = 305,
92+
StripByteCounts = 279,
93+
StripOffsets = 273,
94+
SubfileType = 255, // TODO add support
95+
Threshholding = 263, // TODO add support
96+
XResolution = 282,
97+
YResolution = 283,
8198
// Advanced tags
82-
Predictor 317;
99+
Predictor = 317,
83100
}
101+
}
102+
103+
impl Tag {
104+
pub fn from_u16(val: u16) -> Self {
105+
Self::__from_inner_type(val).unwrap_or_else(Tag::Unknown)
106+
}
84107

85-
#[derive(Clone, Copy, Debug, FromPrimitive)]
86-
pub enum Type {
108+
pub fn to_u16(&self) -> u16 {
109+
Self::__to_inner_type(self)
110+
}
111+
}
112+
113+
tags! {
114+
/// The type of an IFD entry (a 2 byte field).
115+
pub enum Type(u16) {
87116
BYTE = 1,
88117
ASCII = 2,
89118
SHORT = 3,
@@ -94,6 +123,18 @@ pub enum Type {
94123
SLONG = 9,
95124
SRATIONAL = 10,
96125
}
126+
}
127+
128+
impl Type {
129+
pub fn from_u16(val: u16) -> Option<Self> {
130+
Self::__from_inner_type(val).ok()
131+
}
132+
133+
pub fn to_u16(&self) -> u16 {
134+
Self::__to_inner_type(self)
135+
}
136+
}
137+
97138

98139
#[allow(unused_qualifications)]
99140
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -104,6 +145,8 @@ pub enum Value {
104145
Rational(u32, u32),
105146
SRational(i32, i32),
106147
Ascii(String),
148+
#[doc(hidden)] // Do not match against this.
149+
__NonExhaustive,
107150
}
108151

109152
impl Value {

src/decoder/mod.rs

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use num_traits::{FromPrimitive, Num};
21
use std::collections::HashMap;
32
use std::io::{self, Read, Seek};
43
use std::cmp;
@@ -9,6 +8,7 @@ use self::ifd::Directory;
98

109
use self::stream::{ByteOrder, EndianReader, LZWReader, DeflateReader, PackBitsReader, SmartReader};
1110

11+
#[macro_use]
1212
pub mod ifd;
1313
mod stream;
1414

@@ -80,8 +80,8 @@ impl<'a> DecodingBuffer<'a> {
8080
}
8181
}
8282

83-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
84-
pub enum PhotometricInterpretation {
83+
tags! {
84+
pub enum PhotometricInterpretation(u16) {
8585
WhiteIsZero = 0,
8686
BlackIsZero = 1,
8787
RGB = 2,
@@ -91,9 +91,10 @@ pub enum PhotometricInterpretation {
9191
YCbCr = 6,
9292
CIELab = 8,
9393
}
94+
}
9495

95-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
96-
pub enum CompressionMethod {
96+
tags! {
97+
pub enum CompressionMethod(u16) {
9798
None = 1,
9899
Huffman = 2,
99100
Fax3 = 3,
@@ -104,18 +105,61 @@ pub enum CompressionMethod {
104105
OldDeflate = 0x80B2,
105106
PackBits = 0x8005,
106107
}
108+
}
107109

108-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
109-
pub enum PlanarConfiguration {
110+
tags! {
111+
pub enum PlanarConfiguration(u16) {
110112
Chunky = 1,
111113
Planar = 2,
112114
}
115+
}
113116

114-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
115-
enum Predictor {
117+
tags! {
118+
enum Predictor(u16) {
116119
None = 1,
117120
Horizontal = 2,
118121
}
122+
}
123+
124+
impl PhotometricInterpretation {
125+
pub fn from_u16(val: u16) -> Option<Self> {
126+
Self::__from_inner_type(val).ok()
127+
}
128+
129+
pub fn to_u16(&self) -> u16 {
130+
Self::__to_inner_type(self)
131+
}
132+
}
133+
134+
impl CompressionMethod {
135+
pub fn from_u16(val: u16) -> Option<Self> {
136+
Self::__from_inner_type(val).ok()
137+
}
138+
139+
pub fn to_u16(&self) -> u16 {
140+
Self::__to_inner_type(self)
141+
}
142+
}
143+
144+
impl PlanarConfiguration {
145+
pub fn from_u16(val: u16) -> Option<Self> {
146+
Self::__from_inner_type(val).ok()
147+
}
148+
149+
pub fn to_u16(&self) -> u16 {
150+
Self::__to_inner_type(self)
151+
}
152+
}
153+
154+
impl Predictor {
155+
pub fn from_u16(val: u16) -> Option<Self> {
156+
Self::__from_inner_type(val).ok()
157+
}
158+
159+
pub fn to_u16(&self) -> u16 {
160+
Self::__to_inner_type(self)
161+
}
162+
}
119163

120164
#[derive(Debug)]
121165
struct StripDecodeState {
@@ -191,7 +235,7 @@ impl Wrapping for u16 {
191235

192236
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize)
193237
where
194-
T: Num + Copy + Wrapping,
238+
T: Copy + Wrapping,
195239
{
196240
let width = size.0 as usize;
197241
let height = size.1 as usize;
@@ -334,8 +378,9 @@ impl<R: Read + Seek> Decoder<R> {
334378
self.width = self.get_tag_u32(ifd::Tag::ImageWidth)?;
335379
self.height = self.get_tag_u32(ifd::Tag::ImageLength)?;
336380
self.strip_decoder = None;
337-
self.photometric_interpretation = match FromPrimitive::from_u32(
338-
self.get_tag_u32(ifd::Tag::PhotometricInterpretation)?
381+
// TODO: error on non-SHORT value.
382+
self.photometric_interpretation = match PhotometricInterpretation::from_u16(
383+
self.get_tag_u32(ifd::Tag::PhotometricInterpretation)? as u16
339384
) {
340385
Some(val) => val,
341386
None => {
@@ -344,8 +389,9 @@ impl<R: Read + Seek> Decoder<R> {
344389
))
345390
}
346391
};
392+
// TODO: error on non-SHORT value.
347393
if let Some(val) = self.find_tag_u32(ifd::Tag::Compression)? {
348-
match FromPrimitive::from_u32(val) {
394+
match CompressionMethod::from_u16(val as u16) {
349395
Some(method) => self.compression_method = method,
350396
None => {
351397
return Err(TiffError::UnsupportedError(
@@ -454,7 +500,7 @@ impl<R: Read + Seek> Decoder<R> {
454500
// Value 4 bytes either a pointer the value itself
455501
fn read_entry(&mut self) -> TiffResult<Option<(ifd::Tag, ifd::Entry)>> {
456502
let tag = ifd::Tag::from_u16(self.read_short()?);
457-
let type_: ifd::Type = match FromPrimitive::from_u16(self.read_short()?) {
503+
let type_ = match ifd::Type::from_u16(self.read_short()?) {
458504
Some(t) => t,
459505
None => {
460506
// Unknown type. Skip this entry according to spec.
@@ -720,7 +766,8 @@ impl<R: Read + Seek> Decoder<R> {
720766
));
721767
}
722768
if let Ok(predictor) = self.get_tag_u32(ifd::Tag::Predictor) {
723-
match FromPrimitive::from_u32(predictor) {
769+
// TODO: error on non-SHORT value.
770+
match Predictor::from_u16(predictor as u16) {
724771
Some(Predictor::None) => (),
725772
Some(Predictor::Horizontal) => {
726773
rev_hpredict(
@@ -734,6 +781,7 @@ impl<R: Read + Seek> Decoder<R> {
734781
predictor,
735782
)))
736783
}
784+
Some(Predictor::__NonExhaustive) => unreachable!(),
737785
}
738786
}
739787
Ok(())

src/encoder/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> {
441441
}
442442

443443
self.ifd
444-
.insert(tag.to_u16(), (<T>::FIELD_TYPE as u16, value.count(), bytes));
444+
.insert(tag.to_u16(), (<T>::FIELD_TYPE.to_u16(), value.count(), bytes));
445445
}
446446

447447
fn write_directory(&mut self) -> TiffResult<u64> {
@@ -568,7 +568,7 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
568568
encoder.write_tag(Tag::Compression, 1u16);
569569

570570
encoder.write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE);
571-
encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE as u16);
571+
encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16());
572572

573573
encoder.write_tag(Tag::RowsPerStrip, rows_per_strip as u32);
574574

src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
extern crate byteorder;
1010
extern crate lzw;
1111
extern crate miniz_oxide;
12-
#[macro_use]
13-
extern crate num_derive;
14-
extern crate num_traits;
1512

1613
pub mod decoder;
1714
pub mod encoder;

0 commit comments

Comments
 (0)