diff options
Diffstat (limited to 'src/com/android/gallery3d/exif/ExifParser.java')
-rw-r--r-- | src/com/android/gallery3d/exif/ExifParser.java | 98 |
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 |