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 getOrientation(byte[] jpeg)24 public static int getOrientation(byte[] jpeg) { 25 if (jpeg == null) { 26 return 0; 27 } 28 29 int offset = 0; 30 int length = 0; 31 32 // ISO/IEC 10918-1:1993(E) 33 while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) { 34 int marker = jpeg[offset] & 0xFF; 35 36 // Check if the marker is a padding. 37 if (marker == 0xFF) { 38 continue; 39 } 40 offset++; 41 42 // Check if the marker is SOI or TEM. 43 if (marker == 0xD8 || marker == 0x01) { 44 continue; 45 } 46 // Check if the marker is EOI or SOS. 47 if (marker == 0xD9 || marker == 0xDA) { 48 break; 49 } 50 51 // Get the length and check if it is reasonable. 52 length = pack(jpeg, offset, 2, false); 53 if (length < 2 || offset + length > jpeg.length) { 54 Log.e(TAG, "Invalid length"); 55 return 0; 56 } 57 58 // Break if the marker is EXIF in APP1. 59 if (marker == 0xE1 && length >= 8 && 60 pack(jpeg, offset + 2, 4, false) == 0x45786966 && 61 pack(jpeg, offset + 6, 2, false) == 0) { 62 offset += 8; 63 length -= 8; 64 break; 65 } 66 67 // Skip other markers. 68 offset += length; 69 length = 0; 70 } 71 72 // JEITA CP-3451 Exif Version 2.2 73 if (length > 8) { 74 // Identify the byte order. 75 int tag = pack(jpeg, offset, 4, false); 76 if (tag != 0x49492A00 && tag != 0x4D4D002A) { 77 Log.e(TAG, "Invalid byte order"); 78 return 0; 79 } 80 boolean littleEndian = (tag == 0x49492A00); 81 82 // Get the offset and check if it is reasonable. 83 int count = pack(jpeg, offset + 4, 4, littleEndian) + 2; 84 if (count < 10 || count > length) { 85 Log.e(TAG, "Invalid offset"); 86 return 0; 87 } 88 offset += count; 89 length -= count; 90 91 // Get the count and go through all the elements. 92 count = pack(jpeg, offset - 2, 2, littleEndian); 93 while (count-- > 0 && length >= 12) { 94 // Get the tag and check if it is orientation. 95 tag = pack(jpeg, offset, 2, littleEndian); 96 if (tag == 0x0112) { 97 // We do not really care about type and count, do we? 98 int orientation = pack(jpeg, offset + 8, 2, littleEndian); 99 switch (orientation) { 100 case 1: 101 return 0; 102 case 3: 103 return 180; 104 case 6: 105 return 90; 106 case 8: 107 return 270; 108 } 109 Log.i(TAG, "Unsupported orientation"); 110 return 0; 111 } 112 offset += 12; 113 length -= 12; 114 } 115 } 116 117 Log.i(TAG, "Orientation not found"); 118 return 0; 119 } 120 pack(byte[] bytes, int offset, int length, boolean littleEndian)121 private static int pack(byte[] bytes, int offset, int length, 122 boolean littleEndian) { 123 int step = 1; 124 if (littleEndian) { 125 offset += length - 1; 126 step = -1; 127 } 128 129 int value = 0; 130 while (length-- > 0) { 131 value = (value << 8) | (bytes[offset] & 0xFF); 132 offset += step; 133 } 134 return value; 135 } 136 } 137