19323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook/*
29323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * Copyright (C) 2010 The Android Open Source Project
39323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook *
49323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * Licensed under the Apache License, Version 2.0 (the "License");
59323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * you may not use this file except in compliance with the License.
69323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * You may obtain a copy of the License at
79323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook *
89323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook *      http://www.apache.org/licenses/LICENSE-2.0
99323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook *
109323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * Unless required by applicable law or agreed to in writing, software
119323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * distributed under the License is distributed on an "AS IS" BASIS,
129323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * See the License for the specific language governing permissions and
149323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook * limitations under the License.
159323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook */
169323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
179323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrookpackage com.android.ex.photo.util;
189323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
199323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrookimport android.util.Log;
209323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
219323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrookpublic class Exif {
229323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook    private static final String TAG = "CameraExif";
239323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
249323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook    // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
259323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook    public static int getOrientation(byte[] jpeg) {
269323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        if (jpeg == null) {
279323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            return 0;
289323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        }
299323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
309323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        int offset = 0;
319323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        int length = 0;
329323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
339323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        // ISO/IEC 10918-1:1993(E)
349323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
359323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            int marker = jpeg[offset] & 0xFF;
369323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
379323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Check if the marker is a padding.
389323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            if (marker == 0xFF) {
399323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                continue;
409323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            }
419323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            offset++;
429323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
439323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Check if the marker is SOI or TEM.
449323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            if (marker == 0xD8 || marker == 0x01) {
459323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                continue;
469323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            }
479323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Check if the marker is EOI or SOS.
489323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            if (marker == 0xD9 || marker == 0xDA) {
499323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                break;
509323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            }
519323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
529323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Get the length and check if it is reasonable.
539323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            length = pack(jpeg, offset, 2, false);
549323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            if (length < 2 || offset + length > jpeg.length) {
559323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                Log.e(TAG, "Invalid length");
569323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                return 0;
579323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            }
589323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
599323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Break if the marker is EXIF in APP1.
609323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            if (marker == 0xE1 && length >= 8 &&
619323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                    pack(jpeg, offset + 2, 4, false) == 0x45786966 &&
629323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                    pack(jpeg, offset + 6, 2, false) == 0) {
639323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                offset += 8;
649323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                length -= 8;
659323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                break;
669323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            }
679323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
689323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Skip other markers.
699323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            offset += length;
709323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            length = 0;
719323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        }
729323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
739323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        // JEITA CP-3451 Exif Version 2.2
749323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        if (length > 8) {
759323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Identify the byte order.
769323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            int tag = pack(jpeg, offset, 4, false);
779323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            if (tag != 0x49492A00 && tag != 0x4D4D002A) {
789323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                Log.e(TAG, "Invalid byte order");
799323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                return 0;
809323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            }
819323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            boolean littleEndian = (tag == 0x49492A00);
829323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
839323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Get the offset and check if it is reasonable.
849323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
859323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            if (count < 10 || count > length) {
869323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                Log.e(TAG, "Invalid offset");
879323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                return 0;
889323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            }
899323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            offset += count;
909323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            length -= count;
919323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
929323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            // Get the count and go through all the elements.
939323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            count = pack(jpeg, offset - 2, 2, littleEndian);
949323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            while (count-- > 0 && length >= 12) {
959323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                // Get the tag and check if it is orientation.
969323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                tag = pack(jpeg, offset, 2, littleEndian);
979323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                if (tag == 0x0112) {
989323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                    // We do not really care about type and count, do we?
999323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                    int orientation = pack(jpeg, offset + 8, 2, littleEndian);
1009323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                    switch (orientation) {
1019323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                        case 1:
1029323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                            return 0;
1039323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                        case 3:
1049323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                            return 180;
1059323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                        case 6:
1069323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                            return 90;
1079323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                        case 8:
1089323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                            return 270;
1099323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                    }
1109323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                    Log.i(TAG, "Unsupported orientation");
1119323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                    return 0;
1129323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                }
1139323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                offset += 12;
1149323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook                length -= 12;
1159323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            }
1169323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        }
1179323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
1189323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        Log.i(TAG, "Orientation not found");
1199323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        return 0;
1209323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook    }
1219323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
1229323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook    private static int pack(byte[] bytes, int offset, int length,
1239323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            boolean littleEndian) {
1249323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        int step = 1;
1259323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        if (littleEndian) {
1269323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            offset += length - 1;
1279323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            step = -1;
1289323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        }
1299323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook
1309323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        int value = 0;
1319323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        while (length-- > 0) {
1329323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            value = (value << 8) | (bytes[offset] & 0xFF);
1339323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook            offset += step;
1349323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        }
1359323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook        return value;
1369323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook    }
1379323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook}
138