ExifInterface.java revision 872a30ec723ebdd97de764406544516545d7c9d4
120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync/* 220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * Copyright (C) 2007 The Android Open Source Project 320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * Licensed under the Apache License, Version 2.0 (the "License"); 520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * you may not use this file except in compliance with the License. 620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * You may obtain a copy of the License at 720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * http://www.apache.org/licenses/LICENSE-2.0 920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 1020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * Unless required by applicable law or agreed to in writing, software 1120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * distributed under the License is distributed on an "AS IS" BASIS, 1220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * See the License for the specific language governing permissions and 1420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * limitations under the License. 1520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync */ 1620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo syncpackage android.media; 1820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 19700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Changimport java.io.IOException; 20099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Changimport java.text.ParsePosition; 21099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Changimport java.text.SimpleDateFormat; 22099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Changimport java.util.Date; 2320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo syncimport java.util.HashMap; 2420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo syncimport java.util.Map; 2520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 2620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync/** 27700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * This is a class for reading and writing Exif tags in a JPEG file. 2820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync */ 2920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo syncpublic class ExifInterface { 3020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // The Exif tag names 3220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_ORIENTATION = "Orientation"; 33099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang public static final String TAG_DATETIME = "DateTime"; 3420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_MAKE = "Make"; 3520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_MODEL = "Model"; 3620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_FLASH = "Flash"; 3720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_IMAGE_WIDTH = "ImageWidth"; 3820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_IMAGE_LENGTH = "ImageLength"; 3920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_GPS_LATITUDE = "GPSLatitude"; 4020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_GPS_LONGITUDE = "GPSLongitude"; 4120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef"; 4220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef"; 4320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync public static final String TAG_WHITE_BALANCE = "WhiteBalance"; 4420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 45700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // Constants used for the Orientation Exif tag. 46700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_UNDEFINED = 0; 47700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_NORMAL = 1; 48700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_FLIP_HORIZONTAL = 2; // left right reversed mirror 49700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_ROTATE_180 = 3; 50700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_FLIP_VERTICAL = 4; // upside down mirror 51700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_TRANSPOSE = 5; // flipped about top-left <--> bottom-right axis 52700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_ROTATE_90 = 6; // rotate 90 cw to right it 53700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_TRANSVERSE = 7; // flipped about top-right <--> bottom-left axis 54700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int ORIENTATION_ROTATE_270 = 8; // rotate 270 to right it 55700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang 56700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // Constants used for white balance 57700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int WHITEBALANCE_AUTO = 0; 58700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public static final int WHITEBALANCE_MANUAL = 1; 5920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync static { 6120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync System.loadLibrary("exif"); 6220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 6320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 64700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang private String mFilename; 65700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang private HashMap<String, String> mAttributes; 66872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang private boolean mHasThumbnail; 6720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 68700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // Because the underlying implementation (jhead) uses static variables, 69700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // there can only be one user at a time for the native functions (and 70700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // they cannot keep state in the native code across function calls). We 71872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang // use sLock to serialize the accesses. 72700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang private static Object sLock = new Object(); 7320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 7420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync /** 75700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Reads Exif tags from the specified JPEG file. 7620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync */ 77700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public ExifInterface(String filename) throws IOException { 78700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang mFilename = filename; 79700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang loadAttributes(); 8020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 8120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 82700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang /** 83700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Returns the value of the specified tag or {@code null} if there 84872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * is no such tag in the JPEG file. 85700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * 86700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * @param tag the name of the tag. 87700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang */ 88700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public String getAttribute(String tag) { 89700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang return mAttributes.get(tag); 9020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 9120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 9220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync /** 93872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * Returns the integer value of the specified tag. If there is no such tag 94872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * in the JPEG file or the value cannot be parsed as integer, return 95872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * @{code defaultValue}. 96872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * 97872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * @param tag the name of the tag. 98872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * @param defaultValue the value to return if the tag is not available. 99872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang */ 100872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang public int getAttributeInt(String tag, int defaultValue) { 101872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang String value = mAttributes.get(tag); 102872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang if (value == null) return defaultValue; 103872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang try { 104872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang return Integer.valueOf(value); 105872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang } catch (NumberFormatException ex) { 106872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang return defaultValue; 107872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang } 108872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang } 109872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang 110872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang /** 111700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Set the value of the specified tag. 112700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * 113700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * @param tag the name of the tag. 114700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * @param value the value of the tag. 11520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync */ 116700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public void setAttribute(String tag, String value) { 117700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang mAttributes.put(tag, value); 11820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 11920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync /** 121700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Initialize mAttributes with the attributes from the file mFilename. 122700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * 123700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * mAttributes is a HashMap which stores the Exif attributes of the file. 124700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * The key is the standard tag name and the value is the tag's value: e.g. 125700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Model -> Nikon. Numeric values are stored as strings. 126700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * 127700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * This function also initialize mHasThumbnail to indicate whether the 128700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * file has a thumbnail inside. 12920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync */ 130872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang private void loadAttributes() throws IOException { 13120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // format of string passed from native C code: 13220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // "attrCnt attr1=valueLen value1attr2=value2Len value2..." 13320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // example: 13420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO" 135700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang mAttributes = new HashMap<String, String>(); 13620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 137700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String attrStr; 138700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang synchronized (sLock) { 139700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang attrStr = getAttributesNative(mFilename); 140700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 14120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // get count 14320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync int ptr = attrStr.indexOf(' '); 14420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync int count = Integer.parseInt(attrStr.substring(0, ptr)); 14520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // skip past the space between item count and the rest of the attributes 14620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync ++ptr; 14720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync for (int i = 0; i < count; i++) { 14920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // extract the attribute name 15020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync int equalPos = attrStr.indexOf('=', ptr); 15120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync String attrName = attrStr.substring(ptr, equalPos); 15220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync ptr = equalPos + 1; // skip past = 15320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // extract the attribute value length 15520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync int lenPos = attrStr.indexOf(' ', ptr); 15620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync int attrLen = Integer.parseInt(attrStr.substring(ptr, lenPos)); 15720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync ptr = lenPos + 1; // skip pas the space 15820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // extract the attribute value 16020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync String attrValue = attrStr.substring(ptr, ptr + attrLen); 16120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync ptr += attrLen; 16220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 16320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync if (attrName.equals("hasThumbnail")) { 16420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync mHasThumbnail = attrValue.equalsIgnoreCase("true"); 16520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } else { 166700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang mAttributes.put(attrName, attrValue); 16720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 16820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 16920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 17020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 17120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync /** 172700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Save the tag data into the JPEG file. This is expensive because it involves 173700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * copying all the JPG data from one file to another and deleting the old file 174872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * and renaming the other. It's best to use {@link #setAttribute(String,String)} 175872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * to set all attributes to write and make a single call rather than multiple 176872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * calls for each attribute. 17720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync */ 178700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public void saveAttributes() throws IOException { 179700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // format of string passed to native C code: 180700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // "attrCnt attr1=valueLen value1attr2=value2Len value2..." 181700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // example: 182700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO" 183700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang StringBuilder sb = new StringBuilder(); 184700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang int size = mAttributes.size(); 185700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang if (mAttributes.containsKey("hasThumbnail")) { 186700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang --size; 187700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 188700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang sb.append(size + " "); 189700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang for (Map.Entry<String, String> iter : mAttributes.entrySet()) { 190700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String key = iter.getKey(); 191700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang if (key.equals("hasThumbnail")) { 192700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // this is a fake attribute not saved as an exif tag 193700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang continue; 194700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 195700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String val = iter.getValue(); 196700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang sb.append(key + "="); 197700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang sb.append(val.length() + " "); 198700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang sb.append(val); 199700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 200700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String s = sb.toString(); 201700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang synchronized (sLock) { 202700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang saveAttributesNative(mFilename, s); 203700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang commitChangesNative(mFilename); 204700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 205700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 206700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang 207700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang /** 208700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Returns true if the JPEG file has a thumbnail. 209700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang */ 210700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public boolean hasThumbnail() { 211700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang return mHasThumbnail; 212700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 213700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang 214700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang /** 215700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Returns the thumbnail inside the JPEG file, or {@code null} if there is no thumbnail. 216872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * The returned data is in JPEG format and can be decoded using 217872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)} 218700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang */ 219700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public byte[] getThumbnail() { 220700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang synchronized (sLock) { 221700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang return getThumbnailNative(mFilename); 222700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 223700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 224700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang 225700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang /** 226872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * Stores the latitude and longitude value in a float array. The first element is 227872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * the latitude, and the second element is the longitude. Returns false if the 228872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * Exif tags are not available. 22920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync */ 230872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang public boolean getLatLong(float output[]) { 231700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String latValue = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE); 232700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String latRef = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE_REF); 233700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String lngValue = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE); 234700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String lngRef = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE_REF); 23520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 236872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang if (latValue != null && latRef != null && lngValue != null && lngRef != null) { 237872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang output[0] = convertRationalLatLonToFloat(latValue, latRef); 238872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang output[1] = convertRationalLatLonToFloat(lngValue, lngRef); 239872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang return true; 240872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang } else { 241872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang return false; 24220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 24320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 24420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 245099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang private static SimpleDateFormat sFormatter = 246099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); 247099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang 248700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang /** 249700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Returns number of milliseconds since Jan. 1, 1970, midnight GMT. 250700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang * Returns -1 if the date time information if not available. 251872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang * @hide 252700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang */ 253700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang public long getDateTime() { 254700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang String dateTimeString = mAttributes.get(TAG_DATETIME); 255099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang if (dateTimeString == null) return -1; 256099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang 257099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang ParsePosition pos = new ParsePosition(0); 258099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang try { 259099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang Date date = sFormatter.parse(dateTimeString, pos); 260a7bdedabf447a559e0b914e4e5623f3af5ac8ef1Chih-Chung Chang if (date == null) return -1; 261099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang return date.getTime(); 262099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang } catch (IllegalArgumentException ex) { 263099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang return -1; 264099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang } 265099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang } 266099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang 267700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang private static float convertRationalLatLonToFloat( 26820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync String rationalString, String ref) { 26920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync try { 27020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync String [] parts = rationalString.split(","); 27120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 27220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync String [] pair; 27320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync pair = parts[0].split("/"); 27420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync int degrees = (int) (Float.parseFloat(pair[0].trim()) 27520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync / Float.parseFloat(pair[1].trim())); 27620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 27720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync pair = parts[1].split("/"); 27820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync int minutes = (int) ((Float.parseFloat(pair[0].trim()) 27920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync / Float.parseFloat(pair[1].trim()))); 28020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 28120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync pair = parts[2].split("/"); 28220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync float seconds = Float.parseFloat(pair[0].trim()) 28320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync / Float.parseFloat(pair[1].trim()); 28420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 28520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync float result = degrees + (minutes / 60F) + (seconds / (60F * 60F)); 28620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync if ((ref.equals("S") || ref.equals("W"))) { 28720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync return -result; 28820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 28920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync return result; 29020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } catch (RuntimeException ex) { 29120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // if for whatever reason we can't parse the lat long then return 29220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // null 29320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync return 0f; 29420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 29520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 29620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 29720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync private native boolean appendThumbnailNative(String fileName, 29820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync String thumbnailFileName); 29920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 30020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync private native void saveAttributesNative(String fileName, 30120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync String compressedAttributes); 30220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 30320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync private native String getAttributesNative(String fileName); 30420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 30520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync private native void commitChangesNative(String fileName); 30620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 30720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync private native byte[] getThumbnailNative(String fileName); 30820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync} 309