1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.camera; 18 19 import android.util.Log; 20 21 public class Exif { 22 private static final String TAG = "CameraExif"; 23 24 // Returns the degrees in clockwise. Values are 0, 90, 180, or 270. 25 public static int getOrientation(byte[] jpeg) { 26 if (jpeg == null) { 27 return 0; 28 } 29 30 int offset = 0; 31 int length = 0; 32 33 // ISO/IEC 10918-1:1993(E) 34 while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) { 35 int marker = jpeg[offset] & 0xFF; 36 37 // Check if the marker is a padding. 38 if (marker == 0xFF) { 39 continue; 40 } 41 offset++; 42 43 // Check if the marker is SOI or TEM. 44 if (marker == 0xD8 || marker == 0x01) { 45 continue; 46 } 47 // Check if the marker is EOI or SOS. 48 if (marker == 0xD9 || marker == 0xDA) { 49 break; 50 } 51 52 // Get the length and check if it is reasonable. 53 length = pack(jpeg, offset, 2, false); 54 if (length < 2 || offset + length > jpeg.length) { 55 Log.e(TAG, "Invalid length"); 56 return 0; 57 } 58 59 // Break if the marker is EXIF in APP1. 60 if (marker == 0xE1 && length >= 8 && 61 pack(jpeg, offset + 2, 4, false) == 0x45786966 && 62 pack(jpeg, offset + 6, 2, false) == 0) { 63 offset += 8; 64 length -= 8; 65 break; 66 } 67 68 // Skip other markers. 69 offset += length; 70 length = 0; 71 } 72 73 // JEITA CP-3451 Exif Version 2.2 74 if (length > 8) { 75 // Identify the byte order. 76 int tag = pack(jpeg, offset, 4, false); 77 if (tag != 0x49492A00 && tag != 0x4D4D002A) { 78 Log.e(TAG, "Invalid byte order"); 79 return 0; 80 } 81 boolean littleEndian = (tag == 0x49492A00); 82 83 // Get the offset and check if it is reasonable. 84 int count = pack(jpeg, offset + 4, 4, littleEndian) + 2; 85 if (count < 10 || count > length) { 86 Log.e(TAG, "Invalid offset"); 87 return 0; 88 } 89 offset += count; 90 length -= count; 91 92 // Get the count and go through all the elements. 93 count = pack(jpeg, offset - 2, 2, littleEndian); 94 while (count-- > 0 && length >= 12) { 95 // Get the tag and check if it is orientation. 96 tag = pack(jpeg, offset, 2, littleEndian); 97 if (tag == 0x0112) { 98 // We do not really care about type and count, do we? 99 int orientation = pack(jpeg, offset + 8, 2, littleEndian); 100 switch (orientation) { 101 case 1: 102 return 0; 103 case 3: 104 return 180; 105 case 6: 106 return 90; 107 case 8: 108 return 270; 109 } 110 Log.i(TAG, "Unsupported orientation"); 111 return 0; 112 } 113 offset += 12; 114 length -= 12; 115 } 116 } 117 118 Log.i(TAG, "Orientation not found"); 119 return 0; 120 } 121 122 private static int pack(byte[] bytes, int offset, int length, 123 boolean littleEndian) { 124 int step = 1; 125 if (littleEndian) { 126 offset += length - 1; 127 step = -1; 128 } 129 130 int value = 0; 131 while (length-- > 0) { 132 value = (value << 8) | (bytes[offset] & 0xFF); 133 offset += step; 134 } 135 return value; 136 } 137 } 138