1c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou/* 2c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * Copyright (C) 2012 The Android Open Source Project 3c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * 4c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * Licensed under the Apache License, Version 2.0 (the "License"); 5c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * you may not use this file except in compliance with the License. 6c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * You may obtain a copy of the License at 7c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * 8c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * http://www.apache.org/licenses/LICENSE-2.0 9c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * 10c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * Unless required by applicable law or agreed to in writing, software 11c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * distributed under the License is distributed on an "AS IS" BASIS, 12c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * See the License for the specific language governing permissions and 14c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou * limitations under the License. 15c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou */ 16c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 17a16e7b50f3148f581439509279f242092e254309ztenghuipackage com.android.camera.exif; 18c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 192bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log; 20c274ded801f745d6318186958107622e7a4fef33Ruben Brunk 21c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.io.IOException; 22c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.io.InputStream; 23c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.nio.ByteBuffer; 24c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.nio.ByteOrder; 25c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.util.ArrayList; 26c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.util.List; 27c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 28c274ded801f745d6318186958107622e7a4fef33Ruben Brunkclass ExifModifier { 292bca210e5fc8a77685775ffb403096167b017dceAngus Kong public static final Log.Tag TAG = new Log.Tag("ExifModifier"); 30c274ded801f745d6318186958107622e7a4fef33Ruben Brunk public static final boolean DEBUG = false; 31c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private final ByteBuffer mByteBuffer; 32c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private final ExifData mTagToModified; 33c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>(); 34c274ded801f745d6318186958107622e7a4fef33Ruben Brunk private final ExifInterface mInterface; 35c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private int mOffsetBase; 36c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 37c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private static class TagOffset { 38c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou final int mOffset; 39c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou final ExifTag mTag; 40c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 41c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou TagOffset(ExifTag tag, int offset) { 42c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTag = tag; 43c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mOffset = offset; 44c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 45c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 46c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 47c274ded801f745d6318186958107622e7a4fef33Ruben Brunk protected ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef) throws IOException, 48c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifInvalidFormatException { 49c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer = byteBuffer; 50c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mOffsetBase = byteBuffer.position(); 51c274ded801f745d6318186958107622e7a4fef33Ruben Brunk mInterface = iRef; 52c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou InputStream is = null; 53c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou try { 54c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou is = new ByteBufferInputStream(byteBuffer); 55c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou // Do not require any IFD; 56c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifParser parser = ExifParser.parse(is, mInterface); 57c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified = new ExifData(parser.getByteOrder()); 58c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mOffsetBase += parser.getTiffStartPosition(); 59c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.position(0); 60c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } finally { 61c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifInterface.closeSilently(is); 62c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 63c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 64c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 65c274ded801f745d6318186958107622e7a4fef33Ruben Brunk protected ByteOrder getByteOrder() { 66c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou return mTagToModified.getByteOrder(); 67c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 68c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 69c274ded801f745d6318186958107622e7a4fef33Ruben Brunk protected boolean commit() throws IOException, ExifInvalidFormatException { 70c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou InputStream is = null; 71c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou try { 72c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou is = new ByteBufferInputStream(mByteBuffer); 73c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou int flag = 0; 74c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou IfdData[] ifdDatas = new IfdData[] { 75c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_0), 76c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_1), 77c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF), 78c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY), 79c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS) 80c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou }; 81c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 82c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifdDatas[IfdId.TYPE_IFD_0] != null) { 83c274ded801f745d6318186958107622e7a4fef33Ruben Brunk flag |= ExifParser.OPTION_IFD_0; 84c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 85c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifdDatas[IfdId.TYPE_IFD_1] != null) { 86c274ded801f745d6318186958107622e7a4fef33Ruben Brunk flag |= ExifParser.OPTION_IFD_1; 87c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 88c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) { 89c274ded801f745d6318186958107622e7a4fef33Ruben Brunk flag |= ExifParser.OPTION_IFD_EXIF; 90c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 91c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) { 92c274ded801f745d6318186958107622e7a4fef33Ruben Brunk flag |= ExifParser.OPTION_IFD_GPS; 93c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 94c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) { 95c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou flag |= ExifParser.OPTION_IFD_INTEROPERABILITY; 96c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 97c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 98c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifParser parser = ExifParser.parse(is, flag, mInterface); 99c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou int event = parser.next(); 100c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou IfdData currIfd = null; 101c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou while (event != ExifParser.EVENT_END) { 102c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou switch (event) { 103c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifParser.EVENT_START_OF_IFD: 104c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou currIfd = ifdDatas[parser.getCurrentIfd()]; 105c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (currIfd == null) { 106c274ded801f745d6318186958107622e7a4fef33Ruben Brunk parser.skipRemainingTagsInCurrentIfd(); 107c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 108c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 109c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifParser.EVENT_NEW_TAG: 110c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou ExifTag oldTag = parser.getTag(); 111c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou ExifTag newTag = currIfd.getTag(oldTag.getTagId()); 112c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (newTag != null) { 113c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (newTag.getComponentCount() != oldTag.getComponentCount() 114c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou || newTag.getDataType() != oldTag.getDataType()) { 115c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou return false; 116c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } else { 117c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset())); 118c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou currIfd.removeTag(oldTag.getTagId()); 119c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (currIfd.getTagCount() == 0) { 120c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou parser.skipRemainingTagsInCurrentIfd(); 121c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 122c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 123c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 124c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 125c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 126c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou event = parser.next(); 127c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 128c274ded801f745d6318186958107622e7a4fef33Ruben Brunk for (IfdData ifd : ifdDatas) { 129c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifd != null && ifd.getTagCount() > 0) { 130c274ded801f745d6318186958107622e7a4fef33Ruben Brunk return false; 131c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 132c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 133c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou modify(); 134c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } finally { 135c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifInterface.closeSilently(is); 136c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 137c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou return true; 138c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 139c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 140c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private void modify() { 141c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.order(getByteOrder()); 142c274ded801f745d6318186958107622e7a4fef33Ruben Brunk for (TagOffset tagOffset : mTagOffsets) { 143c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou writeTagValue(tagOffset.mTag, tagOffset.mOffset); 144c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 145c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 146c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 147c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private void writeTagValue(ExifTag tag, int offset) { 148c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (DEBUG) { 149c274ded801f745d6318186958107622e7a4fef33Ruben Brunk Log.v(TAG, "modifying tag to: \n" + tag.toString()); 150c274ded801f745d6318186958107622e7a4fef33Ruben Brunk Log.v(TAG, "at offset: " + offset); 151c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 152c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.position(offset + mOffsetBase); 153c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou switch (tag.getDataType()) { 154c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_ASCII: 155c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou byte buf[] = tag.getStringByte(); 156c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (buf.length == tag.getComponentCount()) { 157c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou buf[buf.length - 1] = 0; 158c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.put(buf); 159c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } else { 160c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.put(buf); 161c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.put((byte) 0); 162c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 163c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 164c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_LONG: 165c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNSIGNED_LONG: 166c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou for (int i = 0, n = tag.getComponentCount(); i < n; i++) { 167c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.putInt((int) tag.getValueAt(i)); 168c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 169c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 170c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_RATIONAL: 171c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNSIGNED_RATIONAL: 172c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou for (int i = 0, n = tag.getComponentCount(); i < n; i++) { 173c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou Rational v = tag.getRational(i); 174c274ded801f745d6318186958107622e7a4fef33Ruben Brunk mByteBuffer.putInt((int) v.getNumerator()); 175c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.putInt((int) v.getDenominator()); 176c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 177c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 178c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNDEFINED: 179c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNSIGNED_BYTE: 180c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou buf = new byte[tag.getComponentCount()]; 181c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou tag.getBytes(buf); 182c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.put(buf); 183c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 184c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNSIGNED_SHORT: 185c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou for (int i = 0, n = tag.getComponentCount(); i < n; i++) { 186c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.putShort((short) tag.getValueAt(i)); 187c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 188c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 189c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 190c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 191c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 192c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou public void modifyTag(ExifTag tag) { 193c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.addTag(tag); 194c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 195c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou} 196