• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.gallery3d.data;
18 
19 import android.util.Log;
20 
21 import java.io.IOException;
22 import java.io.InputStream;
23 
24 public class Exif {
25     private static final String TAG = "CameraExif";
26 
getOrientation(InputStream is)27     public static int getOrientation(InputStream is) {
28         if (is == null) {
29             return 0;
30         }
31 
32         byte[] buf = new byte[8];
33         int length = 0;
34 
35         // ISO/IEC 10918-1:1993(E)
36         while (read(is, buf, 2) && (buf[0] & 0xFF) == 0xFF) {
37             int marker = buf[1] & 0xFF;
38 
39             // Check if the marker is a padding.
40             if (marker == 0xFF) {
41                 continue;
42             }
43 
44             // Check if the marker is SOI or TEM.
45             if (marker == 0xD8 || marker == 0x01) {
46                 continue;
47             }
48             // Check if the marker is EOI or SOS.
49             if (marker == 0xD9 || marker == 0xDA) {
50                 return 0;
51             }
52 
53             // Get the length and check if it is reasonable.
54             if (!read(is, buf, 2)) {
55                 return 0;
56             }
57             length = pack(buf, 0, 2, false);
58             if (length < 2) {
59                 Log.e(TAG, "Invalid length");
60                 return 0;
61             }
62             length -= 2;
63 
64             // Break if the marker is EXIF in APP1.
65             if (marker == 0xE1 && length >= 6) {
66                 if (!read(is, buf, 6)) return 0;
67                 length -= 6;
68                 if (pack(buf, 0, 4, false) == 0x45786966 &&
69                     pack(buf, 4, 2, false) == 0) {
70                     break;
71                 }
72             }
73 
74             // Skip other markers.
75             try {
76                 is.skip(length);
77             } catch (IOException ex) {
78                 return 0;
79             }
80             length = 0;
81         }
82 
83         // JEITA CP-3451 Exif Version 2.2
84         if (length > 8) {
85             int offset = 0;
86             byte[] jpeg = new byte[length];
87             if (!read(is, jpeg, length)) {
88                 return 0;
89             }
90 
91             // Identify the byte order.
92             int tag = pack(jpeg, offset, 4, false);
93             if (tag != 0x49492A00 && tag != 0x4D4D002A) {
94                 Log.e(TAG, "Invalid byte order");
95                 return 0;
96             }
97             boolean littleEndian = (tag == 0x49492A00);
98 
99             // Get the offset and check if it is reasonable.
100             int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
101             if (count < 10 || count > length) {
102                 Log.e(TAG, "Invalid offset");
103                 return 0;
104             }
105             offset += count;
106             length -= count;
107 
108             // Get the count and go through all the elements.
109             count = pack(jpeg, offset - 2, 2, littleEndian);
110             while (count-- > 0 && length >= 12) {
111                 // Get the tag and check if it is orientation.
112                 tag = pack(jpeg, offset, 2, littleEndian);
113                 if (tag == 0x0112) {
114                     // We do not really care about type and count, do we?
115                     int orientation = pack(jpeg, offset + 8, 2, littleEndian);
116                     switch (orientation) {
117                         case 1:
118                             return 0;
119                         case 3:
120                             return 180;
121                         case 6:
122                             return 90;
123                         case 8:
124                             return 270;
125                     }
126                     Log.i(TAG, "Unsupported orientation");
127                     return 0;
128                 }
129                 offset += 12;
130                 length -= 12;
131             }
132         }
133 
134         Log.i(TAG, "Orientation not found");
135         return 0;
136     }
137 
pack(byte[] bytes, int offset, int length, boolean littleEndian)138     private static int pack(byte[] bytes, int offset, int length,
139             boolean littleEndian) {
140         int step = 1;
141         if (littleEndian) {
142             offset += length - 1;
143             step = -1;
144         }
145 
146         int value = 0;
147         while (length-- > 0) {
148             value = (value << 8) | (bytes[offset] & 0xFF);
149             offset += step;
150         }
151         return value;
152     }
153 
read(InputStream is, byte[] buf, int length)154     private static boolean read(InputStream is, byte[] buf, int length) {
155         try {
156             return is.read(buf, 0, length) == length;
157         } catch (IOException ex) {
158             return false;
159         }
160     }
161 }
162