From e81de49429e1c29385baffc7ce17b7188badc49a Mon Sep 17 00:00:00 2001 From: Earl Ou Date: Thu, 9 Aug 2012 14:17:33 +0800 Subject: A simple ExifReader and its test Change-Id: I1a30d24591bbdab288e04e3705ece388b533f247 --- src/com/android/gallery3d/exif/ExifData.java | 36 ++++++ src/com/android/gallery3d/exif/ExifReader.java | 150 +++++++++++++++++++++++++ src/com/android/gallery3d/exif/IfdData.java | 114 +++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 src/com/android/gallery3d/exif/ExifData.java create mode 100644 src/com/android/gallery3d/exif/ExifReader.java create mode 100644 src/com/android/gallery3d/exif/IfdData.java (limited to 'src/com/android') diff --git a/src/com/android/gallery3d/exif/ExifData.java b/src/com/android/gallery3d/exif/ExifData.java new file mode 100644 index 000000000..2c316f701 --- /dev/null +++ b/src/com/android/gallery3d/exif/ExifData.java @@ -0,0 +1,36 @@ +/* + * 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; + + +public class ExifData { + public static final int TYPE_IFD_0 = 0; + public static final int TYPE_IFD_EXIF = 1; + public static final int TYPE_IFD_1 = 2; + public static final int TYPE_IFD_GPS = 3; + public static final int TYPE_IFD_INTEROPERABILITY = 4; + + private final IfdData[] mIfdDatas = new IfdData[5]; + + public IfdData getIfdData(int ifdType) { + return mIfdDatas[ifdType]; + } + + public void addIfdData(IfdData data) { + mIfdDatas[data.getIfdType()] = data; + } +} diff --git a/src/com/android/gallery3d/exif/ExifReader.java b/src/com/android/gallery3d/exif/ExifReader.java new file mode 100644 index 000000000..f406cb739 --- /dev/null +++ b/src/com/android/gallery3d/exif/ExifReader.java @@ -0,0 +1,150 @@ +/* + * 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.IOException; +import java.io.InputStream; + +public class ExifReader { + + public ExifData getExifData(InputStream inputStream) throws ExifInvalidFormatException, + IOException { + ExifParser parser = new ExifParser(); + IfdParser ifdParser = parser.parse(inputStream); + ExifData exifData = new ExifData(); + IfdData ifdData = new IfdData(ExifData.TYPE_IFD_0); + parseIfd(ifdParser, ifdData, exifData); + exifData.addIfdData(ifdData); + return exifData; + } + + public void parseIfd(IfdParser ifdParser, IfdData ifdData, ExifData exifData) + throws IOException, ExifInvalidFormatException { + int type = ifdParser.next(); + while (type != IfdParser.TYPE_END) { + switch (type) { + case IfdParser.TYPE_NEW_TAG: + ExifTag tag = ifdParser.readTag(); + if (tag.getDataSize() > 4) { + long offset = ifdParser.readUnsignedInt(); + ifdParser.waitValueOfTag(tag, offset); + } else if (tag.getTagId() == ExifTag.TIFF_TAG.TAG_EXIF_IFD + || tag.getTagId() == ExifTag.TIFF_TAG.TAG_GPS_IFD + || tag.getTagId() == ExifTag.EXIF_TAG.TAG_INTEROPERABILITY_IFD) { + long offset = ifdParser.readUnsignedInt(); + ifdParser.waitValueOfTag(tag, offset); + ifdData.addTag(tag, offset); + } else { + readAndSaveTag(tag, ifdParser, ifdData); + } + break; + case IfdParser.TYPE_NEXT_IFD: + IfdData ifd1 = new IfdData(ExifData.TYPE_IFD_1); + parseIfd(ifdParser.parseIfdBlock(), ifd1, exifData); + exifData.addIfdData(ifd1); + break; + case IfdParser.TYPE_VALUE_OF_PREV_TAG: + tag = ifdParser.getCorrespodingExifTag(); + if(tag.getTagId() == ExifTag.TIFF_TAG.TAG_EXIF_IFD) { + IfdData ifd = new IfdData(ExifData.TYPE_IFD_EXIF); + parseIfd(ifdParser.parseIfdBlock(), ifd, exifData); + exifData.addIfdData(ifd); + } else if(tag.getTagId() == ExifTag.TIFF_TAG.TAG_GPS_IFD) { + IfdData ifd = new IfdData(ExifData.TYPE_IFD_GPS); + parseIfd(ifdParser.parseIfdBlock(), ifd, exifData); + exifData.addIfdData(ifd); + } else if(tag.getTagId() == ExifTag.EXIF_TAG.TAG_INTEROPERABILITY_IFD) { + IfdData ifd = new IfdData(ExifData.TYPE_IFD_INTEROPERABILITY); + parseIfd(ifdParser.parseIfdBlock(), ifd, exifData); + exifData.addIfdData(ifd); + } else { + readAndSaveTag(tag, ifdParser, ifdData); + } + break; + } + type = ifdParser.next(); + } + } + + public void readAndSaveTag(ExifTag tag, IfdParser parser, IfdData ifdData) + throws IOException { + switch(tag.getDataType()) { + case ExifTag.TYPE_BYTE: + { + byte buf[] = new byte[tag.getComponentCount()]; + parser.read(buf); + ifdData.addTag(tag, buf); + break; + } + case ExifTag.TYPE_ASCII: + ifdData.addTag(tag, parser.readString(tag.getComponentCount())); + break; + case ExifTag.TYPE_INT: + { + long value[] = new long[tag.getComponentCount()]; + for (int i = 0, n = value.length; i < n; i++) { + value[i] = parser.readUnsignedInt(); + } + ifdData.addTag(tag, value); + break; + } + case ExifTag.TYPE_RATIONAL: + { + Rational value[] = new Rational[tag.getComponentCount()]; + for (int i = 0, n = value.length; i < n; i++) { + value[i] = parser.readUnsignedRational(); + } + ifdData.addTag(tag, value); + break; + } + case ExifTag.TYPE_SHORT: + { + int value[] = new int[tag.getComponentCount()]; + for (int i = 0, n = value.length; i < n; i++) { + value[i] = parser.readUnsignedShort(); + } + ifdData.addTag(tag, value); + break; + } + case ExifTag.TYPE_SINT: + { + int value[] = new int[tag.getComponentCount()]; + for (int i = 0, n = value.length; i < n; i++) { + value[i] = parser.readInt(); + } + ifdData.addTag(tag, value); + break; + } + case ExifTag.TYPE_SRATIONAL: + { + Rational value[] = new Rational[tag.getComponentCount()]; + for (int i = 0, n = value.length; i < n; i++) { + value[i] = parser.readRational(); + } + ifdData.addTag(tag, value); + break; + } + case ExifTag.TYPE_UNDEFINED: + { + byte buf[] = new byte[tag.getComponentCount()]; + parser.read(buf); + ifdData.addTag(tag, buf); + break; + } + } + } +} diff --git a/src/com/android/gallery3d/exif/IfdData.java b/src/com/android/gallery3d/exif/IfdData.java new file mode 100644 index 000000000..b0d063023 --- /dev/null +++ b/src/com/android/gallery3d/exif/IfdData.java @@ -0,0 +1,114 @@ +/* + * 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.lang.reflect.Array; +import java.util.HashMap; +import java.util.Map; + +public class IfdData { + + private final int mIfdType; + private final Map mExifTags = new HashMap(); + private final Map mValues = new HashMap(); + + public IfdData(int ifdType) { + mIfdType = ifdType; + } + + public ExifTag[] getAllTags(ExifTag[] outTag) { + return mExifTags.values().toArray(outTag); + } + + public int getIfdType() { + return mIfdType; + } + + public ExifTag getTag(short tagId) { + return mExifTags.get(tagId); + } + + public short getShort(short tagId, int index) { + return (Short) Array.get(mValues.get(tagId), index); + } + + public short getShort(short tagId) { + return (Short) Array.get(mValues.get(tagId), 0); + } + + public int getUnsignedShort(short tagId, int index) { + return (Integer) Array.get(mValues.get(tagId), index); + } + + public int getUnsignedShort(short tagId) { + return (Integer) Array.get(mValues.get(tagId), 0); + } + + public int getInt(short tagId, int index) { + return (Integer) Array.get(mValues.get(tagId), index); + } + + public int getInt(short tagId) { + return (Integer) Array.get(mValues.get(tagId), 0); + } + + public long getUnsignedInt(short tagId, int index) { + return (Long) Array.get(mValues.get(tagId), index); + } + + public long getUnsignedInt(short tagId) { + return (Long) Array.get(mValues.get(tagId), 0); + } + + public String getString(short tagId) { + return (String) mValues.get(tagId); + } + + public Rational getRational(short tagId, int index) { + return ((Rational[]) mValues.get(tagId))[index]; + } + + public Rational getRational(short tagId) { + return ((Rational[]) mValues.get(tagId))[0]; + } + + public int getBytes(short tagId, byte[] buf) { + return getBytes(tagId, buf, 0, buf.length); + } + + public int getBytes(short tagId, byte[] buf, int offset, int length) { + Object data = mValues.get(tagId); + if (Array.getLength(data) < length + offset) { + System.arraycopy(data, offset, buf, 0, Array.getLength(data) - offset); + return Array.getLength(data) - offset; + } else { + System.arraycopy(data, offset, buf, 0, length); + return length; + } + } + + public void addTag(ExifTag tag, Object object) { + mExifTags.put(tag.getTagId(), tag); + if (object.getClass().isArray() || object.getClass() == String.class) { + mValues.put(tag.getTagId(), object); + } else { + Object array = Array.newInstance(object.getClass(), 1); + Array.set(array, 0, object); + mValues.put(tag.getTagId(), array); + } + } +} -- cgit v1.2.3