summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAngus Kong <shkong@google.com>2012-12-18 22:52:34 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-12-18 22:52:35 -0800
commit74898c35335554397b0cf37a54f5786e97706186 (patch)
tree72e3036ba0a0e8366e0f857311d9b6d80453ec12
parent2df5f8e5197ef6091877a2c13217ecd823738785 (diff)
parentcf6255422bf2751d160c1384895ddae3eeea66b4 (diff)
downloadandroid_packages_apps_Snap-74898c35335554397b0cf37a54f5786e97706186.zip
android_packages_apps_Snap-74898c35335554397b0cf37a54f5786e97706186.tar.gz
android_packages_apps_Snap-74898c35335554397b0cf37a54f5786e97706186.tar.bz2
Merge "ExifModifier" into gb-ub-photos-bryce
-rw-r--r--gallerycommon/src/com/android/gallery3d/exif/ByteBufferInputStream.java48
-rw-r--r--gallerycommon/src/com/android/gallery3d/exif/ExifData.java8
-rw-r--r--gallerycommon/src/com/android/gallery3d/exif/ExifModifier.java186
-rw-r--r--gallerycommon/src/com/android/gallery3d/exif/ExifParser.java101
-rw-r--r--gallerycommon/src/com/android/gallery3d/exif/ExifTag.java6
-rw-r--r--gallerycommon/src/com/android/gallery3d/exif/IfdData.java7
-rw-r--r--tests/src/com/android/gallery3d/exif/ExifModifierTest.java172
-rw-r--r--tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java3
-rw-r--r--tests/src/com/android/gallery3d/exif/ExifTestRunner.java1
9 files changed, 483 insertions, 49 deletions
diff --git a/gallerycommon/src/com/android/gallery3d/exif/ByteBufferInputStream.java b/gallerycommon/src/com/android/gallery3d/exif/ByteBufferInputStream.java
new file mode 100644
index 0000000..7fb9f22
--- /dev/null
+++ b/gallerycommon/src/com/android/gallery3d/exif/ByteBufferInputStream.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed 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 com.android.gallery3d.exif;
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+class ByteBufferInputStream extends InputStream {
+
+ private ByteBuffer mBuf;
+
+ public ByteBufferInputStream(ByteBuffer buf) {
+ mBuf = buf;
+ }
+
+ @Override
+ public int read() {
+ if (!mBuf.hasRemaining()) {
+ return -1;
+ }
+ return mBuf.get() & 0xFF;
+ }
+
+ @Override
+ public int read(byte[] bytes, int off, int len) {
+ if (!mBuf.hasRemaining()) {
+ return -1;
+ }
+
+ len = Math.min(len, mBuf.remaining());
+ mBuf.get(bytes, off, len);
+ return len;
+ }
+}
diff --git a/gallerycommon/src/com/android/gallery3d/exif/ExifData.java b/gallerycommon/src/com/android/gallery3d/exif/ExifData.java
index 6e5c227..b226dd4 100644
--- a/gallerycommon/src/com/android/gallery3d/exif/ExifData.java
+++ b/gallerycommon/src/com/android/gallery3d/exif/ExifData.java
@@ -287,6 +287,14 @@ public class ExifData {
}
/**
+ * Adds the given ExifTag to its corresponding IFD.
+ */
+ public void addTag(ExifTag tag) {
+ IfdData ifdData = getOrCreateIfdData(tag.getIfd());
+ ifdData.setTag(tag);
+ }
+
+ /**
* Adds a thumbnail-related tag with the given tag ID. If the tag of the given ID
* already exists, the original tag will be returned. Otherwise, a new ExifTag will
* be created.
diff --git a/gallerycommon/src/com/android/gallery3d/exif/ExifModifier.java b/gallerycommon/src/com/android/gallery3d/exif/ExifModifier.java
new file mode 100644
index 0000000..da31a29
--- /dev/null
+++ b/gallerycommon/src/com/android/gallery3d/exif/ExifModifier.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed 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 com.android.gallery3d.exif;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExifModifier {
+ private final ByteBuffer mByteBuffer;
+ private final ExifData mTagToModified;
+ private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>();
+ private int mOffsetBase;
+
+ private static class TagOffset {
+ final int mOffset;
+ final ExifTag mTag;
+
+ TagOffset(ExifTag tag, int offset) {
+ mTag = tag;
+ mOffset = offset;
+ }
+
+ public ExifTag getTag() {
+ return mTag;
+ }
+ }
+
+ public ExifModifier(ByteBuffer byteBuffer) throws IOException, ExifInvalidFormatException {
+ mByteBuffer = byteBuffer;
+ mOffsetBase = byteBuffer.position();
+ InputStream is = null;
+ try {
+ is = new ByteBufferInputStream(byteBuffer);
+ // Do not require any IFD;
+ ExifParser parser = ExifParser.parse(is, 0);
+ mTagToModified = new ExifData(parser.getByteOrder());
+ mOffsetBase += parser.getTiffStartPosition();
+ mByteBuffer.position(0);
+ } finally {
+ closeSilently(is);
+ }
+ }
+
+ public ByteOrder getByteOrder() {
+ return mTagToModified.getByteOrder();
+ }
+
+ public boolean commit() throws IOException, ExifInvalidFormatException {
+ InputStream is = null;
+ try {
+ is = new ByteBufferInputStream(mByteBuffer);
+ int flag = 0;
+ IfdData[] ifdDatas = new IfdData[] {
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_0),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_1),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS)
+ };
+
+ if (ifdDatas[IfdId.TYPE_IFD_0] != null) flag |= ExifParser.OPTION_IFD_0;
+ if (ifdDatas[IfdId.TYPE_IFD_1] != null) flag |= ExifParser.OPTION_IFD_1;
+ if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) flag |= ExifParser.OPTION_IFD_EXIF;
+ if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) flag |= ExifParser.OPTION_IFD_GPS;
+ if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) {
+ flag |= ExifParser.OPTION_IFD_INTEROPERABILITY;
+ }
+
+ ExifParser parser = ExifParser.parse(is, flag);
+ int event = parser.next();
+ IfdData currIfd = null;
+ while (event != ExifParser.EVENT_END) {
+ switch (event) {
+ case ExifParser.EVENT_START_OF_IFD:
+ currIfd = ifdDatas[parser.getCurrentIfd()];
+ if (currIfd == null) parser.skipRemainingTagsInCurrentIfd();
+ break;
+ case ExifParser.EVENT_NEW_TAG:
+ ExifTag oldTag = parser.getTag();
+ ExifTag newTag = currIfd.getTag(oldTag.getTagId());
+ if (newTag != null) {
+ if (newTag.getComponentCount() != oldTag.getComponentCount()
+ || newTag.getDataType() != oldTag.getDataType()) {
+ return false;
+ } else {
+ mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset()));
+ currIfd.removeTag(oldTag.getTagId());
+ if (currIfd.getTagCount() == 0) {
+ parser.skipRemainingTagsInCurrentIfd();
+ }
+ }
+ }
+ break;
+ }
+ event = parser.next();
+ }
+ for (IfdData ifd: ifdDatas) {
+ if (ifd != null && ifd.getTagCount() > 0) return false;
+ }
+ modify();
+ } finally {
+ closeSilently(is);
+ }
+ return true;
+ }
+
+ private void modify() {
+ mByteBuffer.order(getByteOrder());
+ for (TagOffset tagOffset: mTagOffsets) {
+ writeTagValue(tagOffset.mTag, tagOffset.mOffset);
+ }
+ }
+
+ private void writeTagValue(ExifTag tag, int offset) {
+ mByteBuffer.position(offset + mOffsetBase);
+ switch (tag.getDataType()) {
+ case ExifTag.TYPE_ASCII:
+ byte buf[] = tag.getStringByte();
+ if (buf.length == tag.getComponentCount()) {
+ buf[buf.length - 1] = 0;
+ mByteBuffer.put(buf);
+ } else {
+ mByteBuffer.put(buf);
+ mByteBuffer.put((byte) 0);
+ }
+ break;
+ case ExifTag.TYPE_LONG:
+ case ExifTag.TYPE_UNSIGNED_LONG:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ mByteBuffer.putInt((int) tag.getValueAt(i));
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL:
+ case ExifTag.TYPE_UNSIGNED_RATIONAL:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ Rational v = tag.getRational(i);
+ mByteBuffer.putInt((int) v.getNominator());
+ mByteBuffer.putInt((int) v.getDenominator());
+ }
+ break;
+ case ExifTag.TYPE_UNDEFINED:
+ case ExifTag.TYPE_UNSIGNED_BYTE:
+ buf = new byte[tag.getComponentCount()];
+ tag.getBytes(buf);
+ mByteBuffer.put(buf);
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ mByteBuffer.putShort((short) tag.getValueAt(i));
+ }
+ break;
+ }
+ }
+
+ public void modifyTag(ExifTag tag) {
+ mTagToModified.addTag(tag);
+ }
+
+ private static void closeSilently(Closeable c) {
+ if (c == null) return;
+ try {
+ c.close();
+ } catch (Throwable t) {
+ // do nothing
+ }
+ }
+}
diff --git a/gallerycommon/src/com/android/gallery3d/exif/ExifParser.java b/gallerycommon/src/com/android/gallery3d/exif/ExifParser.java
index 2cff12a..a1ce13e 100644
--- a/gallerycommon/src/com/android/gallery3d/exif/ExifParser.java
+++ b/gallerycommon/src/com/android/gallery3d/exif/ExifParser.java
@@ -18,7 +18,6 @@ package com.android.gallery3d.exif;
import android.util.Log;
-import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;
@@ -154,6 +153,7 @@ public class ExifParser {
private int mApp1End;
private byte[] mDataAboveIfd0;
private int mIfd0Position;
+ private int mTiffStartPosition;
private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
@@ -190,10 +190,13 @@ public class ExifParser {
throw new ExifInvalidFormatException("Invalid offset " + offset);
}
mIfd0Position = (int) offset;
- registerIfd(IfdId.TYPE_IFD_0, offset);
- if (offset != DEFAULT_IFD0_OFFSET) {
- mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
- read(mDataAboveIfd0);
+ mIfdType = IfdId.TYPE_IFD_0;
+ if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
+ registerIfd(IfdId.TYPE_IFD_0, offset);
+ if (offset != DEFAULT_IFD0_OFFSET) {
+ mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
+ read(mDataAboveIfd0);
+ }
}
}
@@ -203,8 +206,8 @@ public class ExifParser {
* @exception ExifInvalidFormatException
*/
public static ExifParser parse(InputStream inputStream, int options)
- throws IOException, ExifInvalidFormatException {
- return new ExifParser(inputStream, options);
+ throws IOException, ExifInvalidFormatException {
+ return new ExifParser(inputStream, options);
}
/**
@@ -353,7 +356,8 @@ public class ExifParser {
switch (mIfdType) {
case IfdId.TYPE_IFD_0:
return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
- || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
+ || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
+ || isIfdRequested(IfdId.TYPE_IFD_1);
case IfdId.TYPE_IFD_1:
return isThumbnailRequested();
case IfdId.TYPE_IFD_EXIF:
@@ -515,6 +519,8 @@ public class ExifParser {
} else {
readFullTagValue(tag);
mTiffStream.skip(4 - dataSize);
+ // Set the offset to the position of value.
+ tag.setOffset(mTiffStream.getReadByteCount() - 4);
}
return tag;
}
@@ -617,42 +623,42 @@ public class ExifParser {
tag.setValue(value);
}
break;
- case ExifTag.TYPE_UNSIGNED_RATIONAL:
- {
- Rational value[] = new Rational[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readUnsignedRational();
- }
- tag.setValue(value);
- }
- break;
- case ExifTag.TYPE_UNSIGNED_SHORT:
- {
- int value[] = new int[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readUnsignedShort();
- }
- tag.setValue(value);
- }
- break;
- case ExifTag.TYPE_LONG:
- {
- int value[] = new int[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readLong();
- }
- tag.setValue(value);
- }
- break;
- case ExifTag.TYPE_RATIONAL:
- {
- Rational value[] = new Rational[tag.getComponentCount()];
- for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readRational();
- }
- tag.setValue(value);
- }
- break;
+ case ExifTag.TYPE_UNSIGNED_RATIONAL:
+ {
+ Rational value[] = new Rational[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readUnsignedRational();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT:
+ {
+ int value[] = new int[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readUnsignedShort();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_LONG:
+ {
+ int value[] = new int[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readLong();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL:
+ {
+ Rational value[] = new Rational[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readRational();
+ }
+ tag.setValue(value);
+ }
+ break;
}
}
@@ -675,7 +681,7 @@ public class ExifParser {
private boolean seekTiffData(InputStream inputStream) throws IOException,
ExifInvalidFormatException {
- DataInputStream dataStream = new DataInputStream(inputStream);
+ CountedDataInputStream dataStream = new CountedDataInputStream(inputStream);
if (dataStream.readShort() != JpegHeader.SOI) {
throw new ExifInvalidFormatException("Invalid JPEG format");
@@ -695,6 +701,7 @@ public class ExifParser {
headerTail = dataStream.readShort();
length -= 6;
if (header == EXIF_HEADER && headerTail == EXIF_HEADER_TAIL) {
+ mTiffStartPosition = dataStream.getReadByteCount();
mApp1End = length;
return true;
}
@@ -709,6 +716,10 @@ public class ExifParser {
return false;
}
+ int getTiffStartPosition() {
+ return mTiffStartPosition;
+ }
+
/**
* Reads bytes from the InputStream.
*/
diff --git a/gallerycommon/src/com/android/gallery3d/exif/ExifTag.java b/gallerycommon/src/com/android/gallery3d/exif/ExifTag.java
index cda67c2..753b18c 100644
--- a/gallerycommon/src/com/android/gallery3d/exif/ExifTag.java
+++ b/gallerycommon/src/com/android/gallery3d/exif/ExifTag.java
@@ -915,9 +915,9 @@ public class ExifTag {
static boolean isValidType(short type) {
return type == TYPE_UNSIGNED_BYTE || type == TYPE_ASCII ||
- type == TYPE_UNSIGNED_SHORT || type == TYPE_UNSIGNED_LONG ||
- type == TYPE_UNSIGNED_RATIONAL || type == TYPE_UNDEFINED ||
- type == TYPE_LONG || type == TYPE_RATIONAL;
+ type == TYPE_UNSIGNED_SHORT || type == TYPE_UNSIGNED_LONG ||
+ type == TYPE_UNSIGNED_RATIONAL || type == TYPE_UNDEFINED ||
+ type == TYPE_LONG || type == TYPE_RATIONAL;
}
ExifTag(short tagId, short type, int componentCount, int ifd) {
diff --git a/gallerycommon/src/com/android/gallery3d/exif/IfdData.java b/gallerycommon/src/com/android/gallery3d/exif/IfdData.java
index 78f9173..6336049 100644
--- a/gallerycommon/src/com/android/gallery3d/exif/IfdData.java
+++ b/gallerycommon/src/com/android/gallery3d/exif/IfdData.java
@@ -79,6 +79,13 @@ class IfdData {
}
/**
+ * Removes the tag of the given ID
+ */
+ public void removeTag(short tagId) {
+ mExifTags.remove(tagId);
+ }
+
+ /**
* Gets the tags count in the IFD.
*/
public int getTagCount() {
diff --git a/tests/src/com/android/gallery3d/exif/ExifModifierTest.java b/tests/src/com/android/gallery3d/exif/ExifModifierTest.java
new file mode 100644
index 0000000..14e956f
--- /dev/null
+++ b/tests/src/com/android/gallery3d/exif/ExifModifierTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed 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 com.android.gallery3d.exif;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel.MapMode;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExifModifierTest extends ExifXmlDataTestCase {
+
+ private File mTmpFile;
+ private List<Map<Short, List<String>>> mGroundTruth;
+
+ // TYPE_UNDEFINED with 4 components
+ private static final ExifTag sVersionTag = ExifTag.buildTag(ExifTag.TAG_EXIF_VERSION);
+ // TYPE_UNSIGNED_BYTE with 4 components
+ private static final ExifTag sGpsVersionTag = ExifTag.buildTag(ExifTag.TAG_GPS_VERSION_ID);
+ // TYPE ASCII with arbitary length
+ private static final ExifTag sModelTag = ExifTag.buildTag(ExifTag.TAG_MODEL);
+ // TYPE_ASCII with 20 components
+ private static final ExifTag sDateTimeTag = ExifTag.buildTag(ExifTag.TAG_DATE_TIME);
+ // TYPE_UNSIGNED_SHORT with 1 components
+ private static final ExifTag sCompressionTag = ExifTag.buildTag(ExifTag.TAG_COMPRESSION);
+ // TYPE_UNSIGNED_LONG with 1 components
+ private static final ExifTag sThumbnailFormatTag =
+ ExifTag.buildTag(ExifTag.TAG_JPEG_INTERCHANGE_FORMAT);
+ // TYPE_UNSIGNED_RATIONAL with 3 components
+ private static final ExifTag sLongitudeTag = ExifTag.buildTag(ExifTag.TAG_GPS_LONGITUDE);
+ // TYPE_RATIONAL with 1 components
+ private static final ExifTag sShutterTag = ExifTag.buildTag(ExifTag.TAG_SHUTTER_SPEED_VALUE);
+
+ private static final Map<Short, ExifTag> sTestTags = new HashMap<Short, ExifTag>();
+
+ static {
+ sVersionTag.setValue(new byte[] {1, 2, 3, 4});
+ sGpsVersionTag.setValue(new byte[] {4, 3, 2, 1});
+ sModelTag.setValue("end-of-the-world");
+ sDateTimeTag.setValue("2012:12:31 23:59:59");
+ sCompressionTag.setValue(100);
+ sThumbnailFormatTag.setValue(100);
+ sLongitudeTag.setValue(new Rational[] {new Rational(1, 1), new Rational(10, 10),
+ new Rational(100, 100)});
+ sShutterTag.setValue(new Rational(1, 1));
+
+ sTestTags.put(sVersionTag.getTagId(), sVersionTag);
+ sTestTags.put(sGpsVersionTag.getTagId(), sGpsVersionTag);
+ sTestTags.put(sModelTag.getTagId(), sModelTag);
+ sTestTags.put(sDateTimeTag.getTagId(), sDateTimeTag);
+ sTestTags.put(sCompressionTag.getTagId(), sCompressionTag);
+ sTestTags.put(sThumbnailFormatTag.getTagId(), sThumbnailFormatTag);
+ sTestTags.put(sLongitudeTag.getTagId(), sLongitudeTag);
+ sTestTags.put(sShutterTag.getTagId(), sShutterTag);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mGroundTruth = ExifXmlReader.readXml(getXmlParser());
+ mTmpFile = File.createTempFile("exif_test", ".jpg");
+ FileOutputStream os = null;
+ InputStream is = getImageInputStream();
+ try {
+ os = new FileOutputStream(mTmpFile);
+ byte[] buf = new byte[1024];
+ int n;
+ while ((n = is.read(buf)) > 0) {
+ os.write(buf, 0, n);
+ }
+ } finally {
+ Util.closeSilently(os);
+ }
+ }
+
+ public ExifModifierTest(int imageRes, int xmlRes) {
+ super(imageRes, xmlRes);
+ }
+
+ public ExifModifierTest(String imagePath, String xmlPath) {
+ super(imagePath, xmlPath);
+ }
+
+ public void testModify() throws Exception {
+ Map<Short, Boolean> results = new HashMap<Short, Boolean>();
+
+ RandomAccessFile file = null;
+ try {
+ file = new RandomAccessFile(mTmpFile, "rw");
+ MappedByteBuffer buf = file.getChannel().map(MapMode.READ_WRITE, 0, file.length());
+ for (ExifTag tag: sTestTags.values()) {
+ ExifModifier modifier = new ExifModifier(buf);
+ modifier.modifyTag(tag);
+ boolean result = modifier.commit();
+ results.put(tag.getTagId(), result);
+ buf.force();
+ buf.position(0);
+
+ if (!result) {
+ List<String> value = mGroundTruth.get(tag.getIfd()).get(tag.getTagId());
+ assertTrue (String.format("Tag %x, ", tag.getTagId()) + getImageTitle(),
+ value == null || tag.getTagId() == ExifTag.TAG_MODEL);
+ }
+ }
+ } finally {
+ Util.closeSilently(file);
+ }
+
+ // Parse the new file and check the result
+ InputStream is = null;
+ try {
+ is = new FileInputStream(mTmpFile);
+ ExifData data = new ExifReader().read(is);
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ checkIfd(data.getIfdData(i), mGroundTruth.get(i), results);
+ }
+ } finally {
+ Util.closeSilently(is);
+ }
+
+ }
+
+
+ private void checkIfd(IfdData ifd, Map<Short, List<String>> ifdValue,
+ Map<Short, Boolean> results) {
+ if (ifd == null) {
+ assertEquals(getImageTitle(), 0 ,ifdValue.size());
+ return;
+ }
+ ExifTag[] tags = ifd.getAllTags();
+ for (ExifTag tag : tags) {
+ List<String> truth = ifdValue.get(tag.getTagId());
+ assertNotNull(String.format("Tag %x, ", tag.getTagId()) + getImageTitle(), truth);
+ if (truth.contains(null)) continue;
+
+ ExifTag newTag = sTestTags.get(tag.getTagId());
+ if (newTag != null
+ && results.get(tag.getTagId())) {
+ assertEquals(String.format("Tag %x, ", tag.getTagId()) + getImageTitle(),
+ Util.tagValueToString(newTag), Util.tagValueToString(tag));
+ } else {
+ assertTrue(String.format("Tag %x, ", tag.getTagId()) + getImageTitle(),
+ truth.contains(Util.tagValueToString(tag).trim()));
+ }
+ }
+ assertEquals(getImageTitle(), ifdValue.size(), tags.length);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ mTmpFile.delete();
+ }
+}
diff --git a/tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java b/tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java
index 8c98fa0..789fd35 100644
--- a/tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java
+++ b/tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java
@@ -103,7 +103,8 @@ public class ExifOutputStreamTest extends ExifXmlDataTestCase {
}
@Override
- public void tearDown() {
+ public void tearDown() throws Exception {
+ super.tearDown();
mTmpFile.delete();
}
}
diff --git a/tests/src/com/android/gallery3d/exif/ExifTestRunner.java b/tests/src/com/android/gallery3d/exif/ExifTestRunner.java
index 519e871..b094263 100644
--- a/tests/src/com/android/gallery3d/exif/ExifTestRunner.java
+++ b/tests/src/com/android/gallery3d/exif/ExifTestRunner.java
@@ -56,6 +56,7 @@ public class ExifTestRunner extends InstrumentationTestRunner {
addAllTestsFromExifTestCase(ExifParserTest.class, suite);
addAllTestsFromExifTestCase(ExifReaderTest.class, suite);
addAllTestsFromExifTestCase(ExifOutputStreamTest.class, suite);
+ addAllTestsFromExifTestCase(ExifModifierTest.class, suite);
return suite;
}