summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/exif/ExifParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/exif/ExifParser.java')
-rw-r--r--src/com/android/gallery3d/exif/ExifParser.java98
1 files changed, 98 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/exif/ExifParser.java b/src/com/android/gallery3d/exif/ExifParser.java
new file mode 100644
index 000000000..534f2f6d9
--- /dev/null
+++ b/src/com/android/gallery3d/exif/ExifParser.java
@@ -0,0 +1,98 @@
+/*
+ * 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.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
+
+public class ExifParser {
+
+ private static final String TAG = "ExifParser";
+
+ private static final short SOI = (short) 0xFFD8; // SOI marker of JPEG
+ private static final short APP1 = (short) 0xFFE1; // APP1 marker of JPEG
+
+ private static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
+ private static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
+
+ // TIFF header
+ private static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
+ private static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
+ private static final short TIFF_HEADER_TAIL = 0x002A;
+
+ public IfdParser parse(InputStream inputStream) throws ExifInvalidFormatException, IOException{
+ if (!seekTiffData(inputStream)) {
+ return null;
+ }
+ TiffInputStream tiffStream = new TiffInputStream(inputStream);
+ parseTiffHeader(tiffStream);
+ long offset = tiffStream.readUnsignedInt();
+ if (offset > Integer.MAX_VALUE) {
+ throw new ExifInvalidFormatException("Offset value is larger than Integer.MAX_VALUE");
+ }
+ return new IfdParser(tiffStream, (int)offset);
+ }
+
+ private void parseTiffHeader(TiffInputStream tiffStream) throws IOException,
+ ExifInvalidFormatException {
+ short byteOrder = tiffStream.readShort();
+ ByteOrder order;
+ if (LITTLE_ENDIAN_TAG == byteOrder) {
+ tiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+ } else if (BIG_ENDIAN_TAG == byteOrder) {
+ tiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+ } else {
+ throw new ExifInvalidFormatException("Invalid TIFF header");
+ }
+
+ if (tiffStream.readShort() != TIFF_HEADER_TAIL) {
+ throw new ExifInvalidFormatException("Invalid TIFF header");
+ }
+ }
+
+ /**
+ * Try to seek the tiff data. If there is no tiff data, return false, else return true and
+ * the inputstream will be at the start of tiff data
+ */
+ private boolean seekTiffData(InputStream inputStream) throws IOException,
+ ExifInvalidFormatException {
+ DataInputStream dataStream = new DataInputStream(inputStream);
+
+ // SOI and APP1
+ if (dataStream.readShort() != SOI) {
+ throw new ExifInvalidFormatException("Invalid JPEG format");
+ }
+
+ if (dataStream.readShort() != APP1) {
+ return false;
+ }
+
+ // APP1 length, it's not used for us
+ dataStream.readShort();
+
+ // Exif header
+ if (dataStream.readInt() != EXIF_HEADER
+ || dataStream.readShort() != EXIF_HEADER_TAIL) {
+ // There is no EXIF data;
+ return false;
+ }
+
+ return true;
+ }
+} \ No newline at end of file