FileDocCategorySizeDatePackage
ExifInterface.javaAPI DocAndroid 5.1 API92544Thu Mar 12 22:22:42 GMT 2015com.android.gallery3d.exif

ExifInterface

public class ExifInterface extends Object
This class provides methods and constants for reading and writing jpeg file metadata. It contains a collection of ExifTags, and a collection of definitions for creating valid ExifTags. The collection of ExifTags can be updated by: reading new ones from a file, deleting or adding existing ones, or building new ExifTags from a tag definition. These ExifTags can be written to a valid jpeg image as exif metadata.

Each ExifTag has a tag ID (TID) and is stored in a specific image file directory (IFD) as specified by the exif standard. A tag definition can be looked up with a constant that is a combination of TID and IFD. This definition has information about the type, number of components, and valid IFDs for a tag.

see
ExifTag

Fields Summary
public static final int
TAG_NULL
public static final int
IFD_NULL
public static final int
DEFINITION_NULL
public static final int
TAG_IMAGE_WIDTH
Tag constants for Jeita EXIF 2.2
public static final int
TAG_IMAGE_LENGTH
public static final int
TAG_BITS_PER_SAMPLE
public static final int
TAG_COMPRESSION
public static final int
TAG_PHOTOMETRIC_INTERPRETATION
public static final int
TAG_IMAGE_DESCRIPTION
public static final int
TAG_MAKE
public static final int
TAG_MODEL
public static final int
TAG_STRIP_OFFSETS
public static final int
TAG_ORIENTATION
public static final int
TAG_SAMPLES_PER_PIXEL
public static final int
TAG_ROWS_PER_STRIP
public static final int
TAG_STRIP_BYTE_COUNTS
public static final int
TAG_X_RESOLUTION
public static final int
TAG_Y_RESOLUTION
public static final int
TAG_PLANAR_CONFIGURATION
public static final int
TAG_RESOLUTION_UNIT
public static final int
TAG_TRANSFER_FUNCTION
public static final int
TAG_SOFTWARE
public static final int
TAG_DATE_TIME
public static final int
TAG_ARTIST
public static final int
TAG_WHITE_POINT
public static final int
TAG_PRIMARY_CHROMATICITIES
public static final int
TAG_Y_CB_CR_COEFFICIENTS
public static final int
TAG_Y_CB_CR_SUB_SAMPLING
public static final int
TAG_Y_CB_CR_POSITIONING
public static final int
TAG_REFERENCE_BLACK_WHITE
public static final int
TAG_COPYRIGHT
public static final int
TAG_EXIF_IFD
public static final int
TAG_GPS_IFD
public static final int
TAG_JPEG_INTERCHANGE_FORMAT
public static final int
TAG_JPEG_INTERCHANGE_FORMAT_LENGTH
public static final int
TAG_EXPOSURE_TIME
public static final int
TAG_F_NUMBER
public static final int
TAG_EXPOSURE_PROGRAM
public static final int
TAG_SPECTRAL_SENSITIVITY
public static final int
TAG_ISO_SPEED_RATINGS
public static final int
TAG_OECF
public static final int
TAG_EXIF_VERSION
public static final int
TAG_DATE_TIME_ORIGINAL
public static final int
TAG_DATE_TIME_DIGITIZED
public static final int
TAG_COMPONENTS_CONFIGURATION
public static final int
TAG_COMPRESSED_BITS_PER_PIXEL
public static final int
TAG_SHUTTER_SPEED_VALUE
public static final int
TAG_APERTURE_VALUE
public static final int
TAG_BRIGHTNESS_VALUE
public static final int
TAG_EXPOSURE_BIAS_VALUE
public static final int
TAG_MAX_APERTURE_VALUE
public static final int
TAG_SUBJECT_DISTANCE
public static final int
TAG_METERING_MODE
public static final int
TAG_LIGHT_SOURCE
public static final int
TAG_FLASH
public static final int
TAG_FOCAL_LENGTH
public static final int
TAG_SUBJECT_AREA
public static final int
TAG_MAKER_NOTE
public static final int
TAG_USER_COMMENT
public static final int
TAG_SUB_SEC_TIME
public static final int
TAG_SUB_SEC_TIME_ORIGINAL
public static final int
TAG_SUB_SEC_TIME_DIGITIZED
public static final int
TAG_FLASHPIX_VERSION
public static final int
TAG_COLOR_SPACE
public static final int
TAG_PIXEL_X_DIMENSION
public static final int
TAG_PIXEL_Y_DIMENSION
public static final int
TAG_RELATED_SOUND_FILE
public static final int
TAG_INTEROPERABILITY_IFD
public static final int
TAG_FLASH_ENERGY
public static final int
TAG_SPATIAL_FREQUENCY_RESPONSE
public static final int
TAG_FOCAL_PLANE_X_RESOLUTION
public static final int
TAG_FOCAL_PLANE_Y_RESOLUTION
public static final int
TAG_FOCAL_PLANE_RESOLUTION_UNIT
public static final int
TAG_SUBJECT_LOCATION
public static final int
TAG_EXPOSURE_INDEX
public static final int
TAG_SENSING_METHOD
public static final int
TAG_FILE_SOURCE
public static final int
TAG_SCENE_TYPE
public static final int
TAG_CFA_PATTERN
public static final int
TAG_CUSTOM_RENDERED
public static final int
TAG_EXPOSURE_MODE
public static final int
TAG_WHITE_BALANCE
public static final int
TAG_DIGITAL_ZOOM_RATIO
public static final int
TAG_FOCAL_LENGTH_IN_35_MM_FILE
public static final int
TAG_SCENE_CAPTURE_TYPE
public static final int
TAG_GAIN_CONTROL
public static final int
TAG_CONTRAST
public static final int
TAG_SATURATION
public static final int
TAG_SHARPNESS
public static final int
TAG_DEVICE_SETTING_DESCRIPTION
public static final int
TAG_SUBJECT_DISTANCE_RANGE
public static final int
TAG_IMAGE_UNIQUE_ID
public static final int
TAG_GPS_VERSION_ID
public static final int
TAG_GPS_LATITUDE_REF
public static final int
TAG_GPS_LATITUDE
public static final int
TAG_GPS_LONGITUDE_REF
public static final int
TAG_GPS_LONGITUDE
public static final int
TAG_GPS_ALTITUDE_REF
public static final int
TAG_GPS_ALTITUDE
public static final int
TAG_GPS_TIME_STAMP
public static final int
TAG_GPS_SATTELLITES
public static final int
TAG_GPS_STATUS
public static final int
TAG_GPS_MEASURE_MODE
public static final int
TAG_GPS_DOP
public static final int
TAG_GPS_SPEED_REF
public static final int
TAG_GPS_SPEED
public static final int
TAG_GPS_TRACK_REF
public static final int
TAG_GPS_TRACK
public static final int
TAG_GPS_IMG_DIRECTION_REF
public static final int
TAG_GPS_IMG_DIRECTION
public static final int
TAG_GPS_MAP_DATUM
public static final int
TAG_GPS_DEST_LATITUDE_REF
public static final int
TAG_GPS_DEST_LATITUDE
public static final int
TAG_GPS_DEST_LONGITUDE_REF
public static final int
TAG_GPS_DEST_LONGITUDE
public static final int
TAG_GPS_DEST_BEARING_REF
public static final int
TAG_GPS_DEST_BEARING
public static final int
TAG_GPS_DEST_DISTANCE_REF
public static final int
TAG_GPS_DEST_DISTANCE
public static final int
TAG_GPS_PROCESSING_METHOD
public static final int
TAG_GPS_AREA_INFORMATION
public static final int
TAG_GPS_DATE_STAMP
public static final int
TAG_GPS_DIFFERENTIAL
public static final int
TAG_INTEROPERABILITY_INDEX
private static HashSet
sOffsetTags
Tags that contain offset markers. These are included in the banned defines.
protected static HashSet
sBannedDefines
Tags with definitions that cannot be overridden (banned defines).
private static final String
NULL_ARGUMENT_STRING
private ExifData
mData
public static final ByteOrder
DEFAULT_BYTE_ORDER
private static final String
GPS_DATE_FORMAT_STR
private static final String
DATETIME_FORMAT_STR
private final DateFormat
mDateTimeStampFormat
private final DateFormat
mGPSDateStampFormat
private final Calendar
mGPSTimeStampCalendar
private android.util.SparseIntArray
mTagInfo
Constructors Summary
public ExifInterface()


      
        mGPSDateStampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    
Methods Summary
public booleanaddDateTimeStampTag(int tagId, long timestamp, java.util.TimeZone timezone)
Creates, formats, and sets the DateTimeStamp tag for one of: {@link #TAG_DATE_TIME}, {@link #TAG_DATE_TIME_DIGITIZED}, {@link #TAG_DATE_TIME_ORIGINAL}.

param
tagId one of the DateTimeStamp tags.
param
timestamp a timestamp to format.
param
timezone a TimeZone object.
return
true if success, false if the tag could not be set.


                                                       
            
        if (tagId == TAG_DATE_TIME || tagId == TAG_DATE_TIME_DIGITIZED
                || tagId == TAG_DATE_TIME_ORIGINAL) {
            mDateTimeStampFormat.setTimeZone(timezone);
            ExifTag t = buildTag(tagId, mDateTimeStampFormat.format(timestamp));
            if (t == null) {
                return false;
            }
            setTag(t);
        } else {
            return false;
        }
        return true;
    
public booleanaddGpsDateTimeStampTag(long timestamp)
Creates and sets the GPS timestamp tag.

param
timestamp a GPS timestamp.
return
true if success, false if could not be created or set.

        ExifTag t = buildTag(TAG_GPS_DATE_STAMP, mGPSDateStampFormat.format(timestamp));
        if (t == null) {
            return false;
        }
        setTag(t);
        mGPSTimeStampCalendar.setTimeInMillis(timestamp);
        t = buildTag(TAG_GPS_TIME_STAMP, new Rational[] {
                new Rational(mGPSTimeStampCalendar.get(Calendar.HOUR_OF_DAY), 1),
                new Rational(mGPSTimeStampCalendar.get(Calendar.MINUTE), 1),
                new Rational(mGPSTimeStampCalendar.get(Calendar.SECOND), 1)
        });
        if (t == null) {
            return false;
        }
        setTag(t);
        return true;
    
public booleanaddGpsTags(double latitude, double longitude)
Creates and sets all to the GPS tags for a give latitude and longitude.

param
latitude a GPS latitude coordinate.
param
longitude a GPS longitude coordinate.
return
true if success, false if they could not be created or set.

        ExifTag latTag = buildTag(TAG_GPS_LATITUDE, toExifLatLong(latitude));
        ExifTag longTag = buildTag(TAG_GPS_LONGITUDE, toExifLatLong(longitude));
        ExifTag latRefTag = buildTag(TAG_GPS_LATITUDE_REF,
                latitude >= 0 ? ExifInterface.GpsLatitudeRef.NORTH
                        : ExifInterface.GpsLatitudeRef.SOUTH);
        ExifTag longRefTag = buildTag(TAG_GPS_LONGITUDE_REF,
                longitude >= 0 ? ExifInterface.GpsLongitudeRef.EAST
                        : ExifInterface.GpsLongitudeRef.WEST);
        if (latTag == null || longTag == null || latRefTag == null || longRefTag == null) {
            return false;
        }
        setTag(latTag);
        setTag(longTag);
        setTag(latRefTag);
        setTag(longRefTag);
        return true;
    
public ExifTagbuildTag(int tagId, int ifdId, java.lang.Object val)
Creates a tag for a defined tag constant in a given IFD if that IFD is allowed for the tag. This method will fail anytime the appropriate {@link ExifTag#setValue} for this tag's datatype would fail.

param
tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
param
ifdId the IFD that the tag should be in.
param
val the value of the tag to set.
return
an ExifTag object or null if one could not be constructed.
see
#buildTag

        int info = getTagInfo().get(tagId);
        if (info == 0 || val == null) {
            return null;
        }
        short type = getTypeFromInfo(info);
        int definedCount = getComponentCountFromInfo(info);
        boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
        if (!ExifInterface.isIfdAllowed(info, ifdId)) {
            return null;
        }
        ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
        if (!t.setValue(val)) {
            return null;
        }
        return t;
    
public ExifTagbuildTag(int tagId, java.lang.Object val)
Creates a tag for a defined tag constant in the tag's default IFD.

param
tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
param
val the tag's value.
return
an ExifTag object.

        int ifdId = getTrueIfd(tagId);
        return buildTag(tagId, ifdId, val);
    
protected ExifTagbuildUninitializedTag(int tagId)

        int info = getTagInfo().get(tagId);
        if (info == 0) {
            return null;
        }
        short type = getTypeFromInfo(info);
        int definedCount = getComponentCountFromInfo(info);
        boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
        int ifdId = getTrueIfd(tagId);
        ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
        return t;
    
public voidclearExif()
Clears this ExifInterface object's existing exif tags.

        mData = new ExifData(DEFAULT_BYTE_ORDER);
    
protected static voidcloseSilently(java.io.Closeable c)

        if (c != null) {
            try {
                c.close();
            } catch (Throwable e) {
                // ignored
            }
        }
    
public static doubleconvertLatOrLongToDouble(Rational[] coordinate, java.lang.String reference)
Gets the double representation of the GPS latitude or longitude coordinate.

param
coordinate an array of 3 Rationals representing the degrees, minutes, and seconds of the GPS location as defined in the exif specification.
param
reference a GPS reference reperesented by a String containing "N", "S", "E", or "W".
return
the GPS coordinate represented as degrees + minutes/60 + seconds/3600

        try {
            double degrees = coordinate[0].toDouble();
            double minutes = coordinate[1].toDouble();
            double seconds = coordinate[2].toDouble();
            double result = degrees + minutes / 60.0 + seconds / 3600.0;
            if ((reference.equals("S") || reference.equals("W"))) {
                return -result;
            }
            return result;
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new IllegalArgumentException();
        }
    
public static intdefineTag(int ifdId, short tagId)
Returns the constant representing a tag with a given TID and default IFD.

     
        sBannedDefines.add(getTrueTagKey(TAG_NULL));
        sBannedDefines.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
        sBannedDefines.add(getTrueTagKey(TAG_STRIP_BYTE_COUNTS));
    
        return (tagId & 0x0000ffff) | (ifdId << 16);
    
public voiddeleteTag(int tagId, int ifdId)
Removes the ExifTag for a tag constant from the given IFD.

param
tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
param
ifdId the IFD of the ExifTag to remove.

        mData.removeTag(getTrueTagKey(tagId), ifdId);
    
public voiddeleteTag(int tagId)
Removes the ExifTag for a tag constant from that tag's default IFD.

param
tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.

        int ifdId = getDefinedTagDefaultIfd(tagId);
        deleteTag(tagId, ifdId);
    
private voiddoExifStreamIO(java.io.InputStream is, java.io.OutputStream os)

        byte[] buf = new byte[1024];
        int ret = is.read(buf, 0, 1024);
        while (ret != -1) {
            os.write(buf, 0, ret);
            ret = is.read(buf, 0, 1024);
        }
    
public voidforceRewriteExif(java.lang.String filename, java.util.Collection tags)
Attempts to do an in-place rewrite of the exif metadata. If this fails, fall back to overwriting file. This preserves tags that are not being rewritten.

param
filename a String containing a filepath for a jpeg file.
param
tags tags that will be written into the jpeg file over existing tags if possible.
throws
FileNotFoundException
throws
IOException
see
#rewriteExif

        // Attempt in-place write
        if (!rewriteExif(filename, tags)) {
            // Fall back to doing a copy
            ExifData tempData = mData;
            mData = new ExifData(DEFAULT_BYTE_ORDER);
            FileInputStream is = null;
            ByteArrayOutputStream bytes = null;
            try {
                is = new FileInputStream(filename);
                bytes = new ByteArrayOutputStream();
                doExifStreamIO(is, bytes);
                byte[] imageBytes = bytes.toByteArray();
                readExif(imageBytes);
                setTags(tags);
                writeExif(imageBytes, filename);
            } catch (IOException e) {
                closeSilently(is);
                throw e;
            } finally {
                is.close();
                // Prevent clobbering of mData
                mData = tempData;
            }
        }
    
public voidforceRewriteExif(java.lang.String filename)
Attempts to do an in-place rewrite of the exif metadata using the tags in this ExifInterface object. If this fails, fall back to overwriting file. This preserves tags that are not being rewritten.

param
filename a String containing a filepath for a jpeg file.
throws
FileNotFoundException
throws
IOException
see
#rewriteExif

        forceRewriteExif(filename, getAllTags());
    
public intgetActualTagCount(int tagId, int ifdId)
Gets the number of elements for an ExifTag in a given IFD.

param
tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
param
ifdId the IFD containing the ExifTag to check.
return
the number of elements in the ExifTag, if the tag's size is undefined this will return the actual number of elements that is in the ExifTag's value.

        ExifTag t = getTag(tagId, ifdId);
        if (t == null) {
            return 0;
        }
        return t.getComponentCount();
    
public java.util.ListgetAllTags()
Get the exif tags in this ExifInterface object or null if none exist.

return
a List of {@link ExifTag}s.

        return mData.getAllTags();
    
protected static intgetAllowedIfdFlagsFromInfo(int info)

        return info >>> 24;
    
protected static int[]getAllowedIfdsFromInfo(int info)

        int ifdFlags = getAllowedIfdFlagsFromInfo(info);
        int[] ifds = IfdData.getIfds();
        ArrayList<Integer> l = new ArrayList<Integer>();
        for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
            int flag = (ifdFlags >> i) & 1;
            if (flag == 1) {
                l.add(ifds[i]);
            }
        }
        if (l.size() <= 0) {
            return null;
        }
        int[] ret = new int[l.size()];
        int j = 0;
        for (int i : l) {
            ret[j++] = i;
        }
        return ret;
    
protected static intgetComponentCountFromInfo(int info)

        return info & 0x0ffff;
    
public intgetDefinedTagCount(int tagId)
Gets the defined number of elements for a tag.

param
tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
return
the number of elements or {@link ExifTag#SIZE_UNDEFINED} if the tag or the number of elements is not defined.

        int info = getTagInfo().get(tagId);
        if (info == 0) {
            return ExifTag.SIZE_UNDEFINED;
        }
        return getComponentCountFromInfo(info);
    
public intgetDefinedTagDefaultIfd(int tagId)
Gets the default IFD for a tag.

param
tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
return
the default IFD for a tag definition or {@link #IFD_NULL} if no definition exists.

        int info = getTagInfo().get(tagId);
        if (info == DEFINITION_NULL) {
            return IFD_NULL;
        }
        return getTrueIfd(tagId);
    
public shortgetDefinedTagType(int tagId)
Gets the defined type for a tag.

param
tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
return
the type.
see
ExifTag#getDataType()

        int info = getTagInfo().get(tagId);
        if (info == 0) {
            return -1;
        }
        return getTypeFromInfo(info);
    
public java.io.OutputStreamgetExifWriterStream(java.io.OutputStream outStream)
Wraps an OutputStream object with an ExifOutputStream. Exif tags in this ExifInterface object will be added to a jpeg image written to this stream, removing prior exif tags. Other methods of this ExifInterface object should not be called until the returned OutputStream has been closed.

param
outStream an OutputStream to wrap.
return
an OutputStream that wraps the outStream parameter, and adds exif metadata. A jpeg image should be written to this stream.

        if (outStream == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        ExifOutputStream eos = new ExifOutputStream(outStream, this);
        eos.setExifData(mData);
        return eos;
    
public java.io.OutputStreamgetExifWriterStream(java.lang.String exifOutFileName)
Returns an OutputStream object that writes to a file. Exif tags in this ExifInterface object will be added to a jpeg image written to this stream, removing prior exif tags. Other methods of this ExifInterface object should not be called until the returned OutputStream has been closed.

param
exifOutFileName an String containing a filepath for a jpeg file.
return
an OutputStream that writes to the exifOutFileName file, and adds exif metadata. A jpeg image should be written to this stream.
throws
FileNotFoundException

        if (exifOutFileName == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        OutputStream out = null;
        try {
            out = (OutputStream) new FileOutputStream(exifOutFileName);
        } catch (FileNotFoundException e) {
            closeSilently(out);
            throw e;
        }
        return getExifWriterStream(out);
    
protected static intgetFlagsFromAllowedIfds(int[] allowedIfds)

        if (allowedIfds == null || allowedIfds.length == 0) {
            return 0;
        }
        int flags = 0;
        int[] ifds = IfdData.getIfds();
        for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
            for (int j : allowedIfds) {
                if (ifds[i] == j) {
                    flags |= 1 << i;
                    break;
                }
            }
        }
        return flags;
    
public double[]getLatLongAsDoubles()
Gets the GPS latitude and longitude as a pair of doubles from this ExifInterface object's tags, or null if the necessary tags do not exist.

return
an array of 2 doubles containing the latitude, and longitude respectively.
see
#convertLatOrLongToDouble

        Rational[] latitude = getTagRationalValues(TAG_GPS_LATITUDE);
        String latitudeRef = getTagStringValue(TAG_GPS_LATITUDE_REF);
        Rational[] longitude = getTagRationalValues(TAG_GPS_LONGITUDE);
        String longitudeRef = getTagStringValue(TAG_GPS_LONGITUDE_REF);
        if (latitude == null || longitude == null || latitudeRef == null || longitudeRef == null
                || latitude.length < 3 || longitude.length < 3) {
            return null;
        }
        double[] latLon = new double[2];
        latLon[0] = convertLatOrLongToDouble(latitude, latitudeRef);
        latLon[1] = convertLatOrLongToDouble(longitude, longitudeRef);
        return latLon;
    
public static shortgetOrientationValueForRotation(int degrees)
Returns the Orientation ExifTag value for a given number of degrees.

param
degrees the amount an image is rotated in degrees.

        degrees %= 360;
        if (degrees < 0) {
            degrees += 360;
        }
        if (degrees < 90) {
            return Orientation.TOP_LEFT; // 0 degrees
        } else if (degrees < 180) {
            return Orientation.RIGHT_TOP; // 90 degrees cw
        } else if (degrees < 270) {
            return Orientation.BOTTOM_LEFT; // 180 degrees
        } else {
            return Orientation.RIGHT_BOTTOM; // 270 degrees cw
        }
    
public static intgetRotationForOrientationValue(short orientation)
Returns the rotation degrees corresponding to an ExifTag Orientation value.

param
orientation the ExifTag Orientation value.

        switch (orientation) {
            case Orientation.TOP_LEFT:
                return 0;
            case Orientation.RIGHT_TOP:
                return 90;
            case Orientation.BOTTOM_LEFT:
                return 180;
            case Orientation.RIGHT_BOTTOM:
                return 270;
            default:
                return 0;
        }
    
public ExifTaggetTag(int tagId, int ifdId)
Gets an ExifTag for an IFD other than the tag's default.

see
#getTag

        if (!ExifTag.isValidIfd(ifdId)) {
            return null;
        }
        return mData.getTag(getTrueTagKey(tagId), ifdId);
    
public ExifTaggetTag(int tagId)
Returns the ExifTag in that tag's default IFD for a defined tag constant or null if none exists.

param
tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
return
an {@link ExifTag} or null if none exists.

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTag(tagId, ifdId);
    
public java.lang.BytegetTagByteValue(int tagId, int ifdId)

see
#getTagValue

        byte[] l = getTagByteValues(tagId, ifdId);
        if (l == null || l.length <= 0) {
            return null;
        }
        return new Byte(l[0]);
    
public java.lang.BytegetTagByteValue(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagByteValue(tagId, ifdId);
    
public byte[]getTagByteValues(int tagId, int ifdId)

see
#getTagValue

        ExifTag t = getTag(tagId, ifdId);
        if (t == null) {
            return null;
        }
        return t.getValueAsBytes();
    
public byte[]getTagByteValues(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagByteValues(tagId, ifdId);
    
protected intgetTagDefinition(short tagId, int defaultIfd)

        return getTagInfo().get(defineTag(defaultIfd, tagId));
    
protected intgetTagDefinitionForTag(ExifTag tag)

        short type = tag.getDataType();
        int count = tag.getComponentCount();
        int ifd = tag.getIfd();
        return getTagDefinitionForTag(tag.getTagId(), type, count, ifd);
    
protected intgetTagDefinitionForTag(short tagId, short type, int count, int ifd)

        int[] defs = getTagDefinitionsForTagId(tagId);
        if (defs == null) {
            return TAG_NULL;
        }
        SparseIntArray infos = getTagInfo();
        int ret = TAG_NULL;
        for (int i : defs) {
            int info = infos.get(i);
            short def_type = getTypeFromInfo(info);
            int def_count = getComponentCountFromInfo(info);
            int[] def_ifds = getAllowedIfdsFromInfo(info);
            boolean valid_ifd = false;
            for (int j : def_ifds) {
                if (j == ifd) {
                    valid_ifd = true;
                    break;
                }
            }
            if (valid_ifd && type == def_type
                    && (count == def_count || def_count == ExifTag.SIZE_UNDEFINED)) {
                ret = i;
                break;
            }
        }
        return ret;
    
protected int[]getTagDefinitionsForTagId(short tagId)

        int[] ifds = IfdData.getIfds();
        int[] defs = new int[ifds.length];
        int counter = 0;
        SparseIntArray infos = getTagInfo();
        for (int i : ifds) {
            int def = defineTag(i, tagId);
            if (infos.get(def) != DEFINITION_NULL) {
                defs[counter++] = def;
            }
        }
        if (counter == 0) {
            return null;
        }

        return Arrays.copyOfRange(defs, 0, counter);
    
protected android.util.SparseIntArraygetTagInfo()


       
        if (mTagInfo == null) {
            mTagInfo = new SparseIntArray();
            initTagInfo();
        }
        return mTagInfo;
    
public java.lang.IntegergetTagIntValue(int tagId, int ifdId)

see
#getTagValue

        int[] l = getTagIntValues(tagId, ifdId);
        if (l == null || l.length <= 0) {
            return null;
        }
        return new Integer(l[0]);
    
public java.lang.IntegergetTagIntValue(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagIntValue(tagId, ifdId);
    
public int[]getTagIntValues(int tagId, int ifdId)

see
#getTagValue

        ExifTag t = getTag(tagId, ifdId);
        if (t == null) {
            return null;
        }
        return t.getValueAsInts();
    
public int[]getTagIntValues(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagIntValues(tagId, ifdId);
    
public java.lang.LonggetTagLongValue(int tagId, int ifdId)

see
#getTagValue

        long[] l = getTagLongValues(tagId, ifdId);
        if (l == null || l.length <= 0) {
            return null;
        }
        return new Long(l[0]);
    
public java.lang.LonggetTagLongValue(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagLongValue(tagId, ifdId);
    
public long[]getTagLongValues(int tagId, int ifdId)

see
#getTagValue

        ExifTag t = getTag(tagId, ifdId);
        if (t == null) {
            return null;
        }
        return t.getValueAsLongs();
    
public long[]getTagLongValues(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagLongValues(tagId, ifdId);
    
public RationalgetTagRationalValue(int tagId, int ifdId)

see
#getTagValue

        Rational[] l = getTagRationalValues(tagId, ifdId);
        if (l == null || l.length == 0) {
            return null;
        }
        return new Rational(l[0]);
    
public RationalgetTagRationalValue(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagRationalValue(tagId, ifdId);
    
public Rational[]getTagRationalValues(int tagId, int ifdId)

see
#getTagValue

        ExifTag t = getTag(tagId, ifdId);
        if (t == null) {
            return null;
        }
        return t.getValueAsRationals();
    
public Rational[]getTagRationalValues(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagRationalValues(tagId, ifdId);
    
public java.lang.StringgetTagStringValue(int tagId, int ifdId)

see
#getTagValue

        ExifTag t = getTag(tagId, ifdId);
        if (t == null) {
            return null;
        }
        return t.getValueAsString();
    
public java.lang.StringgetTagStringValue(int tagId)

see
#getTagValue

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagStringValue(tagId, ifdId);
    
public java.lang.ObjectgetTagValue(int tagId, int ifdId)
Gets a tag value for an IFD other than the tag's default.

see
#getTagValue

        ExifTag t = getTag(tagId, ifdId);
        return (t == null) ? null : t.getValue();
    
public java.lang.ObjectgetTagValue(int tagId)
Returns the value of the ExifTag in that tag's default IFD for a defined tag constant or null if none exists or the value could not be cast into the return type.

param
tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
return
the value of the ExifTag or null if none exists.

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return getTagValue(tagId, ifdId);
    
public java.util.ListgetTagsForIfdId(int ifdId)
Returns a list of ExifTags that share an IFD (which can be obtained by calling {@link #getTrueIFD} on a defined tag constant) or null if none exist.

param
ifdId an IFD as defined in the exif standard (or with {@link #defineTag}).
return
a List of {@link ExifTag}s.

        return mData.getAllTagsForIfd(ifdId);
    
public java.util.ListgetTagsForTagId(short tagId)
Returns a list of ExifTags that share a TID (which can be obtained by calling {@link #getTrueTagKey} on a defined tag constant) or null if none exist.

param
tagId a TID as defined in the exif standard (or with {@link #defineTag}).
return
a List of {@link ExifTag}s.

        return mData.getAllTagsForTagId(tagId);
    
public byte[]getThumbnail()
Returns the thumbnail if it is jpeg compressed, or null if none exists.

return
the thumbnail as a byte array.

        return mData.getCompressedThumbnail();
    
public android.graphics.BitmapgetThumbnailBitmap()
Returns the thumbnail from IFD1 as a bitmap, or null if none exists.

return
the thumbnail as a bitmap.

        if (mData.hasCompressedThumbnail()) {
            byte[] thumb = mData.getCompressedThumbnail();
            return BitmapFactory.decodeByteArray(thumb, 0, thumb.length);
        } else if (mData.hasUncompressedStrip()) {
            // TODO: implement uncompressed
        }
        return null;
    
public byte[]getThumbnailBytes()
Returns the thumbnail from IFD1 as a byte array, or null if none exists. The bytes may either be an uncompressed strip as specified in the exif standard or a jpeg compressed image.

return
the thumbnail as a byte array.

        if (mData.hasCompressedThumbnail()) {
            return mData.getCompressedThumbnail();
        } else if (mData.hasUncompressedStrip()) {
            // TODO: implement this
        }
        return null;
    
public static intgetTrueIfd(int tag)
Returns the default IFD for a tag constant.

        return tag >>> 16;
    
public static shortgetTrueTagKey(int tag)
Returns the TID for a tag constant.

        // Truncate
        return (short) tag;
    
protected static shortgetTypeFromInfo(int info)

        return (short) ((info >> 16) & 0x0ff);
    
public java.lang.StringgetUserComment()
Decodes the user comment tag into string as specified in the EXIF standard. Returns null if decoding failed.

        return mData.getUserComment();
    
public booleanhasThumbnail()
Check if thumbnail exists.

return
true if a compressed thumbnail exists.

        // TODO: add back in uncompressed strip
        return mData.hasCompressedThumbnail();
    
private voidinitTagInfo()

        /**
         * We put tag information in a 4-bytes integer. The first byte a bitmask
         * representing the allowed IFDs of the tag, the second byte is the data
         * type, and the last two byte are a short value indicating the default
         * component count of this tag.
         */
        // IFD0 tags
        int[] ifdAllowedIfds = {
                IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1
        };
        int ifdFlags = getFlagsFromAllowedIfds(ifdAllowedIfds) << 24;
        mTagInfo.put(ExifInterface.TAG_MAKE,
                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_IMAGE_WIDTH,
                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_IMAGE_LENGTH,
                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_BITS_PER_SAMPLE,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3);
        mTagInfo.put(ExifInterface.TAG_COMPRESSION,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_ORIENTATION, ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16
                | 1);
        mTagInfo.put(ExifInterface.TAG_SAMPLES_PER_PIXEL,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_PLANAR_CONFIGURATION,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_Y_CB_CR_POSITIONING,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_X_RESOLUTION,
                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_Y_RESOLUTION,
                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_RESOLUTION_UNIT,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_STRIP_OFFSETS,
                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_ROWS_PER_STRIP,
                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_STRIP_BYTE_COUNTS,
                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_TRANSFER_FUNCTION,
                ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3 * 256);
        mTagInfo.put(ExifInterface.TAG_WHITE_POINT,
                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_PRIMARY_CHROMATICITIES,
                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
        mTagInfo.put(ExifInterface.TAG_Y_CB_CR_COEFFICIENTS,
                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
        mTagInfo.put(ExifInterface.TAG_REFERENCE_BLACK_WHITE,
                ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
        mTagInfo.put(ExifInterface.TAG_DATE_TIME,
                ifdFlags | ExifTag.TYPE_ASCII << 16 | 20);
        mTagInfo.put(ExifInterface.TAG_IMAGE_DESCRIPTION,
                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_MAKE,
                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_MODEL,
                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_SOFTWARE,
                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_ARTIST,
                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_COPYRIGHT,
                ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_EXIF_IFD,
                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_IFD,
                ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        // IFD1 tags
        int[] ifd1AllowedIfds = {
            IfdId.TYPE_IFD_1
        };
        int ifdFlags1 = getFlagsFromAllowedIfds(ifd1AllowedIfds) << 24;
        mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT,
                ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
                ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        // Exif tags
        int[] exifAllowedIfds = {
            IfdId.TYPE_IFD_EXIF
        };
        int exifFlags = getFlagsFromAllowedIfds(exifAllowedIfds) << 24;
        mTagInfo.put(ExifInterface.TAG_EXIF_VERSION,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
        mTagInfo.put(ExifInterface.TAG_FLASHPIX_VERSION,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
        mTagInfo.put(ExifInterface.TAG_COLOR_SPACE,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_COMPONENTS_CONFIGURATION,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
        mTagInfo.put(ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_PIXEL_X_DIMENSION,
                exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_PIXEL_Y_DIMENSION,
                exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_MAKER_NOTE,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_USER_COMMENT,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_RELATED_SOUND_FILE,
                exifFlags | ExifTag.TYPE_ASCII << 16 | 13);
        mTagInfo.put(ExifInterface.TAG_DATE_TIME_ORIGINAL,
                exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
        mTagInfo.put(ExifInterface.TAG_DATE_TIME_DIGITIZED,
                exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
        mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME,
                exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_ORIGINAL,
                exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_DIGITIZED,
                exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_IMAGE_UNIQUE_ID,
                exifFlags | ExifTag.TYPE_ASCII << 16 | 33);
        mTagInfo.put(ExifInterface.TAG_EXPOSURE_TIME,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_F_NUMBER,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_EXPOSURE_PROGRAM,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SPECTRAL_SENSITIVITY,
                exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_ISO_SPEED_RATINGS,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_OECF,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_SHUTTER_SPEED_VALUE,
                exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_APERTURE_VALUE,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_BRIGHTNESS_VALUE,
                exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_EXPOSURE_BIAS_VALUE,
                exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_MAX_APERTURE_VALUE,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_METERING_MODE,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_LIGHT_SOURCE,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_FLASH,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SUBJECT_AREA,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_FLASH_ENERGY,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SUBJECT_LOCATION,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_EXPOSURE_INDEX,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SENSING_METHOD,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_FILE_SOURCE,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SCENE_TYPE,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_CFA_PATTERN,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_CUSTOM_RENDERED,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_EXPOSURE_MODE,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_WHITE_BALANCE,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_DIGITAL_ZOOM_RATIO,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH_IN_35_MM_FILE,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SCENE_CAPTURE_TYPE,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GAIN_CONTROL,
                exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_CONTRAST,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SATURATION,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_SHARPNESS,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION,
                exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE_RANGE,
                exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_INTEROPERABILITY_IFD, exifFlags
                | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
        // GPS tag
        int[] gpsAllowedIfds = {
            IfdId.TYPE_IFD_GPS
        };
        int gpsFlags = getFlagsFromAllowedIfds(gpsAllowedIfds) << 24;
        mTagInfo.put(ExifInterface.TAG_GPS_VERSION_ID,
                gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 4);
        mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE_REF,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE_REF,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE,
                gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
        mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE,
                gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
        mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE_REF,
                gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_TIME_STAMP,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
        mTagInfo.put(ExifInterface.TAG_GPS_SATTELLITES,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_GPS_STATUS,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_MEASURE_MODE,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_DOP,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_SPEED_REF,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_SPEED,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_TRACK_REF,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_TRACK,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_MAP_DATUM,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE_REF,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING_REF,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE_REF,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
        mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE,
                gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
        mTagInfo.put(ExifInterface.TAG_GPS_PROCESSING_METHOD,
                gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_GPS_AREA_INFORMATION,
                gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
        mTagInfo.put(ExifInterface.TAG_GPS_DATE_STAMP,
                gpsFlags | ExifTag.TYPE_ASCII << 16 | 11);
        mTagInfo.put(ExifInterface.TAG_GPS_DIFFERENTIAL,
                gpsFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 11);
        // Interoperability tag
        int[] interopAllowedIfds = {
            IfdId.TYPE_IFD_INTEROPERABILITY
        };
        int interopFlags = getFlagsFromAllowedIfds(interopAllowedIfds) << 24;
        mTagInfo.put(TAG_INTEROPERABILITY_INDEX, interopFlags | ExifTag.TYPE_ASCII << 16
                | ExifTag.SIZE_UNDEFINED);
    
protected static booleanisIfdAllowed(int info, int ifd)

        int[] ifds = IfdData.getIfds();
        int ifdFlags = getAllowedIfdFlagsFromInfo(info);
        for (int i = 0; i < ifds.length; i++) {
            if (ifd == ifds[i] && ((ifdFlags >> i) & 1) == 1) {
                return true;
            }
        }
        return false;
    
protected static booleanisOffsetTag(short tag)
Returns true if tag TID is one of the following: {@link TAG_EXIF_IFD}, {@link TAG_GPS_IFD}, {@link TAG_JPEG_INTERCHANGE_FORMAT}, {@link TAG_STRIP_OFFSETS}, {@link TAG_INTEROPERABILITY_IFD}

Note: defining tags with these TID's is disallowed.

param
tag a tag's TID (can be obtained from a defined tag constant with {@link #getTrueTagKey}).
return
true if the TID is that of an offset tag.

        return sOffsetTags.contains(tag);
    
public booleanisTagCountDefined(int tagId)
Checks whether a tag has a defined number of elements.

param
tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
return
true if the tag has a defined number of elements.

        int info = getTagInfo().get(tagId);
        // No value in info can be zero, as all tags have a non-zero type
        if (info == 0) {
            return false;
        }
        return getComponentCountFromInfo(info) != ExifTag.SIZE_UNDEFINED;
    
public booleanisThumbnailCompressed()
Check if thumbnail is compressed.

return
true if the thumbnail is compressed.

        return mData.hasCompressedThumbnail();
    
public voidreadExif(byte[] jpeg)
Reads the exif tags from a byte array, clearing this ExifInterface object's existing exif tags.

param
jpeg a byte array containing a jpeg compressed image.
throws
IOException

        readExif(new ByteArrayInputStream(jpeg));
    
public voidreadExif(java.io.InputStream inStream)
Reads the exif tags from an InputStream, clearing this ExifInterface object's existing exif tags.

param
inStream an InputStream containing a jpeg compressed image.
throws
IOException

        if (inStream == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        ExifData d = null;
        try {
            d = new ExifReader(this).read(inStream);
        } catch (ExifInvalidFormatException e) {
            throw new IOException("Invalid exif format : " + e);
        }
        mData = d;
    
public voidreadExif(java.lang.String inFileName)
Reads the exif tags from a file, clearing this ExifInterface object's existing exif tags.

param
inFileName a string representing the filepath to jpeg file.
throws
FileNotFoundException
throws
IOException

        if (inFileName == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        InputStream is = null;
        try {
            is = (InputStream) new BufferedInputStream(new FileInputStream(inFileName));
            readExif(is);
        } catch (IOException e) {
            closeSilently(is);
            throw e;
        }
        is.close();
    
public voidremoveCompressedThumbnail()
Clears the compressed thumbnail if it exists.

        mData.setCompressedThumbnail(null);
    
public voidremoveTagDefinition(int tagId)
Removes a tag definition for given defined tag constant.

param
tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.

        getTagInfo().delete(tagId);
    
public voidresetTagDefinitions()
Resets tag definitions to the default ones.

        mTagInfo = null;
    
public booleanrewriteExif(java.lang.String filename, java.util.Collection tags)
Attempts to do an in-place rewrite the exif metadata in a file for the given tags. If tags do not exist or do not have the same size as the existing exif tags, this method will fail.

param
filename a String containing a filepath for a jpeg file with exif tags to rewrite.
param
tags tags that will be written into the jpeg file over existing tags if possible.
return
true if success, false if could not overwrite. If false, no changes are made to the file.
throws
FileNotFoundException
throws
IOException

        RandomAccessFile file = null;
        InputStream is = null;
        boolean ret;
        try {
            File temp = new File(filename);
            is = new BufferedInputStream(new FileInputStream(temp));

            // Parse beginning of APP1 in exif to find size of exif header.
            ExifParser parser = null;
            try {
                parser = ExifParser.parse(is, this);
            } catch (ExifInvalidFormatException e) {
                throw new IOException("Invalid exif format : ", e);
            }
            long exifSize = parser.getOffsetToExifEndFromSOF();

            // Free up resources
            is.close();
            is = null;

            // Open file for memory mapping.
            file = new RandomAccessFile(temp, "rw");
            long fileLength = file.length();
            if (fileLength < exifSize) {
                throw new IOException("Filesize changed during operation");
            }

            // Map only exif header into memory.
            ByteBuffer buf = file.getChannel().map(MapMode.READ_WRITE, 0, exifSize);

            // Attempt to overwrite tag values without changing lengths (avoids
            // file copy).
            ret = rewriteExif(buf, tags);
        } catch (IOException e) {
            closeSilently(file);
            throw e;
        } finally {
            closeSilently(is);
        }
        file.close();
        return ret;
    
public booleanrewriteExif(java.nio.ByteBuffer buf, java.util.Collection tags)
Attempts to do an in-place rewrite the exif metadata in a ByteBuffer for the given tags. If tags do not exist or do not have the same size as the existing exif tags, this method will fail.

param
buf a ByteBuffer containing a jpeg file with existing exif tags to rewrite.
param
tags tags that will be written into the jpeg ByteBuffer over existing tags if possible.
return
true if success, false if could not overwrite. If false, no changes are made to the ByteBuffer.
throws
IOException

        ExifModifier mod = null;
        try {
            mod = new ExifModifier(buf, this);
            for (ExifTag t : tags) {
                mod.modifyTag(t);
            }
            return mod.commit();
        } catch (ExifInvalidFormatException e) {
            throw new IOException("Invalid exif format : " + e);
        }
    
public booleansetCompressedThumbnail(byte[] thumb)
Sets the thumbnail to be a jpeg compressed image. Clears any prior thumbnail.

param
thumb a byte array containing a jpeg compressed image.
return
true if the thumbnail was set.

        mData.clearThumbnailAndStrips();
        mData.setCompressedThumbnail(thumb);
        return true;
    
public booleansetCompressedThumbnail(android.graphics.Bitmap thumb)
Sets the thumbnail to be a jpeg compressed bitmap. Clears any prior thumbnail.

param
thumb a bitmap to compress to a jpeg thumbnail.
return
true if the thumbnail was set.

        ByteArrayOutputStream thumbnail = new ByteArrayOutputStream();
        if (!thumb.compress(Bitmap.CompressFormat.JPEG, 90, thumbnail)) {
            return false;
        }
        return setCompressedThumbnail(thumbnail.toByteArray());
    
public voidsetExif(java.util.Collection tags)
Sets the exif tags, clearing this ExifInterface object's existing exif tags.

param
tags a collection of exif tags to set.

        clearExif();
        setTags(tags);
    
public ExifTagsetTag(ExifTag tag)
Puts an ExifTag into this ExifInterface object's tags, removing a previous ExifTag with the same TID and IFD. The IFD it is put into will be the one the tag was created with in {@link #buildTag}.

param
tag an ExifTag to put into this ExifInterface's tags.
return
the previous ExifTag with the same TID and IFD or null if none exists.

        return mData.addTag(tag);
    
public intsetTagDefinition(short tagId, int defaultIfd, short tagType, short defaultComponentCount, int[] allowedIfds)
Creates a new tag definition in this ExifInterface object for a given TID and default IFD. Creating a definition with the same TID and default IFD as a previous definition will override it.

param
tagId the TID for the tag.
param
defaultIfd the default IFD for the tag.
param
tagType the type of the tag (see {@link ExifTag#getDataType()}).
param
defaultComponentCount the number of elements of this tag's type in the tags value.
param
allowedIfds the IFD's this tag is allowed to be put in.
return
the defined tag constant (e.g. {@link #TAG_IMAGE_WIDTH}) or {@link #TAG_NULL} if the definition could not be made.

        if (sBannedDefines.contains(tagId)) {
            return TAG_NULL;
        }
        if (ExifTag.isValidType(tagType) && ExifTag.isValidIfd(defaultIfd)) {
            int tagDef = defineTag(defaultIfd, tagId);
            if (tagDef == TAG_NULL) {
                return TAG_NULL;
            }
            int[] otherDefs = getTagDefinitionsForTagId(tagId);
            SparseIntArray infos = getTagInfo();
            // Make sure defaultIfd is in allowedIfds
            boolean defaultCheck = false;
            for (int i : allowedIfds) {
                if (defaultIfd == i) {
                    defaultCheck = true;
                }
                if (!ExifTag.isValidIfd(i)) {
                    return TAG_NULL;
                }
            }
            if (!defaultCheck) {
                return TAG_NULL;
            }

            int ifdFlags = getFlagsFromAllowedIfds(allowedIfds);
            // Make sure no identical tags can exist in allowedIfds
            if (otherDefs != null) {
                for (int def : otherDefs) {
                    int tagInfo = infos.get(def);
                    int allowedFlags = getAllowedIfdFlagsFromInfo(tagInfo);
                    if ((ifdFlags & allowedFlags) != 0) {
                        return TAG_NULL;
                    }
                }
            }
            getTagInfo().put(tagDef, ifdFlags << 24 | (tagType << 16) | defaultComponentCount);
            return tagDef;
        }
        return TAG_NULL;
    
public booleansetTagValue(int tagId, int ifdId, java.lang.Object val)
Sets the value of an ExifTag if it exists in the given IFD. The value must be the correct type and length for that ExifTag.

param
tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
param
ifdId the IFD that the ExifTag is in.
param
val the value to set.
return
true if success, false if the ExifTag doesn't exist or the value is the wrong type/length.
see
#setTagValue

        ExifTag t = getTag(tagId, ifdId);
        if (t == null) {
            return false;
        }
        return t.setValue(val);
    
public booleansetTagValue(int tagId, java.lang.Object val)
Sets the value of an ExifTag if it exists it's default IFD. The value must be the correct type and length for that ExifTag.

param
tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
param
val the value to set.
return
true if success, false if the ExifTag doesn't exist or the value is the wrong type/length.

        int ifdId = getDefinedTagDefaultIfd(tagId);
        return setTagValue(tagId, ifdId, val);
    
public voidsetTags(java.util.Collection tags)
Puts a collection of ExifTags into this ExifInterface objects's tags. Any previous ExifTags with the same TID and IFDs will be removed.

param
tags a Collection of ExifTags.
see
#setTag

        for (ExifTag t : tags) {
            setTag(t);
        }
    
private static Rational[]toExifLatLong(double value)

        // convert to the format dd/1 mm/1 ssss/100
        value = Math.abs(value);
        int degrees = (int) value;
        value = (value - degrees) * 60;
        int minutes = (int) value;
        value = (value - minutes) * 6000;
        int seconds = (int) value;
        return new Rational[] {
                new Rational(degrees, 1), new Rational(minutes, 1), new Rational(seconds, 100)
        };
    
public voidwriteExif(byte[] jpeg, java.io.OutputStream exifOutStream)
Writes the tags from this ExifInterface object into a jpeg image, removing prior exif tags.

param
jpeg a byte array containing a jpeg compressed image.
param
exifOutStream an OutputStream to which the jpeg image with added exif tags will be written.
throws
IOException

        if (jpeg == null || exifOutStream == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        OutputStream s = getExifWriterStream(exifOutStream);
        s.write(jpeg, 0, jpeg.length);
        s.flush();
    
public voidwriteExif(android.graphics.Bitmap bmap, java.io.OutputStream exifOutStream)
Writes the tags from this ExifInterface object into a jpeg compressed bitmap, removing prior exif tags.

param
bmap a bitmap to compress and write exif into.
param
exifOutStream the OutputStream to which the jpeg image with added exif tags will be written.
throws
IOException

        if (bmap == null || exifOutStream == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        OutputStream s = getExifWriterStream(exifOutStream);
        bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
        s.flush();
    
public voidwriteExif(java.io.InputStream jpegStream, java.io.OutputStream exifOutStream)
Writes the tags from this ExifInterface object into a jpeg stream, removing prior exif tags.

param
jpegStream an InputStream containing a jpeg compressed image.
param
exifOutStream an OutputStream to which the jpeg image with added exif tags will be written.
throws
IOException

        if (jpegStream == null || exifOutStream == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        OutputStream s = getExifWriterStream(exifOutStream);
        doExifStreamIO(jpegStream, s);
        s.flush();
    
public voidwriteExif(byte[] jpeg, java.lang.String exifOutFileName)
Writes the tags from this ExifInterface object into a jpeg image, removing prior exif tags.

param
jpeg a byte array containing a jpeg compressed image.
param
exifOutFileName a String containing the filepath to which the jpeg image with added exif tags will be written.
throws
FileNotFoundException
throws
IOException

        if (jpeg == null || exifOutFileName == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        OutputStream s = null;
        try {
            s = getExifWriterStream(exifOutFileName);
            s.write(jpeg, 0, jpeg.length);
            s.flush();
        } catch (IOException e) {
            closeSilently(s);
            throw e;
        }
        s.close();
    
public voidwriteExif(android.graphics.Bitmap bmap, java.lang.String exifOutFileName)
Writes the tags from this ExifInterface object into a jpeg compressed bitmap, removing prior exif tags.

param
bmap a bitmap to compress and write exif into.
param
exifOutFileName a String containing the filepath to which the jpeg image with added exif tags will be written.
throws
FileNotFoundException
throws
IOException

        if (bmap == null || exifOutFileName == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        OutputStream s = null;
        try {
            s = getExifWriterStream(exifOutFileName);
            bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
            s.flush();
        } catch (IOException e) {
            closeSilently(s);
            throw e;
        }
        s.close();
    
public voidwriteExif(java.io.InputStream jpegStream, java.lang.String exifOutFileName)
Writes the tags from this ExifInterface object into a jpeg stream, removing prior exif tags.

param
jpegStream an InputStream containing a jpeg compressed image.
param
exifOutFileName a String containing the filepath to which the jpeg image with added exif tags will be written.
throws
FileNotFoundException
throws
IOException

        if (jpegStream == null || exifOutFileName == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        OutputStream s = null;
        try {
            s = getExifWriterStream(exifOutFileName);
            doExifStreamIO(jpegStream, s);
            s.flush();
        } catch (IOException e) {
            closeSilently(s);
            throw e;
        }
        s.close();
    
public voidwriteExif(java.lang.String jpegFileName, java.lang.String exifOutFileName)
Writes the tags from this ExifInterface object into a jpeg file, removing prior exif tags.

param
jpegFileName a String containing the filepath for a jpeg file.
param
exifOutFileName a String containing the filepath to which the jpeg image with added exif tags will be written.
throws
FileNotFoundException
throws
IOException

        if (jpegFileName == null || exifOutFileName == null) {
            throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
        }
        InputStream is = null;
        try {
            is = new FileInputStream(jpegFileName);
            writeExif(is, exifOutFileName);
        } catch (IOException e) {
            closeSilently(is);
            throw e;
        }
        is.close();