From 104c45677660586026a7e74ef8c47d396403d50e Mon Sep 17 00:00:00 2001 From: Michael Jurka Date: Mon, 8 Jul 2013 18:03:46 -0700 Subject: Initial implementation of new wallpaper picker. Change-Id: Ib4c5ac4989b4959fa62465d9cde3cac662e24949 --- src/com/android/gallery3d/exif/ExifData.java | 348 +++++++++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 src/com/android/gallery3d/exif/ExifData.java (limited to 'src/com/android/gallery3d/exif/ExifData.java') diff --git a/src/com/android/gallery3d/exif/ExifData.java b/src/com/android/gallery3d/exif/ExifData.java new file mode 100644 index 000000000..8422382bb --- /dev/null +++ b/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 mStripBytes = new ArrayList(); + 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 getAllTags() { + ArrayList ret = new ArrayList(); + 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 getAllTagsForIfd(int ifd) { + IfdData d = mIfdDatas[ifd]; + if (d == null) { + return null; + } + ExifTag[] tags = d.getAllTags(); + if (tags == null) { + return null; + } + ArrayList ret = new ArrayList(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 getAllTagsForTagId(short tag) { + ArrayList ret = new ArrayList(); + 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; + } + +} -- cgit v1.2.3