Provide a way to write EXIF data into files using Sanselan.writeImage().
SanselanConstants get a PARAM_KEY_EXIF, similar to PARAM_KEY_XMP_XML,
which references a TiffOutputSet containing EXIF tags to be written
into the image. Only 2 file image formats support support EXIF: JPEG
and TIFF. Since Sanselan's JPEG currently doesn't write files at all,
only TIFF has been patched, and what it does is merge the TiffOutputSet
given by the user with the TiffOutputSet generated by writing the image,
not allowing the user's one to override any tags generated internally,
but otherwise allowing any field and any directory to be written
into the output file.

Also eliminates Java < 5 boxing of primitives (Findbugs).



git-svn-id: https://svn.apache.org/repos/asf/commons/proper/sanselan/trunk@1292909 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/commons/sanselan/SanselanConstants.java b/src/main/java/org/apache/commons/sanselan/SanselanConstants.java
index c2eb881..1074dfe 100644
--- a/src/main/java/org/apache/commons/sanselan/SanselanConstants.java
+++ b/src/main/java/org/apache/commons/sanselan/SanselanConstants.java
@@ -101,6 +101,16 @@
      *
      * Only used when writing images.
      * <p>
+     * Valid values: TiffOutputSet to write into the image's EXIF metadata.
+     * <p>
+     */
+    public static final String PARAM_KEY_EXIF = "EXIF";
+
+    /**
+     * Parameter key.
+     *
+     * Only used when writing images.
+     * <p>
      * Valid values: String of XMP XML.
      * <p>
      */
diff --git a/src/main/java/org/apache/commons/sanselan/common/bytesource/ByteSourceInputStream.java b/src/main/java/org/apache/commons/sanselan/common/bytesource/ByteSourceInputStream.java
index 1a3b630..b91c693 100644
--- a/src/main/java/org/apache/commons/sanselan/common/bytesource/ByteSourceInputStream.java
+++ b/src/main/java/org/apache/commons/sanselan/common/bytesource/ByteSourceInputStream.java
@@ -207,7 +207,7 @@
         long skipped;
         while ((skipped = is.skip(1024)) > 0)
             result += skipped;
-        streamLength = new Long(result);
+        streamLength = result;
         return result;
     }
 
diff --git a/src/main/java/org/apache/commons/sanselan/common/mylzw/MyLzwCompressor.java b/src/main/java/org/apache/commons/sanselan/common/mylzw/MyLzwCompressor.java
index e88f463..5cbfddc 100644
--- a/src/main/java/org/apache/commons/sanselan/common/mylzw/MyLzwCompressor.java
+++ b/src/main/java/org/apache/commons/sanselan/common/mylzw/MyLzwCompressor.java
@@ -75,7 +75,7 @@
             {
                 Object key = arrayToKey((byte) codes);
 
-                map.put(key, new Integer(codes));
+                map.put(key, codes);
             }
         }
     }
@@ -235,7 +235,7 @@
 
         if (!cleared)
         {
-            map.put(key, new Integer(codes));
+            map.put(key, codes);
             codes++;
         }
 
diff --git a/src/main/java/org/apache/commons/sanselan/formats/dcx/DcxImageParser.java b/src/main/java/org/apache/commons/sanselan/formats/dcx/DcxImageParser.java
index a511b37..099ca61 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/dcx/DcxImageParser.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/dcx/DcxImageParser.java
@@ -145,7 +145,7 @@
                 int pageOffset = read4Bytes("PageTable", is, "Not a Valid DCX File");
                 if (pageOffset == 0)
                     break;
-                pageTable.add(new Integer(pageOffset));
+                pageTable.add(pageOffset);
             }
 
             if (id != DcxHeader.DCX_ID)
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 1219ef8..72ec3aa 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
@@ -253,9 +253,7 @@
 
     private static TagInfo getTag(int directoryType, int tag)
     {
-        Object key = new Integer(tag);
-
-        List<TagInfo> possibleMatches = ALL_TAG_MAP.get(key);
+        List<TagInfo> possibleMatches = ALL_TAG_MAP.get(tag);
 
         if (null == possibleMatches)
         {
@@ -608,13 +606,12 @@
         for (int i = 0; i < tags.size(); i++)
         {
             TagInfo tag = tags.get(i);
-            Object key = new Integer(tag.tag);
 
-            List<TagInfo> tagList = map.get(key);
+            List<TagInfo> tagList = map.get(tag.tag);
             if (tagList == null)
             {
                 tagList = new ArrayList<TagInfo>();
-                map.put(key, tagList);
+                map.put(tag.tag, tagList);
             }
             tagList.add(tag);
 
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 a4ac6dd..02157ff 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
@@ -69,13 +69,12 @@
         for (int i = 0; i < tags.size(); i++)
         {
             TagInfo tag = tags.get(i);
-            Object key = new Integer(tag.tag);
 
-            Integer count = map.get(key);
+            Integer count = map.get(tag.tag);
             if (count == null)
-                map.put(key, new Integer(1));
+                map.put(tag.tag, 1);
             else
-                map.put(key, new Integer(count.intValue() + 1));
+                map.put(tag.tag, count + 1);
         }
 
         return map;
@@ -271,7 +270,7 @@
     public TiffField findField(TagInfo tagInfo, boolean exactDirectoryMatch) throws ImageReadException
     {
         // Please keep this method in sync with TiffField's getTag()
-        Integer tagCount = tagCounts.get(new Integer(tagInfo.tag));
+        Integer tagCount = tagCounts.get(tagInfo.tag);
         int tagsMatching = tagCount == null ? 0 : tagCount.intValue();
 
         List<? extends IImageMetadataItem> directories = getDirectories();
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 700a4d9..ee18745 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
@@ -118,7 +118,6 @@
             boolean ignoreNextDirectory, List<Number> visited)
             throws ImageReadException, IOException
     {
-        Number key = new Integer(offset);
 
         // Debug.debug();
         // Debug.debug("dir offset", offset + " (0x" +
@@ -129,9 +128,9 @@
         // Debug.debug("dirType", dirType);
         // Debug.debug();
 
-        if (visited.contains(key))
+        if (visited.contains(offset))
             return false;
-        visited.add(key);
+        visited.add(offset);
 
         InputStream is = null;
         try
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeByte.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeByte.java
index 7d1c941..1a6b52d 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeByte.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeByte.java
@@ -30,7 +30,7 @@
     public Object getSimpleValue(TiffField entry)
     {
         if (entry.length == 1)
-            return new Byte(entry.valueOffsetBytes[0]);
+            return entry.valueOffsetBytes[0];
 
         return getRawBytes(entry);
     }
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeLong.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeLong.java
index 3e98dfe..48b8b6d 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeLong.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeLong.java
@@ -30,9 +30,9 @@
     public Object getSimpleValue(TiffField entry)
     {
         if (entry.length == 1)
-            return new Integer(convertByteArrayToInt(name + " ("
+            return convertByteArrayToInt(name + " ("
                     + entry.tagInfo.name + ")", entry.valueOffsetBytes,
-                    entry.byteOrder));
+                    entry.byteOrder);
 
         return convertByteArrayToIntArray(name + " (" + entry.tagInfo.name
                 + ")", getRawBytes(entry), 0, entry.length, entry.byteOrder);
diff --git a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeUnknown.java b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeUnknown.java
index 1c80b66..3314f9b 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeUnknown.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/tiff/fieldtypes/FieldTypeUnknown.java
@@ -37,7 +37,7 @@
         //        Debug.debug("unknown field type. entry.oversizeValue", entry.oversizeValue);
 
         if (entry.length == 1)
-            return new Byte(entry.valueOffsetBytes[0]);
+            return entry.valueOffsetBytes[0];
 
         return getRawBytes(entry);
     }
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 54bfd68..cced1ca 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
@@ -23,6 +23,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -84,9 +85,8 @@
         {
             TiffOutputDirectory directory = directories
                     .get(i);
-            int dirType = directory.type;
-            Integer key = new Integer(dirType);
-            directoryTypeMap.put(key, directory);
+            final int dirType = directory.type;
+            directoryTypeMap.put(dirType, directory);
             // Debug.debug("validating dirType", dirType + " ("
             // + directory.getFields().size() + " fields)");
 
@@ -120,11 +120,11 @@
                 }
             } else
             {
-                if (directoryIndices.contains(key))
+                if (directoryIndices.contains(dirType))
                     throw new ImageWriteException(
                             "More than one directory with index: " + dirType
                                     + ".");
-                directoryIndices.add(new Integer(dirType));
+                directoryIndices.add(dirType);
                 // dirMap.put(arg0, arg1)
             }
 
@@ -134,12 +134,11 @@
             {
                 TiffOutputField field = (TiffOutputField) fields.get(j);
 
-                Integer fieldKey = new Integer(field.tag);
-                if (fieldTags.contains(fieldKey))
+                if (fieldTags.contains(field.tag))
                     throw new ImageWriteException("Tag ("
                             + field.tagInfo.getDescription()
                             + ") appears twice in directory.");
-                fieldTags.add(fieldKey);
+                fieldTags.add(field.tag);
 
                 if (field.tag == ExifTagConstants.EXIF_TAG_EXIF_OFFSET.tag)
                 {
@@ -187,7 +186,7 @@
         }
 
         TiffOutputDirectory rootDirectory = directoryTypeMap
-                .get(new Integer(DIRECTORY_TYPE_ROOT));
+                .get(DIRECTORY_TYPE_ROOT);
 
         // prepare results
         TiffOutputSummary result = new TiffOutputSummary(byteOrder,
@@ -267,6 +266,12 @@
         if (params.containsKey(PARAM_KEY_FORMAT))
             params.remove(PARAM_KEY_FORMAT);
         
+        TiffOutputSet userExif = null;
+        if (params.containsKey(PARAM_KEY_EXIF))
+        {
+            userExif = (TiffOutputSet) params.remove(PARAM_KEY_EXIF);
+        }
+        
         String xmpXml = null;
         if (params.containsKey(PARAM_KEY_XMP_XML))
         {
@@ -464,9 +469,32 @@
         TiffImageData tiffImageData = new TiffImageData.Strips(imageData,
                 rowsPerStrip);
         directory.setTiffImageData(tiffImageData);
+        
+        if (userExif != null) {
+            combineUserExifIntoFinalExif(userExif, outputSet);
+        }
 
         write(os, outputSet);
     }
+    
+    private void combineUserExifIntoFinalExif(TiffOutputSet userExif, TiffOutputSet outputSet) throws ImageWriteException {
+        List<TiffOutputDirectory> outputDirectories = outputSet.getDirectories();
+        Collections.sort(outputDirectories, TiffOutputDirectory.COMPARATOR);
+        for (TiffOutputDirectory userDirectory : userExif.getDirectories()) {
+            int location = Collections.binarySearch(outputDirectories,
+                    userDirectory, TiffOutputDirectory.COMPARATOR);
+            if (location < 0) {
+                outputSet.addDirectory(userDirectory);
+            } else {
+                TiffOutputDirectory outputDirectory = outputDirectories.get(location);
+                for (TiffOutputField userField : userDirectory.getFields()) {
+                    if (outputDirectory.findField(userField.tagInfo) == null) {
+                        outputDirectory.add(userField);
+                    }
+                }
+            }
+        }
+    }
 
     private byte[][] getStrips(BufferedImage src, int samplesPerPixel,
             int bitsPerSample, int rowsPerStrip)
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 b9b3207..82d2012 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
@@ -61,6 +61,17 @@
     private final List<TiffOutputField> fields = new ArrayList<TiffOutputField>();
     private final int byteOrder;
     private TiffOutputDirectory nextDirectory = null;
+    public static final Comparator<TiffOutputDirectory> COMPARATOR = new Comparator<TiffOutputDirectory>() {
+        public int compare(TiffOutputDirectory o1, TiffOutputDirectory o2) {
+            if (o1.type < o2.type) {
+                return -1;
+            } else if (o1.type > o2.type) {
+                return 1;
+            } else {
+                return 0;
+            }
+        }
+    };
 
     public void setNextDirectory(TiffOutputDirectory nextDirectory)
     {
@@ -87,8 +98,8 @@
     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);
+            //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);
diff --git a/src/main/java/org/apache/commons/sanselan/formats/xpm/XpmImageParser.java b/src/main/java/org/apache/commons/sanselan/formats/xpm/XpmImageParser.java
index 38fdb71..4b0db83 100644
--- a/src/main/java/org/apache/commons/sanselan/formats/xpm/XpmImageParser.java
+++ b/src/main/java/org/apache/commons/sanselan/formats/xpm/XpmImageParser.java
@@ -86,8 +86,8 @@
                     int green = Integer.parseInt(line.substring(4, 7));
                     int blue = Integer.parseInt(line.substring(8, 11));
                     String colorName = line.substring(11).trim();
-                    colors.put(colorName, new Integer(0xff000000 |
-                            (red << 16) | (green << 8) | blue));
+                    colors.put(colorName, 0xff000000 |
+                            (red << 16) | (green << 8) | blue);
                 }
                 catch (NumberFormatException nfe)
                 {
diff --git a/src/main/java/org/apache/commons/sanselan/palette/MedianCutQuantizer.java b/src/main/java/org/apache/commons/sanselan/palette/MedianCutQuantizer.java
index 4155bf0..0d1b673 100644
--- a/src/main/java/org/apache/commons/sanselan/palette/MedianCutQuantizer.java
+++ b/src/main/java/org/apache/commons/sanselan/palette/MedianCutQuantizer.java
@@ -206,11 +206,11 @@
                 argb &= mask;
 
                 ColorCount color = color_map
-                        .get(new Integer(argb));
+                        .get(argb);
                 if (color == null)
                 {
                     color = new ColorCount(argb);
-                    color_map.put(new Integer(argb), color);
+                    color_map.put(argb, color);
                     if (color_map.keySet().size() > max)
                         return null;
                 }