summaryrefslogtreecommitdiffstats
path: root/WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java
diff options
context:
space:
mode:
Diffstat (limited to 'WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java')
-rw-r--r--WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java348
1 files changed, 348 insertions, 0 deletions
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java
new file mode 100644
index 000000000..8422382bb
--- /dev/null
+++ b/WallpaperPicker/src/com/android/gallery3d/exif/ExifData.java
@@ -0,0 +1,348 @@
+/*
+ * 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 android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class stores the EXIF header in IFDs according to the JPEG
+ * specification. It is the result produced by {@link ExifReader}.
+ *
+ * @see ExifReader
+ * @see IfdData
+ */
+class ExifData {
+ private static final String TAG = "ExifData";
+ private static final byte[] USER_COMMENT_ASCII = {
+ 0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
+ };
+ private static final byte[] USER_COMMENT_JIS = {
+ 0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ private static final byte[] USER_COMMENT_UNICODE = {
+ 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
+ };
+
+ private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
+ private byte[] mThumbnail;
+ private ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
+ private final ByteOrder mByteOrder;
+
+ ExifData(ByteOrder order) {
+ mByteOrder = order;
+ }
+
+ /**
+ * Gets the compressed thumbnail. Returns null if there is no compressed
+ * thumbnail.
+ *
+ * @see #hasCompressedThumbnail()
+ */
+ protected byte[] getCompressedThumbnail() {
+ return mThumbnail;
+ }
+
+ /**
+ * Sets the compressed thumbnail.
+ */
+ protected void setCompressedThumbnail(byte[] thumbnail) {
+ mThumbnail = thumbnail;
+ }
+
+ /**
+ * Returns true it this header contains a compressed thumbnail.
+ */
+ protected boolean hasCompressedThumbnail() {
+ return mThumbnail != null;
+ }
+
+ /**
+ * Adds an uncompressed strip.
+ */
+ protected 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.
+ */
+ protected int getStripCount() {
+ return mStripBytes.size();
+ }
+
+ /**
+ * Gets the strip at the specified index.
+ *
+ * @exceptions #IndexOutOfBoundException
+ */
+ protected byte[] getStrip(int index) {
+ return mStripBytes.get(index);
+ }
+
+ /**
+ * Returns true if this header contains uncompressed strip.
+ */
+ protected boolean hasUncompressedStrip() {
+ return mStripBytes.size() != 0;
+ }
+
+ /**
+ * Gets the byte order.
+ */
+ protected ByteOrder getByteOrder() {
+ return mByteOrder;
+ }
+
+ /**
+ * Returns the {@link IfdData} object corresponding to a given IFD if it
+ * exists or null.
+ */
+ protected IfdData getIfdData(int ifdId) {
+ if (ExifTag.isValidIfd(ifdId)) {
+ return mIfdDatas[ifdId];
+ }
+ return null;
+ }
+
+ /**
+ * Adds IFD data. If IFD data of the same type already exists, it will be
+ * replaced by the new data.
+ */
+ protected void addIfdData(IfdData data) {
+ mIfdDatas[data.getId()] = data;
+ }
+
+ /**
+ * Returns the {@link IfdData} object corresponding to a given IFD or
+ * generates one if none exist.
+ */
+ protected IfdData getOrCreateIfdData(int ifdId) {
+ IfdData ifdData = mIfdDatas[ifdId];
+ if (ifdData == null) {
+ ifdData = new IfdData(ifdId);
+ mIfdDatas[ifdId] = ifdData;
+ }
+ return ifdData;
+ }
+
+ /**
+ * Returns the tag with a given TID in the given IFD if the tag exists.
+ * Otherwise returns null.
+ */
+ protected ExifTag getTag(short tag, int ifd) {
+ IfdData ifdData = mIfdDatas[ifd];
+ return (ifdData == null) ? null : ifdData.getTag(tag);
+ }
+
+ /**
+ * Adds the given ExifTag to its default IFD and returns an existing ExifTag
+ * with the same TID or null if none exist.
+ */
+ protected ExifTag addTag(ExifTag tag) {
+ if (tag != null) {
+ int ifd = tag.getIfd();
+ return addTag(tag, ifd);
+ }
+ return null;
+ }
+
+ /**
+ * Adds the given ExifTag to the given IFD and returns an existing ExifTag
+ * with the same TID or null if none exist.
+ */
+ protected ExifTag addTag(ExifTag tag, int ifdId) {
+ if (tag != null && ExifTag.isValidIfd(ifdId)) {
+ IfdData ifdData = getOrCreateIfdData(ifdId);
+ return ifdData.setTag(tag);
+ }
+ return null;
+ }
+
+ protected void clearThumbnailAndStrips() {
+ mThumbnail = null;
+ mStripBytes.clear();
+ }
+
+ /**
+ * Removes the thumbnail and its related tags. IFD1 will be removed.
+ */
+ protected void removeThumbnailData() {
+ clearThumbnailAndStrips();
+ mIfdDatas[IfdId.TYPE_IFD_1] = null;
+ }
+
+ /**
+ * Removes the tag with a given TID and IFD.
+ */
+ protected void removeTag(short tagId, int ifdId) {
+ IfdData ifdData = mIfdDatas[ifdId];
+ if (ifdData == null) {
+ return;
+ }
+ ifdData.removeTag(tagId);
+ }
+
+ /**
+ * Decodes the user comment tag into string as specified in the EXIF
+ * standard. Returns null if decoding failed.
+ */
+ protected String getUserComment() {
+ IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
+ if (ifdData == null) {
+ return null;
+ }
+ ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
+ if (tag == null) {
+ return null;
+ }
+ if (tag.getComponentCount() < 8) {
+ return null;
+ }
+
+ byte[] buf = new byte[tag.getComponentCount()];
+ tag.getBytes(buf);
+
+ byte[] code = new byte[8];
+ System.arraycopy(buf, 0, code, 0, 8);
+
+ try {
+ if (Arrays.equals(code, USER_COMMENT_ASCII)) {
+ return new String(buf, 8, buf.length - 8, "US-ASCII");
+ } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
+ return new String(buf, 8, buf.length - 8, "EUC-JP");
+ } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
+ return new String(buf, 8, buf.length - 8, "UTF-16");
+ } else {
+ return null;
+ }
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, "Failed to decode the user comment");
+ return null;
+ }
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s in the ExifData or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTags() {
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
+ for (IfdData d : mIfdDatas) {
+ if (d != null) {
+ ExifTag[] tags = d.getAllTags();
+ if (tags != null) {
+ for (ExifTag t : tags) {
+ ret.add(t);
+ }
+ }
+ }
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s in a given IFD or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTagsForIfd(int ifd) {
+ IfdData d = mIfdDatas[ifd];
+ if (d == null) {
+ return null;
+ }
+ ExifTag[] tags = d.getAllTags();
+ if (tags == null) {
+ return null;
+ }
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
+ for (ExifTag t : tags) {
+ ret.add(t);
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s with a given TID or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTagsForTagId(short tag) {
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
+ for (IfdData d : mIfdDatas) {
+ if (d != null) {
+ ExifTag t = d.getTag(tag);
+ if (t != null) {
+ ret.add(t);
+ }
+ }
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof ExifData) {
+ ExifData data = (ExifData) obj;
+ if (data.mByteOrder != mByteOrder ||
+ data.mStripBytes.size() != mStripBytes.size() ||
+ !Arrays.equals(data.mThumbnail, mThumbnail)) {
+ return false;
+ }
+ for (int i = 0; i < mStripBytes.size(); i++) {
+ if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
+ return false;
+ }
+ }
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ IfdData ifd1 = data.getIfdData(i);
+ IfdData ifd2 = getIfdData(i);
+ if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+}