15211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook/*
25211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * Copyright (C) 2010 The Android Open Source Project
35211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook *
45211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * Licensed under the Apache License, Version 2.0 (the "License");
55211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * you may not use this file except in compliance with the License.
65211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * You may obtain a copy of the License at
75211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook *
85211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook *      http://www.apache.org/licenses/LICENSE-2.0
95211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook *
105211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * Unless required by applicable law or agreed to in writing, software
115211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * distributed under the License is distributed on an "AS IS" BASIS,
125211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * See the License for the specific language governing permissions and
145211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook * limitations under the License.
155211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook */
165211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
175211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrookpackage com.android.ex.photo.util;
185211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
195211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrookimport android.util.Log;
205211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
215211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrookpublic class Exif {
225211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook    private static final String TAG = "CameraExif";
235211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
245211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook    // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
255211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook    public static int getOrientation(byte[] jpeg) {
265211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        if (jpeg == null) {
275211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            return 0;
285211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        }
295211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
305211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        int offset = 0;
315211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        int length = 0;
325211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
335211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        // ISO/IEC 10918-1:1993(E)
345211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
355211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            int marker = jpeg[offset] & 0xFF;
365211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
375211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Check if the marker is a padding.
385211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            if (marker == 0xFF) {
395211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                continue;
405211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            }
415211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            offset++;
425211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
435211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Check if the marker is SOI or TEM.
445211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            if (marker == 0xD8 || marker == 0x01) {
455211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                continue;
465211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            }
475211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Check if the marker is EOI or SOS.
485211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            if (marker == 0xD9 || marker == 0xDA) {
495211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                break;
505211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            }
515211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
525211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Get the length and check if it is reasonable.
535211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            length = pack(jpeg, offset, 2, false);
545211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            if (length < 2 || offset + length > jpeg.length) {
555211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                Log.e(TAG, "Invalid length");
565211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                return 0;
575211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            }
585211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
595211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Break if the marker is EXIF in APP1.
605211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            if (marker == 0xE1 && length >= 8 &&
615211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                    pack(jpeg, offset + 2, 4, false) == 0x45786966 &&
625211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                    pack(jpeg, offset + 6, 2, false) == 0) {
635211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                offset += 8;
645211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                length -= 8;
655211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                break;
665211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            }
675211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
685211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Skip other markers.
695211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            offset += length;
705211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            length = 0;
715211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        }
725211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
735211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        // JEITA CP-3451 Exif Version 2.2
745211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        if (length > 8) {
755211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Identify the byte order.
765211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            int tag = pack(jpeg, offset, 4, false);
775211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            if (tag != 0x49492A00 && tag != 0x4D4D002A) {
785211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                Log.e(TAG, "Invalid byte order");
795211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                return 0;
805211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            }
815211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            boolean littleEndian = (tag == 0x49492A00);
825211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
835211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Get the offset and check if it is reasonable.
845211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
855211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            if (count < 10 || count > length) {
865211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                Log.e(TAG, "Invalid offset");
875211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                return 0;
885211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            }
895211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            offset += count;
905211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            length -= count;
915211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
925211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            // Get the count and go through all the elements.
935211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            count = pack(jpeg, offset - 2, 2, littleEndian);
945211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            while (count-- > 0 && length >= 12) {
955211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                // Get the tag and check if it is orientation.
965211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                tag = pack(jpeg, offset, 2, littleEndian);
975211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                if (tag == 0x0112) {
985211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                    // We do not really care about type and count, do we?
995211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                    int orientation = pack(jpeg, offset + 8, 2, littleEndian);
1005211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                    switch (orientation) {
1015211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                        case 1:
1025211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                            return 0;
1035211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                        case 3:
1045211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                            return 180;
1055211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                        case 6:
1065211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                            return 90;
1075211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                        case 8:
1085211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                            return 270;
1095211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                    }
1105211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                    Log.i(TAG, "Unsupported orientation");
1115211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                    return 0;
1125211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                }
1135211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                offset += 12;
1145211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook                length -= 12;
1155211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            }
1165211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        }
1175211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
1185211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        Log.i(TAG, "Orientation not found");
1195211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        return 0;
1205211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook    }
1215211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
1225211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook    private static int pack(byte[] bytes, int offset, int length,
1235211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            boolean littleEndian) {
1245211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        int step = 1;
1255211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        if (littleEndian) {
1265211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            offset += length - 1;
1275211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            step = -1;
1285211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        }
1295211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook
1305211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        int value = 0;
1315211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        while (length-- > 0) {
1325211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            value = (value << 8) | (bytes[offset] & 0xFF);
1335211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook            offset += step;
1345211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        }
1355211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook        return value;
1365211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook    }
1375211e4682a26be787e60b1c56f56b113a2fac26cPaul Westbrook}
138