You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by da...@apache.org on 2013/01/31 06:28:15 UTC

svn commit: r1440856 - in /commons/proper/imaging/trunk/src: main/java/org/apache/commons/imaging/formats/tiff/write/ test/java/org/apache/commons/imaging/formats/jpeg/exif/

Author: damjan
Date: Thu Jan 31 05:28:14 2013
New Revision: 1440856

URL: http://svn.apache.org/viewvc?rev=1440856&view=rev
Log:
Improved EXIF lossless rewriting by allowing some TIFF fields to be frozen
in place (ie. they don't change address in the new file). This saves
a lot of space when rewriting maker notes, since we previously duplicated
them within the already small 64k EXIT size limit.


Modified:
    commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java
    commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffOutputField.java
    commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/ExifRewriteTest.java

Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java?rev=1440856&r1=1440855&r2=1440856&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java Thu Jan 31 05:28:14 2013
@@ -21,6 +21,7 @@ import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -40,7 +41,6 @@ import org.apache.commons.imaging.format
 import org.apache.commons.imaging.formats.tiff.TiffField;
 import org.apache.commons.imaging.formats.tiff.TiffImageData;
 import org.apache.commons.imaging.formats.tiff.TiffReader;
-import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
 import org.apache.commons.imaging.util.Debug;
 
 public class TiffImageWriterLossless extends TiffImageWriterBase {
@@ -87,8 +87,8 @@ public class TiffImageWriterLossless ext
         }
         Debug.debug();
     }
-
-    private List<TiffElement> analyzeOldTiff() throws ImageWriteException,
+    
+    private List<TiffElement> analyzeOldTiff(Map<Integer,TiffOutputField> frozenFields) throws ImageWriteException,
             IOException {
         try {
             final ByteSource byteSource = new ByteSourceArray(exifBytes);
@@ -108,22 +108,16 @@ public class TiffImageWriterLossless ext
                 final List<TiffField> fields = directory.getDirectoryEntrys();
                 for (int f = 0; f < fields.size(); f++) {
                     final TiffField field = fields.get(f);
-                    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
-                        // of the TIFF file, making it impossible
-                        // to move the note to a different location.
-                        // To avoid corrupting these maker notes,
-                        // pretend all maker notes are a gap in the file
-                        // that must be preserved, so the copy that
-                        // will be written later will reference
-                        // the old copy's values. Happy days.
-                        continue;
-                    }
                     final TiffElement oversizeValue = field.getOversizeValueElement();
                     if (oversizeValue != null) {
-                        elements.add(oversizeValue);
+                        final TiffOutputField frozenField = frozenFields.get(field.tag);
+                        if (frozenField != null &&
+                                frozenField.getSeperateValue() != null &&
+                                frozenField.bytesEqual(field.getByteArrayValue())) {
+                            frozenField.getSeperateValue().setOffset(field.valueOffset);
+                        } else {
+                            elements.add(oversizeValue);
+                        }
                     }
                 }
 
@@ -146,7 +140,7 @@ public class TiffImageWriterLossless ext
 
             // dumpElements(byteSource, elements);
 
-            final List<TiffElement> result = new ArrayList<TiffElement>();
+            final List<TiffElement> rewritableElements = new ArrayList<TiffElement>();
             {
                 final int TOLERANCE = 3;
                 // int last = TIFF_HEADER_SIZE;
@@ -159,7 +153,7 @@ public class TiffImageWriterLossless ext
                         start = element;
                         index = lastElementByte;
                     } else if (element.offset - index > TOLERANCE) {
-                        result.add(new TiffElement.Stub(start.offset, index
+                        rewritableElements.add(new TiffElement.Stub(start.offset, index
                                 - start.offset));
                         start = element;
                         index = lastElementByte;
@@ -168,14 +162,14 @@ public class TiffImageWriterLossless ext
                     }
                 }
                 if (null != start) {
-                    result.add(new TiffElement.Stub(start.offset, index
+                    rewritableElements.add(new TiffElement.Stub(start.offset, index
                             - start.offset));
                 }
             }
 
             // dumpElements(byteSource, result);
 
-            return result;
+            return rewritableElements;
         } catch (final ImageReadException e) {
             throw new ImageWriteException(e.getMessage(), e);
         }
@@ -184,13 +178,19 @@ public class TiffImageWriterLossless ext
     @Override
     public void write(final OutputStream os, final TiffOutputSet outputSet)
             throws IOException, ImageWriteException {
-        final List<TiffElement> analysis = analyzeOldTiff();
+        // There are some fields whose address in the file must not change,
+        // unless of course their value is changed. 
+        final Map<Integer,TiffOutputField> frozenFields = new HashMap<Integer,TiffOutputField>();
+        final TiffOutputField makerNoteField = outputSet.findField(EXIF_TAG_MAKER_NOTE);
+        if (makerNoteField != null && makerNoteField.getSeperateValue() != null) {
+            frozenFields.put(EXIF_TAG_MAKER_NOTE.tag, makerNoteField);
+        }
+        List<TiffElement> analysis = analyzeOldTiff(frozenFields);
         final int oldLength = exifBytes.length;
         if (analysis.size() < 1) {
             throw new ImageWriteException("Couldn't analyze old tiff data.");
         } else if (analysis.size() == 1) {
             final TiffElement onlyElement = analysis.get(0);
-            // Debug.debug("onlyElement", onlyElement.getElementDescription());
             if (onlyElement.offset == TIFF_HEADER_SIZE
                     && onlyElement.offset + onlyElement.length
                             + TIFF_HEADER_SIZE == oldLength) {
@@ -199,19 +199,26 @@ public class TiffImageWriterLossless ext
                 return;
             }
         }
-
-        // if (true)
-        // throw new ImageWriteException("hahah");
-
-        // List directories = outputSet.getDirectories();
+        final Map<Integer,TiffOutputField> frozenFieldOffsets = new HashMap<Integer, TiffOutputField>();
+        for (Map.Entry<Integer,TiffOutputField> entry : frozenFields.entrySet()) {
+            final TiffOutputField frozenField = entry.getValue();
+            if (frozenField.getSeperateValue().getOffset() != TiffOutputItem.UNDEFINED_VALUE) {
+                frozenFieldOffsets.put(frozenField.getSeperateValue().getOffset(), frozenField);
+            }
+        }
 
         final TiffOutputSummary outputSummary = validateDirectories(outputSet);
 
-        final List<TiffOutputItem> outputItems = outputSet
+        final List<TiffOutputItem> allOutputItems = outputSet
                 .getOutputItems(outputSummary);
+        final List<TiffOutputItem> outputItems = new ArrayList<TiffOutputItem>();
+        for (TiffOutputItem outputItem : allOutputItems) {
+            if (!frozenFieldOffsets.containsKey(outputItem.getOffset())) {
+                outputItems.add(outputItem);
+            }
+        }
 
         final int outputLength = updateOffsetsStep(analysis, outputItems);
-        // Debug.debug("outputLength", outputLength);
 
         outputSummary.updateOffsets(byteOrder);
 
@@ -259,9 +266,6 @@ public class TiffImageWriterLossless ext
         Collections.sort(unusedElements, ELEMENT_SIZE_COMPARATOR);
         Collections.reverse(unusedElements);
 
-        // Debug.debug("unusedElements");
-        // dumpElements(unusedElements);
-
         // make copy.
         final List<TiffOutputItem> unplacedItems = new ArrayList<TiffOutputItem>(
                 outputItems);
@@ -272,10 +276,6 @@ public class TiffImageWriterLossless ext
             // pop off largest unplaced item.
             final TiffOutputItem outputItem = unplacedItems.remove(0);
             final int outputItemLength = outputItem.getItemLength();
-            // Debug.debug("largest unplaced item: "
-            // + outputItem.getItemDescription() + " (" + outputItemLength
-            // + ")");
-
             // search for the smallest possible element large enough to hold the
             // item.
             TiffElement bestFit = null;
@@ -309,24 +309,6 @@ public class TiffImageWriterLossless ext
         }
 
         return overflowIndex;
-        //
-        // if (true)
-        // throw new IOException("mew");
-        //
-        // // int offset = TIFF_HEADER_SIZE;
-        // int offset = exifBytes.length;
-        //
-        // for (int i = 0; i < outputItems.size(); i++)
-        // {
-        // TiffOutputItem outputItem = (TiffOutputItem) outputItems.get(i);
-        //
-        // outputItem.setOffset(offset);
-        // int itemLength = outputItem.getItemLength();
-        // offset += itemLength;
-        //
-        // int remainder = imageDataPaddingLength(itemLength);
-        // offset += remainder;
-        // }
     }
 
     private static class BufferOutputStream extends OutputStream {

Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffOutputField.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffOutputField.java?rev=1440856&r1=1440855&r2=1440856&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffOutputField.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffOutputField.java Thu Jan 31 05:28:14 2013
@@ -17,6 +17,7 @@
 package org.apache.commons.imaging.formats.tiff.write;
 
 import java.io.IOException;
+import java.util.Arrays;
 
 import org.apache.commons.imaging.ImageWriteException;
 import org.apache.commons.imaging.common.BinaryOutputStream;
@@ -101,6 +102,10 @@ public class TiffOutputField implements 
     protected boolean isLocalValue() {
         return bytes.length <= TIFF_ENTRY_MAX_VALUE_LENGTH;
     }
+    
+    public boolean bytesEqual(final byte[] data) {
+        return Arrays.equals(bytes, data);
+    }
 
     protected void setData(final byte bytes[]) throws ImageWriteException {
         // if(tagInfo.isUnknown())

Modified: commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/ExifRewriteTest.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/ExifRewriteTest.java?rev=1440856&r1=1440855&r2=1440856&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/ExifRewriteTest.java (original)
+++ commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/ExifRewriteTest.java Thu Jan 31 05:28:14 2013
@@ -247,13 +247,6 @@ public class ExifRewriteTest extends Exi
             } catch (final ImageWriteException e) {
                 Debug.debug("imageFile", imageFile.getAbsoluteFile());
                 Debug.debug(e);
-                // FIXME: this image has 28kB of Maker Notes, causing the APP1
-                // segment
-                // to go beyond 64kB, so ignore the exception this throws.
-                if (!imageFile.getName().equalsIgnoreCase(
-                        "Nikon D50 - 2007.12.19.n.DSC_3656.JPG")) {
-                    throw e;
-                }
             }
 
         }