FileDocCategorySizeDatePackage
ExifInterface.javaAPI DocAndroid 5.1 API16257Thu Mar 12 22:22:30 GMT 2015android.media

ExifInterface

public class ExifInterface extends Object
This is a class for reading and writing Exif tags in a JPEG file.

Fields Summary
public static final String
TAG_ORIENTATION
Type is int.
public static final String
TAG_DATETIME
Type is String.
public static final String
TAG_MAKE
Type is String.
public static final String
TAG_MODEL
Type is String.
public static final String
TAG_FLASH
Type is int.
public static final String
TAG_IMAGE_WIDTH
Type is int.
public static final String
TAG_IMAGE_LENGTH
Type is int.
public static final String
TAG_GPS_LATITUDE
String. Format is "num1/denom1,num2/denom2,num3/denom3".
public static final String
TAG_GPS_LONGITUDE
String. Format is "num1/denom1,num2/denom2,num3/denom3".
public static final String
TAG_GPS_LATITUDE_REF
Type is String.
public static final String
TAG_GPS_LONGITUDE_REF
Type is String.
public static final String
TAG_EXPOSURE_TIME
Type is String.
public static final String
TAG_APERTURE
Type is String.
public static final String
TAG_ISO
Type is String.
public static final String
TAG_GPS_ALTITUDE
The altitude (in meters) based on the reference in TAG_GPS_ALTITUDE_REF. Type is rational.
public static final String
TAG_GPS_ALTITUDE_REF
0 if the altitude is above sea level. 1 if the altitude is below sea level. Type is int.
public static final String
TAG_GPS_TIMESTAMP
Type is String.
public static final String
TAG_GPS_DATESTAMP
Type is String.
public static final String
TAG_WHITE_BALANCE
Type is int.
public static final String
TAG_FOCAL_LENGTH
Type is rational.
public static final String
TAG_GPS_PROCESSING_METHOD
Type is String. Name of GPS processing method used for location finding.
public static final int
ORIENTATION_UNDEFINED
public static final int
ORIENTATION_NORMAL
public static final int
ORIENTATION_FLIP_HORIZONTAL
public static final int
ORIENTATION_ROTATE_180
public static final int
ORIENTATION_FLIP_VERTICAL
public static final int
ORIENTATION_TRANSPOSE
public static final int
ORIENTATION_ROTATE_90
public static final int
ORIENTATION_TRANSVERSE
public static final int
ORIENTATION_ROTATE_270
public static final int
WHITEBALANCE_AUTO
public static final int
WHITEBALANCE_MANUAL
private static SimpleDateFormat
sFormatter
private String
mFilename
private HashMap
mAttributes
private boolean
mHasThumbnail
private static final Object
sLock
Constructors Summary
public ExifInterface(String filename)
Reads Exif tags from the specified JPEG file.


                 
         
        if (filename == null) {
            throw new IllegalArgumentException("filename cannot be null");
        }
        mFilename = filename;
        loadAttributes();
    
Methods Summary
private native booleanappendThumbnailNative(java.lang.String fileName, java.lang.String thumbnailFileName)

private native voidcommitChangesNative(java.lang.String fileName)

private static floatconvertRationalLatLonToFloat(java.lang.String rationalString, java.lang.String ref)

        try {
            String [] parts = rationalString.split(",");

            String [] pair;
            pair = parts[0].split("/");
            double degrees = Double.parseDouble(pair[0].trim())
                    / Double.parseDouble(pair[1].trim());

            pair = parts[1].split("/");
            double minutes = Double.parseDouble(pair[0].trim())
                    / Double.parseDouble(pair[1].trim());

            pair = parts[2].split("/");
            double seconds = Double.parseDouble(pair[0].trim())
                    / Double.parseDouble(pair[1].trim());

            double result = degrees + (minutes / 60.0) + (seconds / 3600.0);
            if ((ref.equals("S") || ref.equals("W"))) {
                return (float) -result;
            }
            return (float) result;
        } catch (NumberFormatException e) {
            // Some of the nubmers are not valid
            throw new IllegalArgumentException();
        } catch (ArrayIndexOutOfBoundsException e) {
            // Some of the rational does not follow the correct format
            throw new IllegalArgumentException();
        }
    
public doublegetAltitude(double defaultValue)
Return the altitude in meters. If the exif tag does not exist, return defaultValue.

param
defaultValue the value to return if the tag is not available.

        double altitude = getAttributeDouble(TAG_GPS_ALTITUDE, -1);
        int ref = getAttributeInt(TAG_GPS_ALTITUDE_REF, -1);

        if (altitude >= 0 && ref >= 0) {
            return (double) (altitude * ((ref == 1) ? -1 : 1));
        } else {
            return defaultValue;
        }
    
public java.lang.StringgetAttribute(java.lang.String tag)
Returns the value of the specified tag or {@code null} if there is no such tag in the JPEG file.

param
tag the name of the tag.

        return mAttributes.get(tag);
    
public doublegetAttributeDouble(java.lang.String tag, double defaultValue)
Returns the double value of the specified rational tag. If there is no such tag in the JPEG file or the value cannot be parsed as double, return defaultValue.

param
tag the name of the tag.
param
defaultValue the value to return if the tag is not available.

        String value = mAttributes.get(tag);
        if (value == null) return defaultValue;
        try {
            int index = value.indexOf("/");
            if (index == -1) return defaultValue;
            double denom = Double.parseDouble(value.substring(index + 1));
            if (denom == 0) return defaultValue;
            double num = Double.parseDouble(value.substring(0, index));
            return num / denom;
        } catch (NumberFormatException ex) {
            return defaultValue;
        }
    
public intgetAttributeInt(java.lang.String tag, int defaultValue)
Returns the integer value of the specified tag. If there is no such tag in the JPEG file or the value cannot be parsed as integer, return defaultValue.

param
tag the name of the tag.
param
defaultValue the value to return if the tag is not available.

        String value = mAttributes.get(tag);
        if (value == null) return defaultValue;
        try {
            return Integer.valueOf(value);
        } catch (NumberFormatException ex) {
            return defaultValue;
        }
    
private native java.lang.StringgetAttributesNative(java.lang.String fileName)

public longgetDateTime()
Returns number of milliseconds since Jan. 1, 1970, midnight. Returns -1 if the date time information if not available.

hide

        String dateTimeString = mAttributes.get(TAG_DATETIME);
        if (dateTimeString == null) return -1;

        ParsePosition pos = new ParsePosition(0);
        try {
            Date datetime = sFormatter.parse(dateTimeString, pos);
            if (datetime == null) return -1;
            return datetime.getTime();
        } catch (IllegalArgumentException ex) {
            return -1;
        }
    
public longgetGpsDateTime()
Returns number of milliseconds since Jan. 1, 1970, midnight UTC. Returns -1 if the date time information if not available.

hide

        String date = mAttributes.get(TAG_GPS_DATESTAMP);
        String time = mAttributes.get(TAG_GPS_TIMESTAMP);
        if (date == null || time == null) return -1;

        String dateTimeString = date + ' " + time;
        if (dateTimeString == null) return -1;

        ParsePosition pos = new ParsePosition(0);
        try {
            Date datetime = sFormatter.parse(dateTimeString, pos);
            if (datetime == null) return -1;
            return datetime.getTime();
        } catch (IllegalArgumentException ex) {
            return -1;
        }
    
public booleangetLatLong(float[] output)
Stores the latitude and longitude value in a float array. The first element is the latitude, and the second element is the longitude. Returns false if the Exif tags are not available.

        String latValue = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE);
        String latRef = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE_REF);
        String lngValue = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE);
        String lngRef = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE_REF);

        if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
            try {
                output[0] = convertRationalLatLonToFloat(latValue, latRef);
                output[1] = convertRationalLatLonToFloat(lngValue, lngRef);
                return true;
            } catch (IllegalArgumentException e) {
                // if values are not parseable
            }
        }

        return false;
    
public byte[]getThumbnail()
Returns the thumbnail inside the JPEG file, or {@code null} if there is no thumbnail. The returned data is in JPEG format and can be decoded using {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)}

        synchronized (sLock) {
            return getThumbnailNative(mFilename);
        }
    
private native byte[]getThumbnailNative(java.lang.String fileName)

public long[]getThumbnailRange()
Returns the offset and length of thumbnail inside the JPEG file, or {@code null} if there is no thumbnail.

return
two-element array, the offset in the first value, and length in the second, or {@code null} if no thumbnail was found.
hide

        synchronized (sLock) {
            return getThumbnailRangeNative(mFilename);
        }
    
private native long[]getThumbnailRangeNative(java.lang.String fileName)

public booleanhasThumbnail()
Returns true if the JPEG file has a thumbnail.

        return mHasThumbnail;
    
private voidloadAttributes()
Initialize mAttributes with the attributes from the file mFilename. mAttributes is a HashMap which stores the Exif attributes of the file. The key is the standard tag name and the value is the tag's value: e.g. Model -> Nikon. Numeric values are stored as strings. This function also initialize mHasThumbnail to indicate whether the file has a thumbnail inside.

        // format of string passed from native C code:
        // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
        // example:
        // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
        mAttributes = new HashMap<String, String>();

        String attrStr;
        synchronized (sLock) {
            attrStr = getAttributesNative(mFilename);
        }

        // get count
        int ptr = attrStr.indexOf(' ");
        int count = Integer.parseInt(attrStr.substring(0, ptr));
        // skip past the space between item count and the rest of the attributes
        ++ptr;

        for (int i = 0; i < count; i++) {
            // extract the attribute name
            int equalPos = attrStr.indexOf('=", ptr);
            String attrName = attrStr.substring(ptr, equalPos);
            ptr = equalPos + 1;     // skip past =

            // extract the attribute value length
            int lenPos = attrStr.indexOf(' ", ptr);
            int attrLen = Integer.parseInt(attrStr.substring(ptr, lenPos));
            ptr = lenPos + 1;       // skip pas the space

            // extract the attribute value
            String attrValue = attrStr.substring(ptr, ptr + attrLen);
            ptr += attrLen;

            if (attrName.equals("hasThumbnail")) {
                mHasThumbnail = attrValue.equalsIgnoreCase("true");
            } else {
                mAttributes.put(attrName, attrValue);
            }
        }
    
public voidsaveAttributes()
Save the tag data into the JPEG file. This is expensive because it involves copying all the JPG data from one file to another and deleting the old file and renaming the other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write and make a single call rather than multiple calls for each attribute.

        // format of string passed to native C code:
        // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
        // example:
        // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
        StringBuilder sb = new StringBuilder();
        int size = mAttributes.size();
        if (mAttributes.containsKey("hasThumbnail")) {
            --size;
        }
        sb.append(size + " ");
        for (Map.Entry<String, String> iter : mAttributes.entrySet()) {
            String key = iter.getKey();
            if (key.equals("hasThumbnail")) {
                // this is a fake attribute not saved as an exif tag
                continue;
            }
            String val = iter.getValue();
            sb.append(key + "=");
            sb.append(val.length() + " ");
            sb.append(val);
        }
        String s = sb.toString();
        synchronized (sLock) {
            saveAttributesNative(mFilename, s);
            commitChangesNative(mFilename);
        }
    
private native voidsaveAttributesNative(java.lang.String fileName, java.lang.String compressedAttributes)

public voidsetAttribute(java.lang.String tag, java.lang.String value)
Set the value of the specified tag.

param
tag the name of the tag.
param
value the value of the tag.

        mAttributes.put(tag, value);