193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/* 293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Copyright (C) 2013 The Android Open Source Project 393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Licensed under the Apache License, Version 2.0 (the "License"); 593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * you may not use this file except in compliance with the License. 693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * You may obtain a copy of the License at 793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * http://www.apache.org/licenses/LICENSE-2.0 993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 1093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Unless required by applicable law or agreed to in writing, software 1193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * distributed under the License is distributed on an "AS IS" BASIS, 1293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * See the License for the specific language governing permissions and 1493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * limitations under the License. 1593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 1693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpackage com.android.bitmap.util; 1893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.Log; 2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.io.ByteArrayInputStream; 2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport java.io.InputStream; 2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/** 2593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * TODO 2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Exif and InputStreamBuffer were pulled in from frameworks/ex/photo, and should be part of a 2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * separate library that is used by both this and chips. 2893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpublic class Exif { 3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static final String TAG = Exif.class.getSimpleName(); 3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Returns the degrees in clockwise. Values are 0, 90, 180, or 270. 3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param inputStream The input stream will not be closed for you. 3593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @param byteSize Recommended parameter declaring the length of the input stream. If you 3693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * pass in -1, we will have to read more from the input stream. 3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @return 0, 90, 180, or 270. 3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public static int getOrientation(final InputStream inputStream, final long byteSize) { 4093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (inputStream == null) { 4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 0; 4293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /* 4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Looking at this algorithm, we never look ahead more than 8 bytes. As long as we call 4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein advanceTo() at the end of every loop, we should never have to reallocate a larger buffer. 4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Also, the most we ever read backwards is 4 bytes. pack() reads backwards if the encoding 4993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein is in little endian format. These following two lines potentially reads 4 bytes backwards: 5093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int tag = pack(jpeg, offset, 4, false); 5293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein count = pack(jpeg, offset - 2, 2, littleEndian); 5393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein To be safe, we will always advance to some index-4, so we'll need 4 more for the +8 5593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein look ahead, which makes it a +12 look ahead total. Use 16 just in case my analysis is off. 5693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein This means we only need to allocate a single 16 byte buffer. 5893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Note: If you do not pass in byteSize parameter, a single large allocation will occur. 6093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein For a 1MB image, I see one 30KB allocation. This is due to the line containing: 6193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein has(jpeg, byteSize, offset + length - 1) 6393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 6493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein where length is a variable int (around 30KB above) read from the EXIF headers. 6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 6693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein This is still much better than allocating a 1MB byte[] which we were doing before. 6793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 6893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int lookAhead = 16; 7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int readBackwards = 4; 7193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final InputStreamBuffer jpeg = new InputStreamBuffer(inputStream, lookAhead, false); 7293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 7393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int offset = 0; 7493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int length = 0; 7593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (has(jpeg, byteSize, 1)) { 7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // JPEG image files begin with FF D8. Only JPEG images have EXIF data. 7893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final boolean possibleJpegFormat = jpeg.get(0) == (byte) 0xFF 7993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein && jpeg.get(1) == (byte) 0xD8; 8093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (!possibleJpegFormat) { 8193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 0; 8293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 8393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 8493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 8593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // ISO/IEC 10918-1:1993(E) 8693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein while (has(jpeg, byteSize, offset + 3) && (jpeg.get(offset++) & 0xFF) == 0xFF) { 8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int marker = jpeg.get(offset) & 0xFF; 8893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 8993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Check if the marker is a padding. 9093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (marker == 0xFF) { 9193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein continue; 9293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 9393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein offset++; 9493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 9593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Check if the marker is SOI or TEM. 9693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (marker == 0xD8 || marker == 0x01) { 9793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein continue; 9893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 9993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Check if the marker is EOI or SOS. 10093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (marker == 0xD9 || marker == 0xDA) { 10193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Loop ends. 10293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein jpeg.advanceTo(offset - readBackwards); 10393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein break; 10493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 10593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Get the length and check if it is reasonable. 10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein length = pack(jpeg, offset, 2, false); 10893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (length < 2 || !has(jpeg, byteSize, offset + length - 1)) { 10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.e(TAG, "Invalid length"); 11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 0; 11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 11293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 11393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Break if the marker is EXIF in APP1. 11493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (marker == 0xE1 && length >= 8 && 11593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein pack(jpeg, offset + 2, 4, false) == 0x45786966 && 11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein pack(jpeg, offset + 6, 2, false) == 0) { 11793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein offset += 8; 11893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein length -= 8; 11993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Loop ends. 12093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein jpeg.advanceTo(offset - readBackwards); 12193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein break; 12293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 12493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Skip other markers. 12593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein offset += length; 12693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein length = 0; 12793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 12893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Loop ends. 12993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein jpeg.advanceTo(offset - readBackwards); 13093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 13193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 13293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // JEITA CP-3451 Exif Version 2.2 13393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (length > 8) { 13493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Identify the byte order. 13593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int tag = pack(jpeg, offset, 4, false); 13693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (tag != 0x49492A00 && tag != 0x4D4D002A) { 13793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.e(TAG, "Invalid byte order"); 13893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 0; 13993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 14093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final boolean littleEndian = (tag == 0x49492A00); 14193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 14293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Get the offset and check if it is reasonable. 14393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int count = pack(jpeg, offset + 4, 4, littleEndian) + 2; 14493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (count < 10 || count > length) { 14593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.e(TAG, "Invalid offset"); 14693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 0; 14793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 14893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein offset += count; 14993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein length -= count; 15093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 15193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Offset has changed significantly. 15293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein jpeg.advanceTo(offset - readBackwards); 15393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 15493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Get the count and go through all the elements. 15593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein count = pack(jpeg, offset - 2, 2, littleEndian); 15693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 15793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein while (count-- > 0 && length >= 12) { 15893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Get the tag and check if it is orientation. 15993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein tag = pack(jpeg, offset, 2, littleEndian); 16093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (tag == 0x0112) { 16193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // We do not really care about type and count, do we? 16293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int orientation = pack(jpeg, offset + 8, 2, littleEndian); 16393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein switch (orientation) { 16493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case 1: 16593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 0; 16693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case 3: 16793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 180; 16893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case 6: 16993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 90; 17093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case 8: 17193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 270; 17293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 17393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.i(TAG, "Unsupported orientation"); 17493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 0; 17593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 17693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein offset += 12; 17793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein length -= 12; 17893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 17993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Loop ends. 18093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein jpeg.advanceTo(offset - readBackwards); 18193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 18293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 18393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 18493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return 0; 18593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 18693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 18793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static int pack(final InputStreamBuffer bytes, int offset, int length, 18893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final boolean littleEndian) { 18993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int step = 1; 19093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (littleEndian) { 19193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein offset += length - 1; 19293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein step = -1; 19393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 19493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 19593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int value = 0; 19693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein while (length-- > 0) { 19793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein value = (value << 8) | (bytes.get(offset) & 0xFF); 19893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein offset += step; 19993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 20093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return value; 20193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 20293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 20393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static boolean has(final InputStreamBuffer jpeg, final long byteSize, final int index) { 20493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (byteSize >= 0) { 20593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return index < byteSize; 20693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 20793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // For large values of index, this will cause the internal buffer to resize. 20893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return jpeg.has(index); 20993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 21093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 21193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 21293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Deprecated 21393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public static int getOrientation(final byte[] jpeg) { 21493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return getOrientation(new ByteArrayInputStream(jpeg), jpeg.length); 21593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 21693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein}