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