ExifModifier.java revision c274ded801f745d6318186958107622e7a4fef33
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 17c06c8045b159d68f8fda051d59a0eb82215067eeEarl Oupackage com.android.gallery3d.exif; 18c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 19c274ded801f745d6318186958107622e7a4fef33Ruben Brunkimport android.util.Log; 20c274ded801f745d6318186958107622e7a4fef33Ruben Brunk 21c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.io.Closeable; 22c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.io.IOException; 23c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.io.InputStream; 24c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.nio.ByteBuffer; 25c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.nio.ByteOrder; 26c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.util.ArrayList; 27c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ouimport java.util.List; 28c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 29c274ded801f745d6318186958107622e7a4fef33Ruben Brunkclass ExifModifier { 30c274ded801f745d6318186958107622e7a4fef33Ruben Brunk public static final String TAG = "ExifModifier"; 31c274ded801f745d6318186958107622e7a4fef33Ruben Brunk public static final boolean DEBUG = false; 32c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private final ByteBuffer mByteBuffer; 33c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private final ExifData mTagToModified; 34c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>(); 35c274ded801f745d6318186958107622e7a4fef33Ruben Brunk private final ExifInterface mInterface; 36c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private int mOffsetBase; 37c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 38c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private static class TagOffset { 39c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou final int mOffset; 40c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou final ExifTag mTag; 41c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 42c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou TagOffset(ExifTag tag, int offset) { 43c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTag = tag; 44c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mOffset = offset; 45c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 46c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 47c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 48c274ded801f745d6318186958107622e7a4fef33Ruben Brunk protected ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef) throws IOException, 49c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifInvalidFormatException { 50c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer = byteBuffer; 51c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mOffsetBase = byteBuffer.position(); 52c274ded801f745d6318186958107622e7a4fef33Ruben Brunk mInterface = iRef; 53c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou InputStream is = null; 54c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou try { 55c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou is = new ByteBufferInputStream(byteBuffer); 56c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou // Do not require any IFD; 57c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifParser parser = ExifParser.parse(is, mInterface); 58c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified = new ExifData(parser.getByteOrder()); 59c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mOffsetBase += parser.getTiffStartPosition(); 60c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.position(0); 61c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } finally { 62c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifInterface.closeSilently(is); 63c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 64c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 65c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 66c274ded801f745d6318186958107622e7a4fef33Ruben Brunk protected ByteOrder getByteOrder() { 67c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou return mTagToModified.getByteOrder(); 68c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 69c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 70c274ded801f745d6318186958107622e7a4fef33Ruben Brunk protected boolean commit() throws IOException, ExifInvalidFormatException { 71c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou InputStream is = null; 72c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou try { 73c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou is = new ByteBufferInputStream(mByteBuffer); 74c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou int flag = 0; 75c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou IfdData[] ifdDatas = new IfdData[] { 76c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_0), 77c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_1), 78c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF), 79c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY), 80c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS) 81c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou }; 82c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 83c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifdDatas[IfdId.TYPE_IFD_0] != null) { 84c274ded801f745d6318186958107622e7a4fef33Ruben Brunk flag |= ExifParser.OPTION_IFD_0; 85c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 86c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifdDatas[IfdId.TYPE_IFD_1] != null) { 87c274ded801f745d6318186958107622e7a4fef33Ruben Brunk flag |= ExifParser.OPTION_IFD_1; 88c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 89c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) { 90c274ded801f745d6318186958107622e7a4fef33Ruben Brunk flag |= ExifParser.OPTION_IFD_EXIF; 91c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 92c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) { 93c274ded801f745d6318186958107622e7a4fef33Ruben Brunk flag |= ExifParser.OPTION_IFD_GPS; 94c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 95c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) { 96c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou flag |= ExifParser.OPTION_IFD_INTEROPERABILITY; 97c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 98c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 99c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifParser parser = ExifParser.parse(is, flag, mInterface); 100c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou int event = parser.next(); 101c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou IfdData currIfd = null; 102c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou while (event != ExifParser.EVENT_END) { 103c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou switch (event) { 104c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifParser.EVENT_START_OF_IFD: 105c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou currIfd = ifdDatas[parser.getCurrentIfd()]; 106c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (currIfd == null) { 107c274ded801f745d6318186958107622e7a4fef33Ruben Brunk parser.skipRemainingTagsInCurrentIfd(); 108c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 109c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 110c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifParser.EVENT_NEW_TAG: 111c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou ExifTag oldTag = parser.getTag(); 112c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou ExifTag newTag = currIfd.getTag(oldTag.getTagId()); 113c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (newTag != null) { 114c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (newTag.getComponentCount() != oldTag.getComponentCount() 115c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou || newTag.getDataType() != oldTag.getDataType()) { 116c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou return false; 117c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } else { 118c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset())); 119c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou currIfd.removeTag(oldTag.getTagId()); 120c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (currIfd.getTagCount() == 0) { 121c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou parser.skipRemainingTagsInCurrentIfd(); 122c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 123c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 124c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 125c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 126c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 127c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou event = parser.next(); 128c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 129c274ded801f745d6318186958107622e7a4fef33Ruben Brunk for (IfdData ifd : ifdDatas) { 130c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (ifd != null && ifd.getTagCount() > 0) { 131c274ded801f745d6318186958107622e7a4fef33Ruben Brunk return false; 132c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 133c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 134c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou modify(); 135c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } finally { 136c274ded801f745d6318186958107622e7a4fef33Ruben Brunk ExifInterface.closeSilently(is); 137c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 138c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou return true; 139c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 140c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 141c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private void modify() { 142c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.order(getByteOrder()); 143c274ded801f745d6318186958107622e7a4fef33Ruben Brunk for (TagOffset tagOffset : mTagOffsets) { 144c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou writeTagValue(tagOffset.mTag, tagOffset.mOffset); 145c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 146c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 147c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 148c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou private void writeTagValue(ExifTag tag, int offset) { 149c274ded801f745d6318186958107622e7a4fef33Ruben Brunk if (DEBUG) { 150c274ded801f745d6318186958107622e7a4fef33Ruben Brunk Log.v(TAG, "modifying tag to: \n" + tag.toString()); 151c274ded801f745d6318186958107622e7a4fef33Ruben Brunk Log.v(TAG, "at offset: " + offset); 152c274ded801f745d6318186958107622e7a4fef33Ruben Brunk } 153c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.position(offset + mOffsetBase); 154c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou switch (tag.getDataType()) { 155c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_ASCII: 156c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou byte buf[] = tag.getStringByte(); 157c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou if (buf.length == tag.getComponentCount()) { 158c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou buf[buf.length - 1] = 0; 159c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.put(buf); 160c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } else { 161c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.put(buf); 162c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.put((byte) 0); 163c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 164c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 165c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_LONG: 166c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNSIGNED_LONG: 167c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou for (int i = 0, n = tag.getComponentCount(); i < n; i++) { 168c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.putInt((int) tag.getValueAt(i)); 169c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 170c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 171c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_RATIONAL: 172c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNSIGNED_RATIONAL: 173c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou for (int i = 0, n = tag.getComponentCount(); i < n; i++) { 174c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou Rational v = tag.getRational(i); 175c274ded801f745d6318186958107622e7a4fef33Ruben Brunk mByteBuffer.putInt((int) v.getNumerator()); 176c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.putInt((int) v.getDenominator()); 177c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 178c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 179c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNDEFINED: 180c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNSIGNED_BYTE: 181c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou buf = new byte[tag.getComponentCount()]; 182c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou tag.getBytes(buf); 183c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.put(buf); 184c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 185c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou case ExifTag.TYPE_UNSIGNED_SHORT: 186c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou for (int i = 0, n = tag.getComponentCount(); i < n; i++) { 187c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mByteBuffer.putShort((short) tag.getValueAt(i)); 188c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 189c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou break; 190c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 191c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 192c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou 193c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou public void modifyTag(ExifTag tag) { 194c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou mTagToModified.addTag(tag); 195c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou } 196c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou} 197