From fd745274358be4afdc0876985b108c2a20ef6b06 Mon Sep 17 00:00:00 2001 From: Earl Ou Date: Thu, 16 Aug 2012 10:41:57 +0800 Subject: Read thumbnail into ExifData Change-Id: Iccc0fbbda1734795ff431075bade700ca5076a08 --- src/com/android/gallery3d/exif/ExifData.java | 57 +++++++++++++++++++++ src/com/android/gallery3d/exif/ExifReader.java | 14 +++++- .../com/android/gallery3d/exif/ExifReaderTest.java | 58 +++++++++++++++++++++- 3 files changed, 126 insertions(+), 3 deletions(-) diff --git a/src/com/android/gallery3d/exif/ExifData.java b/src/com/android/gallery3d/exif/ExifData.java index 712698ef4..5b0e3d8e4 100644 --- a/src/com/android/gallery3d/exif/ExifData.java +++ b/src/com/android/gallery3d/exif/ExifData.java @@ -15,6 +15,9 @@ */ package com.android.gallery3d.exif; + +import java.util.ArrayList; + /** * This class stores the EXIF header in IFDs according to the JPEG specification. * It is the result produced by {@link ExifReader}. @@ -23,6 +26,8 @@ package com.android.gallery3d.exif; */ public class ExifData { private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT]; + private byte[] mThumbnail; + private ArrayList mStripBytes = new ArrayList(); /** * Gets the IFD data of the specified IFD. @@ -44,4 +49,56 @@ public class ExifData { public void addIfdData(IfdData data) { mIfdDatas[data.getId()] = data; } + + /** + * Gets the compressed thumbnail. Returns null if there is no compressed thumbnail. + * + * @see #hasCompressedThumbnail() + */ + public byte[] getCompressedThumbnail() { + return mThumbnail; + } + + /** + * Sets the compressed thumbnail. + */ + public void setCompressedThumbnail(byte[] thumbnail) { + mThumbnail = thumbnail; + } + + /** + * Returns true it this header contains a compressed thumbnail. + */ + public boolean hasCompressedThumbnail() { + return mThumbnail != null; + } + + /** + * Adds an uncompressed strip. + */ + public void setStripBytes(int index, byte[] strip) { + if (index < mStripBytes.size()) { + mStripBytes.set(index, strip); + } else { + for (int i = mStripBytes.size(); i < index; i++) { + mStripBytes.add(null); + } + mStripBytes.add(strip); + } + } + + /** + * Gets the strip count + */ + public int getStripCount() { + return mStripBytes.size(); + } + + /** + * Gets the strip at the specified index. + * @exceptions #IndexOutOfBoundException + */ + public byte[] getStrip(int index) { + return mStripBytes.get(index); + } } \ No newline at end of file diff --git a/src/com/android/gallery3d/exif/ExifReader.java b/src/com/android/gallery3d/exif/ExifReader.java index 125b6c65e..c259461f2 100644 --- a/src/com/android/gallery3d/exif/ExifReader.java +++ b/src/com/android/gallery3d/exif/ExifReader.java @@ -24,11 +24,11 @@ import java.io.InputStream; */ public class ExifReader { /** - * Parse the inputStream and return all Exif data. + * Parses the inputStream and and returns the EXIF data in an {@link ExifData}. * @throws ExifInvalidFormatException * @throws IOException */ - public ExifData getExifData(InputStream inputStream) throws ExifInvalidFormatException, + public ExifData read(InputStream inputStream) throws ExifInvalidFormatException, IOException { ExifParser parser = ExifParser.parse(inputStream); ExifData exifData = new ExifData(); @@ -56,6 +56,16 @@ public class ExifReader { } exifData.getIfdData(tag.getIfd()).setTag(tag); break; + case ExifParser.EVENT_COMPRESSED_IMAGE: + byte buf[] = new byte[parser.getCompressedImageSize()]; + parser.read(buf); + exifData.setCompressedThumbnail(buf); + break; + case ExifParser.EVENT_UNCOMPRESSED_STRIP: + buf = new byte[parser.getStripSize()]; + parser.read(buf); + exifData.setStripBytes(parser.getStripIndex(), buf); + break; } event = parser.next(); } diff --git a/tests/src/com/android/gallery3d/exif/ExifReaderTest.java b/tests/src/com/android/gallery3d/exif/ExifReaderTest.java index c0c2f9f81..67e695682 100644 --- a/tests/src/com/android/gallery3d/exif/ExifReaderTest.java +++ b/tests/src/com/android/gallery3d/exif/ExifReaderTest.java @@ -17,6 +17,7 @@ package com.android.gallery3d.exif; import android.content.res.XmlResourceParser; +import android.graphics.BitmapFactory; import android.test.InstrumentationTestCase; import java.io.IOException; @@ -56,12 +57,67 @@ public class ExifReaderTest extends InstrumentationTestCase { public void testRead() throws ExifInvalidFormatException, IOException { ExifReader reader = new ExifReader(); - ExifData exifData = reader.getExifData(mImageInputStream); + 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); + checkThumbnail(exifData); + } + + private void checkThumbnail(ExifData exifData) { + IfdData ifd1 = exifData.getIfdData(IfdId.TYPE_IFD_1); + if (ifd1 != null) { + if (ifd1.getTag(ExifTag.TIFF_TAG.TAG_COMPRESSION).getUnsignedShort() == + ExifTag.TIFF_TAG.COMPRESSION_JPEG) { + assertTrue(exifData.hasCompressedThumbnail()); + byte[] thumbnail = exifData.getCompressedThumbnail(); + assertTrue(BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length) != null); + } else { + // Try to check the strip count with the formula provided by EXIF spec. + int planarType = ExifTag.TIFF_TAG.PLANAR_CONFIGURATION_CHUNKY; + ExifTag planarTag = ifd1.getTag(ExifTag.TIFF_TAG.TAG_PLANAR_CONFIGURATION); + if (planarTag != null) { + planarType = planarTag.getUnsignedShort(); + } + + ExifTag heightTag = ifd1.getTag(ExifTag.TIFF_TAG.TAG_IMAGE_HEIGHT); + ExifTag rowPerStripTag = ifd1.getTag(ExifTag.TIFF_TAG.TAG_ROWS_PER_STRIP); + + int imageLength = getUnsignedIntOrShort(heightTag); + int rowsPerStrip = getUnsignedIntOrShort(rowPerStripTag); + int stripCount = ifd1.getTag( + ExifTag.TIFF_TAG.TAG_STRIP_OFFSETS).getComponentCount(); + + if (planarType == ExifTag.TIFF_TAG.PLANAR_CONFIGURATION_CHUNKY) { + assertTrue(stripCount == (imageLength + rowsPerStrip - 1) / rowsPerStrip); + } else { + ExifTag samplePerPixelTag = ifd1.getTag(ExifTag.TIFF_TAG.TAG_SAMPLES_PER_PIXEL); + int samplePerPixel = samplePerPixelTag.getUnsignedShort(); + assertTrue(stripCount == + (imageLength + rowsPerStrip - 1) / rowsPerStrip * samplePerPixel); + } + + for (int i = 0; i < stripCount; i++) { + ExifTag byteCountTag = ifd1.getTag(ExifTag.TIFF_TAG.TAG_STRIP_BYTE_COUNTS); + if (byteCountTag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) { + assertEquals(byteCountTag.getUnsignedShort(i), exifData.getStrip(i).length); + } else { + assertEquals( + byteCountTag.getUnsignedInt(i), exifData.getStrip(i).length); + } + } + } + } + } + + private int getUnsignedIntOrShort(ExifTag tag) { + if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) { + return tag.getUnsignedShort(); + } else { + return (int) tag.getUnsignedInt(); + } } private void checkIfd(IfdData ifd, HashMap ifdValue) { -- cgit v1.2.3