/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java

https://github.com/aizuzi/platform_frameworks_base · Java · 348 lines · 219 code · 32 blank · 97 comment · 65 complexity · cd980b2f91c60ae6353d7478cda1b511 MD5 · raw file

  1. /*
  2. * Copyright (C) 2012 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.android.gallery3d.exif;
  17. import android.util.Log;
  18. import java.io.UnsupportedEncodingException;
  19. import java.nio.ByteOrder;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.List;
  23. /**
  24. * This class stores the EXIF header in IFDs according to the JPEG
  25. * specification. It is the result produced by {@link ExifReader}.
  26. *
  27. * @see ExifReader
  28. * @see IfdData
  29. */
  30. class ExifData {
  31. private static final String TAG = "ExifData";
  32. private static final byte[] USER_COMMENT_ASCII = {
  33. 0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
  34. };
  35. private static final byte[] USER_COMMENT_JIS = {
  36. 0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
  37. };
  38. private static final byte[] USER_COMMENT_UNICODE = {
  39. 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
  40. };
  41. private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
  42. private byte[] mThumbnail;
  43. private ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
  44. private final ByteOrder mByteOrder;
  45. ExifData(ByteOrder order) {
  46. mByteOrder = order;
  47. }
  48. /**
  49. * Gets the compressed thumbnail. Returns null if there is no compressed
  50. * thumbnail.
  51. *
  52. * @see #hasCompressedThumbnail()
  53. */
  54. protected byte[] getCompressedThumbnail() {
  55. return mThumbnail;
  56. }
  57. /**
  58. * Sets the compressed thumbnail.
  59. */
  60. protected void setCompressedThumbnail(byte[] thumbnail) {
  61. mThumbnail = thumbnail;
  62. }
  63. /**
  64. * Returns true it this header contains a compressed thumbnail.
  65. */
  66. protected boolean hasCompressedThumbnail() {
  67. return mThumbnail != null;
  68. }
  69. /**
  70. * Adds an uncompressed strip.
  71. */
  72. protected void setStripBytes(int index, byte[] strip) {
  73. if (index < mStripBytes.size()) {
  74. mStripBytes.set(index, strip);
  75. } else {
  76. for (int i = mStripBytes.size(); i < index; i++) {
  77. mStripBytes.add(null);
  78. }
  79. mStripBytes.add(strip);
  80. }
  81. }
  82. /**
  83. * Gets the strip count.
  84. */
  85. protected int getStripCount() {
  86. return mStripBytes.size();
  87. }
  88. /**
  89. * Gets the strip at the specified index.
  90. *
  91. * @exceptions #IndexOutOfBoundException
  92. */
  93. protected byte[] getStrip(int index) {
  94. return mStripBytes.get(index);
  95. }
  96. /**
  97. * Returns true if this header contains uncompressed strip.
  98. */
  99. protected boolean hasUncompressedStrip() {
  100. return mStripBytes.size() != 0;
  101. }
  102. /**
  103. * Gets the byte order.
  104. */
  105. protected ByteOrder getByteOrder() {
  106. return mByteOrder;
  107. }
  108. /**
  109. * Returns the {@link IfdData} object corresponding to a given IFD if it
  110. * exists or null.
  111. */
  112. protected IfdData getIfdData(int ifdId) {
  113. if (ExifTag.isValidIfd(ifdId)) {
  114. return mIfdDatas[ifdId];
  115. }
  116. return null;
  117. }
  118. /**
  119. * Adds IFD data. If IFD data of the same type already exists, it will be
  120. * replaced by the new data.
  121. */
  122. protected void addIfdData(IfdData data) {
  123. mIfdDatas[data.getId()] = data;
  124. }
  125. /**
  126. * Returns the {@link IfdData} object corresponding to a given IFD or
  127. * generates one if none exist.
  128. */
  129. protected IfdData getOrCreateIfdData(int ifdId) {
  130. IfdData ifdData = mIfdDatas[ifdId];
  131. if (ifdData == null) {
  132. ifdData = new IfdData(ifdId);
  133. mIfdDatas[ifdId] = ifdData;
  134. }
  135. return ifdData;
  136. }
  137. /**
  138. * Returns the tag with a given TID in the given IFD if the tag exists.
  139. * Otherwise returns null.
  140. */
  141. protected ExifTag getTag(short tag, int ifd) {
  142. IfdData ifdData = mIfdDatas[ifd];
  143. return (ifdData == null) ? null : ifdData.getTag(tag);
  144. }
  145. /**
  146. * Adds the given ExifTag to its default IFD and returns an existing ExifTag
  147. * with the same TID or null if none exist.
  148. */
  149. protected ExifTag addTag(ExifTag tag) {
  150. if (tag != null) {
  151. int ifd = tag.getIfd();
  152. return addTag(tag, ifd);
  153. }
  154. return null;
  155. }
  156. /**
  157. * Adds the given ExifTag to the given IFD and returns an existing ExifTag
  158. * with the same TID or null if none exist.
  159. */
  160. protected ExifTag addTag(ExifTag tag, int ifdId) {
  161. if (tag != null && ExifTag.isValidIfd(ifdId)) {
  162. IfdData ifdData = getOrCreateIfdData(ifdId);
  163. return ifdData.setTag(tag);
  164. }
  165. return null;
  166. }
  167. protected void clearThumbnailAndStrips() {
  168. mThumbnail = null;
  169. mStripBytes.clear();
  170. }
  171. /**
  172. * Removes the thumbnail and its related tags. IFD1 will be removed.
  173. */
  174. protected void removeThumbnailData() {
  175. clearThumbnailAndStrips();
  176. mIfdDatas[IfdId.TYPE_IFD_1] = null;
  177. }
  178. /**
  179. * Removes the tag with a given TID and IFD.
  180. */
  181. protected void removeTag(short tagId, int ifdId) {
  182. IfdData ifdData = mIfdDatas[ifdId];
  183. if (ifdData == null) {
  184. return;
  185. }
  186. ifdData.removeTag(tagId);
  187. }
  188. /**
  189. * Decodes the user comment tag into string as specified in the EXIF
  190. * standard. Returns null if decoding failed.
  191. */
  192. protected String getUserComment() {
  193. IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
  194. if (ifdData == null) {
  195. return null;
  196. }
  197. ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
  198. if (tag == null) {
  199. return null;
  200. }
  201. if (tag.getComponentCount() < 8) {
  202. return null;
  203. }
  204. byte[] buf = new byte[tag.getComponentCount()];
  205. tag.getBytes(buf);
  206. byte[] code = new byte[8];
  207. System.arraycopy(buf, 0, code, 0, 8);
  208. try {
  209. if (Arrays.equals(code, USER_COMMENT_ASCII)) {
  210. return new String(buf, 8, buf.length - 8, "US-ASCII");
  211. } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
  212. return new String(buf, 8, buf.length - 8, "EUC-JP");
  213. } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
  214. return new String(buf, 8, buf.length - 8, "UTF-16");
  215. } else {
  216. return null;
  217. }
  218. } catch (UnsupportedEncodingException e) {
  219. Log.w(TAG, "Failed to decode the user comment");
  220. return null;
  221. }
  222. }
  223. /**
  224. * Returns a list of all {@link ExifTag}s in the ExifData or null if there
  225. * are none.
  226. */
  227. protected List<ExifTag> getAllTags() {
  228. ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
  229. for (IfdData d : mIfdDatas) {
  230. if (d != null) {
  231. ExifTag[] tags = d.getAllTags();
  232. if (tags != null) {
  233. for (ExifTag t : tags) {
  234. ret.add(t);
  235. }
  236. }
  237. }
  238. }
  239. if (ret.size() == 0) {
  240. return null;
  241. }
  242. return ret;
  243. }
  244. /**
  245. * Returns a list of all {@link ExifTag}s in a given IFD or null if there
  246. * are none.
  247. */
  248. protected List<ExifTag> getAllTagsForIfd(int ifd) {
  249. IfdData d = mIfdDatas[ifd];
  250. if (d == null) {
  251. return null;
  252. }
  253. ExifTag[] tags = d.getAllTags();
  254. if (tags == null) {
  255. return null;
  256. }
  257. ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
  258. for (ExifTag t : tags) {
  259. ret.add(t);
  260. }
  261. if (ret.size() == 0) {
  262. return null;
  263. }
  264. return ret;
  265. }
  266. /**
  267. * Returns a list of all {@link ExifTag}s with a given TID or null if there
  268. * are none.
  269. */
  270. protected List<ExifTag> getAllTagsForTagId(short tag) {
  271. ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
  272. for (IfdData d : mIfdDatas) {
  273. if (d != null) {
  274. ExifTag t = d.getTag(tag);
  275. if (t != null) {
  276. ret.add(t);
  277. }
  278. }
  279. }
  280. if (ret.size() == 0) {
  281. return null;
  282. }
  283. return ret;
  284. }
  285. @Override
  286. public boolean equals(Object obj) {
  287. if (this == obj) {
  288. return true;
  289. }
  290. if (obj == null) {
  291. return false;
  292. }
  293. if (obj instanceof ExifData) {
  294. ExifData data = (ExifData) obj;
  295. if (data.mByteOrder != mByteOrder ||
  296. data.mStripBytes.size() != mStripBytes.size() ||
  297. !Arrays.equals(data.mThumbnail, mThumbnail)) {
  298. return false;
  299. }
  300. for (int i = 0; i < mStripBytes.size(); i++) {
  301. if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
  302. return false;
  303. }
  304. }
  305. for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
  306. IfdData ifd1 = data.getIfdData(i);
  307. IfdData ifd2 = getIfdData(i);
  308. if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
  309. return false;
  310. }
  311. }
  312. return true;
  313. }
  314. return false;
  315. }
  316. }