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