Use exiftool as ground truth for Exif API test
The ground truth XML file was generated by parsing the
output from Phil Harvey's exiftool. Then we can test photos
from 5000+ different camera provided by exiftool's website.
Change-Id: Ida2c0409929be450a3cbb4331504aadb41138bea
diff --git a/src/com/android/gallery3d/exif/ExifTag.java b/src/com/android/gallery3d/exif/ExifTag.java
index 49cb6ed..86ac7be 100644
--- a/src/com/android/gallery3d/exif/ExifTag.java
+++ b/src/com/android/gallery3d/exif/ExifTag.java
@@ -1361,9 +1361,10 @@
StringBuilder sbuilder = new StringBuilder();
switch (getDataType()) {
case ExifTag.TYPE_UNDEFINED:
+ sbuilder.append(new String((byte[]) mValue));
+ break;
case ExifTag.TYPE_UNSIGNED_BYTE:
- byte buf[] = new byte[getComponentCount()];
- getBytes(buf);
+ byte buf[] = (byte[]) mValue;
for(int i = 0, n = getComponentCount(); i < n; i++) {
if(i != 0) sbuilder.append(" ");
sbuilder.append(String.format("%02x", buf[i]));
@@ -1415,6 +1416,15 @@
|| tagId == TAG_INTEROPERABILITY_IFD;
}
+ /**
+ * Returns true if the ID is one of the following: {@link #TAG_EXIF_IFD},
+ * {@link #TAG_GPS_IFD}, {@link #TAG_INTEROPERABILITY_IFD}
+ */
+ static boolean isSubIfdOffsetTag(short tagId) {
+ return tagId == TAG_EXIF_IFD
+ || tagId == TAG_GPS_IFD
+ || tagId == TAG_INTEROPERABILITY_IFD;
+ }
@Override
public boolean equals(Object obj) {
if (obj instanceof ExifTag) {
diff --git a/tests/src/com/android/gallery3d/exif/ExifParserTest.java b/tests/src/com/android/gallery3d/exif/ExifParserTest.java
index c1ad834..8d4bc3d 100644
--- a/tests/src/com/android/gallery3d/exif/ExifParserTest.java
+++ b/tests/src/com/android/gallery3d/exif/ExifParserTest.java
@@ -16,21 +16,18 @@
package com.android.gallery3d.exif;
-import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.IOException;
import java.io.InputStream;
-import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
public class ExifParserTest extends ExifXmlDataTestCase {
private static final String TAG = "ExifParserTest";
- private HashMap<Short, String> mIfd0Value = new HashMap<Short, String>();
- private HashMap<Short, String> mIfd1Value = new HashMap<Short, String>();
- private HashMap<Short, String> mExifIfdValue = new HashMap<Short, String>();
- private HashMap<Short, String> mInteroperabilityIfdValue = new HashMap<Short, String>();
+ private List<Map<Short, String>> mGroundTruth;
private InputStream mImageInputStream;
@@ -43,12 +40,7 @@
mImageInputStream = getInstrumentation()
.getContext().getResources().openRawResource(mImageResourceId);
- XmlResourceParser parser =
- getInstrumentation().getContext().getResources().getXml(mXmlResourceId);
-
- ExifXmlReader.readXml(parser, mIfd0Value, mIfd1Value, mExifIfdValue
- , mInteroperabilityIfdValue);
- parser.close();
+ mGroundTruth = ExifXmlReader.readXml(getInstrumentation().getContext(), mXmlResourceId);
}
public void testParse() throws IOException, ExifInvalidFormatException {
@@ -80,33 +72,25 @@
}
}
- private void checkTag(ExifTag tag) {
- HashMap<Short, String> truth = null;
- switch (tag.getIfd()) {
- case IfdId.TYPE_IFD_0:
- truth = mIfd0Value;
- break;
- case IfdId.TYPE_IFD_1:
- truth = mIfd1Value;
- break;
- case IfdId.TYPE_IFD_EXIF:
- truth = mExifIfdValue;
- break;
- case IfdId.TYPE_IFD_INTEROPERABILITY:
- truth = mInteroperabilityIfdValue;
- break;
- }
- String truthString = truth.get(tag.getTagId());
- String dataString = tag.valueToString().trim();
+ private void checkTag(ExifTag tag) {
+ // Ignore offset tags since the ground-truth from exiftool doesn't have it.
+ // We can verify it by examining the sub-IFD or thumbnail itself.
+ if (ExifTag.isSubIfdOffsetTag(tag.getTagId())) return;
+
+ String truthString = mGroundTruth.get(tag.getIfd()).get(tag.getTagId());
+
if (truthString == null) {
fail(String.format("Unknown Tag %02x", tag.getTagId()));
}
+
+ String dataString = tag.valueToString().trim();
assertEquals(String.format("Tag %02x", tag.getTagId()), truthString, dataString);
}
- private void parseOneIfd(int ifd, int options, HashMap<Short, String> expectedResult)
+ private void parseOneIfd(int ifd, int options)
throws IOException, ExifInvalidFormatException {
+ Map<Short, String> expectedResult = mGroundTruth.get(ifd);
int numOfTag = 0;
ExifParser parser = ExifParser.parse(mImageInputStream, options);
int event = parser.next();
@@ -116,8 +100,8 @@
assertEquals(ifd, parser.getCurrentIfd());
break;
case ExifParser.EVENT_NEW_TAG:
- numOfTag++;
ExifTag tag = parser.getTag();
+ if (!ExifTag.isSubIfdOffsetTag(tag.getTagId())) numOfTag++;
if (tag.hasValue()) {
checkTag(tag);
} else {
@@ -144,20 +128,19 @@
}
public void testOnlyExifIfd() throws IOException, ExifInvalidFormatException {
- parseOneIfd(IfdId.TYPE_IFD_EXIF, ExifParser.OPTION_IFD_EXIF, mExifIfdValue);
+ parseOneIfd(IfdId.TYPE_IFD_EXIF, ExifParser.OPTION_IFD_EXIF);
}
public void testOnlyIfd0() throws IOException, ExifInvalidFormatException {
- parseOneIfd(IfdId.TYPE_IFD_0, ExifParser.OPTION_IFD_0, mIfd0Value);
+ parseOneIfd(IfdId.TYPE_IFD_0, ExifParser.OPTION_IFD_0);
}
public void testOnlyIfd1() throws IOException, ExifInvalidFormatException {
- parseOneIfd(IfdId.TYPE_IFD_1, ExifParser.OPTION_IFD_1, mIfd1Value);
+ parseOneIfd(IfdId.TYPE_IFD_1, ExifParser.OPTION_IFD_1);
}
public void testOnlyInteroperabilityIfd() throws IOException, ExifInvalidFormatException {
- parseOneIfd(IfdId.TYPE_IFD_INTEROPERABILITY, ExifParser.OPTION_IFD_INTEROPERABILITY
- , mInteroperabilityIfdValue);
+ parseOneIfd(IfdId.TYPE_IFD_INTEROPERABILITY, ExifParser.OPTION_IFD_INTEROPERABILITY);
}
public void testOnlyReadSomeTag() throws IOException, ExifInvalidFormatException {
@@ -227,8 +210,6 @@
@Override
protected void tearDown() throws IOException {
mImageInputStream.close();
- mIfd0Value.clear();
- mIfd1Value.clear();
- mExifIfdValue.clear();
+ mGroundTruth.clear();
}
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/gallery3d/exif/ExifReaderTest.java b/tests/src/com/android/gallery3d/exif/ExifReaderTest.java
index 2691208..1300af0 100644
--- a/tests/src/com/android/gallery3d/exif/ExifReaderTest.java
+++ b/tests/src/com/android/gallery3d/exif/ExifReaderTest.java
@@ -21,15 +21,13 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
public class ExifReaderTest extends ExifXmlDataTestCase {
private static final String TAG = "ExifReaderTest";
- private final HashMap<Short, String> mIfd0Value = new HashMap<Short, String>();
- private final HashMap<Short, String> mIfd1Value = new HashMap<Short, String>();
- private final HashMap<Short, String> mExifIfdValue = new HashMap<Short, String>();
- private final HashMap<Short, String> mInteroperabilityIfdValue = new HashMap<Short, String>();
+ private List<Map<Short, String>> mGroundTruth;
private InputStream mImageInputStream;
@@ -45,19 +43,16 @@
XmlResourceParser parser =
getInstrumentation().getContext().getResources().getXml(mXmlResourceId);
- ExifXmlReader.readXml(parser, mIfd0Value, mIfd1Value, mExifIfdValue
- , mInteroperabilityIfdValue);
+ mGroundTruth = ExifXmlReader.readXml(getInstrumentation().getContext(), mXmlResourceId);
parser.close();
}
public void testRead() throws ExifInvalidFormatException, IOException {
ExifReader reader = new ExifReader();
ExifData exifData = reader.read(mImageInputStream);
- checkIfd(exifData.getIfdData(IfdId.TYPE_IFD_0), mIfd0Value);
- checkIfd(exifData.getIfdData(IfdId.TYPE_IFD_1), mIfd1Value);
- checkIfd(exifData.getIfdData(IfdId.TYPE_IFD_EXIF), mExifIfdValue);
- checkIfd(exifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY),
- mInteroperabilityIfdValue);
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ checkIfd(exifData.getIfdData(i), mGroundTruth.get(i));
+ }
checkThumbnail(exifData);
}
@@ -115,16 +110,19 @@
}
}
- private void checkIfd(IfdData ifd, HashMap<Short, String> ifdValue) {
+ private void checkIfd(IfdData ifd, Map<Short, String> ifdValue) {
if (ifd == null) {
assertEquals(0 ,ifdValue.size());
return;
}
ExifTag[] tags = ifd.getAllTags();
+ int size = 0;
for (ExifTag tag : tags) {
+ if (ExifTag.isSubIfdOffsetTag(tag.getTagId())) continue;
assertEquals(ifdValue.get(tag.getTagId()), tag.valueToString().trim());
+ size++;
}
- assertEquals(ifdValue.size(), tags.length);
+ assertEquals(ifdValue.size(), size);
}
@Override
diff --git a/tests/src/com/android/gallery3d/exif/ExifXmlReader.java b/tests/src/com/android/gallery3d/exif/ExifXmlReader.java
index 72dd313..8e2ad3f 100644
--- a/tests/src/com/android/gallery3d/exif/ExifXmlReader.java
+++ b/tests/src/com/android/gallery3d/exif/ExifXmlReader.java
@@ -16,82 +16,91 @@
package com.android.gallery3d.exif;
+import android.content.Context;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
public class ExifXmlReader {
+ private static final String TAG_EXIF = "exif";
+ private static final String TAG_TAG = "tag";
- private static final String XML_EXIF_TAG = "exif";
- private static final String XML_IFD_TAG = "ifd";
- private static final String XML_IFD_NAME = "name";
- private static final String XML_TAG = "tag";
- private static final String XML_IFD0 = "ifd0";
- private static final String XML_IFD1 = "ifd1";
- private static final String XML_EXIF_IFD = "exif-ifd";
- private static final String XML_INTEROPERABILITY_IFD = "interoperability-ifd";
- private static final String XML_TAG_ID = "id";
+ private static final String IFD0 = "IFD0";
+ private static final String EXIF_IFD = "ExifIFD";
+ private static final String GPS_IFD = "GPS";
+ private static final String IFD1 = "IFD1";
+ private static final String PREFIX_INTEROP_IFD = "InteropIFD";
- public static void readXml(XmlPullParser parser, HashMap<Short, String> ifd0,
- HashMap<Short, String> ifd1, HashMap<Short, String> exifIfd,
- HashMap<Short, String> interoperabilityIfd) throws XmlPullParserException,
- IOException {
+ private static final String ATTR_ID = "id";
+ private static final String ATTR_IFD = "ifd";
+
+ /**
+ * This function read the ground truth XML.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ static public List<Map<Short, String>> readXml(Context context, int xmlResId)
+ throws XmlPullParserException, IOException {
+ XmlPullParser parser = context.getResources().getXml(xmlResId);
+
+ List<Map<Short, String>> exifData =
+ new ArrayList<Map<Short, String>>(IfdId.TYPE_IFD_COUNT);
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ exifData.add(new HashMap<Short, String>());
+ }
while (parser.next() != XmlPullParser.END_DOCUMENT) {
if (parser.getEventType() == XmlPullParser.START_TAG) {
break;
}
}
+ parser.require(XmlPullParser.START_TAG, null, TAG_EXIF);
- assert(parser.getName().equals(XML_EXIF_TAG));
-
- parser.require(XmlPullParser.START_TAG, null, XML_EXIF_TAG);
while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() == XmlPullParser.START_TAG) {
- readXmlIfd(parser, ifd0, ifd1, exifIfd, interoperabilityIfd);
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
}
+
+ parser.require(XmlPullParser.START_TAG, null, TAG_TAG);
+
+ int ifdId = getIfdIdFromString(parser.getAttributeValue(null, ATTR_IFD));
+ short id = Integer.decode(parser.getAttributeValue(null, ATTR_ID)).shortValue();
+
+ String value = "";
+ if (parser.next() == XmlPullParser.TEXT) {
+ value = parser.getText();
+ parser.next();
+ }
+
+ exifData.get(ifdId).put(id, value);
+
+ parser.require(XmlPullParser.END_TAG, null, null);
}
- parser.require(XmlPullParser.END_TAG, null, XML_EXIF_TAG);
+ return exifData;
}
- private static void readXmlIfd(XmlPullParser parser, HashMap<Short, String> ifd0,
- HashMap<Short, String> ifd1, HashMap<Short, String> exifIfd,
- HashMap<Short, String> interoperabilityIfd) throws XmlPullParserException,
- IOException {
- parser.require(XmlPullParser.START_TAG, null, XML_IFD_TAG);
- String name = parser.getAttributeValue(null, XML_IFD_NAME);
- HashMap<Short, String> ifdData = null;
- if (XML_IFD0.equals(name)) {
- ifdData = ifd0;
- } else if (XML_IFD1.equals(name)) {
- ifdData = ifd1;
- } else if (XML_EXIF_IFD.equals(name)) {
- ifdData = exifIfd;
- } else if (XML_INTEROPERABILITY_IFD.equals(name)) {
- ifdData = interoperabilityIfd;
+ static private int getIfdIdFromString(String prefix) {
+ if (IFD0.equals(prefix)) {
+ return IfdId.TYPE_IFD_0;
+ } else if (EXIF_IFD.equals(prefix)) {
+ return IfdId.TYPE_IFD_EXIF;
+ } else if (GPS_IFD.equals(prefix)) {
+ return IfdId.TYPE_IFD_GPS;
+ } else if (IFD1.equals(prefix)) {
+ return IfdId.TYPE_IFD_1;
+ } else if (PREFIX_INTEROP_IFD.equals(prefix)) {
+ return IfdId.TYPE_IFD_INTEROPERABILITY;
} else {
- throw new RuntimeException("Unknown IFD name in xml file: " + name);
+ assert(false);
+ return -1;
}
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() == XmlPullParser.START_TAG) {
- readXmlTag(parser, ifdData);
- }
- }
- parser.require(XmlPullParser.END_TAG, null, XML_IFD_TAG);
}
-
- private static void readXmlTag(XmlPullParser parser, HashMap<Short, String> data)
- throws XmlPullParserException, IOException {
- parser.require(XmlPullParser.START_TAG, null, XML_TAG);
- short id = Integer.decode(parser.getAttributeValue(null, XML_TAG_ID)).shortValue();
- String value = "";
- if (parser.next() == XmlPullParser.TEXT) {
- value = parser.getText();
- parser.next();
- }
- data.put(id, value);
- parser.require(XmlPullParser.END_TAG, null, XML_TAG);
- }
-}
\ No newline at end of file
+}