196 lines
7.2 KiB
Java
196 lines
7.2 KiB
Java
/*
|
|
* 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.IOException;
|
|
import java.io.InputStream;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
class ExifModifier {
|
|
public static final String TAG = "ExifModifier";
|
|
public static final boolean DEBUG = false;
|
|
private final ByteBuffer mByteBuffer;
|
|
private final ExifData mTagToModified;
|
|
private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>();
|
|
private final ExifInterface mInterface;
|
|
private int mOffsetBase;
|
|
|
|
private static class TagOffset {
|
|
final int mOffset;
|
|
final ExifTag mTag;
|
|
|
|
TagOffset(ExifTag tag, int offset) {
|
|
mTag = tag;
|
|
mOffset = offset;
|
|
}
|
|
}
|
|
|
|
protected ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef) throws IOException,
|
|
ExifInvalidFormatException {
|
|
mByteBuffer = byteBuffer;
|
|
mOffsetBase = byteBuffer.position();
|
|
mInterface = iRef;
|
|
InputStream is = null;
|
|
try {
|
|
is = new ByteBufferInputStream(byteBuffer);
|
|
// Do not require any IFD;
|
|
ExifParser parser = ExifParser.parse(is, mInterface);
|
|
mTagToModified = new ExifData(parser.getByteOrder());
|
|
mOffsetBase += parser.getTiffStartPosition();
|
|
mByteBuffer.position(0);
|
|
} finally {
|
|
ExifInterface.closeSilently(is);
|
|
}
|
|
}
|
|
|
|
protected ByteOrder getByteOrder() {
|
|
return mTagToModified.getByteOrder();
|
|
}
|
|
|
|
protected boolean commit() throws IOException, ExifInvalidFormatException {
|
|
InputStream is = null;
|
|
try {
|
|
is = new ByteBufferInputStream(mByteBuffer);
|
|
int flag = 0;
|
|
IfdData[] ifdDatas = new IfdData[] {
|
|
mTagToModified.getIfdData(IfdId.TYPE_IFD_0),
|
|
mTagToModified.getIfdData(IfdId.TYPE_IFD_1),
|
|
mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF),
|
|
mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY),
|
|
mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS)
|
|
};
|
|
|
|
if (ifdDatas[IfdId.TYPE_IFD_0] != null) {
|
|
flag |= ExifParser.OPTION_IFD_0;
|
|
}
|
|
if (ifdDatas[IfdId.TYPE_IFD_1] != null) {
|
|
flag |= ExifParser.OPTION_IFD_1;
|
|
}
|
|
if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) {
|
|
flag |= ExifParser.OPTION_IFD_EXIF;
|
|
}
|
|
if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) {
|
|
flag |= ExifParser.OPTION_IFD_GPS;
|
|
}
|
|
if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) {
|
|
flag |= ExifParser.OPTION_IFD_INTEROPERABILITY;
|
|
}
|
|
|
|
ExifParser parser = ExifParser.parse(is, flag, mInterface);
|
|
int event = parser.next();
|
|
IfdData currIfd = null;
|
|
while (event != ExifParser.EVENT_END) {
|
|
switch (event) {
|
|
case ExifParser.EVENT_START_OF_IFD:
|
|
currIfd = ifdDatas[parser.getCurrentIfd()];
|
|
if (currIfd == null) {
|
|
parser.skipRemainingTagsInCurrentIfd();
|
|
}
|
|
break;
|
|
case ExifParser.EVENT_NEW_TAG:
|
|
ExifTag oldTag = parser.getTag();
|
|
ExifTag newTag = currIfd.getTag(oldTag.getTagId());
|
|
if (newTag != null) {
|
|
if (newTag.getComponentCount() != oldTag.getComponentCount()
|
|
|| newTag.getDataType() != oldTag.getDataType()) {
|
|
return false;
|
|
} else {
|
|
mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset()));
|
|
currIfd.removeTag(oldTag.getTagId());
|
|
if (currIfd.getTagCount() == 0) {
|
|
parser.skipRemainingTagsInCurrentIfd();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
event = parser.next();
|
|
}
|
|
for (IfdData ifd : ifdDatas) {
|
|
if (ifd != null && ifd.getTagCount() > 0) {
|
|
return false;
|
|
}
|
|
}
|
|
modify();
|
|
} finally {
|
|
ExifInterface.closeSilently(is);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void modify() {
|
|
mByteBuffer.order(getByteOrder());
|
|
for (TagOffset tagOffset : mTagOffsets) {
|
|
writeTagValue(tagOffset.mTag, tagOffset.mOffset);
|
|
}
|
|
}
|
|
|
|
private void writeTagValue(ExifTag tag, int offset) {
|
|
if (DEBUG) {
|
|
Log.v(TAG, "modifying tag to: \n" + tag.toString());
|
|
Log.v(TAG, "at offset: " + offset);
|
|
}
|
|
mByteBuffer.position(offset + mOffsetBase);
|
|
switch (tag.getDataType()) {
|
|
case ExifTag.TYPE_ASCII:
|
|
byte buf[] = tag.getStringByte();
|
|
if (buf.length == tag.getComponentCount()) {
|
|
buf[buf.length - 1] = 0;
|
|
mByteBuffer.put(buf);
|
|
} else {
|
|
mByteBuffer.put(buf);
|
|
mByteBuffer.put((byte) 0);
|
|
}
|
|
break;
|
|
case ExifTag.TYPE_LONG:
|
|
case ExifTag.TYPE_UNSIGNED_LONG:
|
|
for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
|
|
mByteBuffer.putInt((int) tag.getValueAt(i));
|
|
}
|
|
break;
|
|
case ExifTag.TYPE_RATIONAL:
|
|
case ExifTag.TYPE_UNSIGNED_RATIONAL:
|
|
for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
|
|
Rational v = tag.getRational(i);
|
|
mByteBuffer.putInt((int) v.getNumerator());
|
|
mByteBuffer.putInt((int) v.getDenominator());
|
|
}
|
|
break;
|
|
case ExifTag.TYPE_UNDEFINED:
|
|
case ExifTag.TYPE_UNSIGNED_BYTE:
|
|
buf = new byte[tag.getComponentCount()];
|
|
tag.getBytes(buf);
|
|
mByteBuffer.put(buf);
|
|
break;
|
|
case ExifTag.TYPE_UNSIGNED_SHORT:
|
|
for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
|
|
mByteBuffer.putShort((short) tag.getValueAt(i));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void modifyTag(ExifTag tag) {
|
|
mTagToModified.addTag(tag);
|
|
}
|
|
}
|