summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/gallery3d/app/CropImage.java13
-rw-r--r--src/com/android/gallery3d/exif/ExifData.java92
-rw-r--r--src/com/android/gallery3d/exif/ExifOutputStream.java22
-rw-r--r--src/com/android/gallery3d/exif/ExifParser.java83
-rw-r--r--src/com/android/gallery3d/exif/ExifTag.java772
-rw-r--r--src/com/android/gallery3d/exif/IfdData.java2
-rw-r--r--tests/src/com/android/gallery3d/exif/ExifParserTest.java2
-rw-r--r--tests/src/com/android/gallery3d/exif/ExifReaderTest.java6
8 files changed, 817 insertions, 175 deletions
diff --git a/src/com/android/gallery3d/app/CropImage.java b/src/com/android/gallery3d/app/CropImage.java
index c77f57c05..78eeac700 100644
--- a/src/com/android/gallery3d/app/CropImage.java
+++ b/src/com/android/gallery3d/app/CropImage.java
@@ -59,7 +59,6 @@ import com.android.gallery3d.exif.ExifData;
import com.android.gallery3d.exif.ExifOutputStream;
import com.android.gallery3d.exif.ExifReader;
import com.android.gallery3d.exif.ExifTag;
-import com.android.gallery3d.exif.IfdId;
import com.android.gallery3d.picasasource.PicasaSource;
import com.android.gallery3d.ui.BitmapTileProvider;
import com.android.gallery3d.ui.CropView;
@@ -399,16 +398,8 @@ public class CropImage extends AbstractGalleryActivity {
}
private void changeExifImageSizeTags(ExifData data, int width, int height) {
- // FIXME: would the image size be too large for TYPE_UNSIGHED_SHORT?
- ExifTag tag = new ExifTag(ExifTag.TAG_IMAGE_WIDTH,
- ExifTag.TYPE_UNSIGNED_SHORT, 1, IfdId.TYPE_IFD_0);
- tag.setValue(new int[] {width});
- data.getIfdData(IfdId.TYPE_IFD_0).setTag(tag);
-
- tag = new ExifTag(ExifTag.TAG_IMAGE_LENGTH,
- ExifTag.TYPE_UNSIGNED_SHORT, 1, IfdId.TYPE_IFD_0);
- tag.setValue(new int[] {height});
- data.getIfdData(IfdId.TYPE_IFD_0).setTag(tag);
+ data.addTag(ExifTag.TAG_IMAGE_WIDTH).setValue(width);
+ data.addTag(ExifTag.TAG_IMAGE_LENGTH).setValue(height);
}
private Uri saveToMediaProvider(JobContext jc, Bitmap cropped) {
diff --git a/src/com/android/gallery3d/exif/ExifData.java b/src/com/android/gallery3d/exif/ExifData.java
index 0c16cc9aa..59b5f97ea 100644
--- a/src/com/android/gallery3d/exif/ExifData.java
+++ b/src/com/android/gallery3d/exif/ExifData.java
@@ -36,16 +36,7 @@ public class ExifData {
mByteOrder = order;
}
- /**
- * Gets the IFD data of the specified IFD.
- *
- * @see IfdId#TYPE_IFD_0
- * @see IfdId#TYPE_IFD_1
- * @see IfdId#TYPE_IFD_EXIF
- * @see IfdId#TYPE_IFD_GPS
- * @see IfdId#TYPE_IFD_INTEROPERABILITY
- */
- public IfdData getIfdData(int ifdId) {
+ IfdData getIfdData(int ifdId) {
return mIfdDatas[ifdId];
}
@@ -53,7 +44,7 @@ public class ExifData {
* Adds IFD data. If IFD data of the same type already exists,
* it will be replaced by the new data.
*/
- public void addIfdData(IfdData data) {
+ void addIfdData(IfdData data) {
mIfdDatas[data.getId()] = data;
}
@@ -143,6 +134,11 @@ public class ExifData {
return false;
}
+ /**
+ * Adds {@link ExifTag#TAG_GPS_LATITUDE}, {@link ExifTag#TAG_GPS_LONGITUDE},
+ * {@link ExifTag#TAG_GPS_LATITUDE_REF} and {@link ExifTag#TAG_GPS_LONGITUDE_REF} with the
+ * given latitude and longitude.
+ */
public void addGpsTags(double latitude, double longitude) {
IfdData gpsIfd = getIfdData(IfdId.TYPE_IFD_GPS);
if (gpsIfd == null) {
@@ -182,4 +178,78 @@ public class ExifData {
return new Rational[] {
new Rational(degrees, 1), new Rational(minutes, 1), new Rational(seconds, 100)};
}
+
+ private IfdData getOrCreateIfdData(int ifdId) {
+ IfdData ifdData = mIfdDatas[ifdId];
+ if (ifdData == null) {
+ ifdData = new IfdData(ifdId);
+ mIfdDatas[ifdId] = ifdData;
+ }
+ return ifdData;
+ }
+
+ /**
+ * Gets the tag with the given tag ID. Returns null if the tag does not exist. For tags
+ * related to interoperability or thumbnail, call {@link #getInteroperabilityTag(short)} and
+ * {@link #getThumbnailTag(short)} respectively.
+ */
+ public ExifTag getTag(short tagId) {
+ int ifdId = ExifTag.getIfdIdFromTagId(tagId);
+ IfdData ifdData = mIfdDatas[ifdId];
+ return (ifdData == null) ? null : ifdData.getTag(tagId);
+ }
+
+ /**
+ * Gets the thumbnail-related tag with the given tag ID.
+ */
+ public ExifTag getThumbnailTag(short tagId) {
+ IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_1];
+ return (ifdData == null) ? null : ifdData.getTag(tagId);
+ }
+
+ /**
+ * Gets the interoperability-related tag with the given tag ID.
+ */
+ public ExifTag getInteroperabilityTag(short tagId) {
+ IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_INTEROPERABILITY];
+ return (ifdData == null) ? null : ifdData.getTag(tagId);
+ }
+
+ /**
+ * Adds a tag with the given tag ID. The original tag will be replaced by the new tag. For tags
+ * related to interoperability or thumbnail, call {@link #addInteroperabilityTag(short)} or
+ * {@link #addThumbnailTag(short)} respectively.
+ * @exception IllegalArgumentException if the tag ID is invalid.
+ */
+ public ExifTag addTag(short tagId) {
+ int ifdId = ExifTag.getIfdIdFromTagId(tagId);
+ IfdData ifdData = getOrCreateIfdData(ifdId);
+ ExifTag tag = ExifTag.buildTag(tagId);
+ ifdData.setTag(tag);
+ return tag;
+ }
+
+ /**
+ * Adds a thumbnail-related tag with the given tag ID. The original tag will be replaced
+ * by the new tag.
+ * @exception IllegalArgumentException if the tag ID is invalid.
+ */
+ public ExifTag addThumbnailTag(short tagId) {
+ IfdData ifdData = getOrCreateIfdData(IfdId.TYPE_IFD_1);
+ ExifTag tag = ExifTag.buildThumbnailTag(tagId);
+ ifdData.setTag(tag);
+ return tag;
+ }
+
+ /**
+ * Adds an interoperability-related tag with the given tag ID. The original tag will be
+ * replaced by the new tag.
+ * @exception IllegalArgumentException if the tag ID is invalid.
+ */
+ public ExifTag addInteroperabilityTag(short tagId) {
+ IfdData ifdData = getOrCreateIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+ ExifTag tag = ExifTag.buildInteroperabilityTag(tagId);
+ ifdData.setTag(tag);
+ return tag;
+ }
} \ No newline at end of file
diff --git a/src/com/android/gallery3d/exif/ExifOutputStream.java b/src/com/android/gallery3d/exif/ExifOutputStream.java
index 9466faa58..b8db8e34c 100644
--- a/src/com/android/gallery3d/exif/ExifOutputStream.java
+++ b/src/com/android/gallery3d/exif/ExifOutputStream.java
@@ -221,9 +221,9 @@ public class ExifOutputStream extends FilterOutputStream {
dataOutputStream.write(0);
}
break;
- case ExifTag.TYPE_INT:
+ case ExifTag.TYPE_LONG:
for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
- dataOutputStream.writeInt(tag.getInt(i));
+ dataOutputStream.writeInt(tag.getLong(i));
}
break;
case ExifTag.TYPE_RATIONAL:
@@ -238,9 +238,9 @@ public class ExifOutputStream extends FilterOutputStream {
tag.getBytes(buf);
dataOutputStream.write(buf);
break;
- case ExifTag.TYPE_UNSIGNED_INT:
+ case ExifTag.TYPE_UNSIGNED_LONG:
for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
- dataOutputStream.writeInt((int) tag.getUnsignedInt(i));
+ dataOutputStream.writeInt((int) tag.getUnsignedLong(i));
}
break;
case ExifTag.TYPE_UNSIGNED_SHORT:
@@ -271,7 +271,7 @@ public class ExifOutputStream extends FilterOutputStream {
mExifData.addIfdData(ifd0);
}
ExifTag exifOffsetTag = new ExifTag(ExifTag.TAG_EXIF_IFD,
- ExifTag.TYPE_UNSIGNED_INT, 1, IfdId.TYPE_IFD_0);
+ ExifTag.TYPE_UNSIGNED_LONG, 1, IfdId.TYPE_IFD_0);
ifd0.setTag(exifOffsetTag);
// Exif IFD is required for all file.
@@ -285,7 +285,7 @@ public class ExifOutputStream extends FilterOutputStream {
IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
if (gpsIfd != null) {
ExifTag gpsOffsetTag = new ExifTag(ExifTag.TAG_GPS_IFD,
- ExifTag.TYPE_UNSIGNED_INT, 1, IfdId.TYPE_IFD_0);
+ ExifTag.TYPE_UNSIGNED_LONG, 1, IfdId.TYPE_IFD_0);
ifd0.setTag(gpsOffsetTag);
}
@@ -293,7 +293,7 @@ public class ExifOutputStream extends FilterOutputStream {
IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
if (interIfd != null) {
ExifTag interOffsetTag = new ExifTag(ExifTag.TAG_INTEROPERABILITY_IFD,
- ExifTag.TYPE_UNSIGNED_INT, 1, IfdId.TYPE_IFD_EXIF);
+ ExifTag.TYPE_UNSIGNED_LONG, 1, IfdId.TYPE_IFD_EXIF);
exifIfd.setTag(interOffsetTag);
}
@@ -306,10 +306,10 @@ public class ExifOutputStream extends FilterOutputStream {
mExifData.addIfdData(ifd1);
}
ExifTag offsetTag = new ExifTag(ExifTag.TAG_JPEG_INTERCHANGE_FORMAT,
- ExifTag.TYPE_UNSIGNED_INT, 1, IfdId.TYPE_IFD_1);
+ ExifTag.TYPE_UNSIGNED_LONG, 1, IfdId.TYPE_IFD_1);
ifd1.setTag(offsetTag);
ExifTag lengthTag = new ExifTag(ExifTag.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
- ExifTag.TYPE_UNSIGNED_INT, 1, IfdId.TYPE_IFD_1);
+ ExifTag.TYPE_UNSIGNED_LONG, 1, IfdId.TYPE_IFD_1);
lengthTag.setValue(mExifData.getCompressedThumbnail().length);
ifd1.setTag(lengthTag);
} else if (mExifData.hasUncompressedStrip()){
@@ -319,9 +319,9 @@ public class ExifOutputStream extends FilterOutputStream {
}
int stripCount = mExifData.getStripCount();
ExifTag offsetTag = new ExifTag(ExifTag.TAG_STRIP_OFFSETS,
- ExifTag.TYPE_UNSIGNED_INT, stripCount, IfdId.TYPE_IFD_1);
+ ExifTag.TYPE_UNSIGNED_LONG, stripCount, IfdId.TYPE_IFD_1);
ExifTag lengthTag = new ExifTag(ExifTag.TAG_STRIP_BYTE_COUNTS,
- ExifTag.TYPE_UNSIGNED_INT, stripCount, IfdId.TYPE_IFD_1);
+ ExifTag.TYPE_UNSIGNED_LONG, stripCount, IfdId.TYPE_IFD_1);
long[] lengths = new long[stripCount];
for (int i = 0; i < mExifData.getStripCount(); i++) {
lengths[i] = mExifData.getStrip(i).length;
diff --git a/src/com/android/gallery3d/exif/ExifParser.java b/src/com/android/gallery3d/exif/ExifParser.java
index dfa818409..f1e52c5b3 100644
--- a/src/com/android/gallery3d/exif/ExifParser.java
+++ b/src/com/android/gallery3d/exif/ExifParser.java
@@ -230,7 +230,7 @@ public class ExifParser {
}
return EVENT_NEW_TAG;
} else if (offset == endOfTags) {
- long ifdOffset = readUnsignedInt();
+ long ifdOffset = readUnsignedLong();
// There is a link to ifd1 at the end of ifd0
if (mIfdType == IfdId.TYPE_IFD_0) {
if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
@@ -296,7 +296,7 @@ public class ExifParser {
} else {
skipTo(endOfTags);
}
- long ifdOffset = readUnsignedInt();
+ long ifdOffset = readUnsignedLong();
// For ifd0, there is a link to ifd1 in the end of all tags
if (mIfdType == IfdId.TYPE_IFD_0
&& (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
@@ -340,7 +340,7 @@ public class ExifParser {
* @see #registerForTagValue(ExifTag)
* @see #read(byte[])
* @see #read(byte[], int, int)
- * @see #readInt()
+ * @see #readLong()
* @see #readRational()
* @see #readShort()
* @see #readString(int)
@@ -396,7 +396,9 @@ public class ExifParser {
if (mStripSizeTag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
return mStripSizeTag.getUnsignedShort(mImageEvent.stripIndex);
} else {
- return (int) mStripSizeTag.getUnsignedInt(mImageEvent.stripIndex);
+ // Cast unsigned int to int since the strip size is always smaller
+ // than the size of APP1 (65536)
+ return (int) mStripSizeTag.getUnsignedLong(mImageEvent.stripIndex);
}
}
@@ -406,7 +408,9 @@ public class ExifParser {
*/
public int getCompressedImageSize() {
if (mJpegSizeTag == null) return 0;
- return (int) mJpegSizeTag.getUnsignedInt(0);
+ // Cast unsigned int to int since the thumbnail is always smaller
+ // than the size of APP1 (65536)
+ return (int) mJpegSizeTag.getUnsignedLong(0);
}
private void skipTo(int offset) throws IOException {
@@ -429,6 +433,8 @@ public class ExifParser {
}
private void registerIfd(int ifdType, long offset) {
+ // Cast unsigned int to int since the offset is always smaller
+ // than the size of APP1 (65536)
mCorrespondingEvent.put((int) offset, new IfdEvent(ifdType, isIfdRequested(ifdType)));
}
@@ -474,22 +480,22 @@ public class ExifParser {
case ExifTag.TAG_EXIF_IFD:
if (isIfdRequested(IfdId.TYPE_IFD_EXIF)
|| isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
- registerIfd(IfdId.TYPE_IFD_EXIF, tag.getUnsignedInt(0));
+ registerIfd(IfdId.TYPE_IFD_EXIF, tag.getUnsignedLong(0));
}
break;
case ExifTag.TAG_GPS_IFD:
if (isIfdRequested(IfdId.TYPE_IFD_GPS)) {
- registerIfd(IfdId.TYPE_IFD_GPS, tag.getUnsignedInt(0));
+ registerIfd(IfdId.TYPE_IFD_GPS, tag.getUnsignedLong(0));
}
break;
case ExifTag.TAG_INTEROPERABILITY_IFD:
if (isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
- registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getUnsignedInt(0));
+ registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getUnsignedLong(0));
}
break;
case ExifTag.TAG_JPEG_INTERCHANGE_FORMAT:
if (isThumbnailRequested()) {
- registerCompressedImage(tag.getUnsignedInt(0));
+ registerCompressedImage(tag.getUnsignedLong(0));
}
break;
case ExifTag.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH:
@@ -504,7 +510,7 @@ public class ExifParser {
if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
registerUncompressedStrip(i, tag.getUnsignedShort(i));
} else {
- registerUncompressedStrip(i, tag.getUnsignedInt(i));
+ registerUncompressedStrip(i, tag.getUnsignedLong(i));
}
}
} else {
@@ -535,11 +541,11 @@ public class ExifParser {
case ExifTag.TYPE_ASCII:
tag.setValue(readString(tag.getComponentCount()));
break;
- case ExifTag.TYPE_UNSIGNED_INT:
+ case ExifTag.TYPE_UNSIGNED_LONG:
{
long value[] = new long[tag.getComponentCount()];
for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readUnsignedInt();
+ value[i] = readUnsignedLong();
}
tag.setValue(value);
}
@@ -562,11 +568,11 @@ public class ExifParser {
tag.setValue(value);
}
break;
- case ExifTag.TYPE_INT:
+ case ExifTag.TYPE_LONG:
{
int value[] = new int[tag.getComponentCount()];
for (int i = 0, n = value.length; i < n; i++) {
- value[i] = readInt();
+ value[i] = readLong();
}
tag.setValue(value);
}
@@ -629,14 +635,24 @@ public class ExifParser {
&& dataStream.readShort() == EXIF_HEADER_TAIL);
}
+ /**
+ * Reads bytes from the InputStream.
+ */
public int read(byte[] buffer, int offset, int length) throws IOException {
return mTiffStream.read(buffer, offset, length);
}
+ /**
+ * Equivalent to read(buffer, 0, buffer.length).
+ */
public int read(byte[] buffer) throws IOException {
return mTiffStream.read(buffer);
}
+ /**
+ * Reads a String from the InputStream with UTF8 charset.
+ * This is used for reading values of type {@link ExifTag#TYPE_ASCII}.
+ */
public String readString(int n) throws IOException {
if (n > 0) {
byte[] buf = new byte[n];
@@ -647,37 +663,52 @@ public class ExifParser {
}
}
+ /**
+ * Reads a String from the InputStream with the given charset.
+ * This is used for reading values of type {@link ExifTag#TYPE_ASCII}.
+ */
public String readString(int n, Charset charset) throws IOException {
byte[] buf = new byte[n];
mTiffStream.readOrThrow(buf);
return new String(buf, 0, n - 1, charset);
}
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_SHORT} from the InputStream.
+ */
public int readUnsignedShort() throws IOException {
- return readShort() & 0xffff;
+ return mTiffStream.readShort() & 0xffff;
}
- public long readUnsignedInt() throws IOException {
- return readInt() & 0xffffffffL;
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_LONG} from the InputStream.
+ */
+ public long readUnsignedLong() throws IOException {
+ return readLong() & 0xffffffffL;
}
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_RATIONAL} from the InputStream.
+ */
public Rational readUnsignedRational() throws IOException {
- long nomi = readUnsignedInt();
- long denomi = readUnsignedInt();
+ long nomi = readUnsignedLong();
+ long denomi = readUnsignedLong();
return new Rational(nomi, denomi);
}
- public int readInt() throws IOException {
+ /**
+ * Reads value of type {@link ExifTag#TYPE_LONG} from the InputStream.
+ */
+ public int readLong() throws IOException {
return mTiffStream.readInt();
}
- public short readShort() throws IOException {
- return mTiffStream.readShort();
- }
-
+ /**
+ * Reads value of type {@link ExifTag#TYPE_RATIONAL} from the InputStream.
+ */
public Rational readRational() throws IOException {
- int nomi = readInt();
- int denomi = readInt();
+ int nomi = readLong();
+ int denomi = readLong();
return new Rational(nomi, denomi);
}
diff --git a/src/com/android/gallery3d/exif/ExifTag.java b/src/com/android/gallery3d/exif/ExifTag.java
index 72a2f98ab..1aa84e565 100644
--- a/src/com/android/gallery3d/exif/ExifTag.java
+++ b/src/com/android/gallery3d/exif/ExifTag.java
@@ -16,7 +16,8 @@
package com.android.gallery3d.exif;
-import java.lang.reflect.Array;
+import android.util.SparseArray;
+
import java.util.Arrays;
/**
@@ -182,7 +183,7 @@ public class ExifTag {
}
/**
- * Contants for {@link #TAG_COMPRESSION}
+ * Constants for {@link #TAG_COMPRESSION}
*/
public static interface Compression {
public static final short UNCOMPRESSION = 1;
@@ -254,19 +255,19 @@ public class ExifTag {
// LSB
public static final short DID_NOT_FIRED = 0;
public static final short FIRED = 1;
- // 1~2 bits
+ // 1st~2nd bits
public static final short RETURN_NO_STROBE_RETURN_DETECTION_FUNCTION = 0 << 1;
public static final short RETURN_STROBE_RETURN_LIGHT_NOT_DETECTED = 2 << 1;
public static final short RETURN_STROBE_RETURN_LIGHT_DETECTED = 3 << 1;
- // 3~4 bits
+ // 3rd~4th bits
public static final short MODE_UNKNOWN = 0 << 3;
public static final short MODE_COMPULSORY_FLASH_FIRING = 1 << 3;
public static final short MODE_COMPULSORY_FLASH_SUPPRESSION = 2 << 3;
public static final short MODE_AUTO_MODE = 3 << 3;
- // 5 bit
+ // 5th bit
public static final short FUNCTION_PRESENT = 0 << 5;
public static final short FUNCTION_NO_FUNCTION = 1 << 5;
- // 6 bit
+ // 6th bit
public static final short RED_EYE_REDUCTION_NO_OR_UNKNOWN = 0 << 6;
public static final short RED_EYE_REDUCTION_SUPPORT = 1 << 6;
}
@@ -487,13 +488,42 @@ public class ExifTag {
public static final short DIFFERENTIAL_CORRECTION_APPLIED = 1;
}
+ /**
+ * The BYTE type in the EXIF standard. An 8-bit unsigned integer.
+ */
public static final short TYPE_UNSIGNED_BYTE = 1;
+ /**
+ * The ASCII type in the EXIF standard. An 8-bit byte containing one 7-bit ASCII code.
+ * The final byte is terminated with NULL.
+ */
public static final short TYPE_ASCII = 2;
+ /**
+ * The SHORT type in the EXIF standard. A 16-bit (2-byte) unsigned integer
+ */
public static final short TYPE_UNSIGNED_SHORT = 3;
- public static final short TYPE_UNSIGNED_INT = 4;
+ /**
+ * The LONG type in the EXIF standard. A 32-bit (4-byte) unsigned integer
+ */
+ public static final short TYPE_UNSIGNED_LONG = 4;
+ /**
+ * The RATIONAL type of EXIF standard. It consists of two LONGs. The first one is the numerator
+ * and the second one expresses the denominator.
+ */
public static final short TYPE_UNSIGNED_RATIONAL = 5;
+ /**
+ * The UNDEFINED type in the EXIF standard. An 8-bit byte that can take any value
+ * depending on the field definition.
+ */
public static final short TYPE_UNDEFINED = 7;
- public static final short TYPE_INT = 9;
+ /**
+ * The SLONG type in the EXIF standard. A 32-bit (4-byte) signed integer
+ * (2's complement notation).
+ */
+ public static final short TYPE_LONG = 9;
+ /**
+ * The SRATIONAL type of EXIF standard. It consists of two SLONGs. The first one is the
+ * numerator and the second one is the denominator.
+ */
public static final short TYPE_RATIONAL = 10;
private static final int TYPE_TO_SIZE_MAP[] = new int[11];
@@ -501,10 +531,10 @@ public class ExifTag {
TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_BYTE] = 1;
TYPE_TO_SIZE_MAP[TYPE_ASCII] = 1;
TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_SHORT] = 2;
- TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_INT] = 4;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_LONG] = 4;
TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_RATIONAL] = 8;
TYPE_TO_SIZE_MAP[TYPE_UNDEFINED] = 1;
- TYPE_TO_SIZE_MAP[TYPE_INT] = 4;
+ TYPE_TO_SIZE_MAP[TYPE_LONG] = 4;
TYPE_TO_SIZE_MAP[TYPE_RATIONAL] = 8;
}
@@ -512,11 +542,11 @@ public class ExifTag {
* Gets the element size of the given data type.
*
* @see #TYPE_ASCII
- * @see #TYPE_INT
+ * @see #TYPE_LONG
* @see #TYPE_RATIONAL
* @see #TYPE_UNDEFINED
* @see #TYPE_UNSIGNED_BYTE
- * @see #TYPE_UNSIGNED_INT
+ * @see #TYPE_UNSIGNED_LONG
* @see #TYPE_UNSIGNED_RATIONAL
* @see #TYPE_UNSIGNED_SHORT
*/
@@ -524,17 +554,366 @@ public class ExifTag {
return TYPE_TO_SIZE_MAP[type];
}
+ private static volatile SparseArray<Integer> sTagInfo = null;
+ private static volatile SparseArray<Integer> sInteroperTagInfo = null;
+ private static final int SIZE_UNDEFINED = 0;
+
+ private static SparseArray<Integer> getTagInfo() {
+ if (sTagInfo == null) {
+ synchronized(ExifTag.class) {
+ if (sTagInfo == null) {
+ sTagInfo = new SparseArray<Integer>();
+ initTagInfo();
+ }
+ }
+ }
+ return sTagInfo;
+ }
+
+ private static SparseArray<Integer> getInteroperTagInfo() {
+ if (sInteroperTagInfo == null) {
+ synchronized(ExifTag.class) {
+ if (sInteroperTagInfo == null) {
+ sInteroperTagInfo = new SparseArray<Integer>();
+ sInteroperTagInfo.put(TAG_INTEROPERABILITY_INDEX,
+ (IfdId.TYPE_IFD_INTEROPERABILITY << 24)
+ | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ }
+ }
+ }
+ return sInteroperTagInfo;
+ }
+
+ private static void initTagInfo() {
+ /**
+ * We put tag information in a 4-bytes integer. The first byte is the
+ * IFD of the tag, and the second byte is the default data type. The
+ * last two byte are a short value indicating the component count of this
+ * tag.
+ */
+ sTagInfo.put(TAG_MAKE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_IMAGE_WIDTH,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_IMAGE_LENGTH,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_BITS_PER_SAMPLE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 3);
+ sTagInfo.put(TAG_COMPRESSION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_PHOTOMETRIC_INTERPRETATION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_ORIENTATION, (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SAMPLES_PER_PIXEL,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_PLANAR_CONFIGURATION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_Y_CB_CR_SUB_SAMPLING,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 2);
+ sTagInfo.put(TAG_Y_CB_CR_POSITIONING,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_X_RESOLUTION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_Y_RESOLUTION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_RESOLUTION_UNIT,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_STRIP_OFFSETS,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_ROWS_PER_STRIP,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_STRIP_BYTE_COUNTS,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_JPEG_INTERCHANGE_FORMAT,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_TRANSFER_FUNCTION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 3 * 256);
+ sTagInfo.put(TAG_WHITE_POINT,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 2);
+ sTagInfo.put(TAG_PRIMARY_CHROMATICITIES,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 6);
+ sTagInfo.put(TAG_Y_CB_CR_COEFFICIENTS,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 3);
+ sTagInfo.put(TAG_REFERENCE_BLACK_WHITE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 6);
+ sTagInfo.put(TAG_DATE_TIME,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | 20);
+ sTagInfo.put(TAG_IMAGE_DESCRIPTION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_MAKE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_MODEL,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SOFTWARE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_ARTIST,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_COPYRIGHT,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_EXIF_IFD,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_GPS_IFD,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+
+ // EXIF TAG
+ sTagInfo.put(TAG_EXIF_VERSION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 4);
+ sTagInfo.put(TAG_FLASHPIX_VERSION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 4);
+ sTagInfo.put(TAG_COLOR_SPACE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_COMPONENTS_CONFIGURATION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 4);
+ sTagInfo.put(TAG_COMPRESSED_BITS_PER_PIXEL,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_PIXEL_X_DIMENSION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_PIXEL_Y_DIMENSION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_MAKER_NOTE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_USER_COMMENT,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_RELATED_SOUND_FILE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | 13);
+ sTagInfo.put(TAG_DATE_TIME_ORIGINAL,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | 20);
+ sTagInfo.put(TAG_DATE_TIME_DIGITIZED,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | 20);
+ sTagInfo.put(TAG_SUB_SEC_TIME,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SUB_SEC_TIME_ORIGINAL,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SUB_SEC_TIME_DIGITIZED,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_IMAGE_UNIQUE_ID,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | 33);
+ sTagInfo.put(TAG_EXPOSURE_TIME,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_F_NUMBER,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_EXPOSURE_PROGRAM,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SPECTRAL_SENSITIVITY,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_ISO_SPEED_RATINGS,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_OECF,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SHUTTER_SPEED_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_APERTURE_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_BRIGHTNESS_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_EXPOSURE_BIAS_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_MAX_APERTURE_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_SUBJECT_DISTANCE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_METERING_MODE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_LIGHT_SOURCE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_FLASH,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_FOCAL_LENGTH,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_SUBJECT_AREA,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_FLASH_ENERGY,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_SPATIAL_FREQUENCY_RESPONSE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_FOCAL_PLANE_X_RESOLUTION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_FOCAL_PLANE_Y_RESOLUTION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_FOCAL_PLANE_RESOLUTION_UNIT,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SUBJECT_LOCATION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 2);
+ sTagInfo.put(TAG_EXPOSURE_INDEX,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_SENSING_METHOD,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_FILE_SOURCE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 1);
+ sTagInfo.put(TAG_SCENE_TYPE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 1);
+ sTagInfo.put(TAG_CFA_PATTERN,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_CUSTOM_RENDERED,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_EXPOSURE_MODE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_WHITE_BALANCE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_DIGITAL_ZOOM_RATIO,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_FOCAL_LENGTH_IN_35_MM_FILE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SCENE_CAPTURE_TYPE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_GAIN_CONTROL,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_CONTRAST,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SATURATION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SHARPNESS,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_DEVICE_SETTING_DESCRIPTION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SUBJECT_DISTANCE_RANGE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ // GPS tag
+ sTagInfo.put(TAG_GPS_VERSION_ID,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_BYTE << 16 | 4);
+ sTagInfo.put(TAG_GPS_LATITUDE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_LONGITUDE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_LATITUDE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_RATIONAL << 16 | 3);
+ sTagInfo.put(TAG_GPS_LONGITUDE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_RATIONAL << 16 | 3);
+ sTagInfo.put(TAG_GPS_ALTITUDE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_BYTE << 16 | 1);
+ sTagInfo.put(TAG_GPS_ALTITUDE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_TIME_STAMP,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 3);
+ sTagInfo.put(TAG_GPS_SATTELLITES,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_GPS_STATUS,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_MEASURE_MODE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_DOP,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_SPEED_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_SPEED,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_TRACK_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_TRACK,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_IMG_DIRECTION_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_IMG_DIRECTION,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_MAP_DATUM,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_GPS_DEST_LATITUDE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_DEST_LATITUDE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_DEST_BEARING_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_DEST_BEARING,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_DEST_DISTANCE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_DEST_DISTANCE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_PROCESSING_METHOD,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_GPS_AREA_INFORMATION,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_GPS_DATA_STAMP,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 11);
+ sTagInfo.put(TAG_GPS_DIFFERENTIAL,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_SHORT << 16 | 11);
+ }
+
private final short mTagId;
private final short mDataType;
private final int mIfd;
+ private final boolean mComponentCountDefined;
private int mComponentCount;
private Object mValue;
private int mOffset;
- public ExifTag(short tagId, short type, int componentCount, int ifd) {
+ static private short getTypeFromInfo(int info) {
+ return (short) ((info >> 16) & 0xff);
+ }
+
+ static private int getComponentCountFromInfo(int info) {
+ return info & 0xffff;
+ }
+
+ static private int getIfdIdFromInfo(int info) {
+ return (info >> 24) & 0xff;
+ }
+
+ static private boolean getComponentCountDefined(short tagId, int ifd) {
+ Integer info = (ifd == IfdId.TYPE_IFD_INTEROPERABILITY) ?
+ getInteroperTagInfo().get(tagId) : getTagInfo().get(tagId);
+ if (info == null) return false;
+ return getComponentCountFromInfo(info) != SIZE_UNDEFINED;
+ }
+
+ static int getIfdIdFromTagId(short tagId) {
+ Integer info = getTagInfo().get(tagId);
+ if (info == null) {
+ throw new IllegalArgumentException("Unknown Tag ID: " + tagId);
+ }
+ return getIfdIdFromInfo(info);
+ }
+
+ /**
+ * Create a tag with given ID. For tags related to interoperability and thumbnail, call
+ * {@link #buildInteroperabilityTag(short)} and {@link #buildThumbnailTag(short)} respectively.
+ * @exception IllegalArgumentException If the ID is invalid.
+ */
+ static public ExifTag buildTag(short tagId) {
+ Integer info = getTagInfo().get(tagId);
+ if (info == null) {
+ throw new IllegalArgumentException("Unknown Tag ID: " + tagId);
+ }
+ return new ExifTag(tagId, getTypeFromInfo(info),
+ getComponentCountFromInfo(info),
+ getIfdIdFromInfo(info));
+ }
+
+ /**
+ * Create a tag related to thumbnail with given ID.
+ * @exception IllegalArgumentException If the ID is invalid.
+ */
+ static public ExifTag buildThumbnailTag(short tagId) {
+ Integer info = getTagInfo().get(tagId);
+ if (info == null || getIfdIdFromInfo(info) != IfdId.TYPE_IFD_0) {
+ throw new IllegalArgumentException("Unknown Thumnail Tag ID: " + tagId);
+ }
+ return new ExifTag(tagId, getTypeFromInfo(info),
+ getComponentCountFromInfo(info),
+ IfdId.TYPE_IFD_1);
+ }
+
+ /**
+ * Create a tag related to interoperability with given ID.
+ * @exception IllegalArgumentException If the ID is invalid.
+ */
+ static public ExifTag buildInteroperabilityTag(short tagId) {
+ Integer info = getInteroperTagInfo().get(tagId);
+ if (info == null || getIfdIdFromInfo(info) != IfdId.TYPE_IFD_INTEROPERABILITY) {
+ throw new RuntimeException("Unknown Interoperability Tag ID: " + tagId);
+ }
+ return new ExifTag(tagId, getTypeFromInfo(info),
+ getComponentCountFromInfo(info),
+ IfdId.TYPE_IFD_INTEROPERABILITY);
+ }
+
+ ExifTag(short tagId, short type, int componentCount, int ifd) {
mTagId = tagId;
mDataType = type;
mComponentCount = componentCount;
+ mComponentCountDefined = getComponentCountDefined(tagId, ifd);
mIfd = ifd;
}
@@ -562,11 +941,11 @@ public class ExifTag {
* Gets the data type of this tag
*
* @see #TYPE_ASCII
- * @see #TYPE_INT
+ * @see #TYPE_LONG
* @see #TYPE_RATIONAL
* @see #TYPE_UNDEFINED
* @see #TYPE_UNSIGNED_BYTE
- * @see #TYPE_UNSIGNED_INT
+ * @see #TYPE_UNSIGNED_LONG
* @see #TYPE_UNSIGNED_RATIONAL
* @see #TYPE_UNSIGNED_SHORT
*/
@@ -613,33 +992,126 @@ public class ExifTag {
mOffset = offset;
}
- /**
- * Sets integer values into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to the length.
- */
- public void setValue(int[] value) {
- long[] data = new long[value.length];
- for (int i = 0; i < value.length; i++) {
- data[i] = value[i];
+ private void checkComponentCountOrThrow(int count)
+ throws IllegalArgumentException {
+ if (mComponentCountDefined && (mComponentCount != count)) {
+ throw new IllegalArgumentException("Tag " + mTagId + ": Required "
+ + mComponentCount + " components but was given " + count
+ + " component(s)");
}
- mValue = data;
- mComponentCount = value.length;
}
- /**
- * Sets integer value into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to 1.
- */
- public void setValue(int value) {
- mValue = new long[] {value};
- mComponentCount = 1;
+ private void throwTypeNotMatchedException(String className)
+ throws IllegalArgumentException {
+ throw new IllegalArgumentException("Tag " + mTagId + ": expect type " +
+ convertTypeToString(mDataType) + " but got " + className);
+ }
+
+ private static String convertTypeToString(short type) {
+ switch (type) {
+ case TYPE_UNSIGNED_BYTE:
+ return "UNSIGNED_BYTE";
+ case TYPE_ASCII:
+ return "ASCII";
+ case TYPE_UNSIGNED_SHORT:
+ return "UNSIGNED_SHORT";
+ case TYPE_UNSIGNED_LONG:
+ return "UNSIGNED_LONG";
+ case TYPE_UNSIGNED_RATIONAL:
+ return "UNSIGNED_RATIONAL";
+ case TYPE_UNDEFINED:
+ return "UNDEFINED";
+ case TYPE_LONG:
+ return "LONG";
+ case TYPE_RATIONAL:
+ return "RATIONAL";
+ default:
+ return "";
+ }
+ }
+
+ private static final int UNSIGNED_SHORT_MAX = 65535;
+ private static final long UNSIGNED_LONG_MAX = 4294967295L;
+ private static final long LONG_MAX = Integer.MAX_VALUE;
+ private static final long LONG_MIN = Integer.MIN_VALUE;
+
+ private void checkOverflowForUnsignedShort(int[] value) {
+ for (int v : value) {
+ if (v > UNSIGNED_SHORT_MAX || v < 0) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type UNSIGNED_SHORT");
+ }
+ }
+ }
+
+ private void checkOverflowForUnsignedLong(long[] value) {
+ for (long v: value) {
+ if (v < 0 || v > UNSIGNED_LONG_MAX) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type UNSIGNED_LONG");
+ }
+ }
+ }
+
+ private void checkOverflowForUnsignedLong(int[] value) {
+ for (int v: value) {
+ if (v < 0) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type UNSIGNED_LONG");
+ }
+ }
+ }
+
+ private void checkOverflowForUnsignedRational(Rational[] value) {
+ for (Rational v: value) {
+ if (v.getNominator() < 0 || v.getDenominator() < 0
+ || v.getNominator() > UNSIGNED_LONG_MAX
+ || v.getDenominator() > UNSIGNED_LONG_MAX) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type UNSIGNED_RATIONAL");
+ }
+ }
+ }
+
+ private void checkOverflowForRational(Rational[] value) {
+ for (Rational v: value) {
+ if (v.getNominator() < LONG_MIN || v.getDenominator() < LONG_MIN
+ || v.getNominator() > LONG_MAX
+ || v.getDenominator() > LONG_MAX) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type RATIONAL");
+ }
+ }
}
/**
- * Sets short values into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to the length.
+ * Sets integer values into this tag.
+ * @exception IllegalArgumentException for the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+ * <li>The value overflows. </li>
+ * <li>The value.length does NOT match the definition of component count in
+ * EXIF standard.</li>
+ * </ul>
*/
- public void setValue(short[] value) {
+ public void setValue(int[] value) {
+ checkComponentCountOrThrow(value.length);
+ if (mDataType != TYPE_UNSIGNED_SHORT && mDataType != TYPE_LONG &&
+ mDataType != TYPE_UNSIGNED_LONG) {
+ throwTypeNotMatchedException("int");
+ }
+ if (mDataType == TYPE_UNSIGNED_SHORT) {
+ checkOverflowForUnsignedShort(value);
+ } else if (mDataType == TYPE_UNSIGNED_LONG) {
+ checkOverflowForUnsignedLong(value);
+ }
+
long[] data = new long[value.length];
for (int i = 0; i < value.length; i++) {
data[i] = value[i];
@@ -649,141 +1121,218 @@ public class ExifTag {
}
/**
- * Sets short value into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to 1.
+ * Sets integer values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The component count in the definition of EXIF standard is not 1.</li>
+ * </ul>
*/
- public void setValue(short value) {
- mValue = new long[] {value};
- mComponentCount = 1;
+ public void setValue(int value) {
+ checkComponentCountOrThrow(1);
+ setValue(new int[] {value});
}
/**
- * Sets long values into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to the length.
+ * Sets long values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+ * <li>The value overflows. </li>
+ * <li>The value.length does NOT match the definition of component count in
+ * EXIF standard.</li>
+ * </ul>
*/
public void setValue(long[] value) {
- long[] data = new long[value.length];
- System.arraycopy(value, 0, data, 0, value.length);
- mValue = data;
+ checkComponentCountOrThrow(value.length);
+ if (mDataType != TYPE_UNSIGNED_LONG) {
+ throwTypeNotMatchedException("long");
+ }
+ checkOverflowForUnsignedLong(value);
+ mValue = value;
mComponentCount = value.length;
}
/**
- * Sets long value into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to 1.
+ * Sets long values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+ * <li>The value overflows. </li>
+ * <li>The component count in the definition of EXIF standard is not 1.</li>
+ * </ul>
*/
public void setValue(long value) {
- mValue = new long[] {value};
- mComponentCount = 1;
+ setValue(new long[] {value});
}
/**
- * Sets String value into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to
- * value.length() + 1.
+ * Sets string values into this tag.
+ * @exception IllegalArgumentException If the data type is not {@link #TYPE_ASCII}
+ * or value.length() + 1 does NOT fit the definition of the component count in the
+ * EXIF standard.
*/
public void setValue(String value) {
+ checkComponentCountOrThrow(value.length() + 1);
+ if (mDataType != TYPE_ASCII) {
+ throwTypeNotMatchedException("String");
+ }
mComponentCount = value.length() + 1;
mValue = value;
}
/**
- * Sets Rational values into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to the length.
+ * Sets Rational values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL} or
+ * {@link #TYPE_RATIONAL} .</li>
+ * <li>The value overflows. </li>
+ * <li>The value.length does NOT match the definition of component count in
+ * EXIF standard.</li>
+ * </ul>
*/
public void setValue(Rational[] value) {
- mValue = new Rational[value.length];
- System.arraycopy(value, 0, mValue, 0, value.length);
+ if (mDataType == TYPE_UNSIGNED_RATIONAL) {
+ checkOverflowForUnsignedRational(value);
+ } else if (mDataType == TYPE_RATIONAL) {
+ checkOverflowForRational(value);
+ } else {
+ throwTypeNotMatchedException("Rational");
+ }
+ checkComponentCountOrThrow(value.length);
+ mValue = value;
mComponentCount = value.length;
}
/**
- * Sets Rational value into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to 1.
- */
+ * Sets Rational values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL} or
+ * {@link #TYPE_RATIONAL} .</li>
+ * <li>The value overflows. </li>
+ * <li>The component count in the definition of EXIF standard is not 1.</li>
+ * </ul>
+ * */
public void setValue(Rational value) {
- mValue = new Rational[] {value};
- mComponentCount = 1;
+ setValue(new Rational[] {value});
}
/**
- * Sets byte values into this tag. This is useful when we want to modify the tags
- * and write it back to the JPEG file. The component count will be set to the length.
- */
+ * Sets byte values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
+ * {@link #TYPE_UNDEFINED} .</li>
+ * <li>The length does NOT match the definition of component count in EXIF standard.</li>
+ * </ul>
+ * */
public void setValue(byte[] value, int offset, int length) {
- long[] data = new long[length];
- for (int i = 0; i < length; i++) {
- data[i] = value[i + offset];
+ checkComponentCountOrThrow(length);
+ if (mDataType != TYPE_UNSIGNED_BYTE && mDataType != TYPE_UNDEFINED) {
+ throwTypeNotMatchedException("byte");
}
- mValue = data;
+ mValue = new byte[length];
+ System.arraycopy(value, offset, mValue, 0, length);
mComponentCount = length;
}
/**
- * Sets the byte array as the value of this tag.
- * This is equivalent to setValue(value, 0, value.length).
+ * Equivalent to setValue(value, 0, value.length).
*/
public void setValue(byte[] value) {
setValue(value, 0, value.length);
}
- public short getShort(int index) {
- if (mValue instanceof long[]) {
- return (short) (((long[]) mValue) [index]);
- } else {
- throw new RuntimeException("There is no numerical value in this tag");
- }
- }
-
+ /**
+ * Gets the {@link #TYPE_UNSIGNED_SHORT} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_UNSIGNED_SHORT}.
+ */
public int getUnsignedShort(int index) {
- if (mValue instanceof long[]) {
- return (int) (((long[]) mValue) [index]);
- } else {
- throw new RuntimeException("There is no numerical value in this tag");
+ if (mDataType != TYPE_UNSIGNED_SHORT) {
+ throw new IllegalArgumentException("Cannot get UNSIGNED_SHORT value from "
+ + convertTypeToString(mDataType));
}
+ return (int) (((long[]) mValue) [index]);
}
- public int getInt(int index) {
- if (mValue instanceof long[]) {
- return (int) (((long[]) mValue) [index]);
- } else {
- throw new RuntimeException("There is no numerical value in this tag");
+ /**
+ * Gets the {@link #TYPE_LONG} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_LONG}.
+ */
+ public int getLong(int index) {
+ if (mDataType != TYPE_LONG) {
+ throw new IllegalArgumentException("Cannot get LONG value from "
+ + convertTypeToString(mDataType));
}
+ return (int) (((long[]) mValue) [index]);
}
- public long getUnsignedInt(int index) {
- if (mValue instanceof long[]) {
- return ((long[]) mValue) [index];
- } else {
- throw new RuntimeException("There is no numerical value in this tag");
+ /**
+ * Gets the {@link #TYPE_UNSIGNED_LONG} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_UNSIGNED_LONG}.
+ */
+ public long getUnsignedLong(int index) {
+ if (mDataType != TYPE_UNSIGNED_LONG) {
+ throw new IllegalArgumentException("Cannot get UNSIGNED LONG value from "
+ + convertTypeToString(mDataType));
}
+ return ((long[]) mValue) [index];
}
+ /**
+ * Gets the {@link #TYPE_ASCII} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_ASCII}.
+ */
public String getString() {
+ if (mDataType != TYPE_ASCII) {
+ throw new IllegalArgumentException("Cannot get ASCII value from "
+ + convertTypeToString(mDataType));
+ }
return (String) mValue;
}
+ /**
+ * Gets the {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_RATIONAL} or
+ * {@link #TYPE_UNSIGNED_RATIONAL}.
+ */
public Rational getRational(int index) {
- Object value = Array.get(mValue, index);
- if (value instanceof Rational) {
- return (Rational) value;
- } else {
- throw new RuntimeException("There is no Rational value in this tag");
+ if ((mDataType != TYPE_RATIONAL) && (mDataType != TYPE_UNSIGNED_RATIONAL)) {
+ throw new IllegalArgumentException("Cannot get RATIONAL value from "
+ + convertTypeToString(mDataType));
}
+ return ((Rational[]) mValue) [index];
}
+ /**
+ * Equivalent to getBytes(buffer, 0, buffer.length).
+ */
public void getBytes(byte[] buf) {
getBytes(buf, 0, buf.length);
}
+ /**
+ * Gets the {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE} data.
+ *
+ * @param buf the byte array in which to store the bytes read.
+ * @param offset the initial position in buffer to store the bytes.
+ * @param length the maximum number of bytes to store in buffer. If length > component count,
+ * only the valid bytes will be stored.
+ *
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_UNDEFINED} or
+ * {@link #TYPE_UNSIGNED_BYTE}.
+ */
public void getBytes(byte[] buf, int offset, int length) {
- if (!(mValue instanceof long[])) {
- throw new RuntimeException("There is no byte value in this tag");
- }
- long[] data = (long[]) mValue;
- for (int i = 0; i < length; i++) {
- buf[offset + i] = (byte) data[i];
+ if ((mDataType != TYPE_UNDEFINED) && (mDataType != TYPE_UNSIGNED_BYTE)) {
+ throw new IllegalArgumentException("Cannot get BYTE value from "
+ + convertTypeToString(mDataType));
}
+ System.arraycopy(mValue, 0, buf, offset,
+ (length > mComponentCount) ? mComponentCount : length);
}
/**
@@ -802,13 +1351,12 @@ public class ExifTag {
}
break;
case ExifTag.TYPE_ASCII:
- // trim the string for comparison between xml
- sbuilder.append(getString().trim());
+ sbuilder.append(getString());
break;
- case ExifTag.TYPE_UNSIGNED_INT:
+ case ExifTag.TYPE_UNSIGNED_LONG:
for(int i = 0, n = getComponentCount(); i < n; i++) {
if(i != 0) sbuilder.append(" ");
- sbuilder.append(getUnsignedInt(i));
+ sbuilder.append(getUnsignedLong(i));
}
break;
case ExifTag.TYPE_RATIONAL:
@@ -825,10 +1373,10 @@ public class ExifTag {
sbuilder.append(getUnsignedShort(i));
}
break;
- case ExifTag.TYPE_INT:
+ case ExifTag.TYPE_LONG:
for(int i = 0, n = getComponentCount(); i < n; i++) {
if(i != 0) sbuilder.append(" ");
- sbuilder.append(getInt(i));
+ sbuilder.append(getLong(i));
}
break;
}
@@ -840,7 +1388,7 @@ public class ExifTag {
* {@link #TAG_GPS_IFD}, {@link #TAG_JPEG_INTERCHANGE_FORMAT},
* {@link #TAG_STRIP_OFFSETS}, {@link #TAG_INTEROPERABILITY_IFD}
*/
- public static boolean isOffsetTag(short tagId) {
+ static boolean isOffsetTag(short tagId) {
return tagId == TAG_EXIF_IFD
|| tagId == TAG_GPS_IFD
|| tagId == TAG_JPEG_INTERCHANGE_FORMAT
@@ -852,7 +1400,6 @@ public class ExifTag {
public boolean equals(Object obj) {
if (obj instanceof ExifTag) {
ExifTag tag = (ExifTag) obj;
- boolean isArray = mValue != null && mValue.getClass().isArray();
if (mValue != null) {
if (mValue instanceof long[]) {
if (!(tag.mValue instanceof long[])) return false;
@@ -860,6 +1407,9 @@ public class ExifTag {
} else if (mValue instanceof Rational[]) {
if (!(tag.mValue instanceof Rational[])) return false;
return Arrays.equals((Rational[]) mValue, (Rational[]) tag.mValue);
+ } else if (mValue instanceof byte[]) {
+ if (!(tag.mValue instanceof byte[])) return false;
+ return Arrays.equals((byte[]) mValue, (byte[]) tag.mValue);
} else {
return mValue.equals(tag.mValue);
}
diff --git a/src/com/android/gallery3d/exif/IfdData.java b/src/com/android/gallery3d/exif/IfdData.java
index a2b367fc5..78f9173cc 100644
--- a/src/com/android/gallery3d/exif/IfdData.java
+++ b/src/com/android/gallery3d/exif/IfdData.java
@@ -25,7 +25,7 @@ import java.util.Map;
* @see ExifData
* @see ExifTag
*/
-public class IfdData {
+class IfdData {
private final int mIfdId;
private final Map<Short, ExifTag> mExifTags = new HashMap<Short, ExifTag>();
diff --git a/tests/src/com/android/gallery3d/exif/ExifParserTest.java b/tests/src/com/android/gallery3d/exif/ExifParserTest.java
index 1af106f3b..549fb0681 100644
--- a/tests/src/com/android/gallery3d/exif/ExifParserTest.java
+++ b/tests/src/com/android/gallery3d/exif/ExifParserTest.java
@@ -103,7 +103,7 @@ public class ExifParserTest extends InstrumentationTestCase {
}
String truthString = truth.get(tag.getTagId());
- String dataString = tag.valueToString();
+ String dataString = tag.valueToString().trim();
if (truthString == null) {
fail(String.format("Unknown Tag %02x", tag.getTagId()));
}
diff --git a/tests/src/com/android/gallery3d/exif/ExifReaderTest.java b/tests/src/com/android/gallery3d/exif/ExifReaderTest.java
index 236c0aea2..74b8bd3d8 100644
--- a/tests/src/com/android/gallery3d/exif/ExifReaderTest.java
+++ b/tests/src/com/android/gallery3d/exif/ExifReaderTest.java
@@ -105,7 +105,7 @@ public class ExifReaderTest extends InstrumentationTestCase {
assertEquals(byteCountTag.getUnsignedShort(i), exifData.getStrip(i).length);
} else {
assertEquals(
- byteCountTag.getUnsignedInt(i), exifData.getStrip(i).length);
+ byteCountTag.getUnsignedLong(i), exifData.getStrip(i).length);
}
}
}
@@ -116,7 +116,7 @@ public class ExifReaderTest extends InstrumentationTestCase {
if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
return tag.getUnsignedShort(0);
} else {
- return (int) tag.getUnsignedInt(0);
+ return (int) tag.getUnsignedLong(0);
}
}
@@ -127,7 +127,7 @@ public class ExifReaderTest extends InstrumentationTestCase {
}
ExifTag[] tags = ifd.getAllTags();
for (ExifTag tag : tags) {
- assertEquals(ifdValue.get(tag.getTagId()), tag.valueToString());
+ assertEquals(ifdValue.get(tag.getTagId()), tag.valueToString().trim());
}
assertEquals(ifdValue.size(), tags.length);
}