Merge pull request #63 from image-rs/tagged

Replace FromPrimitive with our own tag macro
This commit is contained in:
HeroicKatora authored and GitHub committed 2019-11-12 20:14:25 +01:00
commit 8e1c67ee53
5 files changed
+163 -77

No files matched your search

-2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
-3
View File
@@ -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;