Many TIFF cleanups. Subclassed TagInfo for
each possible combination of allowed types,
and made each TIFF tag constant one of those
subclasses. Deleted TiffOutputField.create()
and instead added TiffOutputDirectory.add(),
which is overloaded for each possible
combination of TagInfo subclass and the
Java type that can be written into it.
Similarly changed TiffDirectory so
TIFF types can be read with strong
typing.

Short/short[] is now handled properly
inside the TIFF implementation, instead of
always converting to Integer/int[].

Converted tests and internal code
to the new API where possible.

This essentially adds a high-level
type-safe API for reading and writing
TIFF/EXIF metadata, that's easy to use,
works with IDE code completion,
maybe the first of its kind.

Jira issue key : SANSELAN-31



git-svn-id: https://svn.apache.org/repos/asf/commons/proper/sanselan/trunk@1245871 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index e1d71ac..02cfc92 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -43,6 +43,7 @@
  * SANSELAN-59 - deleted confusing redefinition of some constants.
  * Altered TIFF tag searching to do an exact directory match when possible.
  * SANSELAN-48 - added support for reading and writing CCITT Modified Huffman, Group 3 and Group 4 images.
+ * SANSELAN-31 - added a high level type-safe API for reading and writing EXIF fields.
 
 Release 0.97
 ------------
diff --git a/src/main/java/org/apache/commons/sanselan/common/BinaryConversions.java b/src/main/java/org/apache/commons/sanselan/common/BinaryConversions.java
new file mode 100644
index 0000000..f6b1eef
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/common/BinaryConversions.java
@@ -0,0 +1,362 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.common;
+
+public class BinaryConversions implements BinaryConstants {
+    public static byte[] convertToByteArray(short[] values, int byteOrder) {
+        return convertToByteArray(values, 0, values.length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(short[] values, int length, int byteOrder) {
+        return convertToByteArray(values, 0, length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(short[] values, int offset, int length, int byteOrder) {
+        byte[] result = new byte[length * 2];
+        for (int i = 0; i < length; i++) {
+            short value = values[offset + i];
+            int start = i * 2;
+            if (byteOrder == BYTE_ORDER_MOTOROLA) {
+                result[start + 0] = (byte) (value >> 8);
+                result[start + 1] = (byte) (value >> 0);
+            } else {
+                result[start + 1] = (byte) (value >> 8);
+                result[start + 0] = (byte) (value >> 0);
+            }
+        }
+        return result;
+    }
+    
+    public static byte[] convertToByteArray(int[] values, int byteOrder) {
+        return convertToByteArray(values, 0, values.length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(int[] values, int length, int byteOrder) {
+        return convertToByteArray(values, 0, length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(int[] values, int offset, int length, int byteOrder) {
+        byte[] result = new byte[length * 4];
+        for (int i = 0; i < length; i++) {
+            int value = values[offset + i];
+            int start = i * 4;
+            if (byteOrder == BYTE_ORDER_MOTOROLA) {
+                result[start + 0] = (byte) (value >> 24);
+                result[start + 1] = (byte) (value >> 16);
+                result[start + 2] = (byte) (value >> 8);
+                result[start + 3] = (byte) (value >> 0);
+            } else {
+                result[start + 3] = (byte) (value >> 24);
+                result[start + 2] = (byte) (value >> 16);
+                result[start + 1] = (byte) (value >> 8);
+                result[start + 0] = (byte) (value >> 0);
+            }
+        }
+        return result;
+    }
+
+    public static byte[] convertToByteArray(float[] values, int byteOrder) {
+        return convertToByteArray(values, 0, values.length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(float[] values, int length, int byteOrder) {
+        return convertToByteArray(values, 0, length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(float[] values, int offset, int length, int byteOrder) {
+        byte[] result = new byte[values.length * 4];
+        for (int i = 0; i < values.length; i++) {
+            float value = values[i];
+            int bits = Float.floatToRawIntBits(value);
+            int start = i * 4;
+            if (byteOrder == BYTE_ORDER_INTEL) {
+                result[start + 0] = (byte) (0xff & (bits >> 0));
+                result[start + 1] = (byte) (0xff & (bits >> 8));
+                result[start + 2] = (byte) (0xff & (bits >> 16));
+                result[start + 3] = (byte) (0xff & (bits >> 24));
+            } else {
+                result[start + 3] = (byte) (0xff & (bits >> 0));
+                result[start + 2] = (byte) (0xff & (bits >> 8));
+                result[start + 1] = (byte) (0xff & (bits >> 16));
+                result[start + 0] = (byte) (0xff & (bits >> 24));
+            }
+        }
+        return result;
+    }
+    
+    public static byte[] convertToByteArray(double[] values, int byteOrder) {
+        return convertToByteArray(values, 0, values.length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(double[] values, int length, int byteOrder) {
+        return convertToByteArray(values, 0, length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(double[] values, int offset, int length, int byteOrder) {
+        byte[] result = new byte[length * 8];
+        for (int i = 0; i < length; i++) {
+            double value = values[offset + i];
+            long bits = Double.doubleToRawLongBits(value);
+            int start = i * 8;
+            if (byteOrder == BYTE_ORDER_INTEL) {
+                result[start + 0] = (byte) (0xff & (bits >> 0));
+                result[start + 1] = (byte) (0xff & (bits >> 8));
+                result[start + 2] = (byte) (0xff & (bits >> 16));
+                result[start + 3] = (byte) (0xff & (bits >> 24));
+                result[start + 4] = (byte) (0xff & (bits >> 32));
+                result[start + 5] = (byte) (0xff & (bits >> 40));
+                result[start + 6] = (byte) (0xff & (bits >> 48));
+                result[start + 7] = (byte) (0xff & (bits >> 56));
+            } else {
+                result[start + 7] = (byte) (0xff & (bits >> 0));
+                result[start + 6] = (byte) (0xff & (bits >> 8));
+                result[start + 5] = (byte) (0xff & (bits >> 16));
+                result[start + 4] = (byte) (0xff & (bits >> 24));
+                result[start + 3] = (byte) (0xff & (bits >> 32));
+                result[start + 2] = (byte) (0xff & (bits >> 40));
+                result[start + 1] = (byte) (0xff & (bits >> 48));
+                result[start + 0] = (byte) (0xff & (bits >> 56));
+            }
+        }
+        return result;
+    }
+    
+    public static byte[] convertToByteArray(RationalNumber[] values, int byteOrder) {
+        return convertToByteArray(values, 0, values.length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(RationalNumber[] values, int length, int byteOrder) {
+        return convertToByteArray(values, 0, length, byteOrder);
+    }
+    
+    public static byte[] convertToByteArray(RationalNumber[] values, int offset, int length, int byteOrder) {
+        byte[] result = new byte[length * 8];
+        for (int i = 0; i < length; i++) {
+            RationalNumber value = values[offset + i];
+            int start = i * 8;
+            if (byteOrder == BYTE_ORDER_MOTOROLA) {
+                result[start + 0] = (byte) (value.numerator >> 24);
+                result[start + 1] = (byte) (value.numerator >> 16);
+                result[start + 2] = (byte) (value.numerator >> 8);
+                result[start + 3] = (byte) (value.numerator >> 0);
+                result[start + 4] = (byte) (value.divisor >> 24);
+                result[start + 5] = (byte) (value.divisor >> 16);
+                result[start + 6] = (byte) (value.divisor >> 8);
+                result[start + 7] = (byte) (value.divisor >> 0);
+            } else {
+                result[start + 3] = (byte) (value.numerator >> 24);
+                result[start + 2] = (byte) (value.numerator >> 16);
+                result[start + 1] = (byte) (value.numerator >> 8);
+                result[start + 0] = (byte) (value.numerator >> 0);
+                result[start + 7] = (byte) (value.divisor >> 24);
+                result[start + 6] = (byte) (value.divisor >> 16);
+                result[start + 5] = (byte) (value.divisor >> 8);
+                result[start + 4] = (byte) (value.divisor >> 0);
+            }
+        }
+        return result;
+    }
+
+    public static short convertToShort(byte[] bytes, int byteOrder) {
+        return convertToShort(bytes, 0, byteOrder);
+    }
+    
+    public static short convertToShort(byte[] bytes, int offset, int byteOrder) {
+        int byte0 = 0xff & bytes[offset + 0];
+        int byte1 = 0xff & bytes[offset + 1];
+        if (byteOrder == BYTE_ORDER_MOTOROLA) {
+            return (short) ((byte0 << 8) | byte1);
+        } else {
+            return (short) ((byte1 << 8) | byte0);
+        }
+    }
+    
+    public static short[] convertToShortArray(byte[] bytes, int byteOrder) {
+        return convertToShortArray(bytes, 0, bytes.length, byteOrder);
+    }
+    
+    public static short[] convertToShortArray(byte[] bytes, int length, int byteOrder) {
+        return convertToShortArray(bytes, 0, length, byteOrder);
+    }
+    
+    public static short[] convertToShortArray(byte[] bytes, int offset, int length, int byteOrder) {
+        short[] result = new short[length / 2];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = convertToShort(bytes, offset + 2*i, byteOrder);
+        }
+        return result;
+    }
+
+    public static int convertToInt(byte[] bytes, int byteOrder) {
+        return convertToInt(bytes, 0, byteOrder);
+    }
+    
+    public static int convertToInt(byte[] bytes, int offset, int byteOrder) {
+        int byte0 = 0xff & bytes[offset + 0];
+        int byte1 = 0xff & bytes[offset + 1];
+        int byte2 = 0xff & bytes[offset + 2];
+        int byte3 = 0xff & bytes[offset + 3];
+        if (byteOrder == BYTE_ORDER_MOTOROLA) {
+            return (byte0 << 24) | (byte1 << 16) |
+                    (byte2 << 8) | byte3;
+        } else {
+            return (byte3 << 24) | (byte2 << 16) |
+                    (byte1 << 8) | byte0;
+        }
+    }
+    
+    public static int[] convertToIntArray(byte[] bytes, int byteOrder) {
+        return convertToIntArray(bytes, 0, bytes.length, byteOrder);
+    }
+    
+    public static int[] convertToIntArray(byte[] bytes, int length, int byteOrder) {
+        return convertToIntArray(bytes, 0, length, byteOrder);
+    }
+    
+    public static int[] convertToIntArray(byte[] bytes, int offset, int length, int byteOrder) {
+        int[] result = new int[length / 4];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = convertToInt(bytes, offset + 4*i, byteOrder);
+        }
+        return result;
+    }
+    
+    public static float convertToFloat(byte[] bytes, int byteOrder) {
+        return convertToFloat(bytes, 0, byteOrder);
+    }
+    
+    public static float convertToFloat(byte[] bytes, int offset, int byteOrder) {
+        int byte0 = 0xff & bytes[offset + 0];
+        int byte1 = 0xff & bytes[offset + 1];
+        int byte2 = 0xff & bytes[offset + 2];
+        int byte3 = 0xff & bytes[offset + 3];
+        int bits;
+        if (byteOrder == BYTE_ORDER_MOTOROLA) {
+            bits = (byte0 << 24) | (byte1 << 16) |
+                    (byte2 << 8) | (byte3 << 0);
+        } else {
+            bits = (byte3 << 24) | (byte2 << 16) |
+                    (byte1 << 8) | (byte0 << 0);
+        }
+        return Float.intBitsToFloat(bits);
+    }
+    
+    public static float[] convertToFloatArray(byte[] bytes, int byteOrder) {
+        return convertToFloatArray(bytes, 0, bytes.length, byteOrder);
+    }
+    
+    public static float[] convertToFloatArray(byte[] bytes, int length, int byteOrder) {
+        return convertToFloatArray(bytes, 0, length, byteOrder);
+    }
+
+    public static float[] convertToFloatArray(byte[] bytes, int offset, int length, int byteOrder) {
+        float[] result = new float[length / 4];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = convertToFloat(bytes, offset + 4*i, byteOrder);
+        }
+        return result;
+    }
+    
+    public static double convertToDouble(byte[] bytes, int byteOrder) {
+        return convertToDouble(bytes, 0, byteOrder);
+    }
+    
+    public static double convertToDouble(byte[] bytes, int offset, int byteOrder) {
+        long byte0 = 0xffL & bytes[offset + 0];
+        long byte1 = 0xffL & bytes[offset + 1];
+        long byte2 = 0xffL & bytes[offset + 2];
+        long byte3 = 0xffL & bytes[offset + 3];
+        long byte4 = 0xffL & bytes[offset + 4];
+        long byte5 = 0xffL & bytes[offset + 5];
+        long byte6 = 0xffL & bytes[offset + 6];
+        long byte7 = 0xffL & bytes[offset + 7];
+        long bits;
+        if (byteOrder == BYTE_ORDER_MOTOROLA) {
+            bits = (byte0 << 56) | (byte1 << 48) |
+                    (byte2 << 40) | (byte3 << 32) |
+                    (byte4 << 24) | (byte5 << 16) |
+                    (byte6 << 8) | (byte7 << 0);
+        } else {
+            bits = (byte7 << 56) | (byte6 << 48) |
+                    (byte5 << 40) | (byte4 << 32) |
+                    (byte3 << 24) | (byte2 << 16) |
+                    (byte1 << 8) | (byte0 << 0);
+        }
+        return Double.longBitsToDouble(bits);
+    }
+    
+    public static double[] convertToDoubleArray(byte[] bytes, int byteOrder) {
+        return convertToDoubleArray(bytes, 0, bytes.length, byteOrder);
+    }
+    
+    public static double[] convertToDoubleArray(byte[] bytes, int length, int byteOrder) {
+        return convertToDoubleArray(bytes, 0, length, byteOrder);
+    }
+    
+    public static double[] convertToDoubleArray(byte[] bytes, int offset, int length, int byteOrder) {
+        double[] result = new double[length / 8];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = convertToDouble(bytes, offset + 8*i, byteOrder);
+        }
+        return result;
+    }
+    
+    public static RationalNumber convertToRational(byte[] bytes, int byteOrder) {
+        return convertToRational(bytes, 0, byteOrder);
+    }
+    
+    public static RationalNumber convertToRational(byte[] bytes, int offset, int byteOrder) {
+        int byte0 = 0xff & bytes[offset + 0];
+        int byte1 = 0xff & bytes[offset + 1];
+        int byte2 = 0xff & bytes[offset + 2];
+        int byte3 = 0xff & bytes[offset + 3];
+        int byte4 = 0xff & bytes[offset + 4];
+        int byte5 = 0xff & bytes[offset + 5];
+        int byte6 = 0xff & bytes[offset + 6];
+        int byte7 = 0xff & bytes[offset + 7];
+        int numerator;
+        int divisor;
+        if (byteOrder == BYTE_ORDER_MOTOROLA) {
+            numerator = (byte0 << 24) | (byte1 << 16) |
+                    (byte2 << 8) | byte3;
+            divisor = (byte4 << 24) | (byte5 << 16) |
+                    (byte6 << 8) | byte7;
+        } else {
+            numerator = (byte3 << 24) | (byte2 << 16) |
+                    (byte1 << 8) | byte0;
+            divisor = (byte7 << 24) | (byte6 << 16) |
+                    (byte5 << 8) | byte4;
+        }
+        return new RationalNumber(numerator, divisor);
+    }
+    
+    public static RationalNumber[] convertToRationalArray(byte[] bytes, int byteOrder) {
+        return convertToRationalArray(bytes, 0, bytes.length, byteOrder);
+    }
+    
+    public static RationalNumber[] convertToRationalArray(byte[] bytes, int length, int byteOrder) {
+        return convertToRationalArray(bytes, 0, length, byteOrder);
+    }
+    
+    public static RationalNumber[] convertToRationalArray(byte[] bytes, int offset, int length, int byteOrder) {
+        RationalNumber[] result = new RationalNumber[length / 8];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = convertToRational(bytes, offset + 8*i, byteOrder);
+        }
+        return result;
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/jpeg/JpegImageMetadata.java b/src/main/java/org/apache/commons/sanselan/formats/jpeg/JpegImageMetadata.java
index db1c1c6..362bc7a 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/jpeg/JpegImageMetadata.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/jpeg/JpegImageMetadata.java
@@ -32,7 +32,7 @@
 import org.apache.commons.sanselan.formats.tiff.TiffField;
 import org.apache.commons.sanselan.formats.tiff.TiffImageData;
 import org.apache.commons.sanselan.formats.tiff.TiffImageMetadata;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
 import org.apache.commons.sanselan.util.Debug;
 
 public class JpegImageMetadata implements IImageMetadata {
diff --git a/src/main/java/org/apache/commons/sanselan/formats/jpeg/JpegImageParser.java b/src/main/java/org/apache/commons/sanselan/formats/jpeg/JpegImageParser.java
index 1c6e0e8..084ba24 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/jpeg/JpegImageParser.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/jpeg/JpegImageParser.java
@@ -734,19 +734,19 @@
             {
                 {
                     TiffField field = metadata
-                            .findEXIFValue(TiffTagConstants.XRESOLUTION.tagInfo);
+                            .findEXIFValue(TiffTagConstants.TIFF_TAG_XRESOLUTION);
                     if (field != null)
                         x_density = ((Number) field.getValue()).doubleValue();
                 }
                 {
                     TiffField field = metadata
-                            .findEXIFValue(TiffTagConstants.YRESOLUTION.tagInfo);
+                            .findEXIFValue(TiffTagConstants.TIFF_TAG_YRESOLUTION);
                     if (field != null)
                         y_density = ((Number) field.getValue()).doubleValue();
                 }
                 {
                     TiffField field = metadata
-                            .findEXIFValue(TiffTagConstants.RESOLUTION_UNIT.tagInfo);
+                            .findEXIFValue(TiffTagConstants.TIFF_TAG_RESOLUTION_UNIT);
                     if (field != null)
                     {
                         int density_units = ((Number) field.getValue())
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffContents.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffContents.java
index 58f1c52..4400885 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffContents.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffContents.java
@@ -21,7 +21,7 @@
 import java.util.List;
 
 import org.apache.commons.sanselan.ImageReadException;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
 import org.apache.commons.sanselan.util.Debug;
 
 public class TiffContents
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffDirectory.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffDirectory.java
index 127cfc1..6869b31 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffDirectory.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffDirectory.java
@@ -23,9 +23,21 @@
 import java.util.Map;
 
 import org.apache.commons.sanselan.ImageReadException;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
+import org.apache.commons.sanselan.common.RationalNumber;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffTagConstants;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoAscii;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoByte;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoDouble;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoFloat;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSByte;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShort;
 
 public class TiffDirectory extends TiffElement implements TiffConstants
 //extends BinaryFileFunctions
@@ -121,7 +133,7 @@
 
     public boolean hasJpegImageData() throws ImageReadException
     {
-        if (null != findField(TiffTagConstants.JPEG_INTERCHANGE_FORMAT.tagInfo))
+        if (null != findField(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT))
             return true;
 
         return false;
@@ -129,10 +141,10 @@
 
     public boolean hasTiffImageData() throws ImageReadException
     {
-        if (null != findField(TiffTagConstants.TILE_OFFSETS.tagInfo))
+        if (null != findField(TiffTagConstants.TIFF_TAG_TILE_OFFSETS))
             return true;
 
-        if (null != findField(TiffTagConstants.STRIP_OFFSETS.tagInfo))
+        if (null != findField(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS))
             return true;
 
         return false;
@@ -178,7 +190,145 @@
 
         return null;
     }
-
+    
+    public Object getFieldValue(TagInfo tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        return field.getValue();
+    }
+    
+    public byte[] getFieldValue(TagInfoByte tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        return field.fieldType.getRawBytes(field);
+    }
+    
+    public String[] getFieldValue(TagInfoAscii tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
+    public short[] getFieldValue(TagInfoShort tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
+    public int[] getFieldValue(TagInfoLong tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
+    public RationalNumber[] getFieldValue(TagInfoRational tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
+    public byte[] getFieldValue(TagInfoSByte tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        return field.fieldType.getRawBytes(field);
+    }
+    
+    public short[] getFieldValue(TagInfoSShort tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
+    public int[] getFieldValue(TagInfoSLong tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
+    public RationalNumber[] getFieldValue(TagInfoSRational tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
+    public float[] getFieldValue(TagInfoFloat tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
+    public double[] getFieldValue(TagInfoDouble tag) throws ImageReadException {
+        TiffField field = findField(tag);
+        if (field == null) {
+            return null;
+        }
+        if (!tag.dataTypes.contains(field.fieldType)) {
+            return null;
+        }
+        byte[] bytes = field.fieldType.getRawBytes(field);
+        return tag.getValue(field.byteOrder, bytes);
+    }
+    
     public final class ImageDataElement extends TiffElement
     {
         public ImageDataElement(int offset, int length)
@@ -214,10 +364,10 @@
 
     public List<ImageDataElement> getTiffRawImageDataElements() throws ImageReadException
     {
-        TiffField tileOffsets = findField(TiffTagConstants.TILE_OFFSETS.tagInfo);
-        TiffField tileByteCounts = findField(TiffTagConstants.TILE_BYTE_COUNTS.tagInfo);
-        TiffField stripOffsets = findField(TiffTagConstants.STRIP_OFFSETS.tagInfo);
-        TiffField stripByteCounts = findField(TiffTagConstants.STRIP_BYTE_COUNTS.tagInfo);
+        TiffField tileOffsets = findField(TiffTagConstants.TIFF_TAG_TILE_OFFSETS);
+        TiffField tileByteCounts = findField(TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS);
+        TiffField stripOffsets = findField(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS);
+        TiffField stripByteCounts = findField(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS);
 
         if ((tileOffsets != null) && (tileByteCounts != null))
         {
@@ -233,10 +383,10 @@
 
     public boolean imageDataInStrips() throws ImageReadException
     {
-        TiffField tileOffsets = findField(TiffTagConstants.TILE_OFFSETS.tagInfo);
-        TiffField tileByteCounts = findField(TiffTagConstants.TILE_BYTE_COUNTS.tagInfo);
-        TiffField stripOffsets = findField(TiffTagConstants.STRIP_OFFSETS.tagInfo);
-        TiffField stripByteCounts = findField(TiffTagConstants.STRIP_BYTE_COUNTS.tagInfo);
+        TiffField tileOffsets = findField(TiffTagConstants.TIFF_TAG_TILE_OFFSETS);
+        TiffField tileByteCounts = findField(TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS);
+        TiffField stripOffsets = findField(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS);
+        TiffField stripByteCounts = findField(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS);
 
         if ((tileOffsets != null) && (tileByteCounts != null))
             return false;
@@ -251,8 +401,8 @@
     public ImageDataElement getJpegRawImageDataElement()
             throws ImageReadException
     {
-        TiffField jpegInterchangeFormat = findField(TiffTagConstants.JPEG_INTERCHANGE_FORMAT.tagInfo);
-        TiffField jpegInterchangeFormatLength = findField(TiffTagConstants.JPEG_INTERCHANGE_FORMAT_LENGTH.tagInfo);
+        TiffField jpegInterchangeFormat = findField(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT);
+        TiffField jpegInterchangeFormatLength = findField(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
 
         if ((jpegInterchangeFormat != null)
                 && (jpegInterchangeFormatLength != null))
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffField.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffField.java
index 7fae4cd..1219ef8 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffField.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffField.java
@@ -30,11 +30,11 @@
 import org.apache.commons.sanselan.common.bytesource.ByteSource;
 import org.apache.commons.sanselan.formats.tiff.constants.ExifTagConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.GpsTagConstants;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffTagConstants;
 import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
 
 public class TiffField implements TiffConstants
 {
@@ -111,9 +111,9 @@
 
     private static FieldType getFieldType(int value)
     {
-        for (int i = 0; i < FIELD_TYPES.length; i++)
+        for (int i = 0; i < FIELD_TYPES.size(); i++)
         {
-            FieldType fieldType = FIELD_TYPES[i];
+            FieldType fieldType = FIELD_TYPES.get(i);
             if (fieldType.type == value)
                 return fieldType;
         }
@@ -196,7 +196,7 @@
         // return tagInfo;
         // }
 
-        return TiffTagConstants.UNKNOWN.tagInfo;
+        return TiffTagConstants.TIFF_TAG_UNKNOWN;
 
         // if (true)
         // throw new Error("Why didn't this algorithm work?");
@@ -259,7 +259,7 @@
 
         if (null == possibleMatches)
         {
-            return TiffTagConstants.UNKNOWN.tagInfo;
+            return TiffTagConstants.TIFF_TAG_UNKNOWN;
         }
 
         TagInfo result = getTag(directoryType, tag, possibleMatches);
@@ -362,6 +362,26 @@
         // }
         // return result.toString();
         // }
+        else if (o instanceof short[])
+        {
+            short values[] = (short[]) o;
+            StringBuffer result = new StringBuffer();
+
+            for (int i = 0; i < values.length; i++)
+            {
+                short value = values[i];
+
+                if (i > 50)
+                {
+                    result.append("... (" + values.length + ")");
+                    break;
+                }
+                if (i > 0)
+                    result.append(", ");
+                result.append("" + value);
+            }
+            return result.toString();
+        }
         else if (o instanceof int[])
         {
             int values[] = (int[]) o;
@@ -550,7 +570,7 @@
 
     public String getTagName()
     {
-        if (tagInfo == TiffTagConstants.UNKNOWN.tagInfo)
+        if (tagInfo == TiffTagConstants.TIFF_TAG_UNKNOWN)
             return tagInfo.name + " (0x" + Integer.toHexString(tag) + ")";
         return tagInfo.name;
     }
@@ -663,6 +683,12 @@
             for (int i = 0; i < numbers.length; i++)
                 result[i] = numbers[i].intValue();
             return result;
+        } else if (o instanceof short[]) {
+            short numbers[] = (short[]) o;
+            int result[] = new int[numbers.length];
+            for (int i = 0; i < numbers.length; i++)
+                result[i] = 0xffff & numbers[i];
+            return result;
         } else if (o instanceof int[])
         {
             int numbers[] = (int[]) o;
@@ -693,6 +719,12 @@
             for (int i = 0; i < numbers.length; i++)
                 result[i] = numbers[i].doubleValue();
             return result;
+        } else if (o instanceof short[]) {
+            short numbers[] = (short[]) o;
+            double result[] = new double[numbers.length];
+            for (int i = 0; i < numbers.length; i++)
+                result[i] = numbers[i];
+            return result;
         } else if (o instanceof int[])
         {
             int numbers[] = (int[]) o;
@@ -729,15 +761,19 @@
 
         if (o instanceof Number)
             return ((Number) o).intValue();
-        else if (o instanceof Number[])
-        {
+        else if (o instanceof Number[]) {
             Number numbers[] = (Number[]) o;
             int sum = 0;
             for (int i = 0; i < numbers.length; i++)
                 sum += numbers[i].intValue();
             return sum;
-        } else if (o instanceof int[])
-        {
+        } else if (o instanceof short[]) {
+            short[] numbers = (short[]) o;
+            int sum = 0;
+            for (int i = 0; i < numbers.length; i++)
+                sum += numbers[i];
+            return sum;
+        } else if (o instanceof int[]) {
             int numbers[] = (int[]) o;
             int sum = 0;
             for (int i = 0; i < numbers.length; i++)
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageMetadata.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageMetadata.java
index 7e4b881..a232e1e 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageMetadata.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageMetadata.java
@@ -29,10 +29,10 @@
 import org.apache.commons.sanselan.common.RationalNumber;
 import org.apache.commons.sanselan.formats.tiff.constants.AllTagConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.GpsTagConstants;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
 import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
 import org.apache.commons.sanselan.formats.tiff.write.TiffOutputDirectory;
 import org.apache.commons.sanselan.formats.tiff.write.TiffOutputField;
 import org.apache.commons.sanselan.formats.tiff.write.TiffOutputSet;
@@ -127,7 +127,7 @@
         {
             try
             {
-                TiffOutputDirectory dstDir = new TiffOutputDirectory(type);
+                TiffOutputDirectory dstDir = new TiffOutputDirectory(type, byteOrder);
 
                 List<? extends IImageMetadataItem> entries = getItems();
                 for (int i = 0; i < entries.size(); i++)
@@ -141,7 +141,7 @@
                         // ignore duplicate tags in a directory.
                         continue;
                     }
-                    else if (srcField.tagInfo instanceof TagInfo.Offset)
+                    else if (srcField.tagInfo.isOffset())
                     {
                         // ignore offset fields.
                         continue;
@@ -340,13 +340,13 @@
 
         // more specific example of how to access GPS values.
         TiffField latitudeRefField = gpsDirectory
-                .findField(GpsTagConstants.GPS_LATITUDE_REF.tagInfo);
+                .findField(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
         TiffField latitudeField = gpsDirectory
-                .findField(GpsTagConstants.GPS_LATITUDE.tagInfo);
+                .findField(GpsTagConstants.GPS_TAG_GPS_LATITUDE);
         TiffField longitudeRefField = gpsDirectory
-                .findField(GpsTagConstants.GPS_LONGITUDE_REF.tagInfo);
+                .findField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
         TiffField longitudeField = gpsDirectory
-                .findField(GpsTagConstants.GPS_LONGITUDE.tagInfo);
+                .findField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
 
         if (latitudeRefField == null || latitudeField == null
                 || longitudeRefField == null || longitudeField == null)
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java
index d3e77cb..325b730 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffImageParser.java
@@ -90,10 +90,7 @@
                 .readFirstDirectory(byteSource, params, false, formatCompliance);
         TiffDirectory directory = contents.directories.get(0);
 
-        TiffField field = directory.findField(ExifTagConstants.ICC_PROFILE.tagInfo);
-        if (null == field)
-            return null;
-        return field.oversizeValue;
+        return directory.getFieldValue(ExifTagConstants.EXIF_TAG_ICC_PROFILE);
     }
 
     public Dimension getImageSize(ByteSource byteSource, Map params)
@@ -104,8 +101,15 @@
                 .readFirstDirectory(byteSource, params, false, formatCompliance);
         TiffDirectory directory = contents.directories.get(0);
 
-        int width = directory.findField(TiffTagConstants.IMAGE_WIDTH.tagInfo).getIntValue();
-        int height = directory.findField(TiffTagConstants.IMAGE_LENGTH.tagInfo).getIntValue();
+        TiffField widthField = directory.findField(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, true);
+        TiffField heightField = directory
+                .findField(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, true);
+
+        if ((widthField == null) || (heightField == null))
+            throw new ImageReadException("TIFF image missing size info.");
+
+        int height = heightField.getIntValue();
+        int width = widthField.getIntValue();
 
         return new Dimension(width, height);
     }
@@ -159,9 +163,9 @@
                 .readDirectories(byteSource, false, formatCompliance);
         TiffDirectory directory = contents.directories.get(0);
 
-        TiffField widthField = directory.findField(TiffTagConstants.IMAGE_WIDTH.tagInfo, true);
+        TiffField widthField = directory.findField(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, true);
         TiffField heightField = directory
-                .findField(TiffTagConstants.IMAGE_LENGTH.tagInfo, true);
+                .findField(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, true);
 
         if ((widthField == null) || (heightField == null))
             throw new ImageReadException("TIFF image missing size info.");
@@ -172,7 +176,7 @@
         // -------------------
 
         TiffField resolutionUnitField = directory
-                .findField(TiffTagConstants.RESOLUTION_UNIT.tagInfo);
+                .findField(TiffTagConstants.TIFF_TAG_RESOLUTION_UNIT);
         int resolutionUnit = 2; // Inch
         if ((resolutionUnitField != null)
                 && (resolutionUnitField.getValue() != null))
@@ -193,8 +197,8 @@
             break;
 
         }
-        TiffField xResolutionField = directory.findField(TiffTagConstants.XRESOLUTION.tagInfo);
-        TiffField yResolutionField = directory.findField(TiffTagConstants.YRESOLUTION.tagInfo);
+        TiffField xResolutionField = directory.findField(TiffTagConstants.TIFF_TAG_XRESOLUTION);
+        TiffField yResolutionField = directory.findField(TiffTagConstants.TIFF_TAG_YRESOLUTION);
 
         int physicalWidthDpi = -1;
         float physicalWidthInch = -1;
@@ -224,7 +228,7 @@
         // -------------------
 
         TiffField bitsPerSampleField = directory
-                .findField(TiffTagConstants.BITS_PER_SAMPLE.tagInfo);
+                .findField(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE);
 
         int bitsPerSample = 1;
         if ((bitsPerSampleField != null)
@@ -257,13 +261,13 @@
 
         boolean isTransparent = false; // TODO: wrong
         boolean usesPalette = false;
-        TiffField colorMapField = directory.findField(TiffTagConstants.COLOR_MAP.tagInfo);
+        TiffField colorMapField = directory.findField(TiffTagConstants.TIFF_TAG_COLOR_MAP);
         if (colorMapField != null)
             usesPalette = true;
 
         int colorType = ImageInfo.COLOR_TYPE_RGB;
 
-        int compression = directory.findField(TiffTagConstants.COMPRESSION.tagInfo)
+        int compression = directory.findField(TiffTagConstants.TIFF_TAG_COMPRESSION)
                 .getIntValue();
         String compressionAlgorithm;
 
@@ -315,11 +319,10 @@
                 .readDirectories(byteSource, false, formatCompliance);
         TiffDirectory directory = contents.directories.get(0);
 
-        TiffField xmpField = directory.findField(TiffTagConstants.XMP.tagInfo, false);
-        if (xmpField == null)
+        byte bytes[] = directory.getFieldValue(TiffTagConstants.TIFF_TAG_XMP);
+        if (bytes == null) {
             return null;
-
-        byte bytes[] = xmpField.getByteArrayValue();
+        }
 
         try
         {
@@ -473,20 +476,20 @@
             throw new ImageReadException("TIFF missing entries");
 
         int photometricInterpretation = directory.findField(
-                TiffTagConstants.PHOTOMETRIC_INTERPRETATION.tagInfo, true).getIntValue();
-        int compression = directory.findField(TiffTagConstants.COMPRESSION.tagInfo, true)
+                TiffTagConstants.TIFF_TAG_PHOTOMETRIC_INTERPRETATION, true).getIntValue();
+        int compression = directory.findField(TiffTagConstants.TIFF_TAG_COMPRESSION, true)
                 .getIntValue();
-        int width = directory.findField(TiffTagConstants.IMAGE_WIDTH.tagInfo, true)
+        int width = directory.findField(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, true)
                 .getIntValue();
-        int height = directory.findField(TiffTagConstants.IMAGE_LENGTH.tagInfo, true)
+        int height = directory.findField(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, true)
                 .getIntValue();
         int samplesPerPixel = 1;
-        TiffField samplesPerPixelField = directory.findField(TiffTagConstants.SAMPLES_PER_PIXEL.tagInfo);
+        TiffField samplesPerPixelField = directory.findField(TiffTagConstants.TIFF_TAG_SAMPLES_PER_PIXEL);
         if (samplesPerPixelField != null)
             samplesPerPixel = samplesPerPixelField.getIntValue();
         int bitsPerSample[] = { 1 };
         int bitsPerPixel = samplesPerPixel;
-        TiffField bitsPerSampleField = directory.findField(TiffTagConstants.BITS_PER_SAMPLE.tagInfo);
+        TiffField bitsPerSampleField = directory.findField(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE);
         if (bitsPerSampleField != null)
         {
             bitsPerSample = bitsPerSampleField.getIntArrayValue();
@@ -503,7 +506,7 @@
             // dumpOptionalNumberTag(entries, TIFF_TAG_FREE_OFFSETS);
             // dumpOptionalNumberTag(entries, TIFF_TAG_ORIENTATION);
             // dumpOptionalNumberTag(entries, TIFF_TAG_PLANAR_CONFIGURATION);
-            TiffField predictorField = directory.findField(TiffTagConstants.PREDICTOR.tagInfo);
+            TiffField predictorField = directory.findField(TiffTagConstants.TIFF_TAG_PREDICTOR);
             if (null != predictorField)
                 predictor = predictorField.getIntValueOrArraySum();
         }
@@ -550,7 +553,7 @@
                     invert);
         case 3: // Palette
         {
-            int colorMap[] = directory.findField(TiffTagConstants.COLOR_MAP.tagInfo, true)
+            int colorMap[] = directory.findField(TiffTagConstants.TIFF_TAG_COLOR_MAP, true)
                     .getIntArrayValue();
 
             int expected_colormap_size = 3 * (1 << bitsPerPixel);
@@ -572,15 +575,15 @@
         case 6: //
         {
             double yCbCrCoefficients[] = directory.findField(
-                    TiffTagConstants.YCBCR_COEFFICIENTS.tagInfo, true).getDoubleArrayValue();
+                    TiffTagConstants.TIFF_TAG_YCBCR_COEFFICIENTS, true).getDoubleArrayValue();
 
             int yCbCrPositioning[] = directory.findField(
-                    TiffTagConstants.YCBCR_POSITIONING.tagInfo, true).getIntArrayValue();
+                    TiffTagConstants.TIFF_TAG_YCBCR_POSITIONING, true).getIntArrayValue();
             int yCbCrSubSampling[] = directory.findField(
-                    TiffTagConstants.YCBCR_SUB_SAMPLING.tagInfo, true).getIntArrayValue();
+                    TiffTagConstants.TIFF_TAG_YCBCR_SUB_SAMPLING, true).getIntArrayValue();
 
             double referenceBlackWhite[] = directory.findField(
-                    TiffTagConstants.REFERENCE_BLACK_WHITE.tagInfo, true).getDoubleArrayValue();
+                    TiffTagConstants.TIFF_TAG_REFERENCE_BLACK_WHITE, true).getDoubleArrayValue();
 
             return new PhotometricInterpreterYCbCr(yCbCrCoefficients,
                     yCbCrPositioning, yCbCrSubSampling, referenceBlackWhite,
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffReader.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffReader.java
index 6ef7091..9edf504 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffReader.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/TiffReader.java
@@ -249,9 +249,9 @@
                 {
                     TiffField entry = fields.get(j);
 
-                    if (entry.tag == ExifTagConstants.EXIF_OFFSET.tagInfo.tag
-                            || entry.tag == ExifTagConstants.GPSINFO.tagInfo.tag
-                            || entry.tag == ExifTagConstants.INTEROP_OFFSET.tagInfo.tag)
+                    if (entry.tag == ExifTagConstants.EXIF_TAG_EXIF_OFFSET.tag
+                            || entry.tag == ExifTagConstants.EXIF_TAG_GPSINFO.tag
+                            || entry.tag == ExifTagConstants.EXIF_TAG_INTEROP_OFFSET.tag)
                     { /* do nothing */ }
                     else
                         continue;
@@ -259,11 +259,11 @@
                     int subDirectoryOffset = ((Number) entry.getValue())
                             .intValue();
                     int subDirectoryType;
-                    if (entry.tag == ExifTagConstants.EXIF_OFFSET.tagInfo.tag)
+                    if (entry.tag == ExifTagConstants.EXIF_TAG_EXIF_OFFSET.tag)
                         subDirectoryType = TiffDirectory.DIRECTORY_TYPE_EXIF;
-                    else if (entry.tag == ExifTagConstants.GPSINFO.tagInfo.tag)
+                    else if (entry.tag == ExifTagConstants.EXIF_TAG_GPSINFO.tag)
                         subDirectoryType = TiffDirectory.DIRECTORY_TYPE_GPS;
-                    else if (entry.tag == ExifTagConstants.INTEROP_OFFSET.tagInfo.tag)
+                    else if (entry.tag == ExifTagConstants.EXIF_TAG_INTEROP_OFFSET.tag)
                         subDirectoryType = TiffDirectory.DIRECTORY_TYPE_INTEROPERABILITY;
                     else
                         throw new ImageReadException(
@@ -479,7 +479,7 @@
         if (directory.imageDataInStrips())
         {
             TiffField rowsPerStripField = directory
-                    .findField(TiffTagConstants.ROWS_PER_STRIP.tagInfo);
+                    .findField(TiffTagConstants.TIFF_TAG_ROWS_PER_STRIP);
             if (null == rowsPerStripField)
                 throw new ImageReadException("Can't find rows per strip field.");
             int rowsPerStrip = rowsPerStripField.getIntValue();
@@ -487,13 +487,13 @@
             return new TiffImageData.Strips(data, rowsPerStrip);
         } else
         {
-            TiffField tileWidthField = directory.findField(TiffTagConstants.TILE_WIDTH.tagInfo);
+            TiffField tileWidthField = directory.findField(TiffTagConstants.TIFF_TAG_TILE_WIDTH);
             if (null == tileWidthField)
                 throw new ImageReadException("Can't find tile width field.");
             int tileWidth = tileWidthField.getIntValue();
 
             TiffField tileLengthField = directory
-                    .findField(TiffTagConstants.TILE_LENGTH.tagInfo);
+                    .findField(TiffTagConstants.TIFF_TAG_TILE_LENGTH);
             if (null == tileLengthField)
                 throw new ImageReadException("Can't find tile length field.");
             int tileLength = tileLengthField.getIntValue();
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/AllTagConstants.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/AllTagConstants.java
index 1dcf5c7..aca562a 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/AllTagConstants.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/AllTagConstants.java
@@ -20,13 +20,14 @@
 import java.util.List;
 
 import org.apache.commons.sanselan.SanselanConstants;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
 
 public interface AllTagConstants
         extends
             SanselanConstants
 {
     public static final List<TagInfo> ALL_TAGS = Collections.unmodifiableList(
-            TagConstantsUtils.mergeTagLists(TiffTagConstants.values(),
-                    GpsTagConstants.values(), ExifTagConstants.values()));
+            TagConstantsUtils.mergeTagLists(TiffTagConstants.ALL_TIFF_TAGS,
+                    GpsTagConstants.ALL_GPS_TAGS, ExifTagConstants.ALL_EXIF_TAGS));
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/ExifTagConstants.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/ExifTagConstants.java
index 172ad79..3c48556 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/ExifTagConstants.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/ExifTagConstants.java
@@ -16,961 +16,57 @@
  */
 package org.apache.commons.sanselan.formats.tiff.constants;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-public enum ExifTagConstants
-        implements
-            TiffDirectoryConstants,
-            TiffFieldTypeConstants,
-            TagHolder
-{ /**/
-    INTEROP_INDEX(new TagInfo(
-            "Interop Index", 0x0001, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD)),
-    INTEROP_VERSION(new TagInfo(
-            "Interop Version", 0x0002, FIELD_TYPE_UNDEFINED, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD)),
-    PROCESSING_SOFTWARE(new TagInfo(
-            "Processing Software", 0x000b, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    SUBFILE_TYPE(new TagInfo(
-            "Subfile Type", 0x00fe, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    OLD_SUBFILE_TYPE(new TagInfo(
-            "Old Subfile Type", 0x00ff, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    IMAGE_WIDTH_IFD0(new TagInfo(
-            "Image Width", 0x0100, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    IMAGE_HEIGHT_IFD0(new TagInfo(
-            "Image Height", 0x0101, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    BITS_PER_SAMPLE(new TagInfo(
-            "Bits Per Sample", 0x0102, FIELD_TYPE_SHORT, -1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    COMPRESSION(new TagInfo(
-            "Compression", 0x0103, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    PHOTOMETRIC_INTERPRETATION(new TagInfo(
-            "Photometric Interpretation", 0x0106, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    THRESHOLDING(new TagInfo(
-            "Thresholding", 0x0107, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    CELL_WIDTH(new TagInfo("Cell Width",
-            0x0108, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    CELL_LENGTH(new TagInfo(
-            "Cell Length", 0x0109, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    FILL_ORDER(new TagInfo("Fill Order",
-            0x010a, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    DOCUMENT_NAME(new TagInfo(
-            "Document Name", 0x010d, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    IMAGE_DESCRIPTION(new TagInfo(
-            "Image Description", 0x010e, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    MAKE(new TagInfo("Make", 0x010f,
-            FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    MODEL(new TagInfo("Model", 0x0110,
-            FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    // poly tag public static final TagInfo2 STRIP_OFFSETS(new TagInfo2( "StripOffsets", 0x0111, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    PREVIEW_IMAGE_START_IFD0(new TagInfo.Offset(
-            "Preview Image Start", 0x0111, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    PREVIEW_IMAGE_START_SUB_IFD1(new TagInfo.Offset(
-            "Preview Image Start", 0x0111, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD1)),
-    JPG_FROM_RAW_START_SUB_IFD2(new TagInfo.Offset(
-            "Jpg From Raw Start", 0x0111, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD2)),
-    ORIENTATION(new TagInfo(
-            "Orientation", 0x0112, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    SAMPLES_PER_PIXEL(new TagInfo(
-            "Samples Per Pixel", 0x0115, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    ROWS_PER_STRIP(new TagInfo(
-            "Rows Per Strip", 0x0116, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    // poly tag public static final TagInfo2 STRIP_BYTE_COUNTS(new TagInfo2( "StripByteCounts", 0x0117, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    PREVIEW_IMAGE_LENGTH_IFD0(new TagInfo(
-            "Preview Image Length", 0x0117, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    PREVIEW_IMAGE_LENGTH_SUB_IFD1(new TagInfo(
-            "Preview Image Length", 0x0117, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD1)),
-    JPG_FROM_RAW_LENGTH_SUB_IFD2(new TagInfo(
-            "Jpg From Raw Length", 0x0117, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD2)),
-    MIN_SAMPLE_VALUE(new TagInfo(
-            "Min Sample Value", 0x0118, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    MAX_SAMPLE_VALUE(new TagInfo(
-            "Max Sample Value", 0x0119, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    XRESOLUTION(new TagInfo(
-            "XResolution", 0x011a, FIELD_TYPE_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    YRESOLUTION(new TagInfo(
-            "YResolution", 0x011b, FIELD_TYPE_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    PLANAR_CONFIGURATION(new TagInfo(
-            "Planar Configuration", 0x011c, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    PAGE_NAME(new TagInfo("Page Name",
-            0x011d, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    XPOSITION(new TagInfo("XPosition",
-            0x011e, FIELD_TYPE_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    YPOSITION(new TagInfo("YPosition",
-            0x011f, FIELD_TYPE_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    FREE_OFFSETS(new TagInfo(
-            "Free Offsets", 0x0120, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FREE_BYTE_COUNTS(new TagInfo(
-            "Free Byte Counts", 0x0121, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    GRAY_RESPONSE_UNIT(new TagInfo(
-            "Gray Response Unit", 0x0122, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    GRAY_RESPONSE_CURVE(new TagInfo(
-            "Gray Response Curve", 0x0123, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    T4OPTIONS(new TagInfo("T4 Options",
-            0x0124, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    T6OPTIONS(new TagInfo("T6 Options",
-            0x0125, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    RESOLUTION_UNIT(new TagInfo(
-            "Resolution Unit", 0x0128, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    PAGE_NUMBER(new TagInfo(
-            "Page Number", 0x0129, FIELD_TYPE_SHORT, 2, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    COLOR_RESPONSE_UNIT(new TagInfo(
-            "Color Response Unit", 0x012c, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    TRANSFER_FUNCTION(new TagInfo(
-            "Transfer Function", 0x012d, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SOFTWARE(new TagInfo("Software",
-            0x0131, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    MODIFY_DATE(new TagInfo(
-            "Modify Date", 0x0132, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    ARTIST(new TagInfo("Artist", 0x013b,
-            FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    HOST_COMPUTER(new TagInfo(
-            "Host Computer", 0x013c, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    PREDICTOR(new TagInfo("Predictor",
-            0x013d, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    WHITE_POINT(new TagInfo(
-            "White Point", 0x013e, FIELD_TYPE_RATIONAL, 2, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    PRIMARY_CHROMATICITIES(new TagInfo(
-            "Primary Chromaticities", 0x013f, FIELD_TYPE_RATIONAL, 6,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    COLOR_MAP(new TagInfo("Color Map",
-            0x0140, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    HALFTONE_HINTS(new TagInfo(
-            "Halftone Hints", 0x0141, FIELD_TYPE_SHORT, 2, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    TILE_WIDTH(new TagInfo("Tile Width",
-            0x0142, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    TILE_LENGTH(new TagInfo(
-            "Tile Length", 0x0143, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    TILE_OFFSETS(new TagInfo(
-            "Tile Offsets", 0x0144, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    TILE_BYTE_COUNTS(new TagInfo(
-            "Tile Byte Counts", 0x0145, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BAD_FAX_LINES(new TagInfo(
-            "Bad Fax Lines", 0x0146, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CLEAN_FAX_DATA(new TagInfo(
-            "Clean Fax Data", 0x0147, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CONSECUTIVE_BAD_FAX_LINES(new TagInfo(
-            "Consecutive Bad Fax Lines", 0x0148,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SUB_IFD(new TagInfo("Sub IFD",
-            0x014a, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    INK_SET(new TagInfo("Ink Set",
-            0x014c, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    INK_NAMES(new TagInfo("Ink Names",
-            0x014d, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    NUMBEROF_INKS(new TagInfo(
-            "Numberof Inks", 0x014e, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    DOT_RANGE(new TagInfo("Dot Range",
-            0x0150, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    TARGET_PRINTER(new TagInfo(
-            "Target Printer", 0x0151, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    EXTRA_SAMPLES(new TagInfo(
-            "Extra Samples", 0x0152, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SAMPLE_FORMAT(new TagInfo(
-            "Sample Format", 0x0153, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SMIN_SAMPLE_VALUE(new TagInfo(
-            "SMin Sample Value", 0x0154, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SMAX_SAMPLE_VALUE(new TagInfo(
-            "SMax Sample Value", 0x0155, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    TRANSFER_RANGE(new TagInfo(
-            "Transfer Range", 0x0156, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CLIP_PATH(new TagInfo("Clip Path",
-            0x0157, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    XCLIP_PATH_UNITS(new TagInfo(
-            "XClip Path Units", 0x0158, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    YCLIP_PATH_UNITS(new TagInfo(
-            "YClip Path Units", 0x0159, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    INDEXED(new TagInfo("Indexed",
-            0x015a, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    JPEGTABLES(new TagInfo("JPEGTables",
-            0x015b, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    OPIPROXY(new TagInfo("OPIProxy",
-            0x015f, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    GLOBAL_PARAMETERS_IFD(new TagInfo(
-            "Global Parameters IFD", 0x0190, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    PROFILE_TYPE(new TagInfo(
-            "Profile Type", 0x0191, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FAX_PROFILE(new TagInfo(
-            "Fax Profile", 0x0192, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CODING_METHODS(new TagInfo(
-            "Coding Methods", 0x0193, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    VERSION_YEAR(new TagInfo(
-            "Version Year", 0x0194, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MODE_NUMBER(new TagInfo(
-            "Mode Number", 0x0195, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    DECODE(new TagInfo("Decode", 0x01b1,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    DEFAULT_IMAGE_COLOR(new TagInfo(
-            "Default Image Color", 0x01b2, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    JPEGPROC(new TagInfo("JPEGProc",
-            0x0200, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    // poly tag public static final TagInfo2 THUMBNAIL_OFFSET(new TagInfo2( "ThumbnailOffset", 0x0201, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD1)),
-    PREVIEW_IMAGE_START_MAKER_NOTES(new TagInfo(
-            "Preview Image Start", 0x0201, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_MAKER_NOTES)),
-    JPG_FROM_RAW_START_SUB_IFD(new TagInfo.Offset(
-            "Jpg From Raw Start", 0x0201, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    JPG_FROM_RAW_START_IFD2(new TagInfo.Offset(
-            "Jpg From Raw Start", 0x0201, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD2)),
-    OTHER_IMAGE_START(new TagInfo.Offset(
-            "Other Image Start", 0x0201, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    // poly tag public static final TagInfo2 THUMBNAIL_LENGTH(new TagInfo2( "ThumbnailLength", 0x0202, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD1)),
-    PREVIEW_IMAGE_LENGTH_MAKER_NOTES(new TagInfo(
-            "Preview Image Length", 0x0202, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_MAKER_NOTES)),
-    JPG_FROM_RAW_LENGTH_SUB_IFD(new TagInfo(
-            "Jpg From Raw Length", 0x0202, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    JPG_FROM_RAW_LENGTH_IFD2(new TagInfo(
-            "Jpg From Raw Length", 0x0202, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD2)),
-    OTHER_IMAGE_LENGTH(new TagInfo(
-            "Other Image Length", 0x0202, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    JPEGRESTART_INTERVAL(new TagInfo(
-            "JPEGRestart Interval", 0x0203, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    JPEGLOSSLESS_PREDICTORS(new TagInfo(
-            "JPEGLossless Predictors", 0x0205, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    JPEGPOINT_TRANSFORMS(new TagInfo(
-            "JPEGPoint Transforms", 0x0206, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    JPEGQTABLES(new TagInfo(
-            "JPEGQTables", 0x0207, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    JPEGDCTABLES(new TagInfo(
-            "JPEGDCTables", 0x0208, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    JPEGACTABLES(new TagInfo(
-            "JPEGACTables", 0x0209, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    YCBCR_COEFFICIENTS(new TagInfo(
-            "YCbCr Coefficients", 0x0211, FIELD_TYPE_RATIONAL, 3,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    YCBCR_SUB_SAMPLING(new TagInfo(
-            "YCbCr Sub Sampling", 0x0212, FIELD_TYPE_SHORT, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    YCBCR_POSITIONING(new TagInfo(
-            "YCbCr Positioning", 0x0213, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    REFERENCE_BLACK_WHITE(new TagInfo(
-            "Reference Black White", 0x0214, FIELD_TYPE_RATIONAL, 6,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    STRIP_ROW_COUNTS(new TagInfo(
-            "Strip Row Counts", 0x022f, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    APPLICATION_NOTES(new TagInfo(
-            "Application Notes", 0x02bc, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    RELATED_IMAGE_FILE_FORMAT(new TagInfo(
-            "Related Image File Format", 0x1000, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD)),
-    RELATED_IMAGE_WIDTH(new TagInfo(
-            "Related Image Width", 0x1001, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD)),
-    RELATED_IMAGE_LENGTH(new TagInfo(
-            "Related Image Length", 0x1002, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD)),
-    RATING(new TagInfo("Rating", 0x4746,
-            FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    RATING_PERCENT(new TagInfo(
-            "Rating Percent", 0x4749, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    IMAGE_ID(new TagInfo("Image ID",
-            0x800d, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    WANG_ANNOTATION(new TagInfo(
-            "Wang Annotation", 0x80a4, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MATTEING(new TagInfo("Matteing",
-            0x80e3, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    DATA_TYPE(new TagInfo("Data Type",
-            0x80e4, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_DEPTH(new TagInfo(
-            "Image Depth", 0x80e5, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    TILE_DEPTH(new TagInfo("Tile Depth",
-            0x80e6, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MODEL_2(new TagInfo("Model 2",
-            0x827d, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CFAREPEAT_PATTERN_DIM(new TagInfo(
-            "CFARepeat Pattern Dim", 0x828d, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CFAPATTERN_2(new TagInfo(
-            "CFAPattern 2", 0x828e, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BATTERY_LEVEL(new TagInfo(
-            "Battery Level", 0x828f, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    COPYRIGHT(new TagInfo("Copyright",
-            0x8298, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    EXPOSURE_TIME(new TagInfo(
-            "Exposure Time", 0x829a, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FNUMBER(new TagInfo("FNumber",
-            0x829d, FIELD_TYPE_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    MDFILE_TAG(new TagInfo("MDFile Tag",
-            0x82a5, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MDSCALE_PIXEL(new TagInfo(
-            "MDScale Pixel", 0x82a6, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MDCOLOR_TABLE(new TagInfo(
-            "MDColor Table", 0x82a7, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MDLAB_NAME(new TagInfo("MDLab Name",
-            0x82a8, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MDSAMPLE_INFO(new TagInfo(
-            "MDSample Info", 0x82a9, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MDPREP_DATE(new TagInfo(
-            "MDPrep Date", 0x82aa, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MDPREP_TIME(new TagInfo(
-            "MDPrep Time", 0x82ab, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MDFILE_UNITS(new TagInfo(
-            "MDFile Units", 0x82ac, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    PIXEL_SCALE(new TagInfo(
-            "Pixel Scale", 0x830e, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IPTC_NAA(new TagInfo("IPTC- NAA",
-            0x83bb, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    INTERGRAPH_PACKET_DATA(new TagInfo(
-            "Intergraph Packet Data", 0x847e, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    INTERGRAPH_FLAG_REGISTERS(new TagInfo(
-            "Intergraph Flag Registers", 0x847f,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    INTERGRAPH_MATRIX(new TagInfo(
-            "Intergraph Matrix", 0x8480, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MODEL_TIE_POINT(new TagInfo(
-            "Model Tie Point", 0x8482, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SITE(new TagInfo("Site", 0x84e0,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    COLOR_SEQUENCE(new TagInfo(
-            "Color Sequence", 0x84e1, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IT8HEADER(new TagInfo("IT8 Header",
-            0x84e2, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    RASTER_PADDING(new TagInfo(
-            "Raster Padding", 0x84e3, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BITS_PER_RUN_LENGTH(new TagInfo(
-            "Bits Per Run Length", 0x84e4, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BITS_PER_EXTENDED_RUN_LENGTH(new TagInfo(
-            "Bits Per Extended Run Length", 0x84e5,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    COLOR_TABLE(new TagInfo(
-            "Color Table", 0x84e6, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_COLOR_INDICATOR(new TagInfo(
-            "Image Color Indicator", 0x84e7, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BACKGROUND_COLOR_INDICATOR(new TagInfo(
-            "Background Color Indicator", 0x84e8,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_COLOR_VALUE(new TagInfo(
-            "Image Color Value", 0x84e9, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BACKGROUND_COLOR_VALUE(new TagInfo(
-            "Background Color Value", 0x84ea, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    PIXEL_INTENSITY_RANGE(new TagInfo(
-            "Pixel Intensity Range", 0x84eb, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    TRANSPARENCY_INDICATOR(new TagInfo(
-            "Transparency Indicator", 0x84ec, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    COLOR_CHARACTERIZATION(new TagInfo(
-            "Color Characterization", 0x84ed, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    HCUSAGE(new TagInfo("HCUsage",
-            0x84ee, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SEMINFO(new TagInfo("SEMInfo",
-            0x8546, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    AFCP_IPTC(new TagInfo("AFCP_ IPTC",
-            0x8568, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MODEL_TRANSFORM(new TagInfo(
-            "Model Transform", 0x85d8, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    LEAF_DATA(new TagInfo("Leaf Data",
-            0x8606, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    PHOTOSHOP_SETTINGS(new TagInfo(
-            "Photoshop Settings", 0x8649, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    EXIF_OFFSET(new TagInfo.Offset(
-            "Exif Offset", 0x8769, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    ICC_PROFILE(new TagInfo(
-            "ICC_ Profile", 0x8773, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_LAYER(new TagInfo(
-            "Image Layer", 0x87ac, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    GEO_TIFF_DIRECTORY(new TagInfo(
-            "Geo Tiff Directory", 0x87af, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    GEO_TIFF_DOUBLE_PARAMS(new TagInfo(
-            "Geo Tiff Double Params", 0x87b0, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    GEO_TIFF_ASCII_PARAMS(new TagInfo(
-            "Geo Tiff Ascii Params", 0x87b1, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    EXPOSURE_PROGRAM(new TagInfo(
-            "Exposure Program", 0x8822, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SPECTRAL_SENSITIVITY(new TagInfo(
-            "Spectral Sensitivity", 0x8824, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    GPSINFO(new TagInfo.Offset(
-            "GPSInfo", 0x8825, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    ISO(new TagInfo("ISO", 0x8827,
-            FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    OPTO__ELECTRIC_CONV_FACTOR(new TagInfo(
-            "Opto - Electric Conv Factor", 0x8828,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    INTERLACE(new TagInfo("Interlace",
-            0x8829, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    TIME_ZONE_OFFSET(new TagInfo(
-            "Time Zone Offset", 0x882a, FIELD_TYPE_SSHORT, -1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SELF_TIMER_MODE(new TagInfo(
-            "Self Timer Mode", 0x882b, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FAX_RECV_PARAMS(new TagInfo(
-            "Fax Recv Params", 0x885c, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FAX_SUB_ADDRESS(new TagInfo(
-            "Fax Sub Address", 0x885d, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FAX_RECV_TIME(new TagInfo(
-            "Fax Recv Time", 0x885e, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    LEAF_SUB_IFD(new TagInfo(
-            "Leaf Sub IFD", 0x888a, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    EXIF_VERSION(new TagInfo(
-            "Exif Version", 0x9000, FIELD_TYPE_UNDEFINED, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    DATE_TIME_ORIGINAL(new TagInfo(
-            "Date Time Original", 0x9003, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    CREATE_DATE(new TagInfo(
-            "Create Date", 0x9004, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    COMPONENTS_CONFIGURATION(new TagInfo(
-            "Components Configuration", 0x9101, FIELD_TYPE_UNDEFINED, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    COMPRESSED_BITS_PER_PIXEL(new TagInfo(
-            "Compressed Bits Per Pixel", 0x9102, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SHUTTER_SPEED_VALUE(new TagInfo(
-            "Shutter Speed Value", 0x9201, FIELD_TYPE_SRATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    APERTURE_VALUE(new TagInfo(
-            "Aperture Value", 0x9202, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    BRIGHTNESS_VALUE(new TagInfo(
-            "Brightness Value", 0x9203, FIELD_TYPE_SRATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    EXPOSURE_COMPENSATION(new TagInfo(
-            "Exposure Compensation", 0x9204, FIELD_TYPE_SRATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    MAX_APERTURE_VALUE(new TagInfo(
-            "Max Aperture Value", 0x9205, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SUBJECT_DISTANCE(new TagInfo(
-            "Subject Distance", 0x9206, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    METERING_MODE(new TagInfo(
-            "Metering Mode", 0x9207, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    LIGHT_SOURCE(new TagInfo(
-            "Light Source", 0x9208, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FLASH(new TagInfo("Flash", 0x9209,
-            FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FOCAL_LENGTH(new TagInfo(
-            "Focal Length", 0x920a, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FLASH_ENERGY(new TagInfo(
-            "Flash Energy", 0x920b, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SPATIAL_FREQUENCY_RESPONSE_1(new TagInfo(
-            "Spatial Frequency Response", 0x920c,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    NOISE_1(new TagInfo("Noise", 0x920d,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FOCAL_PLANE_XRESOLUTION(new TagInfo(
-            "Focal Plane XResolution", 0x920e, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FOCAL_PLANE_YRESOLUTION(new TagInfo(
-            "Focal Plane YResolution", 0x920f, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FOCAL_PLANE_RESOLUTION_UNIT(new TagInfo(
-            "Focal Plane Resolution Unit", 0x9210,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_NUMBER_EXIF_IFD(new TagInfo(
-            "Image Number", 0x9211, FIELD_TYPE_LONG, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SECURITY_CLASSIFICATION_EXIF_IFD(new TagInfo(
-            "Security Classification", 0x9212, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    IMAGE_HISTORY_EXIF_IFD(new TagInfo(
-            "Image History", 0x9213, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SUBJECT_LOCATION_1(new TagInfo(
-            "Subject Location", 0x9214, FIELD_TYPE_SHORT, 4,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    EXPOSURE_INDEX(new TagInfo(
-            "Exposure Index", 0x9215, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    TIFF_EPSTANDARD_ID_1(new TagInfo(
-            "TIFF- EPStandard ID", 0x9216, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SENSING_METHOD(new TagInfo(
-            "Sensing Method", 0x9217, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    STO_NITS(new TagInfo("Sto Nits",
-            0x923f, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    //     skipping Maker Note!
-    MAKER_NOTE(new TagInfo("Maker Note",
-            0x927c, FIELD_TYPE_UNDEFINED, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    USER_COMMENT(new TagInfo.Text(
-            "UserComment", 0x9286, FIELD_TYPE_UNDEFINED, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SUB_SEC_TIME(new TagInfo(
-            "Sub Sec Time", 0x9290, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SUB_SEC_TIME_ORIGINAL(new TagInfo(
-            "Sub Sec Time Original", 0x9291, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SUB_SEC_TIME_DIGITIZED(new TagInfo(
-            "Sub Sec Time Digitized", 0x9292, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    IMAGE_SOURCE_DATA(new TagInfo(
-            "Image Source Data", 0x935c, FIELD_TYPE_UNDEFINED, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    XPTITLE(new TagInfo("XPTitle",
-            0x9c9b, FIELD_TYPE_BYTE, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    XPCOMMENT(new TagInfo("XPComment",
-            0x9c9c, FIELD_TYPE_BYTE, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    XPAUTHOR(new TagInfo("XPAuthor",
-            0x9c9d, FIELD_TYPE_BYTE, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    XPKEYWORDS(new TagInfo("XPKeywords",
-            0x9c9e, FIELD_TYPE_BYTE, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    XPSUBJECT(new TagInfo("XPSubject",
-            0x9c9f, FIELD_TYPE_BYTE, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    FLASHPIX_VERSION(new TagInfo(
-            "Flashpix Version", 0xa000, FIELD_TYPE_UNDEFINED, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    COLOR_SPACE(new TagInfo(
-            "Color Space", 0xa001, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    EXIF_IMAGE_WIDTH(new TagInfo(
-            "Exif Image Width", 0xa002, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    EXIF_IMAGE_LENGTH(new TagInfo(
-            "Exif Image Length", 0xa003, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    RELATED_SOUND_FILE(new TagInfo(
-            "Related Sound File", 0xa004, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    INTEROP_OFFSET(new TagInfo.Offset(
-            "Interop Offset", 0xa005, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FLASH_ENERGY_EXIF_IFD(new TagInfo(
-            "Flash Energy", 0xa20b, FIELD_TYPE_RATIONAL, -1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SPATIAL_FREQUENCY_RESPONSE_2(new TagInfo(
-            "Spatial Frequency Response", 0xa20c,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    NOISE_2(new TagInfo("Noise", 0xa20d,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    FOCAL_PLANE_XRESOLUTION_EXIF_IFD(new TagInfo(
-            "Focal Plane XResolution", 0xa20e, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FOCAL_PLANE_YRESOLUTION_EXIF_IFD(new TagInfo(
-            "Focal Plane YResolution", 0xa20f, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FOCAL_PLANE_RESOLUTION_UNIT_EXIF_IFD(new TagInfo(
-            "Focal Plane Resolution Unit", 0xa210, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    IMAGE_NUMBER(new TagInfo(
-            "Image Number", 0xa211, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SECURITY_CLASSIFICATION(new TagInfo(
-            "Security Classification", 0xa212, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_HISTORY(new TagInfo(
-            "Image History", 0xa213, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SUBJECT_LOCATION_2(new TagInfo(
-            "Subject Location", 0xa214, FIELD_TYPE_SHORT, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    EXPOSURE_INDEX_EXIF_IFD(new TagInfo(
-            "Exposure Index", 0xa215, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    TIFF_EPSTANDARD_ID_2(new TagInfo(
-            "TIFF- EPStandard ID", 0xa216, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SENSING_METHOD_EXIF_IFD(new TagInfo(
-            "Sensing Method", 0xa217, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FILE_SOURCE(new TagInfo(
-            "File Source", 0xa300, FIELD_TYPE_UNDEFINED, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SCENE_TYPE(new TagInfo("Scene Type",
-            0xa301, FIELD_TYPE_UNDEFINED, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    CFAPATTERN(new TagInfo("CFAPattern",
-            0xa302, FIELD_TYPE_UNDEFINED, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    CUSTOM_RENDERED(new TagInfo(
-            "Custom Rendered", 0xa401, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    EXPOSURE_MODE(new TagInfo(
-            "Exposure Mode", 0xa402, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    WHITE_BALANCE_1(new TagInfo(
-            "White Balance", 0xa403, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    DIGITAL_ZOOM_RATIO(new TagInfo(
-            "Digital Zoom Ratio", 0xa404, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    FOCAL_LENGTH_IN_35MM_FORMAT(new TagInfo(
-            "Focal Length In 3 5mm Format", 0xa405, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SCENE_CAPTURE_TYPE(new TagInfo(
-            "Scene Capture Type", 0xa406, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    GAIN_CONTROL(new TagInfo(
-            "Gain Control", 0xa407, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    CONTRAST_1(new TagInfo("Contrast",
-            0xa408, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SATURATION_1(new TagInfo(
-            "Saturation", 0xa409, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SHARPNESS_1(new TagInfo("Sharpness",
-            0xa40a, FIELD_TYPE_SHORT, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    DEVICE_SETTING_DESCRIPTION(new TagInfo(
-            "Device Setting Description", 0xa40b,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    SUBJECT_DISTANCE_RANGE(new TagInfo(
-            "Subject Distance Range", 0xa40c, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    IMAGE_UNIQUE_ID(new TagInfo(
-            "Image Unique ID", 0xa420, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    GDALMETADATA(new TagInfo(
-            "GDALMetadata", 0xa480, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    GDALNO_DATA(new TagInfo(
-            "GDALNo Data", 0xa481, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    GAMMA(new TagInfo("Gamma", 0xa500,
-            FIELD_TYPE_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    PIXEL_FORMAT(new TagInfo(
-            "Pixel Format", 0xbc01, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    TRANSFOMATION(new TagInfo(
-            "Transfomation", 0xbc02, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    UNCOMPRESSED(new TagInfo(
-            "Uncompressed", 0xbc03, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_TYPE(new TagInfo("Image Type",
-            0xbc04, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_WIDTH(new TagInfo(
-            "Image Width", 0xbc80, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_HEIGHT(new TagInfo(
-            "Image Height", 0xbc81, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    WIDTH_RESOLUTION(new TagInfo(
-            "Width Resolution", 0xbc82, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    HEIGHT_RESOLUTION(new TagInfo(
-            "Height Resolution", 0xbc83, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    // might be an offset?
-    IMAGE_OFFSET(new TagInfo(
-            "Image Offset", 0xbcc0, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_BYTE_COUNT(new TagInfo(
-            "Image Byte Count", 0xbcc1, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    // might be an offset?
-    ALPHA_OFFSET(new TagInfo(
-            "Alpha Offset", 0xbcc2, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    ALPHA_BYTE_COUNT(new TagInfo(
-            "Alpha Byte Count", 0xbcc3, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    IMAGE_DATA_DISCARD(new TagInfo(
-            "Image Data Discard", 0xbcc4, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    ALPHA_DATA_DISCARD(new TagInfo(
-            "Alpha Data Discard", 0xbcc5, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    OCE_SCANJOB_DESC(new TagInfo(
-            "Oce Scanjob Desc", 0xc427, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    OCE_APPLICATION_SELECTOR(new TagInfo(
-            "Oce Application Selector", 0xc428, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    OCE_IDNUMBER(new TagInfo(
-            "Oce IDNumber", 0xc429, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    OCE_IMAGE_LOGIC(new TagInfo(
-            "Oce Image Logic", 0xc42a, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    ANNOTATIONS(new TagInfo(
-            "Annotations", 0xc44f, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    PRINT_IM(new TagInfo("Print IM",
-            0xc4a5, FIELD_TYPE_UNDEFINED, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    DNG_VERSION(new TagInfo(
-            "DNG Version", 0xc612, FIELD_TYPE_BYTE, 4, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    DNG_BACKWARD_VERSION(new TagInfo(
-            "DNG Backward Version", 0xc613, FIELD_TYPE_BYTE, 4,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    UNIQUE_CAMERA_MODEL(new TagInfo(
-            "Unique Camera Model", 0xc614, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    LOCALIZED_CAMERA_MODEL(new TagInfo(
-            "Localized Camera Model", 0xc615, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    CFAPLANE_COLOR(new TagInfo(
-            "CFAPlane Color", 0xc616, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CFALAYOUT(new TagInfo("CFALayout",
-            0xc617, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    LINEARIZATION_TABLE(new TagInfo(
-            "Linearization Table", 0xc618, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BLACK_LEVEL_REPEAT_DIM(new TagInfo(
-            "Black Level Repeat Dim", 0xc619, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BLACK_LEVEL(new TagInfo(
-            "Black Level", 0xc61a, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BLACK_LEVEL_DELTA_H(new TagInfo(
-            "Black Level Delta H", 0xc61b, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    BLACK_LEVEL_DELTA_V(new TagInfo(
-            "Black Level Delta V", 0xc61c, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    WHITE_LEVEL(new TagInfo(
-            "White Level", 0xc61d, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    DEFAULT_SCALE(new TagInfo(
-            "Default Scale", 0xc61e, FIELD_TYPE_RATIONAL, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    DEFAULT_CROP_ORIGIN(new TagInfo(
-            "Default Crop Origin", 0xc61f, FIELD_TYPE_LONG, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    DEFAULT_CROP_SIZE(new TagInfo(
-            "Default Crop Size", 0xc620, FIELD_TYPE_LONG, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    COLOR_MATRIX_1(new TagInfo(
-            "Color Matrix 1", 0xc621, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    COLOR_MATRIX_2(new TagInfo(
-            "Color Matrix 2", 0xc622, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CAMERA_CALIBRATION_1(new TagInfo(
-            "Camera Calibration 1", 0xc623, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CAMERA_CALIBRATION_2(new TagInfo(
-            "Camera Calibration 2", 0xc624, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    REDUCTION_MATRIX_1(new TagInfo(
-            "Reduction Matrix 1", 0xc625, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    REDUCTION_MATRIX_2(new TagInfo(
-            "Reduction Matrix 2", 0xc626, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    ANALOG_BALANCE(new TagInfo(
-            "Analog Balance", 0xc627, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    AS_SHOT_NEUTRAL(new TagInfo(
-            "As Shot Neutral", 0xc628, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    AS_SHOT_WHITE_XY(new TagInfo(
-            "As Shot White XY", 0xc629, FIELD_TYPE_RATIONAL, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    BASELINE_EXPOSURE(new TagInfo(
-            "Baseline Exposure", 0xc62a, FIELD_TYPE_SRATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    BASELINE_NOISE(new TagInfo(
-            "Baseline Noise", 0xc62b, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    BASELINE_SHARPNESS(new TagInfo(
-            "Baseline Sharpness", 0xc62c, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    BAYER_GREEN_SPLIT(new TagInfo(
-            "Bayer Green Split", 0xc62d, FIELD_TYPE_LONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    LINEAR_RESPONSE_LIMIT(new TagInfo(
-            "Linear Response Limit", 0xc62e, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    CAMERA_SERIAL_NUMBER(new TagInfo(
-            "Camera Serial Number", 0xc62f, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    DNG_LENS_INFO(new TagInfo(
-            "DNG Lens Info", 0xc630, FIELD_TYPE_RATIONAL, 4,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    CHROMA_BLUR_RADIUS(new TagInfo(
-            "Chroma Blur Radius", 0xc631, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    ANTI_ALIAS_STRENGTH(new TagInfo(
-            "Anti Alias Strength", 0xc632, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    SHADOW_SCALE(new TagInfo(
-            "Shadow Scale", 0xc633, FIELD_TYPE_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    // poly tag public static final TagInfo2 SR2PRIVATE(new TagInfo2( "SR2Private", 0xc634, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    DNG_ADOBE_DATA(new TagInfo(
-            "DNG Adobe Data", 0xc634, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    DNG_PENTAX_DATA(new TagInfo(
-            "DNG Pentax Data", 0xc634, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    DNG_PRIVATE_DATA(new TagInfo(
-            "DNG Private Data", 0xc634, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    MAKER_NOTE_SAFETY(new TagInfo(
-            "Maker Note Safety", 0xc635, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    CALIBRATION_ILLUMINANT_1(new TagInfo(
-            "Calibration Illuminant 1", 0xc65a, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    CALIBRATION_ILLUMINANT_2(new TagInfo(
-            "Calibration Illuminant 2", 0xc65b, FIELD_TYPE_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    BEST_QUALITY_SCALE(new TagInfo(
-            "Best Quality Scale", 0xc65c, FIELD_TYPE_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    RAW_DATA_UNIQUE_ID(new TagInfo(
-            "Raw Data Unique ID", 0xc65d, FIELD_TYPE_BYTE, 16,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    ALIAS_LAYER_METADATA(new TagInfo(
-            "Alias Layer Metadata", 0xc660, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    ORIGINAL_RAW_FILE_NAME(new TagInfo(
-            "Original Raw File Name", 0xc68b, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    ORIGINAL_RAW_FILE_DATA(new TagInfo(
-            "Original Raw File Data", 0xc68c, FIELD_TYPE_UNDEFINED, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_IFD0)),
-    ACTIVE_AREA(new TagInfo(
-            "Active Area", 0xc68d, FIELD_TYPE_LONG, 4, TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    MASKED_AREAS(new TagInfo(
-            "Masked Areas", 0xc68e, FIELD_TYPE_LONG, 4, TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD)),
-    AS_SHOT_ICCPROFILE(new TagInfo(
-            "As Shot ICCProfile", 0xc68f, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    AS_SHOT_PRE_PROFILE_MATRIX(new TagInfo(
-            "As Shot Pre Profile Matrix", 0xc690,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CURRENT_ICCPROFILE(new TagInfo(
-            "Current ICCProfile", 0xc691, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    CURRENT_PRE_PROFILE_MATRIX(new TagInfo(
-            "Current Pre Profile Matrix", 0xc692,
-            FIELD_TYPE_DESCRIPTION_UNKNOWN, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN)),
-    OFFSET_SCHEMA(new TagInfo(
-            "Offset Schema", 0xea1d, FIELD_TYPE_SLONG, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    OWNER_NAME(new TagInfo("Owner Name",
-            0xfde8, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SERIAL_NUMBER(new TagInfo(
-            "Serial Number", 0xfde9, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    LENS(new TagInfo("Lens", 0xfdea,
-            FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    RAW_FILE(new TagInfo("Raw File",
-            0xfe4c, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    CONVERTER(new TagInfo("Converter",
-            0xfe4d, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    WHITE_BALANCE_2(new TagInfo(
-            "White Balance", 0xfe4e, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    EXPOSURE(new TagInfo("Exposure",
-            0xfe51, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SHADOWS(new TagInfo("Shadows",
-            0xfe52, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    BRIGHTNESS(new TagInfo("Brightness",
-            0xfe53, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    CONTRAST_2(new TagInfo("Contrast",
-            0xfe54, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SATURATION_2(new TagInfo(
-            "Saturation", 0xfe55, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SHARPNESS_2(new TagInfo("Sharpness",
-            0xfe56, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    SMOOTHNESS(new TagInfo("Smoothness",
-            0xfe57, FIELD_TYPE_ASCII, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD)),
-    MOIRE_FILTER(new TagInfo(
-            "Moire Filter", 0xfe58, FIELD_TYPE_ASCII, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD));
-    
-    public final TagInfo tagInfo;
-    
-    ExifTagConstants(TagInfo tagInfo) {
-        this.tagInfo = tagInfo;
-    }
-    
-    public TagInfo getTagInfo() {
-        return tagInfo;
-    }
-    
-    public static final List<TagInfo> ALL_EXIF_TAGS = Collections.unmodifiableList(
-            TagConstantsUtils.mergeTagLists(values()));
-    
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoAny;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoAscii;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoByte;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoByteOrShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoDouble;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoFloat;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShortOrLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShortOrLongOrRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShortOrRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoText;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoUndefined;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoUnknown;
+
+/**
+ * References:
+ * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
+ * http://tiki-lounge.com/~raf/tiff/fields.html
+ * http://www.awaresystems.be/imaging/tiff/tifftags.html
+ * http://cool.conservation-us.org/bytopic/imaging/std/tiff-f.html
+ * 
+ * DNG: http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec.pdf
+ * 
+ * "Stonits": http://www.anyhere.com/gward/pixformat/tiffluv.html
+ * Alias Sketchbook Pro multi-layer TIFF: http://www.awaresystems.be/imaging/tiff/tifftags/docs/alias.html
+ */
+public interface ExifTagConstants
+        extends
+            TiffFieldTypeConstants
+{
+    public static final TagInfoAscii EXIF_TAG_INTEROP_INDEX = new TagInfoAscii(
+            "Interop Index", 0x0001, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD);
+    public static final TagInfoUndefined EXIF_TAG_INTEROP_VERSION = new TagInfoUndefined(
+            "Interop Version", 0x0002, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD);
+    public static final TagInfoAscii EXIF_TAG_PROCESSING_SOFTWARE = new TagInfoAscii(
+            "Processing Software", 0x000b, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_SUBFILE_TYPE = new TagInfoLong(
+            "Subfile Type", 0x00fe, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int SUBFILE_TYPE_VALUE_FULL_RESOLUTION_IMAGE = 0;
     public static final int SUBFILE_TYPE_VALUE_REDUCED_RESOLUTION_IMAGE = 1;
     public static final int SUBFILE_TYPE_VALUE_SINGLE_PAGE_OF_MULTI_PAGE_IMAGE = 2;
@@ -979,9 +75,21 @@
     public static final int SUBFILE_TYPE_VALUE_TRANSPARENCY_MASK_OF_REDUCED_RESOLUTION_IMAGE = 5;
     public static final int SUBFILE_TYPE_VALUE_TRANSPARENCY_MASK_OF_MULTI_PAGE_IMAGE = 6;
     public static final int SUBFILE_TYPE_VALUE_TRANSPARENCY_MASK_OF_REDUCED_RESOLUTION_MULTI_PAGE_IMAGE = 7;
+    public static final TagInfoShort EXIF_TAG_OLD_SUBFILE_TYPE = new TagInfoShort(
+            "Old Subfile Type", 0x00ff, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int OLD_SUBFILE_TYPE_VALUE_FULL_RESOLUTION_IMAGE = 1;
     public static final int OLD_SUBFILE_TYPE_VALUE_REDUCED_RESOLUTION_IMAGE = 2;
     public static final int OLD_SUBFILE_TYPE_VALUE_SINGLE_PAGE_OF_MULTI_PAGE_IMAGE = 3;
+    public static final TagInfoLong EXIF_TAG_IMAGE_WIDTH_IFD0 = new TagInfoLong(
+            "Image Width", 0x0100, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_IMAGE_HEIGHT_IFD0 = new TagInfoLong(
+            "Image Height", 0x0101, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_BITS_PER_SAMPLE = new TagInfoShort(
+            "Bits Per Sample", 0x0102, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_COMPRESSION = new TagInfoShort(
+            "Compression", 0x0103, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int COMPRESSION_VALUE_UNCOMPRESSED = 1;
     public static final int COMPRESSION_VALUE_CCITT_1D = 2;
     public static final int COMPRESSION_VALUE_T4_GROUP_3_FAX = 3;
@@ -1012,6 +120,9 @@
     public static final int COMPRESSION_VALUE_NIKON_NEF_COMPRESSED = 34713;
     public static final int COMPRESSION_VALUE_KODAK_DCR_COMPRESSED = 65000;
     public static final int COMPRESSION_VALUE_PENTAX_PEF_COMPRESSED = 65535;
+    public static final TagInfoShort EXIF_TAG_PHOTOMETRIC_INTERPRETATION = new TagInfoShort(
+            "Photometric Interpretation", 0x0106, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int PHOTOMETRIC_INTERPRETATION_VALUE_WHITE_IS_ZERO = 0;
     public static final int PHOTOMETRIC_INTERPRETATION_VALUE_BLACK_IS_ZERO = 1;
     public static final int PHOTOMETRIC_INTERPRETATION_VALUE_RGB = 2;
@@ -1026,11 +137,40 @@
     public static final int PHOTOMETRIC_INTERPRETATION_VALUE_PIXAR_LOG_L = 32844;
     public static final int PHOTOMETRIC_INTERPRETATION_VALUE_PIXAR_LOG_LUV = 32845;
     public static final int PHOTOMETRIC_INTERPRETATION_VALUE_LINEAR_RAW = 34892;
+    public static final TagInfoShort EXIF_TAG_THRESHOLDING = new TagInfoShort(
+            "Thresholding", 0x0107, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int THRESHOLDING_VALUE_NO_DITHERING_OR_HALFTONING = 1;
     public static final int THRESHOLDING_VALUE_ORDERED_DITHER_OR_HALFTONE = 2;
     public static final int THRESHOLDING_VALUE_RANDOMIZED_DITHER = 3;
+    public static final TagInfoShort EXIF_TAG_CELL_WIDTH = new TagInfoShort("Cell Width",
+            0x0108, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_CELL_LENGTH = new TagInfoShort(
+            "Cell Length", 0x0109, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_FILL_ORDER = new TagInfoShort("Fill Order",
+            0x010a, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int FILL_ORDER_VALUE_NORMAL = 1;
     public static final int FILL_ORDER_VALUE_REVERSED = 2;
+    public static final TagInfoAscii EXIF_TAG_DOCUMENT_NAME = new TagInfoAscii(
+            "Document Name", 0x010d, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_IMAGE_DESCRIPTION = new TagInfoAscii(
+            "Image Description", 0x010e, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_MAKE = new TagInfoAscii(
+            "Make", 0x010f, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_MODEL = new TagInfoAscii(
+            "Model", 0x0110, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    // public static final TagInfo2 EXIF_TAG_STRIP_OFFSETS = new TagInfo2( "StripOffsets", 0x0111, , 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_PREVIEW_IMAGE_START_IFD0 = new TagInfoLong(
+            "Preview Image Start", 0x0111, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0, true);
+    public static final TagInfoLong EXIF_TAG_PREVIEW_IMAGE_START_SUB_IFD1 = new TagInfoLong(
+            "Preview Image Start", 0x0111, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD1, true);
+    public static final TagInfoLong EXIF_TAG_JPG_FROM_RAW_START_SUB_IFD2 = new TagInfoLong(
+            "Jpg From Raw Start", 0x0111, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD2, true);
+    public static final TagInfoShort EXIF_TAG_ORIENTATION = new TagInfoShort(
+            "Orientation", 0x0112, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int ORIENTATION_VALUE_HORIZONTAL_NORMAL = 1;
     public static final int ORIENTATION_VALUE_MIRROR_HORIZONTAL = 2;
     public static final int ORIENTATION_VALUE_ROTATE_180 = 3;
@@ -1039,35 +179,185 @@
     public static final int ORIENTATION_VALUE_ROTATE_90_CW = 6;
     public static final int ORIENTATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_90_CW = 7;
     public static final int ORIENTATION_VALUE_ROTATE_270_CW = 8;
+    public static final TagInfoShort EXIF_TAG_SAMPLES_PER_PIXEL = new TagInfoShort(
+            "Samples Per Pixel", 0x0115, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_ROWS_PER_STRIP = new TagInfoLong(
+            "Rows Per Strip", 0x0116, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    // poly tag public static final TagInfo2 EXIF_TAG_STRIP_BYTE_COUNTS = new TagInfo2( "StripByteCounts", 0x0117, , 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_PREVIEW_IMAGE_LENGTH_IFD0 = new TagInfoLong(
+            "Preview Image Length", 0x0117, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_PREVIEW_IMAGE_LENGTH_SUB_IFD1 = new TagInfoLong(
+            "Preview Image Length", 0x0117, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD1);
+    public static final TagInfoLong EXIF_TAG_JPG_FROM_RAW_LENGTH_SUB_IFD2 = new TagInfoLong(
+            "Jpg From Raw Length", 0x0117, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD2);
+    public static final TagInfoShort EXIF_TAG_MIN_SAMPLE_VALUE = new TagInfoShort(
+            "Min Sample Value", 0x0118, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_MAX_SAMPLE_VALUE = new TagInfoShort(
+            "Max Sample Value", 0x0119, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_XRESOLUTION = new TagInfoRational(
+            "XResolution", 0x011a, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_YRESOLUTION = new TagInfoRational(
+            "YResolution", 0x011b, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_PLANAR_CONFIGURATION = new TagInfoShort(
+            "Planar Configuration", 0x011c, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int PLANAR_CONFIGURATION_VALUE_CHUNKY = 1;
     public static final int PLANAR_CONFIGURATION_VALUE_PLANAR = 2;
+    public static final TagInfoAscii EXIF_TAG_PAGE_NAME = new TagInfoAscii("Page Name",
+            0x011d, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_XPOSITION = new TagInfoRational("XPosition",
+            0x011e, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_YPOSITION = new TagInfoRational("YPosition",
+            0x011f, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_FREE_OFFSETS = new TagInfoLong(
+            "Free Offsets", 0x0120, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_FREE_BYTE_COUNTS = new TagInfoLong(
+            "Free Byte Counts", 0x0121, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_GRAY_RESPONSE_UNIT = new TagInfoShort(
+            "Gray Response Unit", 0x0122, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int GRAY_RESPONSE_UNIT_VALUE_0_1 = 1;
     public static final int GRAY_RESPONSE_UNIT_VALUE_0_001 = 2;
     public static final int GRAY_RESPONSE_UNIT_VALUE_0_0001 = 3;
     public static final int GRAY_RESPONSE_UNIT_VALUE_1E_05 = 4;
     public static final int GRAY_RESPONSE_UNIT_VALUE_1E_06 = 5;
+    public static final TagInfoShort EXIF_TAG_GRAY_RESPONSE_CURVE = new TagInfoShort(
+            "Gray Response Curve", 0x0123, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_T4OPTIONS = new TagInfoLong("T4 Options",
+            0x0124, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_T6OPTIONS = new TagInfoLong("T6 Options",
+            0x0125, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_RESOLUTION_UNIT = new TagInfoShort(
+            "Resolution Unit", 0x0128, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int RESOLUTION_UNIT_VALUE_NONE = 1;
     public static final int RESOLUTION_UNIT_VALUE_INCHES = 2;
     public static final int RESOLUTION_UNIT_VALUE_CM = 3;
+    public static final TagInfoShort EXIF_TAG_PAGE_NUMBER = new TagInfoShort(
+            "Page Number", 0x0129, 2, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_COLOR_RESPONSE_UNIT = new TagInfoShort(
+            "Color Response Unit", 0x012c, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_TRANSFER_FUNCTION = new TagInfoShort(
+            "Transfer Function", 0x012d, 3*256,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_SOFTWARE = new TagInfoAscii("Software",
+            0x0131, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_MODIFY_DATE = new TagInfoAscii(
+            "Modify Date", 0x0132, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_ARTIST = new TagInfoAscii("Artist", 0x013b,
+            1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_HOST_COMPUTER = new TagInfoAscii(
+            "Host Computer", 0x013c, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_PREDICTOR = new TagInfoShort("Predictor",
+            0x013d, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int PREDICTOR_VALUE_NONE = 1;
     public static final int PREDICTOR_VALUE_HORIZONTAL_DIFFERENCING = 2;
+    public static final TagInfoRational EXIF_TAG_WHITE_POINT = new TagInfoRational(
+            "White Point", 0x013e, 2, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_PRIMARY_CHROMATICITIES = new TagInfoRational(
+            "Primary Chromaticities", 0x013f, 6,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_COLOR_MAP = new TagInfoShort("Color Map",
+            0x0140, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_HALFTONE_HINTS = new TagInfoShort(
+            "Halftone Hints", 0x0141, 2, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShortOrLong EXIF_TAG_TILE_WIDTH = new TagInfoShortOrLong("Tile Width",
+            0x0142, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShortOrLong EXIF_TAG_TILE_LENGTH = new TagInfoShortOrLong(
+            "Tile Length", 0x0143, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_TILE_OFFSETS = new TagInfoLong(
+            "Tile Offsets", 0x0144, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShortOrLong EXIF_TAG_TILE_BYTE_COUNTS = new TagInfoShortOrLong(
+            "Tile Byte Counts", 0x0145, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShortOrLong EXIF_TAG_BAD_FAX_LINES = new TagInfoShortOrLong(
+            "Bad Fax Lines", 0x0146, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_CLEAN_FAX_DATA = new TagInfoShort(
+            "Clean Fax Data", 0x0147, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int CLEAN_FAX_DATA_VALUE_CLEAN = 0;
     public static final int CLEAN_FAX_DATA_VALUE_REGENERATED = 1;
     public static final int CLEAN_FAX_DATA_VALUE_UNCLEAN = 2;
+    public static final TagInfoShortOrLong EXIF_TAG_CONSECUTIVE_BAD_FAX_LINES = new TagInfoShortOrLong(
+            "Consecutive Bad Fax Lines", 0x0148,
+            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_SUB_IFD = new TagInfoLong("Sub IFD",
+            0x014a, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN, true);
+    public static final TagInfoShort EXIF_TAG_INK_SET = new TagInfoShort("Ink Set",
+            0x014c, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int INK_SET_VALUE_CMYK = 1;
     public static final int INK_SET_VALUE_NOT_CMYK = 2;
+    public static final TagInfoAscii EXIF_TAG_INK_NAMES = new TagInfoAscii("Ink Names",
+            0x014d, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_NUMBEROF_INKS = new TagInfoShort(
+            "Numberof Inks", 0x014e, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByteOrShort EXIF_TAG_DOT_RANGE = new TagInfoByteOrShort("Dot Range",
+            0x0150, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_TARGET_PRINTER = new TagInfoAscii(
+            "Target Printer", 0x0151, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_EXTRA_SAMPLES = new TagInfoShort(
+            "Extra Samples", 0x0152, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_SAMPLE_FORMAT = new TagInfoShort(
+            "Sample Format", 0x0153, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int SAMPLE_FORMAT_VALUE_UNSIGNED_INTEGER = 1;
     public static final int SAMPLE_FORMAT_VALUE_TWOS_COMPLEMENT_SIGNED_INTEGER = 2;
     public static final int SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT = 3;
     public static final int SAMPLE_FORMAT_VALUE_UNDEFINED = 4;
     public static final int SAMPLE_FORMAT_VALUE_COMPLEX_INTEGER = 5;
     public static final int SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT_1 = 6;
+    public static final TagInfoAny EXIF_TAG_SMIN_SAMPLE_VALUE = new TagInfoAny(
+            "SMin Sample Value", 0x0154, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAny EXIF_TAG_SMAX_SAMPLE_VALUE = new TagInfoAny(
+            "SMax Sample Value", 0x0155, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_TRANSFER_RANGE = new TagInfoShort(
+            "Transfer Range", 0x0156, 6,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_CLIP_PATH = new TagInfoByte("Clip Path",
+            0x0157, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_XCLIP_PATH_UNITS = new TagInfoLong(
+            "XClip Path Units", 0x0158, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_YCLIP_PATH_UNITS = new TagInfoLong(
+            "YClip Path Units", 0x0159, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_INDEXED = new TagInfoShort("Indexed",
+            0x015a, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int INDEXED_VALUE_NOT_INDEXED = 0;
     public static final int INDEXED_VALUE_INDEXED = 1;
+    public static final TagInfoUndefined EXIF_TAG_JPEGTABLES = new TagInfoUndefined("JPEGTables",
+            0x015b, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_OPIPROXY = new TagInfoShort("OPIProxy",
+            0x015f, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int OPIPROXY_VALUE_HIGHER_RESOLUTION_IMAGE_DOES_NOT_EXIST = 0;
     public static final int OPIPROXY_VALUE_HIGHER_RESOLUTION_IMAGE_EXISTS = 1;
+    public static final TagInfoLong EXIF_TAG_GLOBAL_PARAMETERS_IFD = new TagInfoLong(
+            "Global Parameters IFD", 0x0190, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN, true);
+    public static final TagInfoLong EXIF_TAG_PROFILE_TYPE = new TagInfoLong(
+            "Profile Type", 0x0191, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int PROFILE_TYPE_VALUE_UNSPECIFIED = 0;
     public static final int PROFILE_TYPE_VALUE_GROUP_3_FAX = 1;
+    public static final TagInfoByte EXIF_TAG_FAX_PROFILE = new TagInfoByte(
+            "Fax Profile", 0x0192, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int FAX_PROFILE_VALUE_UNKNOWN = 0;
     public static final int FAX_PROFILE_VALUE_MINIMAL_B_AND_W_LOSSLESS_S = 1;
     public static final int FAX_PROFILE_VALUE_EXTENDED_B_AND_W_LOSSLESS_F = 2;
@@ -1075,10 +365,249 @@
     public static final int FAX_PROFILE_VALUE_LOSSY_COLOR_AND_GRAYSCALE_C = 4;
     public static final int FAX_PROFILE_VALUE_LOSSLESS_COLOR_AND_GRAYSCALE_L = 5;
     public static final int FAX_PROFILE_VALUE_MIXED_RASTER_CONTENT_M = 6;
+    public static final TagInfoLong EXIF_TAG_CODING_METHODS = new TagInfoLong(
+            "Coding Methods", 0x0193, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_VERSION_YEAR = new TagInfoByte(
+            "Version Year", 0x0194, 4,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_MODE_NUMBER = new TagInfoByte(
+            "Mode Number", 0x0195, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_DECODE = new TagInfoRational("Decode", 0x01b1,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_DEFAULT_IMAGE_COLOR = new TagInfoShort(
+            "Default Image Color", 0x01b2, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_JPEGPROC = new TagInfoShort("JPEGProc",
+            0x0200, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int JPEGPROC_VALUE_BASELINE = 1;
     public static final int JPEGPROC_VALUE_LOSSLESS = 14;
+    // poly tag public static final TagInfo2 EXIF_TAG_THUMBNAIL_OFFSET = new TagInfo2( "ThumbnailOffset", 0x0201, , 1, TiffDirectoryType.EXIF_DIRECTORY_IFD1);
+    public static final TagInfoLong EXIF_TAG_PREVIEW_IMAGE_START_MAKER_NOTES = new TagInfoLong(
+            "Preview Image Start", 0x0201, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_MAKER_NOTES);
+    public static final TagInfoLong EXIF_TAG_JPG_FROM_RAW_START_SUB_IFD = new TagInfoLong(
+            "Jpg From Raw Start", 0x0201, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD, true);
+    public static final TagInfoLong EXIF_TAG_JPG_FROM_RAW_START_IFD2 = new TagInfoLong(
+            "Jpg From Raw Start", 0x0201, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD2, true);
+    public static final TagInfoLong EXIF_TAG_OTHER_IMAGE_START = new TagInfoLong(
+            "Other Image Start", 0x0201, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN, true);
+    // poly tag public static final TagInfo2 EXIF_TAG_THUMBNAIL_LENGTH = new TagInfo2( "ThumbnailLength", 0x0202, , 1, TiffDirectoryType.EXIF_DIRECTORY_IFD1);
+    public static final TagInfoLong EXIF_TAG_PREVIEW_IMAGE_LENGTH_MAKER_NOTES = new TagInfoLong(
+            "Preview Image Length", 0x0202, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_MAKER_NOTES);
+    public static final TagInfoLong EXIF_TAG_JPG_FROM_RAW_LENGTH_SUB_IFD = new TagInfoLong(
+            "Jpg From Raw Length", 0x0202, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoLong EXIF_TAG_JPG_FROM_RAW_LENGTH_IFD2 = new TagInfoLong(
+            "Jpg From Raw Length", 0x0202, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD2);
+    public static final TagInfoLong EXIF_TAG_OTHER_IMAGE_LENGTH = new TagInfoLong(
+            "Other Image Length", 0x0202, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_JPEGRESTART_INTERVAL = new TagInfoShort(
+            "JPEGRestart Interval", 0x0203, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_JPEGLOSSLESS_PREDICTORS = new TagInfoShort(
+            "JPEGLossless Predictors", 0x0205, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_JPEGPOINT_TRANSFORMS = new TagInfoShort(
+            "JPEGPoint Transforms", 0x0206, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_JPEGQTABLES = new TagInfoLong(
+            "JPEGQTables", 0x0207, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_JPEGDCTABLES = new TagInfoLong(
+            "JPEGDCTables", 0x0208, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_JPEGACTABLES = new TagInfoLong(
+            "JPEGACTables", 0x0209, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_YCBCR_COEFFICIENTS = new TagInfoRational(
+            "YCbCr Coefficients", 0x0211, 3,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_YCBCR_SUB_SAMPLING = new TagInfoShort(
+            "YCbCr Sub Sampling", 0x0212, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_YCBCR_POSITIONING = new TagInfoShort(
+            "YCbCr Positioning", 0x0213, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int YCB_CR_POSITIONING_VALUE_CENTERED = 1;
     public static final int YCB_CR_POSITIONING_VALUE_CO_SITED = 2;
+    public static final TagInfoRational EXIF_TAG_REFERENCE_BLACK_WHITE = new TagInfoRational(
+            "Reference Black White", 0x0214, 6,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_STRIP_ROW_COUNTS = new TagInfoLong(
+            "Strip Row Counts", 0x022f, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_APPLICATION_NOTES = new TagInfoByte(
+            "Application Notes", 0x02bc, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_RELATED_IMAGE_FILE_FORMAT = new TagInfoAscii(
+            "Related Image File Format", 0x1000, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD);
+    public static final TagInfoShort EXIF_TAG_RELATED_IMAGE_WIDTH = new TagInfoShort(
+            "Related Image Width", 0x1001, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD);
+    public static final TagInfoShort EXIF_TAG_RELATED_IMAGE_LENGTH = new TagInfoShort(
+            "Related Image Length", 0x1002, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_INTEROP_IFD);
+    public static final TagInfoShort EXIF_TAG_RATING = new TagInfoShort("Rating", 0x4746,
+            1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_RATING_PERCENT = new TagInfoShort(
+            "Rating Percent", 0x4749, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_IMAGE_ID = new TagInfoAscii("Image ID",
+            0x800d, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_WANG_ANNOTATION = new TagInfoByte(
+            "Wang Annotation", 0x80a4, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_MATTEING = new TagInfoUnknown("Matteing",
+            0x80e3, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_DATA_TYPE = new TagInfoUnknown("Data Type",
+            0x80e4, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_IMAGE_DEPTH = new TagInfoUnknown(
+            "Image Depth", 0x80e5, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_TILE_DEPTH = new TagInfoUnknown("Tile Depth",
+            0x80e6, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_MODEL_2 = new TagInfoUnknown("Model 2",
+            0x827d, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_CFAREPEAT_PATTERN_DIM = new TagInfoShort(
+            "CFARepeat Pattern Dim", 0x828d, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_CFAPATTERN_2 = new TagInfoByte(
+            "CFAPattern 2", 0x828e, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    // FIXME: rational or ascii!!! N4378
+    public static final TagInfoRational EXIF_TAG_BATTERY_LEVEL = new TagInfoRational(
+            "Battery Level", 0x828f, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_COPYRIGHT = new TagInfoAscii("Copyright",
+            0x8298, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_EXPOSURE_TIME = new TagInfoRational(
+            "Exposure Time", 0x829a, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_FNUMBER = new TagInfoRational("FNumber",
+            0x829d, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoLong EXIF_TAG_MDFILE_TAG = new TagInfoLong("MDFile Tag",
+            0x82a5, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_MDSCALE_PIXEL = new TagInfoRational(
+            "MDScale Pixel", 0x82a6, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_MDCOLOR_TABLE = new TagInfoShort(
+            "MDColor Table", 0x82a7, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_MDLAB_NAME = new TagInfoAscii("MDLab Name",
+            0x82a8, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_MDSAMPLE_INFO = new TagInfoAscii(
+            "MDSample Info", 0x82a9, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_MDPREP_DATE = new TagInfoAscii(
+            "MDPrep Date", 0x82aa, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_MDPREP_TIME = new TagInfoAscii(
+            "MDPrep Time", 0x82ab, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_MDFILE_UNITS = new TagInfoAscii(
+            "MDFile Units", 0x82ac, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoDouble EXIF_TAG_PIXEL_SCALE = new TagInfoDouble(
+            "Pixel Scale", 0x830e, 3,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    // FIXME: other types?
+    public static final TagInfoLong EXIF_TAG_IPTC_NAA = new TagInfoLong("IPTC-NAA",
+            0x83bb, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoShort EXIF_TAG_INTERGRAPH_PACKET_DATA = new TagInfoShort(
+            "Intergraph Packet Data", 0x847e,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_INTERGRAPH_FLAG_REGISTERS = new TagInfoLong(
+            "Intergraph Flag Registers", 0x847f,
+            16, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoDouble EXIF_TAG_INTERGRAPH_MATRIX = new TagInfoDouble(
+            "Intergraph Matrix", 0x8480, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoDouble EXIF_TAG_MODEL_TIE_POINT = new TagInfoDouble(
+            "Model Tie Point", 0x8482, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_SITE = new TagInfoAscii("Site", 0x84e0,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_COLOR_SEQUENCE = new TagInfoAscii(
+            "Color Sequence", 0x84e1, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_IT8HEADER = new TagInfoAscii("IT8 Header",
+            0x84e2, -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_RASTER_PADDING = new TagInfoShort(
+            "Raster Padding", 0x84e3, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_BITS_PER_RUN_LENGTH = new TagInfoShort(
+            "Bits Per Run Length", 0x84e4, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_BITS_PER_EXTENDED_RUN_LENGTH = new TagInfoShort(
+            "Bits Per Extended Run Length", 0x84e5,
+            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_COLOR_TABLE = new TagInfoByte(
+            "Color Table", 0x84e6, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_IMAGE_COLOR_INDICATOR = new TagInfoByte(
+            "Image Color Indicator", 0x84e7, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_BACKGROUND_COLOR_INDICATOR = new TagInfoByte(
+            "Background Color Indicator", 0x84e8,
+            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_IMAGE_COLOR_VALUE = new TagInfoByte(
+            "Image Color Value", 0x84e9, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_BACKGROUND_COLOR_VALUE = new TagInfoByte(
+            "Background Color Value", 0x84ea,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_PIXEL_INTENSITY_RANGE = new TagInfoByte(
+            "Pixel Intensity Range", 0x84eb, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_TRANSPARENCY_INDICATOR = new TagInfoByte(
+            "Transparency Indicator", 0x84ec,
+            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_COLOR_CHARACTERIZATION = new TagInfoAscii(
+            "Color Characterization", 0x84ed, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShortOrLong EXIF_TAG_HCUSAGE = new TagInfoShortOrLong("HCUsage",
+            0x84ee, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_SEMINFO = new TagInfoAscii("SEMInfo",
+            0x8546, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_AFCP_IPTC = new TagInfoLong("AFCP_IPTC",
+            0x8568, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoDouble EXIF_TAG_MODEL_TRANSFORM = new TagInfoDouble(
+            "Model Transform", 0x85d8, 16,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_LEAF_DATA = new TagInfoLong("Leaf Data",
+            0x8606, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_PHOTOSHOP_SETTINGS = new TagInfoByte(
+            "Photoshop Settings", 0x8649, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_EXIF_OFFSET = new TagInfoLong(
+            "Exif Offset", 0x8769, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN, true);
+    public static final TagInfoUndefined EXIF_TAG_ICC_PROFILE = new TagInfoUndefined(
+            "ICC_ Profile", 0x8773, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShortOrLong EXIF_TAG_IMAGE_LAYER = new TagInfoShortOrLong(
+            "Image Layer", 0x87ac, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_GEO_TIFF_DIRECTORY = new TagInfoShort(
+            "Geo Tiff Directory", 0x87af, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoDouble EXIF_TAG_GEO_TIFF_DOUBLE_PARAMS = new TagInfoDouble(
+            "Geo Tiff Double Params", 0x87b0,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_GEO_TIFF_ASCII_PARAMS = new TagInfoAscii(
+            "Geo Tiff Ascii Params", 0x87b1, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_EXPOSURE_PROGRAM = new TagInfoShort(
+            "Exposure Program", 0x8822, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int EXPOSURE_PROGRAM_VALUE_MANUAL = 1;
     public static final int EXPOSURE_PROGRAM_VALUE_PROGRAM_AE = 2;
     public static final int EXPOSURE_PROGRAM_VALUE_APERTURE_PRIORITY_AE = 3;
@@ -1087,6 +616,72 @@
     public static final int EXPOSURE_PROGRAM_VALUE_ACTION_HIGH_SPEED = 6;
     public static final int EXPOSURE_PROGRAM_VALUE_PORTRAIT = 7;
     public static final int EXPOSURE_PROGRAM_VALUE_LANDSCAPE = 8;
+    public static final TagInfoAscii EXIF_TAG_SPECTRAL_SENSITIVITY = new TagInfoAscii(
+            "Spectral Sensitivity", 0x8824, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoLong EXIF_TAG_GPSINFO = new TagInfoLong(
+            "GPSInfo", 0x8825, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN, true);
+    public static final TagInfoShort EXIF_TAG_ISO = new TagInfoShort("ISO", 0x8827,
+            1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoUndefined EXIF_TAG_OPTO__ELECTRIC_CONV_FACTOR = new TagInfoUndefined(
+            "Opto - Electric Conv Factor", 0x8828,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_INTERLACE = new TagInfoShort("Interlace",
+            0x8829, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSShort EXIF_TAG_TIME_ZONE_OFFSET = new TagInfoSShort(
+            "Time Zone Offset", 0x882a, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_SELF_TIMER_MODE = new TagInfoShort(
+            "Self Timer Mode", 0x882b, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoLong EXIF_TAG_FAX_RECV_PARAMS = new TagInfoLong(
+            "Fax Recv Params", 0x885c, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_FAX_SUB_ADDRESS = new TagInfoAscii(
+            "Fax Sub Address", 0x885d, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_FAX_RECV_TIME = new TagInfoLong(
+            "Fax Recv Time", 0x885e, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_LEAF_SUB_IFD = new TagInfoLong(
+            "Leaf Sub IFD", 0x888a, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUndefined EXIF_TAG_EXIF_VERSION = new TagInfoUndefined(
+            "Exif Version", 0x9000, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_DATE_TIME_ORIGINAL = new TagInfoAscii(
+            "Date Time Original", 0x9003, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_CREATE_DATE = new TagInfoAscii(
+            "Create Date", 0x9004, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoUndefined EXIF_TAG_COMPONENTS_CONFIGURATION = new TagInfoUndefined(
+            "Components Configuration", 0x9101, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_COMPRESSED_BITS_PER_PIXEL = new TagInfoRational(
+            "Compressed Bits Per Pixel", 0x9102, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoSRational EXIF_TAG_SHUTTER_SPEED_VALUE = new TagInfoSRational(
+            "Shutter Speed Value", 0x9201, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_APERTURE_VALUE = new TagInfoRational(
+            "Aperture Value", 0x9202, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoSRational EXIF_TAG_BRIGHTNESS_VALUE = new TagInfoSRational(
+            "Brightness Value", 0x9203, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoSRational EXIF_TAG_EXPOSURE_COMPENSATION = new TagInfoSRational(
+            "Exposure Compensation", 0x9204, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_MAX_APERTURE_VALUE = new TagInfoRational(
+            "Max Aperture Value", 0x9205, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_SUBJECT_DISTANCE = new TagInfoRational(
+            "Subject Distance", 0x9206, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_METERING_MODE = new TagInfoShort(
+            "Metering Mode", 0x9207, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int METERING_MODE_VALUE_AVERAGE = 1;
     public static final int METERING_MODE_VALUE_CENTER_WEIGHTED_AVERAGE = 2;
     public static final int METERING_MODE_VALUE_SPOT = 3;
@@ -1094,6 +689,9 @@
     public static final int METERING_MODE_VALUE_MULTI_SEGMENT = 5;
     public static final int METERING_MODE_VALUE_PARTIAL = 6;
     public static final int METERING_MODE_VALUE_OTHER = 255;
+    public static final TagInfoShort EXIF_TAG_LIGHT_SOURCE = new TagInfoShort(
+            "Light Source", 0x9208, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int LIGHT_SOURCE_VALUE_DAYLIGHT = 1;
     public static final int LIGHT_SOURCE_VALUE_FLUORESCENT = 2;
     public static final int LIGHT_SOURCE_VALUE_TUNGSTEN = 3;
@@ -1114,6 +712,8 @@
     public static final int LIGHT_SOURCE_VALUE_D50 = 23;
     public static final int LIGHT_SOURCE_VALUE_ISO_STUDIO_TUNGSTEN = 24;
     public static final int LIGHT_SOURCE_VALUE_OTHER = 255;
+    public static final TagInfoShort EXIF_TAG_FLASH = new TagInfoShort("Flash", 0x9209,
+            1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int FLASH_VALUE_NO_FLASH = 0x0;
     public static final int FLASH_VALUE_FIRED = 0x1;
     public static final int FLASH_VALUE_FIRED_RETURN_NOT_DETECTED = 0x5;
@@ -1141,11 +741,51 @@
     public static final int FLASH_VALUE_AUTO_FIRED_RED_EYE_REDUCTION = 0x59;
     public static final int FLASH_VALUE_AUTO_FIRED_RED_EYE_REDUCTION_RETURN_NOT_DETECTED = 0x5d;
     public static final int FLASH_VALUE_AUTO_FIRED_RED_EYE_REDUCTION_RETURN_DETECTED = 0x5f;
+    public static final TagInfoRational EXIF_TAG_FOCAL_LENGTH = new TagInfoRational(
+            "Focal Length", 0x920a, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_FLASH_ENERGY = new TagInfoRational(
+            "Flash Energy", 0x920b, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUndefined EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE_1 = new TagInfoUndefined(
+            "Spatial Frequency Response", 0x920c,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUndefined EXIF_TAG_NOISE_1 = new TagInfoUndefined("Noise", 0x920d,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_FOCAL_PLANE_XRESOLUTION = new TagInfoRational(
+            "Focal Plane XResolution", 0x920e,
+            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_FOCAL_PLANE_YRESOLUTION = new TagInfoRational(
+            "Focal Plane YResolution", 0x920f,
+            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT = new TagInfoShort(
+            "Focal Plane Resolution Unit", 0x9210,
+            1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_VALUE_NONE = 1;
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_VALUE_INCHES = 2;
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_VALUE_CM = 3;
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_VALUE_MM = 4;
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_VALUE_UM = 5;
+    public static final TagInfoLong EXIF_TAG_IMAGE_NUMBER_EXIF_IFD = new TagInfoLong(
+            "Image Number", 0x9211, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SECURITY_CLASSIFICATION_EXIF_IFD = new TagInfoAscii(
+            "Security Classification", 0x9212, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_IMAGE_HISTORY_EXIF_IFD = new TagInfoAscii(
+            "Image History", 0x9213, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_SUBJECT_LOCATION_1 = new TagInfoShort(
+            "Subject Location", 0x9214, 4,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_EXPOSURE_INDEX = new TagInfoRational(
+            "Exposure Index", 0x9215, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_TIFF_EPSTANDARD_ID_1 = new TagInfoByte(
+            "TIFF- EPStandard ID", 0x9216, 4,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_SENSING_METHOD = new TagInfoShort(
+            "Sensing Method", 0x9217, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int SENSING_METHOD_VALUE_MONOCHROME_AREA = 1;
     public static final int SENSING_METHOD_VALUE_ONE_CHIP_COLOR_AREA = 2;
     public static final int SENSING_METHOD_VALUE_TWO_CHIP_COLOR_AREA = 3;
@@ -1154,14 +794,99 @@
     public static final int SENSING_METHOD_VALUE_MONOCHROME_LINEAR = 6;
     public static final int SENSING_METHOD_VALUE_TRILINEAR = 7;
     public static final int SENSING_METHOD_VALUE_COLOR_SEQUENTIAL_LINEAR = 8;
+    public static final TagInfoDouble EXIF_TAG_STO_NITS = new TagInfoDouble("Sto Nits",
+            0x923f, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    //     skipping Maker Note!
+    public static final TagInfoUndefined EXIF_TAG_MAKER_NOTE = new TagInfoUndefined("Maker Note",
+            0x927c, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoText EXIF_TAG_USER_COMMENT = new TagInfoText(
+            "UserComment", 0x9286, FIELD_TYPE_UNDEFINED, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SUB_SEC_TIME = new TagInfoAscii(
+            "Sub Sec Time", 0x9290, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SUB_SEC_TIME_ORIGINAL = new TagInfoAscii(
+            "Sub Sec Time Original", 0x9291, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SUB_SEC_TIME_DIGITIZED = new TagInfoAscii(
+            "Sub Sec Time Digitized", 0x9292, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoUndefined EXIF_TAG_IMAGE_SOURCE_DATA = new TagInfoUndefined(
+            "Image Source Data", 0x935c, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_XPTITLE = new TagInfoByte("XPTitle",
+            0x9c9b, -1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_XPCOMMENT = new TagInfoByte("XPComment",
+            0x9c9c, -1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_XPAUTHOR = new TagInfoByte("XPAuthor",
+            0x9c9d, -1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_XPKEYWORDS = new TagInfoByte("XPKeywords",
+            0x9c9e, -1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_XPSUBJECT = new TagInfoByte("XPSubject",
+            0x9c9f, -1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoUndefined EXIF_TAG_FLASHPIX_VERSION = new TagInfoUndefined(
+            "Flashpix Version", 0xa000, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_COLOR_SPACE = new TagInfoShort(
+            "Color Space", 0xa001, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int COLOR_SPACE_VALUE_SRGB = 1;
     public static final int COLOR_SPACE_VALUE_ADOBE_RGB = 2;
     public static final int COLOR_SPACE_VALUE_UNCALIBRATED = 65535;
+    public static final TagInfoShort EXIF_TAG_EXIF_IMAGE_WIDTH = new TagInfoShort(
+            "Exif Image Width", 0xa002, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_EXIF_IMAGE_LENGTH = new TagInfoShort(
+            "Exif Image Length", 0xa003, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_RELATED_SOUND_FILE = new TagInfoAscii(
+            "Related Sound File", 0xa004, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoLong EXIF_TAG_INTEROP_OFFSET = new TagInfoLong(
+            "Interop Offset", 0xa005, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN, true);
+    public static final TagInfoRational EXIF_TAG_FLASH_ENERGY_EXIF_IFD = new TagInfoRational(
+            "Flash Energy", 0xa20b, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoUndefined EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE_2 = new TagInfoUndefined(
+            "Spatial Frequency Response", 0xa20c,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_NOISE_2 = new TagInfoUnknown("Noise", 0xa20d,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_FOCAL_PLANE_XRESOLUTION_EXIF_IFD = new TagInfoRational(
+            "Focal Plane XResolution", 0xa20e, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_FOCAL_PLANE_YRESOLUTION_EXIF_IFD = new TagInfoRational(
+            "Focal Plane YResolution", 0xa20f, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT_EXIF_IFD = new TagInfoShort(
+            "Focal Plane Resolution Unit", 0xa210, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_EXIF_IFD_VALUE_NONE = 1;
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_EXIF_IFD_VALUE_INCHES = 2;
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_EXIF_IFD_VALUE_CM = 3;
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_EXIF_IFD_VALUE_MM = 4;
     public static final int FOCAL_PLANE_RESOLUTION_UNIT_EXIF_IFD_VALUE_UM = 5;
+    public static final TagInfoUnknown EXIF_TAG_IMAGE_NUMBER = new TagInfoUnknown(
+            "Image Number", 0xa211, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_SECURITY_CLASSIFICATION = new TagInfoUnknown(
+            "Security Classification", 0xa212,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_IMAGE_HISTORY = new TagInfoUnknown(
+            "Image History", 0xa213, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_SUBJECT_LOCATION_2 = new TagInfoShort(
+            "Subject Location", 0xa214, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoRational EXIF_TAG_EXPOSURE_INDEX_EXIF_IFD = new TagInfoRational(
+            "Exposure Index", 0xa215, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoUnknown EXIF_TAG_TIFF_EPSTANDARD_ID_2 = new TagInfoUnknown(
+            "TIFF-EPStandard ID", 0xa216, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_SENSING_METHOD_EXIF_IFD = new TagInfoShort(
+            "Sensing Method", 0xa217, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int SENSING_METHOD_EXIF_IFD_VALUE_NOT_DEFINED = 1;
     public static final int SENSING_METHOD_EXIF_IFD_VALUE_ONE_CHIP_COLOR_AREA = 2;
     public static final int SENSING_METHOD_EXIF_IFD_VALUE_TWO_CHIP_COLOR_AREA = 3;
@@ -1169,37 +894,92 @@
     public static final int SENSING_METHOD_EXIF_IFD_VALUE_COLOR_SEQUENTIAL_AREA = 5;
     public static final int SENSING_METHOD_EXIF_IFD_VALUE_TRILINEAR = 7;
     public static final int SENSING_METHOD_EXIF_IFD_VALUE_COLOR_SEQUENTIAL_LINEAR = 8;
+    public static final TagInfoUndefined EXIF_TAG_FILE_SOURCE = new TagInfoUndefined(
+            "File Source", 0xa300, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int FILE_SOURCE_VALUE_FILM_SCANNER = 1;
     public static final int FILE_SOURCE_VALUE_REFLECTION_PRINT_SCANNER = 2;
     public static final int FILE_SOURCE_VALUE_DIGITAL_CAMERA = 3;
+    public static final TagInfoUndefined EXIF_TAG_SCENE_TYPE = new TagInfoUndefined("Scene Type",
+            0xa301, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoUndefined EXIF_TAG_CFAPATTERN = new TagInfoUndefined("CFAPattern",
+            0xa302, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_CUSTOM_RENDERED = new TagInfoShort(
+            "Custom Rendered", 0xa401, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int CUSTOM_RENDERED_VALUE_NORMAL = 0;
     public static final int CUSTOM_RENDERED_VALUE_CUSTOM = 1;
+    public static final TagInfoShort EXIF_TAG_EXPOSURE_MODE = new TagInfoShort(
+            "Exposure Mode", 0xa402, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int EXPOSURE_MODE_VALUE_AUTO = 0;
     public static final int EXPOSURE_MODE_VALUE_MANUAL = 1;
     public static final int EXPOSURE_MODE_VALUE_AUTO_BRACKET = 2;
+    public static final TagInfoShort EXIF_TAG_WHITE_BALANCE_1 = new TagInfoShort(
+            "White Balance", 0xa403, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int WHITE_BALANCE_1_VALUE_AUTO = 0;
     public static final int WHITE_BALANCE_1_VALUE_MANUAL = 1;
+    public static final TagInfoRational EXIF_TAG_DIGITAL_ZOOM_RATIO = new TagInfoRational(
+            "Digital Zoom Ratio", 0xa404, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_FOCAL_LENGTH_IN_35MM_FORMAT = new TagInfoShort(
+            "Focal Length In 3 5mm Format", 0xa405, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoShort EXIF_TAG_SCENE_CAPTURE_TYPE = new TagInfoShort(
+            "Scene Capture Type", 0xa406, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int SCENE_CAPTURE_TYPE_VALUE_STANDARD = 0;
     public static final int SCENE_CAPTURE_TYPE_VALUE_LANDSCAPE = 1;
     public static final int SCENE_CAPTURE_TYPE_VALUE_PORTRAIT = 2;
     public static final int SCENE_CAPTURE_TYPE_VALUE_NIGHT = 3;
+    public static final TagInfoShort EXIF_TAG_GAIN_CONTROL = new TagInfoShort(
+            "Gain Control", 0xa407, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int GAIN_CONTROL_VALUE_NONE = 0;
     public static final int GAIN_CONTROL_VALUE_LOW_GAIN_UP = 1;
     public static final int GAIN_CONTROL_VALUE_HIGH_GAIN_UP = 2;
     public static final int GAIN_CONTROL_VALUE_LOW_GAIN_DOWN = 3;
     public static final int GAIN_CONTROL_VALUE_HIGH_GAIN_DOWN = 4;
+    public static final TagInfoShort EXIF_TAG_CONTRAST_1 = new TagInfoShort("Contrast",
+            0xa408, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int CONTRAST_1_VALUE_NORMAL = 0;
     public static final int CONTRAST_1_VALUE_LOW = 1;
     public static final int CONTRAST_1_VALUE_HIGH = 2;
+    public static final TagInfoShort EXIF_TAG_SATURATION_1 = new TagInfoShort(
+            "Saturation", 0xa409, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int SATURATION_1_VALUE_NORMAL = 0;
     public static final int SATURATION_1_VALUE_LOW = 1;
     public static final int SATURATION_1_VALUE_HIGH = 2;
+    public static final TagInfoShort EXIF_TAG_SHARPNESS_1 = new TagInfoShort("Sharpness",
+            0xa40a, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int SHARPNESS_1_VALUE_NORMAL = 0;
     public static final int SHARPNESS_1_VALUE_SOFT = 1;
     public static final int SHARPNESS_1_VALUE_HARD = 2;
+    public static final TagInfoUndefined EXIF_TAG_DEVICE_SETTING_DESCRIPTION = new TagInfoUndefined(
+            "Device Setting Description", 0xa40b,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_SUBJECT_DISTANCE_RANGE = new TagInfoShort(
+            "Subject Distance Range", 0xa40c, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
     public static final int SUBJECT_DISTANCE_RANGE_VALUE_MACRO = 1;
     public static final int SUBJECT_DISTANCE_RANGE_VALUE_CLOSE = 2;
     public static final int SUBJECT_DISTANCE_RANGE_VALUE_DISTANT = 3;
+    public static final TagInfoAscii EXIF_TAG_IMAGE_UNIQUE_ID = new TagInfoAscii(
+            "Image Unique ID", 0xa420, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_GDALMETADATA = new TagInfoAscii(
+            "GDALMetadata", 0xa480, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_GDALNO_DATA = new TagInfoAscii(
+            "GDALNo Data", 0xa481, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_GAMMA = new TagInfoRational("Gamma", 0xa500,
+            1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoByte EXIF_TAG_PIXEL_FORMAT = new TagInfoByte(
+            "Pixel Format", 0xbc01, 16,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    // FIXME: convert to GUIDs
     public static final int PIXEL_FORMAT_VALUE_BLACK_AND_WHITE = 0x5;
     public static final int PIXEL_FORMAT_VALUE_8_BIT_GRAY = 0x8;
     public static final int PIXEL_FORMAT_VALUE_16_BIT_BGR555 = 0x9;
@@ -1255,6 +1035,9 @@
     public static final int PIXEL_FORMAT_VALUE_32_BIT_RGBE = 0x3d;
     public static final int PIXEL_FORMAT_VALUE_16_BIT_GRAY_HALF = 0x3e;
     public static final int PIXEL_FORMAT_VALUE_32_BIT_GRAY_FIXED_POINT = 0x3f;
+    public static final TagInfoLong EXIF_TAG_TRANSFOMATION = new TagInfoLong(
+            "Transfomation", 0xbc02, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int TRANSFOMATION_VALUE_HORIZONTAL_NORMAL = 0;
     public static final int TRANSFOMATION_VALUE_MIRROR_VERTICAL = 1;
     public static final int TRANSFOMATION_VALUE_MIRROR_HORIZONTAL = 2;
@@ -1263,23 +1046,192 @@
     public static final int TRANSFOMATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_90_CW = 5;
     public static final int TRANSFOMATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_270_CW = 6;
     public static final int TRANSFOMATION_VALUE_ROTATE_270_CW = 7;
+    public static final TagInfoLong EXIF_TAG_UNCOMPRESSED = new TagInfoLong(
+            "Uncompressed", 0xbc03, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int UNCOMPRESSED_VALUE_NO = 0;
     public static final int UNCOMPRESSED_VALUE_YES = 1;
+    public static final TagInfoLong EXIF_TAG_IMAGE_TYPE = new TagInfoLong("Image Type",
+            0xbc04, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_IMAGE_WIDTH = new TagInfoLong(
+            "Image Width", 0xbc80, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_IMAGE_HEIGHT = new TagInfoLong(
+            "Image Height", 0xbc81, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoFloat EXIF_TAG_WIDTH_RESOLUTION = new TagInfoFloat(
+            "Width Resolution", 0xbc82, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoFloat EXIF_TAG_HEIGHT_RESOLUTION = new TagInfoFloat(
+            "Height Resolution", 0xbc83, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    // FIXME: might be an offset?
+    public static final TagInfoLong EXIF_TAG_IMAGE_OFFSET = new TagInfoLong(
+            "Image Offset", 0xbcc0, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_IMAGE_BYTE_COUNT = new TagInfoLong(
+            "Image Byte Count", 0xbcc1, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    // FIXME: might be an offset?
+    public static final TagInfoLong EXIF_TAG_ALPHA_OFFSET = new TagInfoLong(
+            "Alpha Offset", 0xbcc2, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoLong EXIF_TAG_ALPHA_BYTE_COUNT = new TagInfoLong(
+            "Alpha Byte Count", 0xbcc3, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_IMAGE_DATA_DISCARD = new TagInfoByte(
+            "Image Data Discard", 0xbcc4, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int IMAGE_DATA_DISCARD_VALUE_FULL_RESOLUTION = 0;
     public static final int IMAGE_DATA_DISCARD_VALUE_FLEXBITS_DISCARDED = 1;
     public static final int IMAGE_DATA_DISCARD_VALUE_HIGH_PASS_FREQUENCY_DATA_DISCARDED = 2;
     public static final int IMAGE_DATA_DISCARD_VALUE_HIGHPASS_AND_LOW_PASS_FREQUENCY_DATA_DISCARDED = 3;
+    public static final TagInfoByte EXIF_TAG_ALPHA_DATA_DISCARD = new TagInfoByte(
+            "Alpha Data Discard", 0xbcc5, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int ALPHA_DATA_DISCARD_VALUE_FULL_RESOLUTION = 0;
     public static final int ALPHA_DATA_DISCARD_VALUE_FLEXBITS_DISCARDED = 1;
     public static final int ALPHA_DATA_DISCARD_VALUE_HIGH_PASS_FREQUENCY_DATA_DISCARDED = 2;
     public static final int ALPHA_DATA_DISCARD_VALUE_HIGHPASS_AND_LOW_PASS_FREQUENCY_DATA_DISCARDED = 3;
+    public static final TagInfoAscii EXIF_TAG_OCE_SCANJOB_DESC = new TagInfoAscii(
+            "Oce Scanjob Desc", 0xc427, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_OCE_APPLICATION_SELECTOR = new TagInfoAscii(
+            "Oce Application Selector", 0xc428,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_OCE_IDNUMBER = new TagInfoAscii(
+            "Oce IDNumber", 0xc429, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_OCE_IMAGE_LOGIC = new TagInfoAscii(
+            "Oce Image Logic", 0xc42a, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUnknown EXIF_TAG_ANNOTATIONS = new TagInfoUnknown(
+            "Annotations", 0xc44f, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUndefined EXIF_TAG_PRINT_IM = new TagInfoUndefined("Print IM",
+            0xc4a5, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_DNG_VERSION = new TagInfoByte(
+            "DNG Version", 0xc612, 4, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_DNG_BACKWARD_VERSION = new TagInfoByte(
+            "DNG Backward Version", 0xc613, 4,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_UNIQUE_CAMERA_MODEL = new TagInfoAscii(
+            "Unique Camera Model", 0xc614, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_LOCALIZED_CAMERA_MODEL = new TagInfoAscii(
+            "Localized Camera Model", 0xc615, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_CFAPLANE_COLOR = new TagInfoByte(
+            "CFAPlane Color", 0xc616, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_CFALAYOUT = new TagInfoShort("CFALayout",
+            0xc617, 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
     public static final int CFALAYOUT_VALUE_RECTANGULAR = 1;
     public static final int CFALAYOUT_VALUE_EVEN_COLUMNS_OFFSET_DOWN_1_2_ROW = 2;
     public static final int CFALAYOUT_VALUE_EVEN_COLUMNS_OFFSET_UP_1_2_ROW = 3;
     public static final int CFALAYOUT_VALUE_EVEN_ROWS_OFFSET_RIGHT_1_2_COLUMN = 4;
     public static final int CFALAYOUT_VALUE_EVEN_ROWS_OFFSET_LEFT_1_2_COLUMN = 5;
+    public static final TagInfoShort EXIF_TAG_LINEARIZATION_TABLE = new TagInfoShort(
+            "Linearization Table", 0xc618, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_BLACK_LEVEL_REPEAT_DIM = new TagInfoShort(
+            "Black Level Repeat Dim", 0xc619,
+            2, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShortOrLongOrRational EXIF_TAG_BLACK_LEVEL = new TagInfoShortOrLongOrRational(
+            "Black Level", 0xc61a, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_BLACK_LEVEL_DELTA_H = new TagInfoSRational(
+            "Black Level Delta H", 0xc61b, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_BLACK_LEVEL_DELTA_V = new TagInfoSRational(
+            "Black Level Delta V", 0xc61c, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShortOrLong EXIF_TAG_WHITE_LEVEL = new TagInfoShortOrLong(
+            "White Level", 0xc61d, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_DEFAULT_SCALE = new TagInfoRational(
+            "Default Scale", 0xc61e, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoShortOrLongOrRational EXIF_TAG_DEFAULT_CROP_ORIGIN = new TagInfoShortOrLongOrRational(
+            "Default Crop Origin", 0xc61f, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoShortOrLongOrRational EXIF_TAG_DEFAULT_CROP_SIZE = new TagInfoShortOrLongOrRational(
+            "Default Crop Size", 0xc620, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoSRational EXIF_TAG_COLOR_MATRIX_1 = new TagInfoSRational(
+            "Color Matrix 1", 0xc621, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_COLOR_MATRIX_2 = new TagInfoSRational(
+            "Color Matrix 2", 0xc622, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_CAMERA_CALIBRATION_1 = new TagInfoSRational(
+            "Camera Calibration 1", 0xc623, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_CAMERA_CALIBRATION_2 = new TagInfoSRational(
+            "Camera Calibration 2", 0xc624, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_REDUCTION_MATRIX_1 = new TagInfoSRational(
+            "Reduction Matrix 1", 0xc625, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_REDUCTION_MATRIX_2 = new TagInfoSRational(
+            "Reduction Matrix 2", 0xc626, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_ANALOG_BALANCE = new TagInfoRational(
+            "Analog Balance", 0xc627, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShortOrRational EXIF_TAG_AS_SHOT_NEUTRAL = new TagInfoShortOrRational(
+            "As Shot Neutral", 0xc628, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoRational EXIF_TAG_AS_SHOT_WHITE_XY = new TagInfoRational(
+            "As Shot White XY", 0xc629, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoSRational EXIF_TAG_BASELINE_EXPOSURE = new TagInfoSRational(
+            "Baseline Exposure", 0xc62a, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_BASELINE_NOISE = new TagInfoRational(
+            "Baseline Noise", 0xc62b, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_BASELINE_SHARPNESS = new TagInfoRational(
+            "Baseline Sharpness", 0xc62c, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_BAYER_GREEN_SPLIT = new TagInfoLong(
+            "Bayer Green Split", 0xc62d, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoRational EXIF_TAG_LINEAR_RESPONSE_LIMIT = new TagInfoRational(
+            "Linear Response Limit", 0xc62e, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoAscii EXIF_TAG_CAMERA_SERIAL_NUMBER = new TagInfoAscii(
+            "Camera Serial Number", 0xc62f, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_DNG_LENS_INFO = new TagInfoRational(
+            "DNG Lens Info", 0xc630, 4,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoRational EXIF_TAG_CHROMA_BLUR_RADIUS = new TagInfoRational(
+            "Chroma Blur Radius", 0xc631, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoRational EXIF_TAG_ANTI_ALIAS_STRENGTH = new TagInfoRational(
+            "Anti Alias Strength", 0xc632, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoRational EXIF_TAG_SHADOW_SCALE = new TagInfoRational(
+            "Shadow Scale", 0xc633, 1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    // poly tag public static final TagInfo2 EXIF_TAG_SR2PRIVATE = new TagInfo2( "SR2Private", 0xc634, , 1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_DNG_ADOBE_DATA = new TagInfoByte(
+            "DNG Adobe Data", 0xc634, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_DNG_PENTAX_DATA = new TagInfoByte(
+            "DNG Pentax Data", 0xc634, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoByte EXIF_TAG_DNG_PRIVATE_DATA = new TagInfoByte(
+            "DNG Private Data", 0xc634, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoShort EXIF_TAG_MAKER_NOTE_SAFETY = new TagInfoShort(
+            "Maker Note Safety", 0xc635, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int MAKER_NOTE_SAFETY_VALUE_UNSAFE = 0;
     public static final int MAKER_NOTE_SAFETY_VALUE_SAFE = 1;
+    public static final TagInfoShort EXIF_TAG_CALIBRATION_ILLUMINANT_1 = new TagInfoShort(
+            "Calibration Illuminant 1", 0xc65a, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int CALIBRATION_ILLUMINANT_1_VALUE_DAYLIGHT = 1;
     public static final int CALIBRATION_ILLUMINANT_1_VALUE_FLUORESCENT = 2;
     public static final int CALIBRATION_ILLUMINANT_1_VALUE_TUNGSTEN = 3;
@@ -1300,6 +1252,9 @@
     public static final int CALIBRATION_ILLUMINANT_1_VALUE_D50 = 23;
     public static final int CALIBRATION_ILLUMINANT_1_VALUE_ISO_STUDIO_TUNGSTEN = 24;
     public static final int CALIBRATION_ILLUMINANT_1_VALUE_OTHER = 255;
+    public static final TagInfoShort EXIF_TAG_CALIBRATION_ILLUMINANT_2 = new TagInfoShort(
+            "Calibration Illuminant 2", 0xc65b, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
     public static final int CALIBRATION_ILLUMINANT_2_VALUE_DAYLIGHT = 1;
     public static final int CALIBRATION_ILLUMINANT_2_VALUE_FLUORESCENT = 2;
     public static final int CALIBRATION_ILLUMINANT_2_VALUE_TUNGSTEN = 3;
@@ -1320,4 +1275,241 @@
     public static final int CALIBRATION_ILLUMINANT_2_VALUE_D50 = 23;
     public static final int CALIBRATION_ILLUMINANT_2_VALUE_ISO_STUDIO_TUNGSTEN = 24;
     public static final int CALIBRATION_ILLUMINANT_2_VALUE_OTHER = 255;
+    public static final TagInfoRational EXIF_TAG_BEST_QUALITY_SCALE = new TagInfoRational(
+            "Best Quality Scale", 0xc65c, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoByte EXIF_TAG_RAW_DATA_UNIQUE_ID = new TagInfoByte(
+            "Raw Data Unique ID", 0xc65d, 16,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoByte EXIF_TAG_ALIAS_LAYER_METADATA = new TagInfoByte(
+            "Alias Layer Metadata", 0xc660, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoAscii EXIF_TAG_ORIGINAL_RAW_FILE_NAME = new TagInfoAscii(
+            "Original Raw File Name", 0xc68b, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoUndefined EXIF_TAG_ORIGINAL_RAW_FILE_DATA = new TagInfoUndefined(
+            "Original Raw File Data", 0xc68c, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_IFD0);
+    public static final TagInfoLong EXIF_TAG_ACTIVE_AREA = new TagInfoLong(
+            "Active Area", 0xc68d, 4, TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoLong EXIF_TAG_MASKED_AREAS = new TagInfoLong(
+            "Masked Areas", 0xc68e, 4, TiffDirectoryType.EXIF_DIRECTORY_SUB_IFD);
+    public static final TagInfoByte EXIF_TAG_AS_SHOT_ICCPROFILE = new TagInfoByte(
+            "As Shot ICCProfile", 0xc68f, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_AS_SHOT_PRE_PROFILE_MATRIX = new TagInfoSRational(
+            "As Shot Pre Profile Matrix", 0xc690,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoUndefined EXIF_TAG_CURRENT_ICCPROFILE = new TagInfoUndefined(
+            "Current ICCProfile", 0xc691, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSRational EXIF_TAG_CURRENT_PRE_PROFILE_MATRIX = new TagInfoSRational(
+            "Current Pre Profile Matrix", 0xc692,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    public static final TagInfoSLong EXIF_TAG_OFFSET_SCHEMA = new TagInfoSLong(
+            "Offset Schema", 0xea1d, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_OWNER_NAME = new TagInfoAscii("Owner Name",
+            0xfde8, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SERIAL_NUMBER = new TagInfoAscii(
+            "Serial Number", 0xfde9, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_LENS = new TagInfoAscii("Lens", 0xfdea,
+            1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_RAW_FILE = new TagInfoAscii("Raw File",
+            0xfe4c, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_CONVERTER = new TagInfoAscii("Converter",
+            0xfe4d, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_WHITE_BALANCE_2 = new TagInfoAscii(
+            "White Balance", 0xfe4e, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_EXPOSURE = new TagInfoAscii("Exposure",
+            0xfe51, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SHADOWS = new TagInfoAscii("Shadows",
+            0xfe52, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_BRIGHTNESS = new TagInfoAscii("Brightness",
+            0xfe53, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_CONTRAST_2 = new TagInfoAscii("Contrast",
+            0xfe54, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SATURATION_2 = new TagInfoAscii(
+            "Saturation", 0xfe55, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SHARPNESS_2 = new TagInfoAscii("Sharpness",
+            0xfe56, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_SMOOTHNESS = new TagInfoAscii("Smoothness",
+            0xfe57, 1, TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+    public static final TagInfoAscii EXIF_TAG_MOIRE_FILTER = new TagInfoAscii(
+            "Moire Filter", 0xfe58, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_EXIF_IFD);
+
+    public static final List<TagInfo> ALL_EXIF_TAGS =
+            Collections.unmodifiableList(Arrays.asList(
+                    EXIF_TAG_INTEROP_INDEX, EXIF_TAG_INTEROP_VERSION,
+                    EXIF_TAG_PROCESSING_SOFTWARE, EXIF_TAG_SUBFILE_TYPE,
+                    EXIF_TAG_OLD_SUBFILE_TYPE, EXIF_TAG_IMAGE_WIDTH_IFD0,
+                    EXIF_TAG_IMAGE_HEIGHT_IFD0, EXIF_TAG_BITS_PER_SAMPLE,
+                    EXIF_TAG_COMPRESSION, EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
+                    EXIF_TAG_THRESHOLDING, EXIF_TAG_CELL_WIDTH, EXIF_TAG_CELL_LENGTH,
+                    EXIF_TAG_FILL_ORDER, EXIF_TAG_DOCUMENT_NAME,
+                    EXIF_TAG_IMAGE_DESCRIPTION, EXIF_TAG_MAKE, EXIF_TAG_MODEL,
+                    EXIF_TAG_PREVIEW_IMAGE_START_IFD0,
+                    EXIF_TAG_PREVIEW_IMAGE_START_SUB_IFD1,
+                    EXIF_TAG_JPG_FROM_RAW_START_SUB_IFD2, EXIF_TAG_ORIENTATION,
+                    EXIF_TAG_SAMPLES_PER_PIXEL, EXIF_TAG_ROWS_PER_STRIP,
+                    EXIF_TAG_PREVIEW_IMAGE_LENGTH_IFD0,
+                    EXIF_TAG_PREVIEW_IMAGE_LENGTH_SUB_IFD1,
+                    EXIF_TAG_JPG_FROM_RAW_LENGTH_SUB_IFD2, EXIF_TAG_MIN_SAMPLE_VALUE,
+                    EXIF_TAG_MAX_SAMPLE_VALUE, EXIF_TAG_XRESOLUTION,
+                    EXIF_TAG_YRESOLUTION, EXIF_TAG_PLANAR_CONFIGURATION,
+                    EXIF_TAG_PAGE_NAME, EXIF_TAG_XPOSITION, EXIF_TAG_YPOSITION,
+                    EXIF_TAG_FREE_OFFSETS, EXIF_TAG_FREE_BYTE_COUNTS,
+                    EXIF_TAG_GRAY_RESPONSE_UNIT, EXIF_TAG_GRAY_RESPONSE_CURVE,
+                    EXIF_TAG_T4OPTIONS, EXIF_TAG_T6OPTIONS, EXIF_TAG_RESOLUTION_UNIT,
+                    EXIF_TAG_PAGE_NUMBER, EXIF_TAG_COLOR_RESPONSE_UNIT,
+                    EXIF_TAG_TRANSFER_FUNCTION, EXIF_TAG_SOFTWARE,
+                    EXIF_TAG_MODIFY_DATE, EXIF_TAG_ARTIST, EXIF_TAG_HOST_COMPUTER,
+                    EXIF_TAG_PREDICTOR, EXIF_TAG_WHITE_POINT,
+                    EXIF_TAG_PRIMARY_CHROMATICITIES, EXIF_TAG_COLOR_MAP,
+                    EXIF_TAG_HALFTONE_HINTS, EXIF_TAG_TILE_WIDTH, EXIF_TAG_TILE_LENGTH,
+                    EXIF_TAG_TILE_OFFSETS, EXIF_TAG_TILE_BYTE_COUNTS,
+                    EXIF_TAG_BAD_FAX_LINES, EXIF_TAG_CLEAN_FAX_DATA,
+                    EXIF_TAG_CONSECUTIVE_BAD_FAX_LINES, EXIF_TAG_SUB_IFD,
+                    EXIF_TAG_INK_SET, EXIF_TAG_INK_NAMES, EXIF_TAG_NUMBEROF_INKS,
+                    EXIF_TAG_DOT_RANGE, EXIF_TAG_TARGET_PRINTER,
+                    EXIF_TAG_EXTRA_SAMPLES, EXIF_TAG_SAMPLE_FORMAT,
+                    EXIF_TAG_SMIN_SAMPLE_VALUE, EXIF_TAG_SMAX_SAMPLE_VALUE,
+                    EXIF_TAG_TRANSFER_RANGE, EXIF_TAG_CLIP_PATH,
+                    EXIF_TAG_XCLIP_PATH_UNITS, EXIF_TAG_YCLIP_PATH_UNITS,
+                    EXIF_TAG_INDEXED, EXIF_TAG_JPEGTABLES, EXIF_TAG_OPIPROXY,
+                    EXIF_TAG_GLOBAL_PARAMETERS_IFD, EXIF_TAG_PROFILE_TYPE,
+                    EXIF_TAG_FAX_PROFILE, EXIF_TAG_CODING_METHODS,
+                    EXIF_TAG_VERSION_YEAR, EXIF_TAG_MODE_NUMBER, EXIF_TAG_DECODE,
+                    EXIF_TAG_DEFAULT_IMAGE_COLOR, EXIF_TAG_JPEGPROC,
+                    EXIF_TAG_PREVIEW_IMAGE_START_MAKER_NOTES,
+                    EXIF_TAG_JPG_FROM_RAW_START_SUB_IFD,
+                    EXIF_TAG_JPG_FROM_RAW_START_IFD2, EXIF_TAG_OTHER_IMAGE_START,
+                    EXIF_TAG_PREVIEW_IMAGE_LENGTH_MAKER_NOTES,
+                    EXIF_TAG_JPG_FROM_RAW_LENGTH_SUB_IFD,
+                    EXIF_TAG_JPG_FROM_RAW_LENGTH_IFD2, EXIF_TAG_OTHER_IMAGE_LENGTH,
+                    EXIF_TAG_JPEGRESTART_INTERVAL, EXIF_TAG_JPEGLOSSLESS_PREDICTORS,
+                    EXIF_TAG_JPEGPOINT_TRANSFORMS, EXIF_TAG_JPEGQTABLES,
+                    EXIF_TAG_JPEGDCTABLES, EXIF_TAG_JPEGACTABLES,
+                    EXIF_TAG_YCBCR_COEFFICIENTS, EXIF_TAG_YCBCR_SUB_SAMPLING,
+                    EXIF_TAG_YCBCR_POSITIONING, EXIF_TAG_REFERENCE_BLACK_WHITE,
+                    EXIF_TAG_STRIP_ROW_COUNTS, EXIF_TAG_APPLICATION_NOTES,
+                    EXIF_TAG_RELATED_IMAGE_FILE_FORMAT, EXIF_TAG_RELATED_IMAGE_WIDTH,
+                    EXIF_TAG_RELATED_IMAGE_LENGTH, EXIF_TAG_RATING,
+                    EXIF_TAG_RATING_PERCENT, EXIF_TAG_IMAGE_ID,
+                    EXIF_TAG_WANG_ANNOTATION, EXIF_TAG_MATTEING, EXIF_TAG_DATA_TYPE,
+                    EXIF_TAG_IMAGE_DEPTH, EXIF_TAG_TILE_DEPTH, EXIF_TAG_MODEL_2,
+                    EXIF_TAG_CFAREPEAT_PATTERN_DIM, EXIF_TAG_CFAPATTERN_2,
+                    EXIF_TAG_BATTERY_LEVEL, EXIF_TAG_COPYRIGHT, EXIF_TAG_EXPOSURE_TIME,
+                    EXIF_TAG_FNUMBER, EXIF_TAG_MDFILE_TAG, EXIF_TAG_MDSCALE_PIXEL,
+                    EXIF_TAG_MDCOLOR_TABLE, EXIF_TAG_MDLAB_NAME,
+                    EXIF_TAG_MDSAMPLE_INFO, EXIF_TAG_MDPREP_DATE, EXIF_TAG_MDPREP_TIME,
+                    EXIF_TAG_MDFILE_UNITS, EXIF_TAG_PIXEL_SCALE, EXIF_TAG_IPTC_NAA,
+                    EXIF_TAG_INTERGRAPH_PACKET_DATA,
+                    EXIF_TAG_INTERGRAPH_FLAG_REGISTERS, EXIF_TAG_INTERGRAPH_MATRIX,
+                    EXIF_TAG_MODEL_TIE_POINT, EXIF_TAG_SITE, EXIF_TAG_COLOR_SEQUENCE,
+                    EXIF_TAG_IT8HEADER, EXIF_TAG_RASTER_PADDING,
+                    EXIF_TAG_BITS_PER_RUN_LENGTH,
+                    EXIF_TAG_BITS_PER_EXTENDED_RUN_LENGTH, EXIF_TAG_COLOR_TABLE,
+                    EXIF_TAG_IMAGE_COLOR_INDICATOR,
+                    EXIF_TAG_BACKGROUND_COLOR_INDICATOR, EXIF_TAG_IMAGE_COLOR_VALUE,
+                    EXIF_TAG_BACKGROUND_COLOR_VALUE, EXIF_TAG_PIXEL_INTENSITY_RANGE,
+                    EXIF_TAG_TRANSPARENCY_INDICATOR, EXIF_TAG_COLOR_CHARACTERIZATION,
+                    EXIF_TAG_HCUSAGE, EXIF_TAG_SEMINFO, EXIF_TAG_AFCP_IPTC,
+                    EXIF_TAG_MODEL_TRANSFORM, EXIF_TAG_LEAF_DATA,
+                    EXIF_TAG_PHOTOSHOP_SETTINGS, EXIF_TAG_EXIF_OFFSET,
+                    EXIF_TAG_ICC_PROFILE, EXIF_TAG_IMAGE_LAYER,
+                    EXIF_TAG_GEO_TIFF_DIRECTORY, EXIF_TAG_GEO_TIFF_DOUBLE_PARAMS,
+                    EXIF_TAG_GEO_TIFF_ASCII_PARAMS, EXIF_TAG_EXPOSURE_PROGRAM,
+                    EXIF_TAG_SPECTRAL_SENSITIVITY, EXIF_TAG_GPSINFO, EXIF_TAG_ISO,
+                    EXIF_TAG_OPTO__ELECTRIC_CONV_FACTOR, EXIF_TAG_INTERLACE,
+                    EXIF_TAG_TIME_ZONE_OFFSET, EXIF_TAG_SELF_TIMER_MODE,
+                    EXIF_TAG_FAX_RECV_PARAMS, EXIF_TAG_FAX_SUB_ADDRESS,
+                    EXIF_TAG_FAX_RECV_TIME, EXIF_TAG_LEAF_SUB_IFD,
+                    EXIF_TAG_EXIF_VERSION, EXIF_TAG_DATE_TIME_ORIGINAL,
+                    EXIF_TAG_CREATE_DATE, EXIF_TAG_COMPONENTS_CONFIGURATION,
+                    EXIF_TAG_COMPRESSED_BITS_PER_PIXEL, EXIF_TAG_SHUTTER_SPEED_VALUE,
+                    EXIF_TAG_APERTURE_VALUE, EXIF_TAG_BRIGHTNESS_VALUE,
+                    EXIF_TAG_EXPOSURE_COMPENSATION, EXIF_TAG_MAX_APERTURE_VALUE,
+                    EXIF_TAG_SUBJECT_DISTANCE, EXIF_TAG_METERING_MODE,
+                    EXIF_TAG_LIGHT_SOURCE, EXIF_TAG_FLASH, EXIF_TAG_FOCAL_LENGTH,
+                    EXIF_TAG_FLASH_ENERGY, EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE_1,
+                    EXIF_TAG_NOISE_1, EXIF_TAG_FOCAL_PLANE_XRESOLUTION,
+                    EXIF_TAG_FOCAL_PLANE_YRESOLUTION,
+                    EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT,
+                    EXIF_TAG_IMAGE_NUMBER_EXIF_IFD,
+                    EXIF_TAG_SECURITY_CLASSIFICATION_EXIF_IFD,
+                    EXIF_TAG_IMAGE_HISTORY_EXIF_IFD, EXIF_TAG_SUBJECT_LOCATION_1,
+                    EXIF_TAG_EXPOSURE_INDEX, EXIF_TAG_TIFF_EPSTANDARD_ID_1,
+                    EXIF_TAG_SENSING_METHOD, EXIF_TAG_STO_NITS, EXIF_TAG_SUB_SEC_TIME,
+                    EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_TAG_SUB_SEC_TIME_DIGITIZED,
+                    EXIF_TAG_IMAGE_SOURCE_DATA, EXIF_TAG_XPTITLE, EXIF_TAG_XPCOMMENT,
+                    EXIF_TAG_XPAUTHOR, EXIF_TAG_XPKEYWORDS, EXIF_TAG_XPSUBJECT,
+                    EXIF_TAG_FLASHPIX_VERSION, EXIF_TAG_COLOR_SPACE,
+                    EXIF_TAG_EXIF_IMAGE_WIDTH, EXIF_TAG_EXIF_IMAGE_LENGTH,
+                    EXIF_TAG_RELATED_SOUND_FILE, EXIF_TAG_INTEROP_OFFSET,
+                    EXIF_TAG_FLASH_ENERGY_EXIF_IFD,
+                    EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE_2, EXIF_TAG_NOISE_2,
+                    EXIF_TAG_FOCAL_PLANE_XRESOLUTION_EXIF_IFD,
+                    EXIF_TAG_FOCAL_PLANE_YRESOLUTION_EXIF_IFD,
+                    EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT_EXIF_IFD,
+                    EXIF_TAG_IMAGE_NUMBER, EXIF_TAG_SECURITY_CLASSIFICATION,
+                    EXIF_TAG_IMAGE_HISTORY, EXIF_TAG_SUBJECT_LOCATION_2,
+                    EXIF_TAG_EXPOSURE_INDEX_EXIF_IFD, EXIF_TAG_TIFF_EPSTANDARD_ID_2,
+                    EXIF_TAG_SENSING_METHOD_EXIF_IFD, EXIF_TAG_FILE_SOURCE,
+                    EXIF_TAG_SCENE_TYPE, EXIF_TAG_CFAPATTERN, EXIF_TAG_CUSTOM_RENDERED,
+                    EXIF_TAG_EXPOSURE_MODE, EXIF_TAG_WHITE_BALANCE_1,
+                    EXIF_TAG_DIGITAL_ZOOM_RATIO, EXIF_TAG_FOCAL_LENGTH_IN_35MM_FORMAT,
+                    EXIF_TAG_SCENE_CAPTURE_TYPE, EXIF_TAG_GAIN_CONTROL,
+                    EXIF_TAG_CONTRAST_1, EXIF_TAG_SATURATION_1, EXIF_TAG_SHARPNESS_1,
+                    EXIF_TAG_DEVICE_SETTING_DESCRIPTION,
+                    EXIF_TAG_SUBJECT_DISTANCE_RANGE, EXIF_TAG_IMAGE_UNIQUE_ID,
+                    EXIF_TAG_GDALMETADATA, EXIF_TAG_GDALNO_DATA, EXIF_TAG_GAMMA,
+                    EXIF_TAG_PIXEL_FORMAT, EXIF_TAG_TRANSFOMATION,
+                    EXIF_TAG_UNCOMPRESSED, EXIF_TAG_IMAGE_TYPE, EXIF_TAG_IMAGE_WIDTH,
+                    EXIF_TAG_IMAGE_HEIGHT, EXIF_TAG_WIDTH_RESOLUTION,
+                    EXIF_TAG_HEIGHT_RESOLUTION, EXIF_TAG_IMAGE_OFFSET,
+                    EXIF_TAG_IMAGE_BYTE_COUNT, EXIF_TAG_ALPHA_OFFSET,
+                    EXIF_TAG_ALPHA_BYTE_COUNT, EXIF_TAG_IMAGE_DATA_DISCARD,
+                    EXIF_TAG_ALPHA_DATA_DISCARD, EXIF_TAG_OCE_SCANJOB_DESC,
+                    EXIF_TAG_OCE_APPLICATION_SELECTOR, EXIF_TAG_OCE_IDNUMBER,
+                    EXIF_TAG_OCE_IMAGE_LOGIC, EXIF_TAG_ANNOTATIONS, EXIF_TAG_PRINT_IM,
+                    EXIF_TAG_DNG_VERSION, EXIF_TAG_DNG_BACKWARD_VERSION,
+                    EXIF_TAG_UNIQUE_CAMERA_MODEL, EXIF_TAG_LOCALIZED_CAMERA_MODEL,
+                    EXIF_TAG_CFAPLANE_COLOR, EXIF_TAG_CFALAYOUT,
+                    EXIF_TAG_LINEARIZATION_TABLE, EXIF_TAG_BLACK_LEVEL_REPEAT_DIM,
+                    EXIF_TAG_BLACK_LEVEL, EXIF_TAG_BLACK_LEVEL_DELTA_H,
+                    EXIF_TAG_BLACK_LEVEL_DELTA_V, EXIF_TAG_WHITE_LEVEL,
+                    EXIF_TAG_DEFAULT_SCALE, EXIF_TAG_DEFAULT_CROP_ORIGIN,
+                    EXIF_TAG_DEFAULT_CROP_SIZE, EXIF_TAG_COLOR_MATRIX_1,
+                    EXIF_TAG_COLOR_MATRIX_2, EXIF_TAG_CAMERA_CALIBRATION_1,
+                    EXIF_TAG_CAMERA_CALIBRATION_2, EXIF_TAG_REDUCTION_MATRIX_1,
+                    EXIF_TAG_REDUCTION_MATRIX_2, EXIF_TAG_ANALOG_BALANCE,
+                    EXIF_TAG_AS_SHOT_NEUTRAL, EXIF_TAG_AS_SHOT_WHITE_XY,
+                    EXIF_TAG_BASELINE_EXPOSURE, EXIF_TAG_BASELINE_NOISE,
+                    EXIF_TAG_BASELINE_SHARPNESS, EXIF_TAG_BAYER_GREEN_SPLIT,
+                    EXIF_TAG_LINEAR_RESPONSE_LIMIT, EXIF_TAG_CAMERA_SERIAL_NUMBER,
+                    EXIF_TAG_DNG_LENS_INFO, EXIF_TAG_CHROMA_BLUR_RADIUS,
+                    EXIF_TAG_ANTI_ALIAS_STRENGTH, EXIF_TAG_SHADOW_SCALE,
+                    EXIF_TAG_DNG_ADOBE_DATA, EXIF_TAG_DNG_PENTAX_DATA,
+                    EXIF_TAG_DNG_PRIVATE_DATA, EXIF_TAG_MAKER_NOTE_SAFETY,
+                    EXIF_TAG_CALIBRATION_ILLUMINANT_1,
+                    EXIF_TAG_CALIBRATION_ILLUMINANT_2, EXIF_TAG_BEST_QUALITY_SCALE,
+                    EXIF_TAG_RAW_DATA_UNIQUE_ID, EXIF_TAG_ALIAS_LAYER_METADATA,
+                    EXIF_TAG_ORIGINAL_RAW_FILE_NAME, EXIF_TAG_ORIGINAL_RAW_FILE_DATA,
+                    EXIF_TAG_ACTIVE_AREA, EXIF_TAG_MASKED_AREAS,
+                    EXIF_TAG_AS_SHOT_ICCPROFILE, EXIF_TAG_AS_SHOT_PRE_PROFILE_MATRIX,
+                    EXIF_TAG_CURRENT_ICCPROFILE, EXIF_TAG_CURRENT_PRE_PROFILE_MATRIX,
+                    EXIF_TAG_OFFSET_SCHEMA, EXIF_TAG_OWNER_NAME,
+                    EXIF_TAG_SERIAL_NUMBER, EXIF_TAG_LENS, EXIF_TAG_RAW_FILE,
+                    EXIF_TAG_CONVERTER, EXIF_TAG_WHITE_BALANCE_2, EXIF_TAG_EXPOSURE,
+                    EXIF_TAG_SHADOWS, EXIF_TAG_BRIGHTNESS, EXIF_TAG_CONTRAST_2,
+                    EXIF_TAG_SATURATION_2, EXIF_TAG_SHARPNESS_2, EXIF_TAG_SMOOTHNESS,
+                    EXIF_TAG_MOIRE_FILTER,
+        
+                    EXIF_TAG_USER_COMMENT, //
+        
+                    EXIF_TAG_MAKER_NOTE));
 }
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/GpsTagConstants.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/GpsTagConstants.java
index bd4c3ef..b64ea04 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/GpsTagConstants.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/GpsTagConstants.java
@@ -16,206 +16,220 @@
  */
 package org.apache.commons.sanselan.formats.tiff.constants;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-public enum GpsTagConstants
-        implements
-            TiffDirectoryConstants,
-            TiffFieldTypeConstants,
-            TagHolder
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoAscii;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoByte;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoText;
+
+public interface GpsTagConstants
+        extends
+            TiffFieldTypeConstants
 {
-    GPS_VERSION_ID(new TagInfo(
-            "GPS Version ID", 0x0000, FIELD_TYPE_DESCRIPTION_BYTE, 4,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoByte GPS_TAG_GPS_VERSION_ID = new TagInfoByte(
+            "GPS Version ID", 0x0000, 4,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_LATITUDE_REF(new TagInfo(
-            "GPS Latitude Ref", 0x0001, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_LATITUDE_REF = new TagInfoAscii(
+            "GPS Latitude Ref", 0x0001, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_LATITUDE_REF_VALUE_NORTH = "N";
+    public static final String GPS_TAG_GPS_LATITUDE_REF_VALUE_SOUTH = "S";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_LATITUDE = new TagInfoRational(
+            "GPS Latitude", 0x0002, 3,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_LATITUDE(new TagInfo(
-            "GPS Latitude", 0x0002, FIELD_TYPE_DESCRIPTION_RATIONAL, 3,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_LONGITUDE_REF = new TagInfoAscii(
+            "GPS Longitude Ref", 0x0003, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_LONGITUDE_REF_VALUE_EAST = "E";
+    public static final String GPS_TAG_GPS_LONGITUDE_REF_VALUE_WEST = "W";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_LONGITUDE = new TagInfoRational(
+            "GPS Longitude", 0x0004, 3,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_LONGITUDE_REF(new TagInfo(
-            "GPS Longitude Ref", 0x0003, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoByte GPS_TAG_GPS_ALTITUDE_REF = new TagInfoByte(
+            "GPS Altitude Ref", 0x0005, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final int GPS_TAG_GPS_ALTITUDE_REF_VALUE_ABOVE_SEA_LEVEL = 0;
+    public static final int GPS_TAG_GPS_ALTITUDE_REF_VALUE_BELOW_SEA_LEVEL = 1;
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_ALTITUDE = new TagInfoRational(
+            "GPS Altitude", 0x0006, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_LONGITUDE(new TagInfo(
-            "GPS Longitude", 0x0004, FIELD_TYPE_DESCRIPTION_RATIONAL, 3,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoRational GPS_TAG_GPS_TIME_STAMP = new TagInfoRational(
+            "GPS Time Stamp", 0x0007, 3,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_ALTITUDE_REF(new TagInfo(
-            "GPS Altitude Ref", 0x0005, FIELD_TYPE_DESCRIPTION_BYTE, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_SATELLITES = new TagInfoAscii(
+            "GPS Satellites", 0x0008, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_ALTITUDE(new TagInfo(
-            "GPS Altitude", 0x0006, FIELD_TYPE_DESCRIPTION_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_STATUS = new TagInfoAscii(
+            "GPS Status", 0x0009, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_STATUS_VALUE_MEASUREMENT_IN_PROGRESS = "A";
+    public static final String GPS_TAG_GPS_STATUS_VALUE_MEASUREMENT_INTEROPERABILITY = "V";
+    // ************************************************************
+    public static final TagInfoAscii GPS_TAG_GPS_MEASURE_MODE = new TagInfoAscii(
+            "GPS Measure Mode", 0x000a, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final int GPS_TAG_GPS_MEASURE_MODE_VALUE_2_DIMENSIONAL_MEASUREMENT = 2;
+    public static final int GPS_TAG_GPS_MEASURE_MODE_VALUE_3_DIMENSIONAL_MEASUREMENT = 3;
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_DOP = new TagInfoRational(
+            "GPS DOP", 0x000b, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_TIME_STAMP(new TagInfo(
-            "GPS Time Stamp", 0x0007, FIELD_TYPE_DESCRIPTION_RATIONAL, 3,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_SPEED_REF = new TagInfoAscii(
+            "GPS Speed Ref", 0x000c, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_SPEED_REF_VALUE_KMPH = "K";
+    public static final String GPS_TAG_GPS_SPEED_REF_VALUE_MPH = "M";
+    public static final String GPS_TAG_GPS_SPEED_REF_VALUE_KNOTS = "N";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_SPEED = new TagInfoRational(
+            "GPS Speed", 0x000d, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_SATELLITES(new TagInfo(
-            "GPS Satellites", 0x0008, FIELD_TYPE_DESCRIPTION_ASCII, -1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_TRACK_REF = new TagInfoAscii(
+            "GPS Track Ref", 0x000e, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_TRACK_REF_VALUE_MAGNETIC_NORTH = "M";
+    public static final String GPS_TAG_GPS_TRACK_REF_VALUE_TRUE_NORTH = "T";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_TRACK = new TagInfoRational(
+            "GPS Track", 0x000f, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_STATUS(new TagInfo("GPS Status",
-            0x0009, FIELD_TYPE_DESCRIPTION_ASCII, 2, TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_IMG_DIRECTION_REF = new TagInfoAscii(
+            "GPS Img Direction Ref", 0x0010, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_IMG_DIRECTION_REF_VALUE_MAGNETIC_NORTH = "M";
+    public static final String GPS_TAG_GPS_IMG_DIRECTION_REF_VALUE_TRUE_NORTH = "T";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_IMG_DIRECTION = new TagInfoRational(
+            "GPS Img Direction", 0x0011, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_MEASURE_MODE(new TagInfo(
-            "GPS Measure Mode", 0x000a, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_MAP_DATUM = new TagInfoAscii(
+            "GPS Map Datum", 0x0012, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_DOP(new TagInfo("GPS DOP",
-            0x000b, FIELD_TYPE_DESCRIPTION_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_DEST_LATITUDE_REF = new TagInfoAscii(
+            "GPS Dest Latitude Ref", 0x0013, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_DEST_LATITUDE_REF_VALUE_NORTH = "N";
+    public static final String GPS_TAG_GPS_DEST_LATITUDE_REF_VALUE_SOUTH = "S";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_DEST_LATITUDE = new TagInfoRational(
+            "GPS Dest Latitude", 0x0014, 3,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_SPEED_REF(new TagInfo(
-            "GPS Speed Ref", 0x000c, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_DEST_LONGITUDE_REF = new TagInfoAscii(
+            "GPS Dest Longitude Ref", 0x0015, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_DEST_LONGITUDE_REF_VALUE_EAST = "E";
+    public static final String GPS_TAG_GPS_DEST_LONGITUDE_REF_VALUE_WEST = "W";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_DEST_LONGITUDE = new TagInfoRational(
+            "GPS Dest Longitude", 0x0016, 3,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_SPEED(new TagInfo("GPS Speed",
-            0x000d, FIELD_TYPE_DESCRIPTION_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_DEST_BEARING_REF = new TagInfoAscii(
+            "GPS Dest Bearing Ref", 0x0017, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_DEST_BEARING_REF_VALUE_MAGNETIC_NORTH = "M";
+    public static final String GPS_TAG_GPS_DEST_BEARING_REF_VALUE_TRUE_NORTH = "T";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_DEST_BEARING = new TagInfoRational(
+            "GPS Dest Bearing", 0x0018, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_TRACK_REF(new TagInfo(
-            "GPS Track Ref", 0x000e, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_DEST_DISTANCE_REF = new TagInfoAscii(
+            "GPS Dest Distance Ref", 0x0019, 2,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
+
+    public static final String GPS_TAG_GPS_DEST_DISTANCE_REF_VALUE_KILOMETERS = "K";
+    public static final String GPS_TAG_GPS_DEST_DISTANCE_REF_VALUE_MILES = "M";
+    public static final String GPS_TAG_GPS_DEST_DISTANCE_REF_VALUE_NAUTICAL_MILES = "N";
+    // ************************************************************
+    public static final TagInfoRational GPS_TAG_GPS_DEST_DISTANCE = new TagInfoRational(
+            "GPS Dest Distance", 0x001a, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_TRACK(new TagInfo("GPS Track",
-            0x000f, FIELD_TYPE_DESCRIPTION_RATIONAL, 1, TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoText GPS_TAG_GPS_PROCESSING_METHOD = new TagInfoText(
+            "GPS Processing Method", 0x001b, FIELD_TYPE_UNKNOWN,
+            -1, TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_IMG_DIRECTION_REF(new TagInfo(
-            "GPS Img Direction Ref", 0x0010, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoText GPS_TAG_GPS_AREA_INFORMATION = new TagInfoText(
+            "GPS Area Information", 0x001c, FIELD_TYPE_UNKNOWN, -1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_IMG_DIRECTION(new TagInfo(
-            "GPS Img Direction", 0x0011, FIELD_TYPE_DESCRIPTION_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoAscii GPS_TAG_GPS_DATE_STAMP = new TagInfoAscii(
+            "GPS Date Stamp", 0x001d, 11,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
     // ************************************************************
-    GPS_MAP_DATUM(new TagInfo(
-            "GPS Map Datum", 0x0012, FIELD_TYPE_DESCRIPTION_ASCII, -1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
+    public static final TagInfoShort GPS_TAG_GPS_DIFFERENTIAL = new TagInfoShort(
+            "GPS Differential", 0x001e, 1,
+            TiffDirectoryType.EXIF_DIRECTORY_GPS);
 
-    // ************************************************************
-    GPS_DEST_LATITUDE_REF(new TagInfo(
-            "GPS Dest Latitude Ref", 0x0013, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DEST_LATITUDE(new TagInfo(
-            "GPS Dest Latitude", 0x0014, FIELD_TYPE_DESCRIPTION_RATIONAL, 3,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DEST_LONGITUDE_REF(new TagInfo(
-            "GPS Dest Longitude Ref", 0x0015, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DEST_LONGITUDE(new TagInfo(
-            "GPS Dest Longitude", 0x0016, FIELD_TYPE_DESCRIPTION_RATIONAL, 3,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DEST_BEARING_REF(new TagInfo(
-            "GPS Dest Bearing Ref", 0x0017, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DEST_BEARING(new TagInfo(
-            "GPS Dest Bearing", 0x0018, FIELD_TYPE_DESCRIPTION_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DEST_DISTANCE_REF(new TagInfo(
-            "GPS Dest Distance Ref", 0x0019, FIELD_TYPE_DESCRIPTION_ASCII, 2,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DEST_DISTANCE(new TagInfo(
-            "GPS Dest Distance", 0x001a, FIELD_TYPE_DESCRIPTION_RATIONAL, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_PROCESSING_METHOD(new TagInfo.Text(
-            "GPS Processing Method", 0x001b, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            -1, TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_AREA_INFORMATION(new TagInfo.Text(
-            "GPS Area Information", 0x001c, FIELD_TYPE_DESCRIPTION_UNKNOWN, -1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DATE_STAMP(new TagInfo(
-            "GPS Date Stamp", 0x001d, FIELD_TYPE_DESCRIPTION_ASCII, 11,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS)),
-
-    // ************************************************************
-    GPS_DIFFERENTIAL(new TagInfo(
-            "GPS Differential", 0x001e, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.EXIF_DIRECTORY_GPS));
-    
-    public final TagInfo tagInfo;
-    
-    GpsTagConstants(TagInfo tagInfo) {
-        this.tagInfo = tagInfo;
-    }
-
-    public static final int GPS_DIFFERENTIAL_VALUE_NO_CORRECTION = 0;
-    public static final int GPS_DIFFERENTIAL_VALUE_DIFFERENTIAL_CORRECTED = 1;
-    public static final String GPS_LONGITUDE_REF_VALUE_EAST = "E";
-    public static final String GPS_LONGITUDE_REF_VALUE_WEST = "W";
-    public static final String GPS_LATITUDE_REF_VALUE_NORTH = "N";
-    public static final String GPS_LATITUDE_REF_VALUE_SOUTH = "S";
-    public static final int GPS_ALTITUDE_REF_VALUE_ABOVE_SEA_LEVEL = 0;
-    public static final int GPS_ALTITUDE_REF_VALUE_BELOW_SEA_LEVEL = 1;
-    public static final String GPS_STATUS_VALUE_MEASUREMENT_IN_PROGRESS = "A";
-    public static final String GPS_STATUS_VALUE_MEASUREMENT_INTEROPERABILITY = "V";
-    public static final int GPS_MEASURE_MODE_VALUE_2_DIMENSIONAL_MEASUREMENT = 2;
-    public static final int GPS_MEASURE_MODE_VALUE_3_DIMENSIONAL_MEASUREMENT = 3;
-    public static final String GPS_SPEED_REF_VALUE_KMPH = "K";
-    public static final String GPS_SPEED_REF_VALUE_MPH = "M";
-    public static final String GPS_SPEED_REF_VALUE_KNOTS = "N";
-    public static final String GPS_TRACK_REF_VALUE_MAGNETIC_NORTH = "M";
-    public static final String GPS_TRACK_REF_VALUE_TRUE_NORTH = "T";
-    public static final String GPS_IMG_DIRECTION_REF_VALUE_MAGNETIC_NORTH = "M";
-    public static final String GPS_IMG_DIRECTION_REF_VALUE_TRUE_NORTH = "T";
-    public static final String GPS_DEST_LATITUDE_REF_VALUE_NORTH = "N";
-    public static final String GPS_DEST_LATITUDE_REF_VALUE_SOUTH = "S";
-    public static final String GPS_DEST_LONGITUDE_REF_VALUE_EAST = "E";
-    public static final String GPS_DEST_LONGITUDE_REF_VALUE_WEST = "W";
-    public static final String GPS_DEST_BEARING_REF_VALUE_MAGNETIC_NORTH = "M";
-    public static final String GPS_DEST_BEARING_REF_VALUE_TRUE_NORTH = "T";
-    public static final String GPS_DEST_DISTANCE_REF_VALUE_KILOMETERS = "K";
-    public static final String GPS_DEST_DISTANCE_REF_VALUE_MILES = "M";
-    public static final String GPS_DEST_DISTANCE_REF_VALUE_NAUTICAL_MILES = "N";
-
+    public static final int GPS_TAG_GPS_DIFFERENTIAL_VALUE_NO_CORRECTION = 0;
+    public static final int GPS_TAG_GPS_DIFFERENTIAL_VALUE_DIFFERENTIAL_CORRECTED = 1;
     // ************************************************************
 
-    public TagInfo getTagInfo() {
-        return tagInfo;
-    }
-    
-    public static final List<TagInfo> ALL_GPS_TAGS = Collections.unmodifiableList(
-            TagConstantsUtils.mergeTagLists(values()));
+    public static final List<TagInfo> ALL_GPS_TAGS =
+            Collections.unmodifiableList(Arrays.asList(
+                    GPS_TAG_GPS_VERSION_ID, GPS_TAG_GPS_LATITUDE_REF,
+                    GPS_TAG_GPS_LATITUDE, GPS_TAG_GPS_LONGITUDE_REF,
+                    GPS_TAG_GPS_LONGITUDE, GPS_TAG_GPS_ALTITUDE_REF,
+                    GPS_TAG_GPS_ALTITUDE, GPS_TAG_GPS_TIME_STAMP,
+                    GPS_TAG_GPS_SATELLITES, GPS_TAG_GPS_STATUS,
+                    GPS_TAG_GPS_MEASURE_MODE, GPS_TAG_GPS_DOP, GPS_TAG_GPS_SPEED_REF,
+                    GPS_TAG_GPS_SPEED, GPS_TAG_GPS_TRACK_REF, GPS_TAG_GPS_TRACK,
+                    GPS_TAG_GPS_IMG_DIRECTION_REF, GPS_TAG_GPS_IMG_DIRECTION,
+                    GPS_TAG_GPS_MAP_DATUM, GPS_TAG_GPS_DEST_LATITUDE_REF,
+                    GPS_TAG_GPS_DEST_LATITUDE, GPS_TAG_GPS_DEST_LONGITUDE_REF,
+                    GPS_TAG_GPS_DEST_LONGITUDE, GPS_TAG_GPS_DEST_BEARING_REF,
+                    GPS_TAG_GPS_DEST_BEARING, GPS_TAG_GPS_DEST_DISTANCE_REF,
+                    GPS_TAG_GPS_DEST_DISTANCE, GPS_TAG_GPS_PROCESSING_METHOD,
+                    GPS_TAG_GPS_AREA_INFORMATION, GPS_TAG_GPS_DATE_STAMP,
+                    GPS_TAG_GPS_DIFFERENTIAL));
 }
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagConstantsUtils.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagConstantsUtils.java
index 8d0a7a7..946d887 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagConstantsUtils.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagConstantsUtils.java
@@ -19,22 +19,24 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
+
 public class TagConstantsUtils implements TiffDirectoryConstants
 {
     private static final TiffDirectoryType[] tiffDirectoryTypes = TiffDirectoryType.values();
 
-    public static List<TagInfo> mergeTagLists(TagHolder[]... tagHolders)
+    public static List<TagInfo> mergeTagLists(List<TagInfo>... tagLists)
     {
         int count = 0;
-        for (int i = 0; i < tagHolders.length; i++) {
-            count += tagHolders[i].length;
+        for (int i = 0; i < tagLists.length; i++) {
+            count += tagLists[i].size();
         }
 
         ArrayList<TagInfo> result = new ArrayList<TagInfo>(count);
 
-        for (int i = 0; i < tagHolders.length; i++) {
-            for (int j = 0; j < tagHolders[i].length; j++) {
-                result.add(tagHolders[i][j].getTagInfo());
+        for (int i = 0; i < tagLists.length; i++) {
+            for (int j = 0; j < tagLists[i].size(); j++) {
+                result.add(tagLists[i].get(j));
             }
         }
 
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagInfo.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagInfo.java
index 0cff2a2..e69de29 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagInfo.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagInfo.java
@@ -1,447 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.sanselan.formats.tiff.constants;
-
-import java.io.UnsupportedEncodingException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-
-import org.apache.commons.sanselan.ImageReadException;
-import org.apache.commons.sanselan.ImageWriteException;
-import org.apache.commons.sanselan.common.BinaryFileFunctions;
-import org.apache.commons.sanselan.formats.tiff.TiffField;
-import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
-import org.apache.commons.sanselan.util.Debug;
-
-public class TagInfo implements TiffDirectoryConstants, TiffFieldTypeConstants
-{
-    protected static final int LENGTH_UNKNOWN = -1;
-
-    public TagInfo(String name, int tag, FieldType dataType, int length,
-            TiffDirectoryType exifDirectory)
-    {
-        this(name, tag, new FieldType[]{
-            dataType
-        }, length, exifDirectory);
-    }
-
-    public TagInfo(String name, int tag, FieldType dataType, int length)
-    {
-        this(name, tag, new FieldType[]{
-            dataType
-        }, length, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
-    }
-
-    public TagInfo(String name, int tag, FieldType dataType,
-            String lengthDescription)
-    {
-        this(name, tag, new FieldType[]{
-            dataType
-        }, LENGTH_UNKNOWN, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
-    }
-
-    public TagInfo(String name, int tag, FieldType dataTypes[],
-            String lengthDescription)
-    {
-        this(name, tag, dataTypes, LENGTH_UNKNOWN, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
-    }
-
-    public TagInfo(String name, int tag, FieldType dataType)
-    {
-        this(name, tag, dataType, LENGTH_UNKNOWN, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
-    }
-
-    public TagInfo(String name, int tag, FieldType dataTypes[], int length,
-            String lengthDescription)
-    {
-        this(name, tag, dataTypes, length, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
-    }
-
-    public final String name;
-    public final int tag;
-    public final FieldType dataTypes[];
-    public final int length;
-    public final TiffDirectoryType directoryType;
-
-    //    public final String lengthDescription;
-
-    public TagInfo(String name, int tag, FieldType dataTypes[], int length,
-            TiffDirectoryType exifDirectory
-    //            , String lengthDescription
-    )
-    {
-        this.name = name;
-        this.tag = tag;
-        this.dataTypes = dataTypes;
-        this.length = length;
-        //        this.lengthDescription = lengthDescription;
-        this.directoryType = exifDirectory;
-    }
-
-    public Object getValue(TiffField entry) throws ImageReadException
-    {
-        Object o = entry.fieldType.getSimpleValue(entry);
-        return o;
-    }
-
-    public byte[] encodeValue(FieldType fieldType, Object value, int byteOrder)
-            throws ImageWriteException
-    {
-        return fieldType.writeData(value, byteOrder);
-    }
-
-    public String getDescription()
-    {
-        return tag + " (0x" + Integer.toHexString(tag) + ": " + name + "): ";
-    }
-
-    public String toString()
-    {
-        return "[TagInfo. tag: " + tag + " (0x" + Integer.toHexString(tag)
-                + ", name: " + name + "]";
-    }
-
-    public boolean isDate()
-    {
-        return false;
-    }
-
-    public boolean isOffset()
-    {
-        return false;
-    }
-
-    public boolean isText()
-    {
-        return false;
-    }
-
-    public boolean isUnknown()
-    {
-        return false;
-    }
-
-    public static class Offset extends TagInfo
-    {
-        public Offset(String name, int tag, FieldType dataTypes[], int length,
-                TiffDirectoryType exifDirectory)
-        {
-            super(name, tag, dataTypes, length, exifDirectory);
-        }
-
-        public Offset(String name, int tag, FieldType dataType, int length,
-                TiffDirectoryType exifDirectory)
-        {
-            super(name, tag, dataType, length, exifDirectory);
-        }
-
-        public Offset(String name, int tag, FieldType dataType, int length)
-        {
-            super(name, tag, dataType, length);
-        }
-
-        //        "Exif Offset", 0x8769, FIELD_TYPE_DESCRIPTION_UNKNOWN, 1,
-        //        EXIF_DIRECTORY_UNKNOWN);
-        public boolean isOffset()
-        {
-            return true;
-        }
-    }
-
-    public static class Date extends TagInfo
-    {
-        public Date(String name, int tag, FieldType dataType, int length)
-        {
-            super(name, tag, dataType, length);
-        }
-
-        private static final DateFormat DATE_FORMAT_1 = new SimpleDateFormat(
-                "yyyy:MM:dd HH:mm:ss");
-        private static final DateFormat DATE_FORMAT_2 = new SimpleDateFormat(
-                "yyyy:MM:dd:HH:mm:ss");
-
-        public Object getValue(TiffField entry) throws ImageReadException
-        {
-            Object o = entry.fieldType.getSimpleValue(entry);
-
-            String s = (String) o;
-            try
-            {
-                java.util.Date date = DATE_FORMAT_1.parse(s);
-                return date;
-            }
-            catch (Exception e)
-            {
-                //        Debug.debug(e);
-            }
-            try
-            {
-                java.util.Date date = DATE_FORMAT_2.parse(s);
-                return date;
-            }
-            catch (Exception e)
-            {
-                Debug.debug(e);
-            }
-
-            return o;
-        }
-
-        public byte[] encodeValue(FieldType fieldType, Object value,
-                int byteOrder) throws ImageWriteException
-        {
-            throw new ImageWriteException("date encode value: " + value + " ("
-                    + Debug.getType(value) + ")");
-            //            return fieldType.writeData(value, byteOrder);
-            //            Object o = entry.fieldType.getSimpleValue(entry);
-            //            byte bytes2[];
-            //            if (tagInfo.isDate())
-            //                bytes2 = fieldType.getRawBytes(srcField);
-            //            else
-            //                bytes2 = fieldType.writeData(value, byteOrder);
-            //            return o;
-        }
-
-        public String toString()
-        {
-            return "[TagInfo. tag: " + tag + ", name: " + name + " (data)"
-                    + "]";
-        }
-
-        // TODO: use polymorphism
-        public boolean isDate()
-        {
-            return true;
-        }
-
-    }
-
-    public static final class Text extends TagInfo
-    {
-        public Text(String name, int tag, FieldType dataType, int length,
-                TiffDirectoryType exifDirectory)
-        {
-            super(name, tag, dataType, length, exifDirectory);
-        }
-
-        public Text(String name, int tag, FieldType dataTypes[], int length,
-                TiffDirectoryType exifDirectory)
-        {
-            super(name, tag, dataTypes, length, exifDirectory);
-        }
-
-        public boolean isText()
-        {
-            return true;
-        }
-
-        private static final class TextEncoding
-        {
-            public final byte prefix[];
-            public final String encodingName;
-
-            public TextEncoding(final byte[] prefix, final String encodingName)
-            {
-                this.prefix = prefix;
-                this.encodingName = encodingName;
-            }
-        }
-
-        private static final TextEncoding TEXT_ENCODING_ASCII = new TextEncoding(
-                new byte[]{
-                        0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00,
-                }, "US-ASCII"); // ITU-T T.50 IA5
-        private static final TextEncoding TEXT_ENCODING_JIS = new TextEncoding(
-                new byte[]{
-                        0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
-                }, "JIS"); // JIS X208-1990
-        private static final TextEncoding TEXT_ENCODING_UNICODE = new TextEncoding(
-                new byte[]{
-                        0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00,
-                // Which Unicode encoding to use, UTF-8?
-                }, "UTF-8"); // Unicode Standard
-        private static final TextEncoding TEXT_ENCODING_UNDEFINED = new TextEncoding(
-                new byte[]{
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                // Try to interpret an undefined text as ISO-8859-1 (Latin)
-                }, "ISO-8859-1"); // Undefined
-        private static final TextEncoding TEXT_ENCODINGS[] = {
-                TEXT_ENCODING_ASCII, //
-                TEXT_ENCODING_JIS, //
-                TEXT_ENCODING_UNICODE, //
-                TEXT_ENCODING_UNDEFINED, //
-        };
-
-        public byte[] encodeValue(FieldType fieldType, Object value,
-                int byteOrder) throws ImageWriteException
-        {
-            if (!(value instanceof String))
-                throw new ImageWriteException("Text value not String: " + value
-                        + " (" + Debug.getType(value) + ")");
-            String s = (String) value;
-
-            try
-            {
-                // try ASCII, with NO prefix.
-                byte asciiBytes[] = s
-                        .getBytes(TEXT_ENCODING_ASCII.encodingName);
-                String decodedAscii = new String(asciiBytes,
-                        TEXT_ENCODING_ASCII.encodingName);
-                if (decodedAscii.equals(s))
-                {
-                    // no unicode/non-ascii values.
-                    byte result[] = new byte[asciiBytes.length
-                            + TEXT_ENCODING_ASCII.prefix.length];
-                    System.arraycopy(TEXT_ENCODING_ASCII.prefix, 0, result, 0,
-                            TEXT_ENCODING_ASCII.prefix.length);
-                    System.arraycopy(asciiBytes, 0, result,
-                            TEXT_ENCODING_ASCII.prefix.length,
-                            asciiBytes.length);
-                    return result;
-                }
-                else
-                {
-                    // use unicode
-                    byte unicodeBytes[] = s
-                            .getBytes(TEXT_ENCODING_UNICODE.encodingName);
-                    byte result[] = new byte[unicodeBytes.length
-                            + TEXT_ENCODING_UNICODE.prefix.length];
-                    System.arraycopy(TEXT_ENCODING_UNICODE.prefix, 0, result,
-                            0, TEXT_ENCODING_UNICODE.prefix.length);
-                    System.arraycopy(unicodeBytes, 0, result,
-                            TEXT_ENCODING_UNICODE.prefix.length,
-                            unicodeBytes.length);
-                    return result;
-                }
-            }
-            catch (UnsupportedEncodingException e)
-            {
-                throw new ImageWriteException(e.getMessage(), e);
-            }
-        }
-
-        public Object getValue(TiffField entry) throws ImageReadException
-        {
-            //            Debug.debug("entry.type", entry.type);
-            //            Debug.debug("entry.type", entry.getDescriptionWithoutValue());
-            //            Debug.debug("entry.type", entry.fieldType);
-
-            if (entry.type == FIELD_TYPE_ASCII.type)
-                return FIELD_TYPE_ASCII.getSimpleValue(entry);
-            else if (entry.type == FIELD_TYPE_UNDEFINED.type)
-            { /* do nothing */ }
-            else if (entry.type == FIELD_TYPE_BYTE.type)
-            { /* do nothing */ }
-            else
-            {
-                Debug.debug("entry.type", entry.type);
-                Debug.debug("entry.directoryType", entry.directoryType);
-                Debug.debug("entry.type", entry.getDescriptionWithoutValue());
-                Debug.debug("entry.type", entry.fieldType);
-                throw new ImageReadException("Text field not encoded as bytes.");
-            }
-
-            byte bytes[] = entry.fieldType.getRawBytes(entry);
-            if (bytes.length < 8)
-            {
-                try
-                {
-                    // try ASCII, with NO prefix.
-                    return new String(bytes, "US-ASCII");
-                }
-                catch (UnsupportedEncodingException e)
-                {
-                    throw new ImageReadException(
-                            "Text field missing encoding prefix.");
-                }
-            }
-
-            for (int i = 0; i < TEXT_ENCODINGS.length; i++)
-            {
-                TextEncoding encoding = TEXT_ENCODINGS[i];
-                if (BinaryFileFunctions.compareBytes(bytes, 0, encoding.prefix,
-                        0, encoding.prefix.length))
-                {
-                    try
-                    {
-                        //                        Debug.debug("encodingName", encoding.encodingName);
-                        return new String(bytes, encoding.prefix.length,
-                                bytes.length - encoding.prefix.length,
-                                encoding.encodingName);
-                    }
-                    catch (UnsupportedEncodingException e)
-                    {
-                        throw new ImageReadException(e.getMessage(), e);
-                    }
-                }
-            }
-
-            //                        Debug.debug("entry.tag", entry.tag + " (0x" + Integer.toHexString(entry.tag ) +")");
-            //                        Debug.debug("entry.type", entry.type);
-            //                        Debug.debug("bytes", bytes, 10);
-            //            throw new ImageReadException(
-            //                    "Unknown Text encoding prefix.");
-
-            try
-            {
-                // try ASCII, with NO prefix.
-                return new String(bytes, "US-ASCII");
-            }
-            catch (UnsupportedEncodingException e)
-            {
-                throw new ImageReadException("Unknown text encoding prefix.");
-            }
-
-        }
-    }
-
-    public static final class Unknown extends TagInfo
-    {
-
-        public Unknown(String name, int tag, FieldType dataTypes[], int length,
-                TiffDirectoryType exifDirectory)
-        {
-            super(name, tag, dataTypes, length, exifDirectory);
-        }
-
-        public boolean isUnknown()
-        {
-            return true;
-        }
-
-        public byte[] encodeValue(FieldType fieldType, Object value,
-                int byteOrder) throws ImageWriteException
-        {
-            //            Debug.debug();
-            //            Debug.debug("unknown tag(0x" + Integer.toHexString(tag) + ") ",
-            //                    this);
-            //            Debug.debug("unknown tag fieldType", fieldType);
-            //            Debug.debug("unknown tag value", value);
-            //            Debug.debug("unknown tag value", Debug.getType(value));
-            byte result[] = super.encodeValue(fieldType, value, byteOrder);
-            //            Debug.debug("unknown tag result", result);
-            return result;
-        }
-
-        public Object getValue(TiffField entry) throws ImageReadException
-        {
-            return super.getValue(entry);
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TiffFieldTypeConstants.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TiffFieldTypeConstants.java
index 7b3aebc..052a3cb 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TiffFieldTypeConstants.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TiffFieldTypeConstants.java
@@ -16,6 +16,10 @@
  */
 package org.apache.commons.sanselan.formats.tiff.constants;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
 import org.apache.commons.sanselan.SanselanConstants;
 import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
 import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldTypeAscii;
@@ -64,40 +68,32 @@
 
     public static final FieldType FIELD_TYPE_UNKNOWN = new FieldTypeUnknown();
 
-    public static final FieldType FIELD_TYPES[] = {
-            FIELD_TYPE_BYTE, FIELD_TYPE_ASCII, FIELD_TYPE_SHORT,
-            FIELD_TYPE_LONG, FIELD_TYPE_RATIONAL, FIELD_TYPE_SBYTE,
-            FIELD_TYPE_UNDEFINED, FIELD_TYPE_SSHORT, FIELD_TYPE_SLONG,
-            FIELD_TYPE_SRATIONAL, FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE,
-    };
+    public static final List<FieldType> FIELD_TYPES =
+            Collections.unmodifiableList(Arrays.asList(
+                    FIELD_TYPE_BYTE, FIELD_TYPE_ASCII, FIELD_TYPE_SHORT,
+                    FIELD_TYPE_LONG, FIELD_TYPE_RATIONAL, FIELD_TYPE_SBYTE,
+                    FIELD_TYPE_UNDEFINED, FIELD_TYPE_SSHORT, FIELD_TYPE_SLONG,
+                    FIELD_TYPE_SRATIONAL, FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE));
 
-    public static final FieldType FIELD_TYPE_ANY[] = FIELD_TYPES;
+    public static final List<FieldType> FIELD_TYPE_ANY = FIELD_TYPES;
 
-    public static final FieldType FIELD_TYPE_DESCRIPTION_LONG[] = {
-        FIELD_TYPE_LONG,
-    };
-    public static final FieldType FIELD_TYPE_DESCRIPTION_SHORT[] = {
-        FIELD_TYPE_SHORT,
-    };
-    public static final FieldType FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG[] = {
-            FIELD_TYPE_SHORT, FIELD_TYPE_LONG,
-    };
-    public static final FieldType FIELD_TYPE_DESCRIPTION_ASCII[] = {
-        FIELD_TYPE_ASCII,
-    };
-    public static final FieldType FIELD_TYPE_DESCRIPTION_LONG_OR_SHORT[] = {
-            FIELD_TYPE_SHORT, FIELD_TYPE_LONG,
-    };
-    public static final FieldType FIELD_TYPE_DESCRIPTION_RATIONAL[] = {
-        FIELD_TYPE_RATIONAL,
-    };
-    public static final FieldType FIELD_TYPE_DESCRIPTION_BYTE_OR_SHORT[] = {
-            FIELD_TYPE_SHORT, FIELD_TYPE_BYTE
-    };
-    public static final FieldType FIELD_TYPE_DESCRIPTION_BYTE[] = {
-        FIELD_TYPE_BYTE,
-    };
-    public static final FieldType FIELD_TYPE_DESCRIPTION_ANY[] = FIELD_TYPE_ANY;
-    public static final FieldType FIELD_TYPE_DESCRIPTION_UNKNOWN[] = null;
-
+    public static final List<FieldType> FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG =
+            Collections.unmodifiableList(Arrays.asList(
+                    FIELD_TYPE_SHORT, FIELD_TYPE_LONG));
+    
+    public static final List<FieldType> FIELD_TYPE_DESCRIPTION_SHORT_OR_RATIONAL =
+            Collections.unmodifiableList(Arrays.asList(
+                    FIELD_TYPE_SHORT, FIELD_TYPE_RATIONAL));
+    
+    public static final List<FieldType> FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG_OR_RATIONAL =
+            Collections.unmodifiableList(Arrays.asList(
+                    FIELD_TYPE_SHORT, FIELD_TYPE_LONG, FIELD_TYPE_RATIONAL));
+    
+    public static final List<FieldType> FIELD_TYPE_DESCRIPTION_LONG_OR_SHORT =
+            Collections.unmodifiableList(Arrays.asList(
+                    FIELD_TYPE_SHORT, FIELD_TYPE_LONG));
+    
+    public static final List<FieldType> FIELD_TYPE_DESCRIPTION_BYTE_OR_SHORT =
+            Collections.unmodifiableList(Arrays.asList(
+                    FIELD_TYPE_SHORT, FIELD_TYPE_BYTE));
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TiffTagConstants.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TiffTagConstants.java
index e599fcc..f277c10 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TiffTagConstants.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TiffTagConstants.java
@@ -16,308 +16,366 @@
  */
 package org.apache.commons.sanselan.formats.tiff.constants;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-public enum TiffTagConstants implements TiffFieldTypeConstants, TagHolder
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoAny;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoAscii;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoByte;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoByteOrShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShortOrLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoUnknown;
+
+public interface TiffTagConstants
+        extends
+            TiffFieldTypeConstants
 {
 
-    NEW_SUBFILE_TYPE(new TagInfo(
-            "New Subfile Type", 0xFE, FIELD_TYPE_DESCRIPTION_LONG, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_NEW_SUBFILE_TYPE = new TagInfoLong(
+            "New Subfile Type", 0xFE, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    SUBFILE_TYPE(new TagInfo(
-            "Subfile Type", 0xFF, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_SUBFILE_TYPE = new TagInfoShort(
+            "Subfile Type", 0xFF, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    IMAGE_WIDTH(new TagInfo(
-            "Image Width", 0x100, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShortOrLong TIFF_TAG_IMAGE_WIDTH = new TagInfoShortOrLong(
+            "Image Width", 0x100, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    IMAGE_LENGTH(new TagInfo(
-            "Image Length", 0x101, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShortOrLong TIFF_TAG_IMAGE_LENGTH = new TagInfoShortOrLong(
+            "Image Length", 0x101, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    BITS_PER_SAMPLE(new TagInfo(
-            "Bits Per Sample", 0x102, FIELD_TYPE_DESCRIPTION_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_BITS_PER_SAMPLE = new TagInfoShort(
+            "Bits Per Sample", 0x102, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    COMPRESSION(new TagInfo(
-            "Compression", 0x103, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_COMPRESSION = new TagInfoShort(
+            "Compression", 0x103, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    PHOTOMETRIC_INTERPRETATION(new TagInfo(
-            "Photometric Interpretation", 0x106, FIELD_TYPE_DESCRIPTION_SHORT,
-            1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_PHOTOMETRIC_INTERPRETATION = new TagInfoShort(
+            "Photometric Interpretation", 0x106, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    THRESHHOLDING(new TagInfo(
-            "Threshholding", 0x107, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_THRESHHOLDING = new TagInfoShort(
+            "Threshholding", 0x107, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    CELL_WIDTH(new TagInfo("Cell Width",
-            0x108, FIELD_TYPE_DESCRIPTION_SHORT, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_CELL_WIDTH = new TagInfoShort(
+            "Cell Width", 0x108, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    CELL_LENGTH(new TagInfo(
-            "Cell Length", 0x109, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_CELL_LENGTH = new TagInfoShort(
+            "Cell Length", 0x109, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    FILL_ORDER(new TagInfo("Fill Order",
-            0x10A, FIELD_TYPE_DESCRIPTION_SHORT, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_FILL_ORDER = new TagInfoShort(
+            "Fill Order", 0x10A, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    DOCUMENT_NAME(new TagInfo(
-            "Document Name", 0x10D, FIELD_TYPE_DESCRIPTION_ASCII, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_DOCUMENT_NAME = new TagInfoAscii(
+            "Document Name", 0x10D, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    IMAGE_DESCRIPTION(new TagInfo(
-            "Image Description", 0x10E, FIELD_TYPE_DESCRIPTION_ASCII, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_IMAGE_DESCRIPTION = new TagInfoAscii(
+            "Image Description", 0x10E, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    MAKE(new TagInfo("Make", 0x10F,
-            FIELD_TYPE_DESCRIPTION_ASCII, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_MAKE = new TagInfoAscii(
+            "Make", 0x10F, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    MODEL(new TagInfo("Model", 0x110,
-            FIELD_TYPE_DESCRIPTION_ASCII, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_MODEL = new TagInfoAscii(
+            "Model", 0x110, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    STRIP_OFFSETS(new TagInfo.Offset(
-            "Strip Offsets", 0x111, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShortOrLong TIFF_TAG_STRIP_OFFSETS = new TagInfoShortOrLong(
+            "Strip Offsets", 0x111, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT, true);
 
-    ORIENTATION(new TagInfo(
-            "Orientation", 0x112, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_ORIENTATION = new TagInfoShort(
+            "Orientation", 0x112, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    SAMPLES_PER_PIXEL(new TagInfo(
-            "Samples Per Pixel", 0x115, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_SAMPLES_PER_PIXEL = new TagInfoShort(
+            "Samples Per Pixel", 0x115, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    ROWS_PER_STRIP(new TagInfo(
-            "Rows Per Strip", 0x116, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShortOrLong TIFF_TAG_ROWS_PER_STRIP = new TagInfoShortOrLong(
+            "Rows Per Strip", 0x116, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    STRIP_BYTE_COUNTS(new TagInfo(
-            "Strip Byte Counts", 0x117, FIELD_TYPE_DESCRIPTION_LONG_OR_SHORT,
-            -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShortOrLong TIFF_TAG_STRIP_BYTE_COUNTS = new TagInfoShortOrLong(
+            "Strip Byte Counts", 0x117, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    MIN_SAMPLE_VALUE(new TagInfo(
-            "Min Sample Value", 0x118, FIELD_TYPE_DESCRIPTION_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_MIN_SAMPLE_VALUE = new TagInfoShort(
+            "Min Sample Value", 0x118, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    MAX_SAMPLE_VALUE(new TagInfo(
-            "Max Sample Value", 0x119, FIELD_TYPE_DESCRIPTION_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_MAX_SAMPLE_VALUE = new TagInfoShort(
+            "Max Sample Value", 0x119, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    XRESOLUTION(new TagInfo(
-            "XResolution", 0x11A, FIELD_TYPE_DESCRIPTION_RATIONAL, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoRational TIFF_TAG_XRESOLUTION = new TagInfoRational(
+            "XResolution", 0x11A, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    YRESOLUTION(new TagInfo(
-            "YResolution", 0x11B, FIELD_TYPE_DESCRIPTION_RATIONAL, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoRational TIFF_TAG_YRESOLUTION = new TagInfoRational(
+            "YResolution", 0x11B, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    PLANAR_CONFIGURATION(new TagInfo(
-            "Planar Configuration", 0x11C, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_PLANAR_CONFIGURATION = new TagInfoShort(
+            "Planar Configuration", 0x11C, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    PAGE_NAME(new TagInfo("Page Name",
-            0x11D, FIELD_TYPE_DESCRIPTION_ASCII, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_PAGE_NAME = new TagInfoAscii(
+            "Page Name", 0x11D, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    XPOSITION(new TagInfo("XPosition",
-            0x11E, FIELD_TYPE_DESCRIPTION_RATIONAL, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoRational TIFF_TAG_XPOSITION = new TagInfoRational(
+            "XPosition", 0x11E, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    YPOSITION(new TagInfo("YPosition",
-            0x11F, FIELD_TYPE_DESCRIPTION_RATIONAL, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoRational TIFF_TAG_YPOSITION = new TagInfoRational(
+            "YPosition",  0x11F, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    FREE_OFFSETS(new TagInfo(
-            "Free Offsets", 0x120, FIELD_TYPE_DESCRIPTION_LONG, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_FREE_OFFSETS = new TagInfoLong(
+            "Free Offsets", 0x120, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    FREE_BYTE_COUNTS(new TagInfo(
-            "Free Byte Counts", 0x121, FIELD_TYPE_DESCRIPTION_LONG, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_FREE_BYTE_COUNTS = new TagInfoLong(
+            "Free Byte Counts", 0x121, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    GRAY_RESPONSE_UNIT(new TagInfo(
-            "Gray Response Unit", 0x122, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_GRAY_RESPONSE_UNIT = new TagInfoShort(
+            "Gray Response Unit", 0x122, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    GRAY_RESPONSE_CURVE(new TagInfo(
-            "Gray Response Curve", 0x123, FIELD_TYPE_DESCRIPTION_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_GRAY_RESPONSE_CURVE = new TagInfoShort(
+            "Gray Response Curve", 0x123, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    T4_OPTIONS(new TagInfo("T4 Options",
-            0x124, FIELD_TYPE_DESCRIPTION_LONG, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_T4_OPTIONS = new TagInfoLong(
+            "T4 Options", 0x124, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    T6_OPTIONS(new TagInfo("T6 Options",
-            0x125, FIELD_TYPE_DESCRIPTION_LONG, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_T6_OPTIONS = new TagInfoLong(
+            "T6 Options", 0x125, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    RESOLUTION_UNIT(new TagInfo(
-            "Resolution Unit", 0x128, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_RESOLUTION_UNIT = new TagInfoShort(
+            "Resolution Unit", 0x128, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    PAGE_NUMBER(new TagInfo(
-            "Page Number", 0x129, FIELD_TYPE_DESCRIPTION_SHORT, 2,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_PAGE_NUMBER = new TagInfoShort(
+            "Page Number", 0x129, 2,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    TRANSFER_FUNCTION(new TagInfo(
-            "Transfer Function", 0x12D, FIELD_TYPE_DESCRIPTION_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_TRANSFER_FUNCTION = new TagInfoShort(
+            "Transfer Function", 0x12D, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    SOFTWARE(new TagInfo("Software",
-            0x131, FIELD_TYPE_DESCRIPTION_ASCII, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_SOFTWARE = new TagInfoAscii(
+            "Software", 0x131, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    DATE_TIME(new TagInfo("Date Time",
-            0x132, FIELD_TYPE_DESCRIPTION_ASCII, 20, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_DATE_TIME = new TagInfoAscii(
+            "Date Time", 0x132, 20,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    ARTIST(new TagInfo("Artist", 0x13B,
-            FIELD_TYPE_DESCRIPTION_ASCII, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_ARTIST = new TagInfoAscii(
+            "Artist", 0x13B, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    HOST_COMPUTER(new TagInfo(
-            "Host Computer", 0x13C, FIELD_TYPE_DESCRIPTION_ASCII, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_HOST_COMPUTER = new TagInfoAscii(
+            "Host Computer", 0x13C, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    PREDICTOR(new TagInfo("Predictor",
-            0x13D, FIELD_TYPE_DESCRIPTION_SHORT, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_PREDICTOR = new TagInfoShort(
+            "Predictor", 0x13D, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    WHITE_POINT(new TagInfo(
-            "White Point", 0x13E, FIELD_TYPE_DESCRIPTION_RATIONAL, 2,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoRational TIFF_TAG_WHITE_POINT = new TagInfoRational(
+            "White Point", 0x13E, 2,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    PRIMARY_CHROMATICITIES(new TagInfo(
-            "Primary Chromaticities", 0x13F, FIELD_TYPE_DESCRIPTION_RATIONAL,
-            6, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoRational TIFF_TAG_PRIMARY_CHROMATICITIES = new TagInfoRational(
+            "Primary Chromaticities", 0x13F, 6,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    COLOR_MAP(new TagInfo("Color Map",
-            0x140, FIELD_TYPE_DESCRIPTION_SHORT, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_COLOR_MAP = new TagInfoShort(
+            "Color Map", 0x140, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    HALFTONE_HINTS(new TagInfo(
-            "Halftone Hints", 0x141, FIELD_TYPE_DESCRIPTION_SHORT, 2,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_HALFTONE_HINTS = new TagInfoShort(
+            "Halftone Hints", 0x141, 2,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    TILE_WIDTH(new TagInfo("Tile Width",
-            0x142, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShortOrLong TIFF_TAG_TILE_WIDTH = new TagInfoShortOrLong(
+            "Tile Width", 0x142, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    TILE_LENGTH(new TagInfo(
-            "Tile Length", 0x143, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShortOrLong TIFF_TAG_TILE_LENGTH = new TagInfoShortOrLong(
+            "Tile Length", 0x143, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    TILE_OFFSETS(new TagInfo.Offset(
-            "Tile Offsets", 0x144, FIELD_TYPE_DESCRIPTION_LONG, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_TILE_OFFSETS = new TagInfoLong(
+            "Tile Offsets", 0x144, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT, true);
 
-    TILE_BYTE_COUNTS(new TagInfo(
-            "Tile Byte Counts", 0x145, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG,
-            -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShortOrLong TIFF_TAG_TILE_BYTE_COUNTS = new TagInfoShortOrLong(
+            "Tile Byte Counts", 0x145, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    INK_SET(new TagInfo("Ink Set",
-            0x14C, FIELD_TYPE_DESCRIPTION_SHORT, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_INK_SET = new TagInfoShort(
+            "Ink Set", 0x14C, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    INK_NAMES(new TagInfo("Ink Names",
-            0x14D, FIELD_TYPE_DESCRIPTION_ASCII, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_INK_NAMES = new TagInfoAscii(
+            "Ink Names", 0x14D, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    NUMBER_OF_INKS(new TagInfo(
-            "Number Of Inks", 0x14E, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_NUMBER_OF_INKS = new TagInfoShort(
+            "Number Of Inks", 0x14E, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    DOT_RANGE(new TagInfo("Dot Range",
-            0x150, FIELD_TYPE_DESCRIPTION_BYTE_OR_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoByteOrShort TIFF_TAG_DOT_RANGE = new TagInfoByteOrShort(
+            "Dot Range", 0x150, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    TARGET_PRINTER(new TagInfo(
-            "Target Printer", 0x151, FIELD_TYPE_DESCRIPTION_ASCII, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_TARGET_PRINTER = new TagInfoAscii(
+            "Target Printer", 0x151, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    EXTRA_SAMPLES(new TagInfo(
-            "Extra Samples", 0x152, FIELD_TYPE_DESCRIPTION_BYTE, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_EXTRA_SAMPLES = new TagInfoShort(
+            "Extra Samples", 0x152, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    SAMPLE_FORMAT(new TagInfo(
-            "Sample Format", 0x153, FIELD_TYPE_DESCRIPTION_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_SAMPLE_FORMAT = new TagInfoShort(
+            "Sample Format", 0x153, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    SMIN_SAMPLE_VALUE(new TagInfo(
-            "SMin Sample Value", 0x154, FIELD_TYPE_DESCRIPTION_ANY, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAny TIFF_TAG_SMIN_SAMPLE_VALUE = new TagInfoAny(
+            "SMin Sample Value", 0x154, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    SMAX_SAMPLE_VALUE(new TagInfo(
-            "SMax Sample Value", 0x155, FIELD_TYPE_DESCRIPTION_ANY, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAny TIFF_TAG_SMAX_SAMPLE_VALUE = new TagInfoAny(
+            "SMax Sample Value", 0x155, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    TRANSFER_RANGE(new TagInfo(
-            "Transfer Range", 0x156, FIELD_TYPE_DESCRIPTION_SHORT, 6,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_TRANSFER_RANGE = new TagInfoShort(
+            "Transfer Range", 0x156, 6,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    JPEG_PROC(new TagInfo("JPEGProc",
-            0x200, FIELD_TYPE_DESCRIPTION_SHORT, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_JPEG_PROC = new TagInfoShort(
+            "JPEGProc", 0x200, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    JPEG_INTERCHANGE_FORMAT(new TagInfo.Offset(
-            "JPEGInterchange Format", 0x201, FIELD_TYPE_DESCRIPTION_LONG, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_JPEG_INTERCHANGE_FORMAT = new TagInfoLong(
+            "JPEGInterchange Format", 0x201, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT, true);
 
-    JPEG_INTERCHANGE_FORMAT_LENGTH(new TagInfo(
+    public static final TagInfoLong TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = new TagInfoLong(
             "JPEGInterchange Format Length", 0x202,
-            FIELD_TYPE_DESCRIPTION_LONG, 1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+            1, TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    JPEG_RESTART_INTERVAL(new TagInfo(
-            "JPEGRestart Interval", 0x203, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_JPEG_RESTART_INTERVAL = new TagInfoShort(
+            "JPEGRestart Interval", 0x203, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    JPEG_LOSSLESS_PREDICTORS(new TagInfo(
-            "JPEGLossless Predictors", 0x205, FIELD_TYPE_DESCRIPTION_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_JPEG_LOSSLESS_PREDICTORS = new TagInfoShort(
+            "JPEGLossless Predictors", 0x205, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    JPEG_POINT_TRANSFORMS(new TagInfo(
-            "JPEGPoint Transforms", 0x206, FIELD_TYPE_DESCRIPTION_SHORT, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_JPEG_POINT_TRANSFORMS = new TagInfoShort(
+            "JPEGPoint Transforms", 0x206, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    JPEG_QTABLES(new TagInfo(
-            "JPEGQTables", 0x207, FIELD_TYPE_DESCRIPTION_LONG, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_JPEG_QTABLES = new TagInfoLong(
+            "JPEGQTables", 0x207, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    JPEG_DCTABLES(new TagInfo(
-            "JPEGDCTables", 0x208, FIELD_TYPE_DESCRIPTION_LONG, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_JPEG_DCTABLES = new TagInfoLong(
+            "JPEGDCTables", 0x208, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    JPEG_ACTABLES(new TagInfo(
-            "JPEGACTables", 0x209, FIELD_TYPE_DESCRIPTION_LONG, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_JPEG_ACTABLES = new TagInfoLong(
+            "JPEGACTables", 0x209, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    YCBCR_COEFFICIENTS(new TagInfo(
-            "YCbCr Coefficients", 0x211, FIELD_TYPE_DESCRIPTION_RATIONAL, 3,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoRational TIFF_TAG_YCBCR_COEFFICIENTS = new TagInfoRational(
+            "YCbCr Coefficients", 0x211, 3,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    YCBCR_SUB_SAMPLING(new TagInfo(
-            "YCbCr Sub Sampling", 0x212, FIELD_TYPE_DESCRIPTION_SHORT, 2,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_YCBCR_SUB_SAMPLING = new TagInfoShort(
+            "YCbCr Sub Sampling", 0x212, 2,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    YCBCR_POSITIONING(new TagInfo(
-            "YCbCr Positioning", 0x213, FIELD_TYPE_DESCRIPTION_SHORT, 1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoShort TIFF_TAG_YCBCR_POSITIONING = new TagInfoShort(
+            "YCbCr Positioning", 0x213, 1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    REFERENCE_BLACK_WHITE(new TagInfo(
-            "Reference Black White", 0x214, FIELD_TYPE_DESCRIPTION_LONG, -1,
-            TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoLong TIFF_TAG_REFERENCE_BLACK_WHITE = new TagInfoLong(
+            "Reference Black White", 0x214, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    COPYRIGHT(new TagInfo("Copyright",
-            0x8298, FIELD_TYPE_DESCRIPTION_ASCII, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoAscii TIFF_TAG_COPYRIGHT = new TagInfoAscii(
+            "Copyright", 0x8298, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
-    XMP(new TagInfo("XMP",
-            0x2BC, FIELD_TYPE_DESCRIPTION_BYTE, -1, TiffDirectoryType.TIFF_DIRECTORY_ROOT)),
+    public static final TagInfoByte TIFF_TAG_XMP = new TagInfoByte(
+            "XMP", 0x2BC, -1,
+            TiffDirectoryType.TIFF_DIRECTORY_ROOT);
 
     // TODO:
-    //    public static final TagInfo2 UNKNOWN(null;
-    UNKNOWN(new TagInfo.Unknown(
-            "Unknown Tag", -1, FIELD_TYPE_DESCRIPTION_UNKNOWN,
-            TagInfo.LENGTH_UNKNOWN, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN));
-    
-    public final TagInfo tagInfo;
-    
-    TiffTagConstants(TagInfo tagInfo) {
-        this.tagInfo = tagInfo;
-    }
-    
-    public TagInfo getTagInfo() {
-        return tagInfo;
-    }
-    
-    public static final List<TagInfo> ALL_TIFF_TAGS = Collections.unmodifiableList(
-            TagConstantsUtils.mergeTagLists(values()));
+    //    public static final TagInfo2 TIFF_TAG_UNKNOWN = null;
+    public static final TagInfo TIFF_TAG_UNKNOWN = new TagInfoUnknown(
+            "Unknown Tag", -1, TagInfo.LENGTH_UNKNOWN,
+            TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+
+    public static final List<TagInfo> ALL_TIFF_TAGS =
+            Collections.unmodifiableList(Arrays.asList(
+                    TIFF_TAG_NEW_SUBFILE_TYPE, TIFF_TAG_SUBFILE_TYPE,
+                    TIFF_TAG_IMAGE_WIDTH, TIFF_TAG_IMAGE_LENGTH,
+                    TIFF_TAG_BITS_PER_SAMPLE, TIFF_TAG_COMPRESSION,
+                    TIFF_TAG_PHOTOMETRIC_INTERPRETATION, TIFF_TAG_THRESHHOLDING,
+                    TIFF_TAG_CELL_WIDTH, TIFF_TAG_CELL_LENGTH, TIFF_TAG_FILL_ORDER,
+                    TIFF_TAG_DOCUMENT_NAME, TIFF_TAG_IMAGE_DESCRIPTION, TIFF_TAG_MAKE,
+                    TIFF_TAG_MODEL, TIFF_TAG_STRIP_OFFSETS, TIFF_TAG_ORIENTATION,
+                    TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TAG_ROWS_PER_STRIP,
+                    TIFF_TAG_STRIP_BYTE_COUNTS, TIFF_TAG_MIN_SAMPLE_VALUE,
+                    TIFF_TAG_MAX_SAMPLE_VALUE, TIFF_TAG_XRESOLUTION,
+                    TIFF_TAG_YRESOLUTION, TIFF_TAG_PLANAR_CONFIGURATION,
+                    TIFF_TAG_PAGE_NAME, TIFF_TAG_XPOSITION, TIFF_TAG_YPOSITION,
+                    TIFF_TAG_FREE_OFFSETS, TIFF_TAG_FREE_BYTE_COUNTS,
+                    TIFF_TAG_GRAY_RESPONSE_UNIT, TIFF_TAG_GRAY_RESPONSE_CURVE,
+                    TIFF_TAG_T4_OPTIONS, TIFF_TAG_T6_OPTIONS, TIFF_TAG_RESOLUTION_UNIT,
+                    TIFF_TAG_PAGE_NUMBER, TIFF_TAG_TRANSFER_FUNCTION,
+                    TIFF_TAG_SOFTWARE, TIFF_TAG_DATE_TIME, TIFF_TAG_ARTIST,
+                    TIFF_TAG_HOST_COMPUTER, TIFF_TAG_PREDICTOR, TIFF_TAG_WHITE_POINT,
+                    TIFF_TAG_PRIMARY_CHROMATICITIES, TIFF_TAG_COLOR_MAP,
+                    TIFF_TAG_HALFTONE_HINTS, TIFF_TAG_TILE_WIDTH, TIFF_TAG_TILE_LENGTH,
+                    TIFF_TAG_TILE_OFFSETS, TIFF_TAG_TILE_BYTE_COUNTS, TIFF_TAG_INK_SET,
+                    TIFF_TAG_INK_NAMES, TIFF_TAG_NUMBER_OF_INKS, TIFF_TAG_DOT_RANGE,
+                    TIFF_TAG_TARGET_PRINTER, TIFF_TAG_EXTRA_SAMPLES,
+                    TIFF_TAG_SAMPLE_FORMAT, TIFF_TAG_SMIN_SAMPLE_VALUE,
+                    TIFF_TAG_SMAX_SAMPLE_VALUE, TIFF_TAG_TRANSFER_RANGE,
+                    TIFF_TAG_JPEG_PROC, TIFF_TAG_JPEG_INTERCHANGE_FORMAT,
+                    TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
+                    TIFF_TAG_JPEG_RESTART_INTERVAL, TIFF_TAG_JPEG_LOSSLESS_PREDICTORS,
+                    TIFF_TAG_JPEG_POINT_TRANSFORMS, TIFF_TAG_JPEG_QTABLES,
+                    TIFF_TAG_JPEG_DCTABLES, TIFF_TAG_JPEG_ACTABLES,
+                    TIFF_TAG_YCBCR_COEFFICIENTS, TIFF_TAG_YCBCR_SUB_SAMPLING,
+                    TIFF_TAG_YCBCR_POSITIONING, TIFF_TAG_REFERENCE_BLACK_WHITE,
+                    TIFF_TAG_COPYRIGHT,
+                    TIFF_TAG_XMP));
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java
index dbf8904..8724163 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/datareaders/DataReader.java
@@ -111,7 +111,7 @@
     protected byte[] decompress(byte compressed[], int compression,
             int expected_size, int tileWidth, int tileHeight) throws ImageReadException, IOException
     {
-        TiffField fillOrderField = directory.findField(TiffTagConstants.FILL_ORDER.tagInfo);
+        TiffField fillOrderField = directory.findField(TiffTagConstants.TIFF_TAG_FILL_ORDER);
         int fillOrder = ExifTagConstants.FILL_ORDER_VALUE_NORMAL;
         if (fillOrderField != null) {
             fillOrder = fillOrderField.getIntValue();
@@ -135,7 +135,7 @@
             case TIFF_COMPRESSION_CCITT_GROUP_3 :
             {
                 int t4Options = 0;
-                TiffField field = directory.findField(TiffTagConstants.T4_OPTIONS.tagInfo);
+                TiffField field = directory.findField(TiffTagConstants.TIFF_TAG_T4_OPTIONS);
                 if (field != null) {
                     t4Options = field.getIntValue();
                 }
@@ -154,7 +154,7 @@
             case TIFF_COMPRESSION_CCITT_GROUP_4 :
             {
                 int t6Options = 0;
-                TiffField field = directory.findField(TiffTagConstants.T6_OPTIONS.tagInfo);
+                TiffField field = directory.findField(TiffTagConstants.TIFF_TAG_T6_OPTIONS);
                 if (field != null) {
                     t6Options = field.getIntValue();
                 }
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeAscii.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeAscii.java
index aeaf10e..811b6a1 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeAscii.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeAscii.java
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.sanselan.formats.tiff.fieldtypes;
 
+import java.io.UnsupportedEncodingException;
+
 import org.apache.commons.sanselan.ImageWriteException;
 import org.apache.commons.sanselan.formats.tiff.TiffField;
 
@@ -29,8 +31,42 @@
     public Object getSimpleValue(TiffField entry) {
         // According to EXIF specification "2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL."
         byte bytes[] = getRawBytes(entry);
-        // Ignore last (should be NULL) byte.
-        return new String(bytes, 0, bytes.length-1);
+        int nullCount = 1;
+        for (int i = 0; i < bytes.length - 1; i++) {
+            if (bytes[i] == 0) {
+                nullCount++;
+            }
+        }
+        String[] strings = new String[nullCount];
+        int stringsAdded = 0;
+        strings[0] = ""; // if we have a 0 length string
+        int nextStringPos = 0;
+        // According to the Exiftool FAQ, http://www.metadataworkinggroup.org
+        // specifies that the TIFF ASCII fields are actually UTF-8.
+        // Exiftool however allows you to configure the charset used.
+        for (int i = 0; i < bytes.length; i++) {
+            if (bytes[i] == 0) {
+                try {
+                    String string = new String(bytes, nextStringPos, i - nextStringPos, "UTF-8");
+                    strings[stringsAdded++] = string;
+                } catch (UnsupportedEncodingException unsupportedEncoding) {
+                }
+                nextStringPos = i + 1;
+            }
+        }
+        if (nextStringPos < bytes.length) {
+            // Buggy file, string wasn't null terminated
+            try {
+                String string = new String(bytes, nextStringPos, bytes.length - nextStringPos, "UTF-8");
+                strings[stringsAdded++] = string;
+            } catch (UnsupportedEncodingException unsupportedEncoding) {
+            }
+        }
+        if (strings.length == 1) {
+            return strings[0];
+        } else {
+            return strings;
+        }
     }
 
     public byte[] writeData(Object o, int byteOrder) throws ImageWriteException
@@ -42,11 +78,33 @@
             result[result.length - 1] = 0;
             return result;
         } else if (o instanceof String) {
-            byte bytes[] = ((String) o).getBytes();
+            byte[] bytes = null;
+            try {
+                bytes = ((String) o).getBytes("UTF-8");
+            } catch (UnsupportedEncodingException cannotHappen) {
+            }
             byte result[] = new byte[bytes.length + 1];
             System.arraycopy(bytes, 0, result, 0, bytes.length);
             result[result.length - 1] = 0;
             return result;
+        } else if (o instanceof String[]) {
+            String[] strings = (String[])o;
+            int totalLength = 0;
+            for (int i = 0; i < strings.length; i++) {
+                totalLength += (strings[i].getBytes().length + 1);
+            }
+            byte[] result = new byte[totalLength];
+            int position = 0;
+            for (int i = 0; i < strings.length; i++) {
+                byte[] bytes = null;
+                try {
+                    bytes = strings[i].getBytes("UTF-8");
+                } catch (UnsupportedEncodingException cannotHappen) {
+                }
+                System.arraycopy(bytes, 0, result, position, bytes.length);
+                position += (bytes.length + 1);
+            }
+            return result;
         }
         else
             throw new ImageWriteException("Unknown data type: " + o);
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeShort.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeShort.java
index 1c09f07..95f99e9 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeShort.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeShort.java
@@ -18,6 +18,7 @@
 
 import org.apache.commons.sanselan.ImageReadException;
 import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryConversions;
 import org.apache.commons.sanselan.formats.tiff.TiffField;
 import org.apache.commons.sanselan.util.Debug;
 
@@ -45,32 +46,29 @@
     public Object getSimpleValue(TiffField entry) throws ImageReadException
     {
         if (entry.length == 1)
-            return new Integer(convertByteArrayToShort(name + " ("
-                    + entry.tagInfo.name + ")", entry.valueOffsetBytes,
-                    entry.byteOrder));
+            return BinaryConversions.convertToShort(entry.valueOffsetBytes, entry.byteOrder);
 
-        return convertByteArrayToShortArray(name + " (" + entry.tagInfo.name
-                + ")", getRawBytes(entry), 0, entry.length, entry.byteOrder);
+        return BinaryConversions.convertToShortArray(getRawBytes(entry), entry.byteOrder);
     }
 
     public byte[] writeData(Object o, int byteOrder) throws ImageWriteException
     {
-        if (o instanceof Integer)
-            return convertShortArrayToByteArray(new int[]{
-                ((Integer) o).intValue(),
+        if (o instanceof Short)
+            return BinaryConversions.convertToByteArray(new short[]{
+                ((Short)o).shortValue(),
             }, byteOrder);
-        else if (o instanceof int[])
+        else if (o instanceof short[])
         {
-            int numbers[] = (int[]) o;
-            return convertShortArrayToByteArray(numbers, byteOrder);
+            short numbers[] = (short[]) o;
+            return BinaryConversions.convertToByteArray(numbers, byteOrder);
         }
-        else if (o instanceof Integer[])
+        else if (o instanceof Short[])
         {
-            Integer numbers[] = (Integer[]) o;
-            int values[] = new int[numbers.length];
+            Short numbers[] = (Short[]) o;
+            short values[] = new short[numbers.length];
             for (int i = 0; i < values.length; i++)
-                values[i] = numbers[i].intValue();
-            return convertShortArrayToByteArray(values, byteOrder);
+                values[i] = numbers[i].shortValue();
+            return BinaryConversions.convertToByteArray(values, byteOrder);
         }
         else
             throw new ImageWriteException("Invalid data: " + o + " ("
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfo.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfo.java
new file mode 100644
index 0000000..97d28a7
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfo.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.sanselan.ImageReadException;
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.formats.tiff.TiffField;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryConstants;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffFieldTypeConstants;
+import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
+
+public abstract class TagInfo implements TiffDirectoryConstants, TiffFieldTypeConstants
+{
+    public static final int LENGTH_UNKNOWN = -1;
+
+    public TagInfo(String name, int tag, FieldType dataType, int length,
+            TiffDirectoryType exifDirectory)
+    {
+        this(name, tag, Arrays.asList(dataType), length, exifDirectory);
+    }
+
+    public TagInfo(String name, int tag, FieldType dataType, int length,
+            TiffDirectoryType exifDirectory, boolean isOffset)
+    {
+        this(name, tag, Arrays.asList(dataType), length, exifDirectory, isOffset);
+    }
+
+    public TagInfo(String name, int tag, FieldType dataType, int length)
+    {
+        this(name, tag, Arrays.asList(dataType), length, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    }
+
+    public TagInfo(String name, int tag, FieldType dataType)
+    {
+        this(name, tag, dataType, LENGTH_UNKNOWN, TiffDirectoryType.EXIF_DIRECTORY_UNKNOWN);
+    }
+
+    public final String name;
+    public final int tag;
+    public final List<FieldType> dataTypes;
+    public final int length;
+    public final TiffDirectoryType directoryType;
+    private final boolean isOffset;
+
+    public TagInfo(String name, int tag, List<FieldType> dataTypes, int length,
+            TiffDirectoryType exifDirectory)
+    {
+        this(name, tag, dataTypes, length, exifDirectory, false);
+    }
+
+    public TagInfo(String name, int tag, List<FieldType> dataTypes, int length,
+            TiffDirectoryType exifDirectory, boolean isOffset)
+    {
+        this.name = name;
+        this.tag = tag;
+        this.dataTypes = Collections.unmodifiableList(new ArrayList<FieldType>(dataTypes));
+        this.length = length;
+        this.directoryType = exifDirectory;
+        this.isOffset = isOffset;
+    }
+    
+    public Object getValue(TiffField entry) throws ImageReadException
+    {
+        Object o = entry.fieldType.getSimpleValue(entry);
+        return o;
+    }
+
+    public byte[] encodeValue(FieldType fieldType, Object value, int byteOrder)
+            throws ImageWriteException
+    {
+        return fieldType.writeData(value, byteOrder);
+    }
+
+    public String getDescription()
+    {
+        return tag + " (0x" + Integer.toHexString(tag) + ": " + name + "): ";
+    }
+
+    public String toString()
+    {
+        return "[TagInfo. tag: " + tag + " (0x" + Integer.toHexString(tag)
+                + ", name: " + name + "]";
+    }
+
+    public boolean isOffset()
+    {
+        return isOffset;
+    }
+
+    public boolean isText()
+    {
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoAny.java
similarity index 69%
rename from src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java
rename to src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoAny.java
index e201beb..26eb244 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoAny.java
@@ -14,8 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.sanselan.formats.tiff.constants;
+package org.apache.commons.sanselan.formats.tiff.taginfos;
 
-public interface TagHolder {
-    TagInfo getTagInfo();
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoAny extends TagInfo {
+    public TagInfoAny(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_ANY, length, directoryType);
+    }
 }
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoAscii.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoAscii.java
new file mode 100644
index 0000000..ca4bdd6
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoAscii.java
@@ -0,0 +1,51 @@
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoAscii extends TagInfo {
+    public TagInfoAscii(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_ASCII, length, directoryType);
+    }
+    
+    public String[] getValue(int byteOrder, byte[] bytes) {
+        int nullCount = 1;
+        for (int i = 0; i < bytes.length - 1; i++) {
+            if (bytes[i] == 0) {
+                nullCount++;
+            }
+        }
+        String[] strings = new String[nullCount + 1];
+        int stringsAdded = 0;
+        strings[0] = ""; // if we have a 0 length string
+        int nextStringPos = 0;
+        // According to the Exiftool FAQ, http://www.metadataworkinggroup.org
+        // specifies that the TIFF ASCII fields are actually UTF-8.
+        // Exiftool however allows you to configure the charset used.
+        for (int i = 0; i < bytes.length; i++) {
+            if (bytes[i] == 0) {
+                try {
+                    String string = new String(bytes, nextStringPos, i - nextStringPos, "UTF-8");
+                    strings[stringsAdded++] = string;
+                } catch (UnsupportedEncodingException unsupportedEncoding) {
+                }
+                nextStringPos = i + 1;
+            }
+        }
+        if (nextStringPos < bytes.length) {
+            // Buggy file, string wasn't null terminated
+            try {
+                String string = new String(bytes, nextStringPos, bytes.length - nextStringPos, "UTF-8");
+                strings[stringsAdded++] = string;
+            } catch (UnsupportedEncodingException unsupportedEncoding) {
+            }
+        }
+        return strings;
+    }
+
+    public byte[] encodeValue(int byteOrder, String... values) throws ImageWriteException {
+        return FIELD_TYPE_ASCII.writeData(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoByte.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoByte.java
new file mode 100644
index 0000000..98b41cf
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoByte.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import java.util.List;
+
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
+
+public class TagInfoByte extends TagInfo {
+    public TagInfoByte(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_BYTE, length, directoryType);
+    }
+    
+    public TagInfoByte(String name, int tag, List<FieldType> fieldTypes,
+            int length, TiffDirectoryType directoryType) {
+        super(name, tag, fieldTypes, length, directoryType);
+    }
+
+    public byte[] encodeValue(int byteOrder, byte... values) {
+        return values;
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoByteOrShort.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoByteOrShort.java
new file mode 100644
index 0000000..59bad8e
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoByteOrShort.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoByteOrShort extends TagInfo {
+    public TagInfoByteOrShort(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_DESCRIPTION_BYTE_OR_SHORT, length, directoryType);
+    }
+    
+    public byte[] encodeValue(int byteOrder, byte... values) {
+        return values;
+    }
+    
+    public byte[] encodeValue(int byteOrder, short... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoDouble.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoDouble.java
new file mode 100644
index 0000000..624e6ec
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoDouble.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoDouble extends TagInfo {
+    public TagInfoDouble(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_DOUBLE, length, directoryType);
+    }
+    
+    public double[] getValue(int byteOrder, byte[] bytes) {
+        return BinaryConversions.convertToDoubleArray(bytes, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, double... values) throws ImageWriteException {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoFloat.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoFloat.java
new file mode 100644
index 0000000..8c73de8
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoFloat.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoFloat extends TagInfo {
+    public TagInfoFloat(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_FLOAT, length, directoryType);
+    }
+    
+    public float[] getValue(int byteOrder, byte[] bytes) {
+        return BinaryConversions.convertToFloatArray(bytes, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, float... values) throws ImageWriteException {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoLong.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoLong.java
new file mode 100644
index 0000000..862d55f
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoLong.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+
+public class TagInfoLong extends TagInfo {
+    public TagInfoLong(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_LONG, length, directoryType);
+    }
+    
+    public TagInfoLong(String name, int tag, int length, TiffDirectoryType directoryType, boolean isOffset) {
+        super(name, tag, FIELD_TYPE_LONG, length, directoryType, isOffset);
+    }
+    
+    public int[] getValue(int byteOrder, byte[] bytes) {
+        return BinaryConversions.convertToIntArray(bytes, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, int... values) throws ImageWriteException {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoRational.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoRational.java
new file mode 100644
index 0000000..3d75feb
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoRational.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.common.RationalNumber;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoRational extends TagInfo {
+    public TagInfoRational(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_RATIONAL, length, directoryType);
+    }
+
+    public RationalNumber[] getValue(int byteOrder, byte[] bytes) {
+        return BinaryConversions.convertToRationalArray(bytes, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, RationalNumber... values) throws ImageWriteException {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSByte.java
similarity index 60%
copy from src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java
copy to src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSByte.java
index e201beb..8f5e0b8 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSByte.java
@@ -14,8 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.sanselan.formats.tiff.constants;
+package org.apache.commons.sanselan.formats.tiff.taginfos;
 
-public interface TagHolder {
-    TagInfo getTagInfo();
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoSByte extends TagInfo {
+    public TagInfoSByte(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_SBYTE, length, directoryType);
+    }
+
+    public byte[] encodeValue(int byteOrder, byte... values) throws ImageWriteException {
+        return values;
+    }
 }
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSLong.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSLong.java
new file mode 100644
index 0000000..329c50c
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSLong.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoSLong extends TagInfo {
+    public TagInfoSLong(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_SLONG, length, directoryType);
+    }
+    
+    public int[] getValue(int byteOrder, byte[] bytes) {
+        return BinaryConversions.convertToIntArray(bytes, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, int... values) throws ImageWriteException {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSRational.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSRational.java
new file mode 100644
index 0000000..2d32f14
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSRational.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.common.RationalNumber;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoSRational extends TagInfo {
+    public TagInfoSRational(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_SRATIONAL, length, directoryType);
+    }
+
+    public RationalNumber[] getValue(int byteOrder, byte[] bytes) {
+        return BinaryConversions.convertToRationalArray(bytes, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, RationalNumber... values) throws ImageWriteException {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSShort.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSShort.java
new file mode 100644
index 0000000..cfb1690
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoSShort.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoSShort extends TagInfo {
+    public TagInfoSShort(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_SSHORT, length, directoryType);
+    }
+    
+    public short[] getValue(int byteOrder, byte[] bytes) {
+        return BinaryConversions.convertToShortArray(bytes, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, short... values) throws ImageWriteException {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShort.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShort.java
new file mode 100644
index 0000000..1ba27f4
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShort.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoShort extends TagInfo {
+    public TagInfoShort(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_SHORT, length, directoryType);
+    }
+    
+    public short[] getValue(int byteOrder, byte[] bytes) {
+        return BinaryConversions.convertToShortArray(bytes, byteOrder);
+    }
+
+    public byte[] encodeValue(int byteOrder, short... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrLong.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrLong.java
new file mode 100644
index 0000000..05705ea
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrLong.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoShortOrLong extends TagInfo {
+    public TagInfoShortOrLong(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, length, directoryType, false);
+    }
+    
+    public TagInfoShortOrLong(String name, int tag, int length, TiffDirectoryType directoryType, boolean isOffset) {
+        super(name, tag, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, length, directoryType, isOffset);
+    }
+    
+    public byte[] encodeValue(int byteOrder, short... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, int... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrLongOrRational.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrLongOrRational.java
new file mode 100644
index 0000000..3693d0c
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrLongOrRational.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.common.RationalNumber;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoShortOrLongOrRational extends TagInfo {
+    public TagInfoShortOrLongOrRational(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_DESCRIPTION_SHORT_OR_LONG, length, directoryType);
+    }
+    
+    public byte[] encodeValue(int byteOrder, short... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, int... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+    
+    public byte[] encodeValue(int byteOrder, RationalNumber... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrRational.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrRational.java
new file mode 100644
index 0000000..ceb984e
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoShortOrRational.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import org.apache.commons.sanselan.common.BinaryConversions;
+import org.apache.commons.sanselan.common.RationalNumber;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoShortOrRational extends TagInfo {
+    public TagInfoShortOrRational(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, FIELD_TYPE_DESCRIPTION_SHORT_OR_RATIONAL, length, directoryType, false);
+    }
+    
+    public byte[] encodeValue(int byteOrder, short... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+
+    public byte[] encodeValue(int byteOrder, RationalNumber... values) {
+        return BinaryConversions.convertToByteArray(values, byteOrder);
+    }
+}
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoText.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoText.java
new file mode 100644
index 0000000..4a9a734
--- /dev/null
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoText.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff.taginfos;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.commons.sanselan.ImageReadException;
+import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.BinaryFileFunctions;
+import org.apache.commons.sanselan.formats.tiff.TiffField;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
+import org.apache.commons.sanselan.util.Debug;
+
+public final class TagInfoText extends TagInfo
+{
+    public TagInfoText(String name, int tag, FieldType dataType, int length,
+            TiffDirectoryType exifDirectory)
+    {
+        super(name, tag, dataType, length, exifDirectory);
+    }
+
+    public boolean isText()
+    {
+        return true;
+    }
+
+    private static final class TextEncoding
+    {
+        public final byte prefix[];
+        public final String encodingName;
+
+        public TextEncoding(final byte[] prefix, final String encodingName)
+        {
+            this.prefix = prefix;
+            this.encodingName = encodingName;
+        }
+    }
+
+    private static final TagInfoText.TextEncoding TEXT_ENCODING_ASCII = new TextEncoding(
+            new byte[]{
+                    0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00,
+            }, "US-ASCII"); // ITU-T T.50 IA5
+    private static final TagInfoText.TextEncoding TEXT_ENCODING_JIS = new TextEncoding(
+            new byte[]{
+                    0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
+            }, "JIS"); // JIS X208-1990
+    private static final TagInfoText.TextEncoding TEXT_ENCODING_UNICODE = new TextEncoding(
+            new byte[]{
+                    0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00,
+            // Which Unicode encoding to use, UTF-8?
+            }, "UTF-8"); // Unicode Standard
+    private static final TagInfoText.TextEncoding TEXT_ENCODING_UNDEFINED = new TextEncoding(
+            new byte[]{
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            // Try to interpret an undefined text as ISO-8859-1 (Latin)
+            }, "ISO-8859-1"); // Undefined
+    private static final TagInfoText.TextEncoding TEXT_ENCODINGS[] = {
+            TEXT_ENCODING_ASCII, //
+            TEXT_ENCODING_JIS, //
+            TEXT_ENCODING_UNICODE, //
+            TEXT_ENCODING_UNDEFINED, //
+    };
+
+    public byte[] encodeValue(FieldType fieldType, Object value,
+            int byteOrder) throws ImageWriteException
+    {
+        if (!(value instanceof String))
+            throw new ImageWriteException("Text value not String: " + value
+                    + " (" + Debug.getType(value) + ")");
+        String s = (String) value;
+
+        try
+        {
+            // try ASCII, with NO prefix.
+            byte asciiBytes[] = s
+                    .getBytes(TEXT_ENCODING_ASCII.encodingName);
+            String decodedAscii = new String(asciiBytes,
+                    TEXT_ENCODING_ASCII.encodingName);
+            if (decodedAscii.equals(s))
+            {
+                // no unicode/non-ascii values.
+                byte result[] = new byte[asciiBytes.length
+                        + TEXT_ENCODING_ASCII.prefix.length];
+                System.arraycopy(TEXT_ENCODING_ASCII.prefix, 0, result, 0,
+                        TEXT_ENCODING_ASCII.prefix.length);
+                System.arraycopy(asciiBytes, 0, result,
+                        TEXT_ENCODING_ASCII.prefix.length,
+                        asciiBytes.length);
+                return result;
+            }
+            else
+            {
+                // use unicode
+                byte unicodeBytes[] = s
+                        .getBytes(TEXT_ENCODING_UNICODE.encodingName);
+                byte result[] = new byte[unicodeBytes.length
+                        + TEXT_ENCODING_UNICODE.prefix.length];
+                System.arraycopy(TEXT_ENCODING_UNICODE.prefix, 0, result,
+                        0, TEXT_ENCODING_UNICODE.prefix.length);
+                System.arraycopy(unicodeBytes, 0, result,
+                        TEXT_ENCODING_UNICODE.prefix.length,
+                        unicodeBytes.length);
+                return result;
+            }
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            throw new ImageWriteException(e.getMessage(), e);
+        }
+    }
+
+    public Object getValue(TiffField entry) throws ImageReadException
+    {
+        //            Debug.debug("entry.type", entry.type);
+        //            Debug.debug("entry.type", entry.getDescriptionWithoutValue());
+        //            Debug.debug("entry.type", entry.fieldType);
+
+        if (entry.type == FIELD_TYPE_ASCII.type)
+            return FIELD_TYPE_ASCII.getSimpleValue(entry);
+        else if (entry.type == FIELD_TYPE_UNDEFINED.type)
+        { /* do nothing */ }
+        else if (entry.type == FIELD_TYPE_BYTE.type)
+        { /* do nothing */ }
+        else
+        {
+            Debug.debug("entry.type", entry.type);
+            Debug.debug("entry.directoryType", entry.directoryType);
+            Debug.debug("entry.type", entry.getDescriptionWithoutValue());
+            Debug.debug("entry.type", entry.fieldType);
+            throw new ImageReadException("Text field not encoded as bytes.");
+        }
+
+        byte bytes[] = entry.fieldType.getRawBytes(entry);
+        if (bytes.length < 8)
+        {
+            try
+            {
+                // try ASCII, with NO prefix.
+                return new String(bytes, "US-ASCII");
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                throw new ImageReadException(
+                        "Text field missing encoding prefix.");
+            }
+        }
+
+        for (int i = 0; i < TEXT_ENCODINGS.length; i++)
+        {
+            TagInfoText.TextEncoding encoding = TEXT_ENCODINGS[i];
+            if (BinaryFileFunctions.compareBytes(bytes, 0, encoding.prefix,
+                    0, encoding.prefix.length))
+            {
+                try
+                {
+                    //                        Debug.debug("encodingName", encoding.encodingName);
+                    return new String(bytes, encoding.prefix.length,
+                            bytes.length - encoding.prefix.length,
+                            encoding.encodingName);
+                }
+                catch (UnsupportedEncodingException e)
+                {
+                    throw new ImageReadException(e.getMessage(), e);
+                }
+            }
+        }
+
+        //                        Debug.debug("entry.tag", entry.tag + " (0x" + Integer.toHexString(entry.tag ) +")");
+        //                        Debug.debug("entry.type", entry.type);
+        //                        Debug.debug("bytes", bytes, 10);
+        //            throw new ImageReadException(
+        //                    "Unknown Text encoding prefix.");
+
+        try
+        {
+            // try ASCII, with NO prefix.
+            return new String(bytes, "US-ASCII");
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            throw new ImageReadException("Unknown text encoding prefix.");
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoUndefined.java
similarity index 66%
copy from src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java
copy to src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoUndefined.java
index e201beb..0203f96 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoUndefined.java
@@ -14,8 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.sanselan.formats.tiff.constants;
+package org.apache.commons.sanselan.formats.tiff.taginfos;
 
-public interface TagHolder {
-    TagInfo getTagInfo();
+import java.util.Arrays;
+
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public class TagInfoUndefined extends TagInfoByte {
+    public TagInfoUndefined(String name, int tag, int length, TiffDirectoryType directoryType) {
+        super(name, tag, Arrays.asList(FIELD_TYPE_UNDEFINED), length, directoryType);
+    }
 }
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoUnknown.java
similarity index 63%
copy from src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java
copy to src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoUnknown.java
index e201beb..5c08724 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/constants/TagHolder.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/taginfos/TagInfoUnknown.java
@@ -14,8 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.sanselan.formats.tiff.constants;
+package org.apache.commons.sanselan.formats.tiff.taginfos;
 
-public interface TagHolder {
-    TagInfo getTagInfo();
-}
+import java.util.Arrays;
+
+import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+
+public final class TagInfoUnknown extends TagInfoByte {
+    public TagInfoUnknown(String name, int tag, int length, TiffDirectoryType exifDirectory) {
+        super(name, tag, Arrays.asList(FIELD_TYPE_UNKNOWN), length, exifDirectory);
+    }
+
+    public boolean isUnknown() {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffImageWriterBase.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffImageWriterBase.java
index 4aad219..54bfd68 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffImageWriterBase.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffImageWriterBase.java
@@ -30,6 +30,7 @@
 import org.apache.commons.sanselan.common.BinaryConstants;
 import org.apache.commons.sanselan.common.BinaryOutputStream;
 import org.apache.commons.sanselan.common.PackBits;
+import org.apache.commons.sanselan.common.RationalNumberUtilities;
 import org.apache.commons.sanselan.common.itu_t4.T4AndT6Compression;
 import org.apache.commons.sanselan.common.mylzw.MyLzwCompressor;
 import org.apache.commons.sanselan.formats.tiff.TiffElement;
@@ -140,19 +141,19 @@
                             + ") appears twice in directory.");
                 fieldTags.add(fieldKey);
 
-                if (field.tag == ExifTagConstants.EXIF_OFFSET.tagInfo.tag)
+                if (field.tag == ExifTagConstants.EXIF_TAG_EXIF_OFFSET.tag)
                 {
                     if (exifDirectoryOffsetField != null)
                         throw new ImageWriteException(
                                 "More than one Exif directory offset field.");
                     exifDirectoryOffsetField = field;
-                } else if (field.tag == ExifTagConstants.INTEROP_OFFSET.tagInfo.tag)
+                } else if (field.tag == ExifTagConstants.EXIF_TAG_INTEROP_OFFSET.tag)
                 {
                     if (interoperabilityDirectoryOffsetField != null)
                         throw new ImageWriteException(
                                 "More than one Interoperability directory offset field.");
                     interoperabilityDirectoryOffsetField = field;
-                } else if (field.tag == ExifTagConstants.GPSINFO.tagInfo.tag)
+                } else if (field.tag == ExifTagConstants.EXIF_TAG_GPSINFO.tag)
                 {
                     if (gpsDirectoryOffsetField != null)
                         throw new ImageWriteException(
@@ -208,7 +209,7 @@
             if (interoperabilityDirectoryOffsetField == null)
             {
                 interoperabilityDirectoryOffsetField = TiffOutputField
-                        .createOffsetField(ExifTagConstants.INTEROP_OFFSET.tagInfo, byteOrder);
+                        .createOffsetField(ExifTagConstants.EXIF_TAG_INTEROP_OFFSET, byteOrder);
                 exifDirectory.add(interoperabilityDirectoryOffsetField);
             }
 
@@ -227,7 +228,7 @@
             if (exifDirectoryOffsetField == null)
             {
                 exifDirectoryOffsetField = TiffOutputField.createOffsetField(
-                        ExifTagConstants.EXIF_OFFSET.tagInfo, byteOrder);
+                        ExifTagConstants.EXIF_TAG_EXIF_OFFSET, byteOrder);
                 rootDirectory.add(exifDirectoryOffsetField);
             }
 
@@ -244,7 +245,7 @@
             if (gpsDirectoryOffsetField == null)
             {
                 gpsDirectoryOffsetField = TiffOutputField.createOffsetField(
-                        ExifTagConstants.GPSINFO.tagInfo, byteOrder);
+                        ExifTagConstants.EXIF_TAG_GPSINFO, byteOrder);
                 rootDirectory.add(gpsDirectoryOffsetField);
             }
 
@@ -410,57 +411,20 @@
         // WriteField stripOffsetsField;
 
         {
-            {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.IMAGE_WIDTH.tagInfo, FIELD_TYPE_LONG, 1,
-                        FIELD_TYPE_LONG.writeData(new int[] { width, },
-                                byteOrder));
-                directory.add(field);
-            }
-            {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.IMAGE_LENGTH.tagInfo, FIELD_TYPE_LONG, 1,
-                        FIELD_TYPE_LONG.writeData(new int[] { height, },
-                                byteOrder));
-                directory.add(field);
-            }
-            {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.PHOTOMETRIC_INTERPRETATION.tagInfo, FIELD_TYPE_SHORT,
-                        1, FIELD_TYPE_SHORT.writeData(
-                                new int[] { photometricInterpretation, },
-                                byteOrder));
-                directory.add(field);
-            }
-            {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.COMPRESSION.tagInfo, FIELD_TYPE_SHORT, 1,
-                        FIELD_TYPE_SHORT.writeData(new int[] { compression, },
-                                byteOrder));
-                directory.add(field);
-            }
-            {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.SAMPLES_PER_PIXEL.tagInfo, FIELD_TYPE_SHORT, 1,
-                        FIELD_TYPE_SHORT.writeData(
-                                new int[] { samplesPerPixel, }, byteOrder));
-                directory.add(field);
-            }
+
+            directory.add(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, width);
+            directory.add(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, height);
+            directory.add(TiffTagConstants.TIFF_TAG_PHOTOMETRIC_INTERPRETATION, (short)photometricInterpretation);
+            directory.add(TiffTagConstants.TIFF_TAG_COMPRESSION, (short)compression);
+            directory.add(TiffTagConstants.TIFF_TAG_SAMPLES_PER_PIXEL, (short)samplesPerPixel);
             
             if (samplesPerPixel == 3)
             {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.BITS_PER_SAMPLE.tagInfo, FIELD_TYPE_SHORT, 3,
-                        FIELD_TYPE_SHORT.writeData(new int[] { bitsPerSample,
-                                bitsPerSample, bitsPerSample, }, byteOrder));
-                directory.add(field);
+                directory.add(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE, (short)bitsPerSample,
+                        (short)bitsPerSample, (short)bitsPerSample);
             } else if (samplesPerPixel == 1)
             {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.BITS_PER_SAMPLE.tagInfo, FIELD_TYPE_SHORT, 1,
-                        FIELD_TYPE_SHORT.writeData(
-                                new int[] { bitsPerSample, }, byteOrder));
-                directory.add(field);
+                directory.add(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE, (short)bitsPerSample);
             }
             // {
             // stripOffsetsField = new WriteField(TIFF_TAG_STRIP_OFFSETS,
@@ -475,62 +439,24 @@
             // WRITE_BYTE_ORDER));
             // directory.add(field);
             // }
-            {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.ROWS_PER_STRIP.tagInfo, FIELD_TYPE_LONG, 1,
-                        FIELD_TYPE_LONG.writeData(new int[] { rowsPerStrip, },
-                                byteOrder));
-                directory.add(field);
-            }
-
-            {
-                int resolutionUnit = 2;// inches.
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.RESOLUTION_UNIT.tagInfo, FIELD_TYPE_SHORT, 1,
-                        FIELD_TYPE_SHORT.writeData(
-                                new int[] { resolutionUnit, }, byteOrder));
-                directory.add(field);
-            }
-
-            {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.XRESOLUTION.tagInfo, FIELD_TYPE_RATIONAL, 1,
-                        FIELD_TYPE_RATIONAL
-                                .writeData(xResolution.intValue(), 1, byteOrder));
-                directory.add(field);
-            }
-
-            {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.YRESOLUTION.tagInfo, FIELD_TYPE_RATIONAL, 1,
-                        FIELD_TYPE_RATIONAL
-                                .writeData(yResolution.intValue(), 1, byteOrder));
-                directory.add(field);
-            }
-            
+            directory.add(TiffTagConstants.TIFF_TAG_ROWS_PER_STRIP, rowsPerStrip);
+            directory.add(TiffTagConstants.TIFF_TAG_RESOLUTION_UNIT, (short)2); // inches
+            directory.add(TiffTagConstants.TIFF_TAG_XRESOLUTION,
+                    RationalNumberUtilities.getRationalNumber(xResolution.doubleValue()));
+            directory.add(TiffTagConstants.TIFF_TAG_YRESOLUTION,
+                    RationalNumberUtilities.getRationalNumber(yResolution.doubleValue()));
             if (t4Options != 0) {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.T4_OPTIONS.tagInfo, FIELD_TYPE_LONG, 1,
-                        FIELD_TYPE_LONG
-                                .writeData(Integer.valueOf(t4Options), byteOrder));
-                directory.add(field);
+                directory.add(TiffTagConstants.TIFF_TAG_T4_OPTIONS, t4Options);
             }
             if (t6Options != 0) {
-                TiffOutputField field = new TiffOutputField(
-                        TiffTagConstants.T6_OPTIONS.tagInfo, FIELD_TYPE_LONG, 1,
-                        FIELD_TYPE_LONG
-                                .writeData(Integer.valueOf(t6Options), byteOrder));
-                directory.add(field);
+                directory.add(TiffTagConstants.TIFF_TAG_T6_OPTIONS, t6Options);
             }
 
 
             if (null != xmpXml)
             {
                 byte xmpXmlBytes[] = xmpXml.getBytes("utf-8");
-
-                TiffOutputField field = new TiffOutputField(TiffTagConstants.XMP.tagInfo,
-                        FIELD_TYPE_BYTE, xmpXmlBytes.length, xmpXmlBytes);
-                directory.add(field);
+                directory.add(TiffTagConstants.TIFF_TAG_XMP, xmpXmlBytes);
             }
 
         }
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffImageWriterLossless.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffImageWriterLossless.java
index ca29587..943f45c 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffImageWriterLossless.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffImageWriterLossless.java
@@ -143,7 +143,7 @@
                 for (int f = 0; f < fields.size(); f++)
                 {
                     TiffField field = fields.get(f);
-                    if (field.tag == ExifTagConstants.MAKER_NOTE.tagInfo.tag) {
+                    if (field.tag == ExifTagConstants.EXIF_TAG_MAKER_NOTE.tag) {
                         // Some maker notes reference values stored
                         // inside the maker note itself
                         // using addresses relative to the beginning
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputDirectory.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputDirectory.java
index de76894..deca567 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputDirectory.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputDirectory.java
@@ -24,23 +24,41 @@
 
 import org.apache.commons.sanselan.ImageWriteException;
 import org.apache.commons.sanselan.common.BinaryOutputStream;
+import org.apache.commons.sanselan.common.RationalNumber;
 import org.apache.commons.sanselan.formats.tiff.JpegImageData;
 import org.apache.commons.sanselan.formats.tiff.TiffDirectory;
 import org.apache.commons.sanselan.formats.tiff.TiffElement;
 import org.apache.commons.sanselan.formats.tiff.TiffImageData;
 import org.apache.commons.sanselan.formats.tiff.constants.TagConstantsUtils;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffDirectoryType;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffFieldTypeConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffTagConstants;
 import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoAscii;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoByte;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoByteOrShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoDouble;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoFloat;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSByte;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoSShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShort;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShortOrLong;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShortOrLongOrRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoShortOrRational;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfoText;
 
 public final class TiffOutputDirectory extends TiffOutputItem implements
         TiffConstants
 {
     public final int type;
     private final List<TiffOutputField> fields = new ArrayList<TiffOutputField>();
-
+    private final int byteOrder;
     private TiffOutputDirectory nextDirectory = null;
 
     public void setNextDirectory(TiffOutputDirectory nextDirectory)
@@ -48,11 +66,239 @@
         this.nextDirectory = nextDirectory;
     }
 
-    public TiffOutputDirectory(final int type)
+    public TiffOutputDirectory(final int type, final int byteOrder)
     {
         this.type = type;
+        this.byteOrder = byteOrder;
+    }
+    
+    public void add(TagInfoByte tagInfo, byte... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_BYTE, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoAscii tagInfo, String... values) throws ImageWriteException {
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        if (tagInfo.length > 0 && tagInfo.length != bytes.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " byte(s), not " + values.length);
+        }
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_ASCII, bytes.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoShort tagInfo, short... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_SHORT, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoLong tagInfo, int... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_LONG, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoRational tagInfo, RationalNumber... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_RATIONAL, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoSByte tagInfo, byte... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_SBYTE, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoSShort tagInfo, short... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_SSHORT, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoSLong tagInfo, int... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_SLONG, values.length, bytes);
+        add(tiffOutputField);
     }
 
+    public void add(TagInfoSRational tagInfo, RationalNumber... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_SRATIONAL, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoFloat tagInfo, float... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_FLOAT, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoDouble tagInfo, double... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_DOUBLE, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoByteOrShort tagInfo, byte... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_SHORT, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoByteOrShort tagInfo, short... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_SHORT, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoShortOrLong tagInfo, short... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_LONG, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoShortOrLong tagInfo, int... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_LONG, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoShortOrLongOrRational tagInfo, short... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_RATIONAL, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoShortOrLongOrRational tagInfo, int... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_RATIONAL, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoShortOrLongOrRational tagInfo, RationalNumber... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_RATIONAL, values.length, bytes);
+        add(tiffOutputField);
+    }
+    
+    public void add(TagInfoShortOrRational tagInfo, short... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_RATIONAL, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoShortOrRational tagInfo, RationalNumber... values) throws ImageWriteException {
+        if (tagInfo.length > 0 && tagInfo.length != values.length) {
+            throw new ImageWriteException("Tag expects " + tagInfo.length +
+                    " value(s), not " + values.length);
+        }
+        byte[] bytes = tagInfo.encodeValue(byteOrder, values);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_RATIONAL, values.length, bytes);
+        add(tiffOutputField);
+    }
+
+    public void add(TagInfoText tagInfo, String value) throws ImageWriteException {
+        byte[] bytes = tagInfo.encodeValue(TiffFieldTypeConstants.FIELD_TYPE_UNKNOWN, value, byteOrder);
+        TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo,
+                TiffFieldTypeConstants.FIELD_TYPE_UNKNOWN, bytes.length, bytes);
+        add(tiffOutputField);
+    }
+    
     public void add(TiffOutputField field)
     {
         fields.add(field);
@@ -192,14 +438,14 @@
     {
         // first validate directory fields.
 
-        removeFieldIfPresent(TiffTagConstants.JPEG_INTERCHANGE_FORMAT.tagInfo);
-        removeFieldIfPresent(TiffTagConstants.JPEG_INTERCHANGE_FORMAT_LENGTH.tagInfo);
+        removeFieldIfPresent(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT);
+        removeFieldIfPresent(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
 
         TiffOutputField jpegOffsetField = null;
         if (null != jpegImageData)
         {
             jpegOffsetField = new TiffOutputField(
-                    TiffTagConstants.JPEG_INTERCHANGE_FORMAT.tagInfo, FIELD_TYPE_LONG, 1,
+                    TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT, FIELD_TYPE_LONG, 1,
                     FieldType.getStubLocalValue());
             add(jpegOffsetField);
 
@@ -208,7 +454,7 @@
                     outputSummary.byteOrder);
 
             TiffOutputField jpegLengthField = new TiffOutputField(
-                    TiffTagConstants.JPEG_INTERCHANGE_FORMAT_LENGTH.tagInfo, FIELD_TYPE_LONG,
+                    TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, FIELD_TYPE_LONG,
                     1, lengthValue);
             add(jpegLengthField);
 
@@ -216,10 +462,10 @@
 
         // --------------------------------------------------------------
 
-        removeFieldIfPresent(TiffTagConstants.STRIP_OFFSETS.tagInfo);
-        removeFieldIfPresent(TiffTagConstants.STRIP_BYTE_COUNTS.tagInfo);
-        removeFieldIfPresent(TiffTagConstants.TILE_OFFSETS.tagInfo);
-        removeFieldIfPresent(TiffTagConstants.TILE_BYTE_COUNTS.tagInfo);
+        removeFieldIfPresent(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS);
+        removeFieldIfPresent(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS);
+        removeFieldIfPresent(TiffTagConstants.TIFF_TAG_TILE_OFFSETS);
+        removeFieldIfPresent(TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS);
 
         TiffOutputField imageDataOffsetField;
         ImageDataOffsets imageDataInfo = null;
@@ -231,12 +477,12 @@
             TagInfo byteCountsTag;
             if (stripsNotTiles)
             {
-                offsetTag = TiffTagConstants.STRIP_OFFSETS.tagInfo;
-                byteCountsTag = TiffTagConstants.STRIP_BYTE_COUNTS.tagInfo;
+                offsetTag = TiffTagConstants.TIFF_TAG_STRIP_OFFSETS;
+                byteCountsTag = TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS;
             } else
             {
-                offsetTag = TiffTagConstants.TILE_OFFSETS.tagInfo;
-                byteCountsTag = TiffTagConstants.TILE_BYTE_COUNTS.tagInfo;
+                offsetTag = TiffTagConstants.TIFF_TAG_TILE_OFFSETS;
+                byteCountsTag = TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS;
             }
 
             // --------
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputField.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputField.java
index 15bb8f8..f1929c9 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputField.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputField.java
@@ -20,9 +20,9 @@
 
 import org.apache.commons.sanselan.ImageWriteException;
 import org.apache.commons.sanselan.common.BinaryOutputStream;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffConstants;
 import org.apache.commons.sanselan.formats.tiff.fieldtypes.FieldType;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
 
 public class TiffOutputField implements TiffConstants
 {
@@ -62,56 +62,6 @@
 
     private int sortHint = -1;
 
-    public static TiffOutputField create(TagInfo tagInfo, int byteOrder,
-            Number number) throws ImageWriteException
-    {
-        if (tagInfo.dataTypes == null || tagInfo.dataTypes.length < 1)
-            throw new ImageWriteException("Tag has no default data type.");
-        FieldType fieldType = tagInfo.dataTypes[0];
-
-        if (tagInfo.length != 1)
-            throw new ImageWriteException("Tag does not expect a single value.");
-
-        byte bytes[] = fieldType.writeData(number, byteOrder);
-
-        return new TiffOutputField(tagInfo.tag, tagInfo, fieldType, 1, bytes);
-    }
-
-    public static TiffOutputField create(TagInfo tagInfo, int byteOrder,
-            Number value[]) throws ImageWriteException
-    {
-        if (tagInfo.dataTypes == null || tagInfo.dataTypes.length < 1)
-            throw new ImageWriteException("Tag has no default data type.");
-        FieldType fieldType = tagInfo.dataTypes[0];
-
-        if (tagInfo.length >= 0 && tagInfo.length != value.length)
-            throw new ImageWriteException("Tag expects " + tagInfo.length + " values.");
-
-        byte bytes[] = fieldType.writeData(value, byteOrder);
-
-        return new TiffOutputField(tagInfo.tag, tagInfo, fieldType,
-                value.length, bytes);
-    }
-
-    public static TiffOutputField create(TagInfo tagInfo, int byteOrder,
-            String value) throws ImageWriteException
-    {
-        FieldType fieldType;
-        if (tagInfo.dataTypes == null || tagInfo.dataTypes.length < 1)
-            fieldType = FIELD_TYPE_ASCII;
-        else
-        {
-            if (tagInfo.dataTypes[0] == FIELD_TYPE_ASCII)
-                fieldType = FIELD_TYPE_ASCII;
-            else
-                throw new ImageWriteException("Tag has unexpected data type.");
-        }
-
-        byte bytes[] = fieldType.writeData(value, byteOrder);
-
-        return new TiffOutputField(tagInfo.tag, tagInfo, fieldType, bytes.length, bytes);
-    }
-
     protected static final TiffOutputField createOffsetField(TagInfo tagInfo,
             int byteOrder) throws ImageWriteException
     {
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputSet.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputSet.java
index 1735f3a..80156e1 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputSet.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/write/TiffOutputSet.java
@@ -20,9 +20,10 @@
 import java.util.List;
 
 import org.apache.commons.sanselan.ImageWriteException;
+import org.apache.commons.sanselan.common.RationalNumberUtilities;
 import org.apache.commons.sanselan.formats.tiff.constants.GpsTagConstants;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffConstants;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
 import org.apache.commons.sanselan.util.Debug;
 
 public final class TiffOutputSet implements TiffConstants
@@ -153,21 +154,12 @@
         String latitudeRef = latitude < 0 ? "S" : "N";
         latitude = Math.abs(latitude);
 
-        {
-            TiffOutputField longitudeRefField = TiffOutputField.create(
-                    GpsTagConstants.GPS_LONGITUDE_REF.tagInfo, byteOrder,
-                    longitudeRef);
-            gpsDirectory.removeField(GpsTagConstants.GPS_LONGITUDE_REF.tagInfo);
-            gpsDirectory.add(longitudeRefField);
-        }
+        gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
+        gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_DEST_LONGITUDE_REF, longitudeRef);
 
-        {
-            TiffOutputField latitudeRefField = TiffOutputField.create(
-                    GpsTagConstants.GPS_LATITUDE_REF.tagInfo, byteOrder,
-                    latitudeRef);
-            gpsDirectory.removeField(GpsTagConstants.GPS_LATITUDE_REF.tagInfo);
-            gpsDirectory.add(latitudeRefField);
-        }
+        gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
+        gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_DEST_LATITUDE_REF, latitudeRef);
+
 
         {
             double value = longitude;
@@ -178,15 +170,12 @@
             value %= 1;
             value *= 60.0;
             double longitudeSeconds = value;
-            Double values[] = {
-                    new Double(longitudeDegrees), new Double(longitudeMinutes),
-                    new Double(longitudeSeconds),
-            };
 
-            TiffOutputField longitudeField = TiffOutputField.create(
-                    GpsTagConstants.GPS_LONGITUDE.tagInfo, byteOrder, values);
-            gpsDirectory.removeField(GpsTagConstants.GPS_LONGITUDE.tagInfo);
-            gpsDirectory.add(longitudeField);
+            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
+            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_DEST_LONGITUDE,
+                    RationalNumberUtilities.getRationalNumber(longitudeDegrees),
+                    RationalNumberUtilities.getRationalNumber(longitudeMinutes),
+                    RationalNumberUtilities.getRationalNumber(longitudeSeconds));
         }
 
         {
@@ -198,15 +187,12 @@
             value %= 1;
             value *= 60.0;
             double latitudeSeconds = value;
-            Double values[] = {
-                    new Double(latitudeDegrees), new Double(latitudeMinutes),
-                    new Double(latitudeSeconds),
-            };
 
-            TiffOutputField latitudeField = TiffOutputField.create(
-                    GpsTagConstants.GPS_LATITUDE.tagInfo, byteOrder, values);
-            gpsDirectory.removeField(GpsTagConstants.GPS_LATITUDE.tagInfo);
-            gpsDirectory.add(latitudeField);
+            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE);
+            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE,
+                    RationalNumberUtilities.getRationalNumber(latitudeDegrees),
+                    RationalNumberUtilities.getRationalNumber(latitudeMinutes),
+                    RationalNumberUtilities.getRationalNumber(latitudeSeconds));
         }
 
     }
@@ -247,7 +233,7 @@
     public TiffOutputDirectory addRootDirectory() throws ImageWriteException
     {
         TiffOutputDirectory result = new TiffOutputDirectory(
-                DIRECTORY_TYPE_ROOT);
+                DIRECTORY_TYPE_ROOT, byteOrder);
         addDirectory(result);
         return result;
     }
@@ -255,14 +241,14 @@
     public TiffOutputDirectory addExifDirectory() throws ImageWriteException
     {
         TiffOutputDirectory result = new TiffOutputDirectory(
-                DIRECTORY_TYPE_EXIF);
+                DIRECTORY_TYPE_EXIF, byteOrder);
         addDirectory(result);
         return result;
     }
 
     public TiffOutputDirectory addGPSDirectory() throws ImageWriteException
     {
-        TiffOutputDirectory result = new TiffOutputDirectory(DIRECTORY_TYPE_GPS);
+        TiffOutputDirectory result = new TiffOutputDirectory(DIRECTORY_TYPE_GPS, byteOrder);
         addDirectory(result);
         return result;
     }
@@ -273,7 +259,7 @@
         getOrCreateExifDirectory();
 
         TiffOutputDirectory result = new TiffOutputDirectory(
-                DIRECTORY_TYPE_INTEROPERABILITY);
+                DIRECTORY_TYPE_INTEROPERABILITY, byteOrder);
         addDirectory(result);
         return result;
     }
diff --git a/src/test/java/org/apache/commons/sanselan/examples/MetadataExample.java b/src/test/java/org/apache/commons/sanselan/examples/MetadataExample.java
index cd0088e..d960484 100644
--- a/src/test/java/org/apache/commons/sanselan/examples/MetadataExample.java
+++ b/src/test/java/org/apache/commons/sanselan/examples/MetadataExample.java
@@ -29,9 +29,9 @@
 import org.apache.commons.sanselan.formats.tiff.TiffImageMetadata;
 import org.apache.commons.sanselan.formats.tiff.constants.ExifTagConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.GpsTagConstants;
-import org.apache.commons.sanselan.formats.tiff.constants.TagInfo;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffConstants;
 import org.apache.commons.sanselan.formats.tiff.constants.TiffTagConstants;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
 
 public class MetadataExample
 {
@@ -58,20 +58,20 @@
             System.out.println("file: " + file.getPath());
 
             // print out various interesting EXIF tags.
-            printTagValue(jpegMetadata, TiffTagConstants.XRESOLUTION.tagInfo);
-            printTagValue(jpegMetadata, TiffTagConstants.DATE_TIME.tagInfo);
+            printTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_XRESOLUTION);
+            printTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_DATE_TIME);
             printTagValue(jpegMetadata,
-                    ExifTagConstants.DATE_TIME_ORIGINAL.tagInfo);
-            printTagValue(jpegMetadata, ExifTagConstants.CREATE_DATE.tagInfo);
-            printTagValue(jpegMetadata, ExifTagConstants.ISO.tagInfo);
+                    ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
+            printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_CREATE_DATE);
+            printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_ISO);
             printTagValue(jpegMetadata,
-                    ExifTagConstants.SHUTTER_SPEED_VALUE.tagInfo);
-            printTagValue(jpegMetadata, ExifTagConstants.APERTURE_VALUE.tagInfo);
-            printTagValue(jpegMetadata, ExifTagConstants.BRIGHTNESS_VALUE.tagInfo);
-            printTagValue(jpegMetadata, GpsTagConstants.GPS_LATITUDE_REF.tagInfo);
-            printTagValue(jpegMetadata, GpsTagConstants.GPS_LATITUDE.tagInfo);
-            printTagValue(jpegMetadata, GpsTagConstants.GPS_LONGITUDE_REF.tagInfo);
-            printTagValue(jpegMetadata, GpsTagConstants.GPS_LONGITUDE.tagInfo);
+                    ExifTagConstants.EXIF_TAG_SHUTTER_SPEED_VALUE);
+            printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
+            printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_BRIGHTNESS_VALUE);
+            printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
+            printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LATITUDE);
+            printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
+            printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
 
             System.out.println();
 
@@ -94,13 +94,13 @@
 
             // more specific example of how to manually access GPS values
             TiffField gpsLatitudeRefField = jpegMetadata
-                    .findEXIFValueWithExactMatch(GpsTagConstants.GPS_LATITUDE_REF.tagInfo);
+                    .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
             TiffField gpsLatitudeField = jpegMetadata
-                    .findEXIFValueWithExactMatch(GpsTagConstants.GPS_LATITUDE.tagInfo);
+                    .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE);
             TiffField gpsLongitudeRefField = jpegMetadata
-                    .findEXIFValueWithExactMatch(GpsTagConstants.GPS_LONGITUDE_REF.tagInfo);
+                    .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
             TiffField gpsLongitudeField = jpegMetadata
-                    .findEXIFValueWithExactMatch(GpsTagConstants.GPS_LONGITUDE.tagInfo);
+                    .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
             if (gpsLatitudeRefField != null && gpsLatitudeField != null
                     && gpsLongitudeRefField != null
                     && gpsLongitudeField != null)
diff --git a/src/test/java/org/apache/commons/sanselan/examples/WriteExifMetadataExample.java b/src/test/java/org/apache/commons/sanselan/examples/WriteExifMetadataExample.java
index a45d32a..9d49449 100644
--- a/src/test/java/org/apache/commons/sanselan/examples/WriteExifMetadataExample.java
+++ b/src/test/java/org/apache/commons/sanselan/examples/WriteExifMetadataExample.java
@@ -26,6 +26,7 @@
 import org.apache.commons.sanselan.ImageWriteException;
 import org.apache.commons.sanselan.Sanselan;
 import org.apache.commons.sanselan.common.IImageMetadata;
+import org.apache.commons.sanselan.common.RationalNumber;
 import org.apache.commons.sanselan.formats.jpeg.JpegImageMetadata;
 import org.apache.commons.sanselan.formats.jpeg.exif.ExifRewriter;
 import org.apache.commons.sanselan.formats.tiff.TiffImageMetadata;
@@ -125,16 +126,13 @@
                 // see
                 // org.apache.commons.sanselan.formats.tiff.constants.AllTagConstants
                 //
-                TiffOutputField aperture = TiffOutputField.create(
-                        ExifTagConstants.APERTURE_VALUE.tagInfo,
-                        outputSet.byteOrder, new Double(0.3));
                 TiffOutputDirectory exifDirectory = outputSet
                         .getOrCreateExifDirectory();
                 // make sure to remove old value if present (this method will
                 // not fail if the tag does not exist).
                 exifDirectory
-                        .removeField(ExifTagConstants.APERTURE_VALUE.tagInfo);
-                exifDirectory.add(aperture);
+                        .removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
+                exifDirectory.add(ExifTagConstants.EXIF_TAG_APERTURE_VALUE, RationalNumber.factoryMethod(3, 10));
             }
 
             {
@@ -232,7 +230,7 @@
                 // Note that this approach is crude: Exif data is organized in
                 // directories. The same tag/field may appear in more than one
                 // directory, and have different meanings in each.
-                outputSet.removeField(ExifTagConstants.APERTURE_VALUE.tagInfo);
+                outputSet.removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
 
                 // Option 2: precision
                 // We know the exact directory the tag should appear in, in this
@@ -246,7 +244,7 @@
                         .getExifDirectory();
                 if (null != exifDirectory)
                     exifDirectory
-                            .removeField(ExifTagConstants.APERTURE_VALUE.tagInfo);
+                            .removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
             }
 
             os = new FileOutputStream(dst);
diff --git a/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/AsciiFieldTest.java b/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/AsciiFieldTest.java
index 2402fc6..9cbb90c 100644
--- a/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/AsciiFieldTest.java
+++ b/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/AsciiFieldTest.java
@@ -59,9 +59,9 @@
         }
 
         Map expectedFieldValues = new Hashtable();
-        expectedFieldValues.put(new Integer(ExifTagConstants.MAKE.tagInfo.tag), "Canon");
-        expectedFieldValues.put(new Integer(ExifTagConstants.MODEL.tagInfo.tag), "Canon PowerShot SD750");
-        expectedFieldValues.put(new Integer(ExifTagConstants.MODIFY_DATE.tagInfo.tag), "2007:12:25 13:34:39");
+        expectedFieldValues.put(new Integer(ExifTagConstants.EXIF_TAG_MAKE.tag), "Canon");
+        expectedFieldValues.put(new Integer(ExifTagConstants.EXIF_TAG_MODEL.tag), "Canon PowerShot SD750");
+        expectedFieldValues.put(new Integer(ExifTagConstants.EXIF_TAG_MODIFY_DATE.tag), "2007:12:25 13:34:39");
         Iterator expectedTags = expectedFieldValues.keySet().iterator();
         while (expectedTags.hasNext()) {
             Integer tag = (Integer) expectedTags.next();
diff --git a/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/MakerNoteFieldTest.java b/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/MakerNoteFieldTest.java
index 09b78aa..4909358 100644
--- a/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/MakerNoteFieldTest.java
+++ b/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/MakerNoteFieldTest.java
@@ -36,7 +36,7 @@
     protected void checkField(File imageFile, TiffField field)
             throws IOException, ImageReadException, ImageWriteException
     {
-        if (field.tag != ExifTagConstants.MAKER_NOTE.tagInfo.tag)
+        if (field.tag != ExifTagConstants.EXIF_TAG_MAKER_NOTE.tag)
         {
             //            if (field.tag == EXIF_TAG_EXIF_OFFSET.tag)
             //                ;
diff --git a/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/TextFieldTest.java b/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/TextFieldTest.java
index 07bf320..b8b3482 100644
--- a/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/TextFieldTest.java
+++ b/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/TextFieldTest.java
@@ -38,12 +38,12 @@
     protected void checkField(File imageFile, TiffField field)
             throws IOException, ImageReadException, ImageWriteException
     {
-        if (field.tag == ExifTagConstants.USER_COMMENT.tagInfo.tag)
+        if (field.tag == ExifTagConstants.EXIF_TAG_USER_COMMENT.tag)
         { /* do nothing */ }
-        else if (field.tag == GpsTagConstants.GPS_PROCESSING_METHOD.tagInfo.tag
+        else if (field.tag == GpsTagConstants.GPS_TAG_GPS_PROCESSING_METHOD.tag
                 && field.directoryType == TiffDirectoryType.EXIF_DIRECTORY_GPS.directoryType)
         { /* do nothing */ }
-        else if (field.tag == GpsTagConstants.GPS_AREA_INFORMATION.tagInfo.tag
+        else if (field.tag == GpsTagConstants.GPS_TAG_GPS_AREA_INFORMATION.tag
                 && field.directoryType == TiffDirectoryType.EXIF_DIRECTORY_GPS.directoryType)
         { /* do nothing */ }
         else
diff --git a/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/WriteTagsTest.java b/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/WriteTagsTest.java
deleted file mode 100644
index 604eca0..0000000
--- a/src/test/java/org/apache/commons/sanselan/formats/jpeg/exif/WriteTagsTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.sanselan.formats.jpeg.exif;
-
-import org.apache.commons.sanselan.SanselanConstants;
-import org.apache.commons.sanselan.common.BinaryConstants;
-import org.apache.commons.sanselan.formats.tiff.constants.ExifTagConstants;
-import org.apache.commons.sanselan.formats.tiff.constants.TiffTagConstants;
-import org.apache.commons.sanselan.formats.tiff.write.TiffOutputField;
-
-public class WriteTagsTest extends ExifBaseTest implements SanselanConstants
-{
-
-    public void test2SHORTS() throws Exception
-    {
-        TiffOutputField.create(
-            ExifTagConstants.PAGE_NUMBER.tagInfo,
-            BinaryConstants.BYTE_ORDER_LITTLE_ENDIAN,
-            new Integer[] { new Integer(1), new Integer(10) } );
-    }
-
-    public void testSHORTS() throws Exception
-    {
-        TiffOutputField.create(
-            TiffTagConstants.BITS_PER_SAMPLE.tagInfo,
-            BinaryConstants.BYTE_ORDER_LITTLE_ENDIAN,
-            new Integer[] { new Integer(1), new Integer(1) } );
-    }
-}
diff --git a/src/test/java/org/apache/commons/sanselan/formats/tiff/TiffTagIntegrityTest.java b/src/test/java/org/apache/commons/sanselan/formats/tiff/TiffTagIntegrityTest.java
new file mode 100644
index 0000000..2346d0c
--- /dev/null
+++ b/src/test/java/org/apache/commons/sanselan/formats/tiff/TiffTagIntegrityTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.sanselan.formats.tiff;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+import org.apache.commons.sanselan.SanselanTest;
+import org.apache.commons.sanselan.formats.tiff.constants.ExifTagConstants;
+import org.apache.commons.sanselan.formats.tiff.constants.GpsTagConstants;
+import org.apache.commons.sanselan.formats.tiff.constants.TiffTagConstants;
+import org.apache.commons.sanselan.formats.tiff.taginfos.TagInfo;
+
+public class TiffTagIntegrityTest extends SanselanTest {
+    public void testTagIntegrity() {
+        verifyFields(TiffTagConstants.class, TiffTagConstants.ALL_TIFF_TAGS);
+        verifyFields(GpsTagConstants.class, GpsTagConstants.ALL_GPS_TAGS);
+        verifyFields(ExifTagConstants.class, ExifTagConstants.ALL_EXIF_TAGS);
+    }
+    
+    private void verifyFields(Class<?> cls, List<TagInfo> tags) {
+        Field[] fields = cls.getFields();
+        int tagCount = 0;
+        int foundCount = 0;
+        for (Field field : fields) {
+            field.setAccessible(true);
+            if (!(field.getType().isInstance(TagInfo.class))) {
+                continue;
+            }
+            ++tagCount;
+            TagInfo src = null;
+            try {
+                src = (TagInfo) field.get(null);
+            } catch (IllegalAccessException illegalAccess) {
+            }
+            if (src == null) {
+                continue;
+            }
+            for (int i = 0; i < tags.size(); i++) {
+                TagInfo tagInfo = tags.get(i);
+                if (tagInfo.tag == src.tag) {
+                    ++foundCount;
+                    break;
+                }
+            }
+        }
+        assertEquals(tagCount, foundCount);
+    }
+}