Home | History | Annotate | Download | only in exif
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.exif;
     18 
     19 import android.graphics.Bitmap;
     20 import android.graphics.BitmapFactory;
     21 import android.util.SparseIntArray;
     22 import com.android.camera.debug.Log;
     23 
     24 import java.io.BufferedInputStream;
     25 import java.io.ByteArrayInputStream;
     26 import java.io.ByteArrayOutputStream;
     27 import java.io.Closeable;
     28 import java.io.File;
     29 import java.io.FileInputStream;
     30 import java.io.FileNotFoundException;
     31 import java.io.FileOutputStream;
     32 import java.io.IOException;
     33 import java.io.InputStream;
     34 import java.io.OutputStream;
     35 import java.io.RandomAccessFile;
     36 import java.nio.ByteBuffer;
     37 import java.nio.ByteOrder;
     38 import java.nio.channels.FileChannel.MapMode;
     39 import java.text.DateFormat;
     40 import java.text.SimpleDateFormat;
     41 import java.util.ArrayList;
     42 import java.util.Arrays;
     43 import java.util.Calendar;
     44 import java.util.Collection;
     45 import java.util.HashSet;
     46 import java.util.List;
     47 import java.util.TimeZone;
     48 
     49 /**
     50  * This class provides methods and constants for reading and writing jpeg file
     51  * metadata. It contains a collection of ExifTags, and a collection of
     52  * definitions for creating valid ExifTags. The collection of ExifTags can be
     53  * updated by: reading new ones from a file, deleting or adding existing ones,
     54  * or building new ExifTags from a tag definition. These ExifTags can be written
     55  * to a valid jpeg image as exif metadata.
     56  * <p>
     57  * Each ExifTag has a tag ID (TID) and is stored in a specific image file
     58  * directory (IFD) as specified by the exif standard. A tag definition can be
     59  * looked up with a constant that is a combination of TID and IFD. This
     60  * definition has information about the type, number of components, and valid
     61  * IFDs for a tag.
     62  *
     63  * @see ExifTag
     64  */
     65 public class ExifInterface {
     66     public static final int TAG_NULL = -1;
     67     public static final int IFD_NULL = -1;
     68     public static final int DEFINITION_NULL = 0;
     69 
     70     /**
     71      * Tag constants for Jeita EXIF 2.2
     72      */
     73     public static final String EXIF_VERSION = "0220";
     74 
     75     // IFD 0
     76     public static final int TAG_IMAGE_WIDTH =
     77         defineTag(IfdId.TYPE_IFD_0, (short) 0x0100);
     78     public static final int TAG_IMAGE_LENGTH =
     79         defineTag(IfdId.TYPE_IFD_0, (short) 0x0101); // Image height
     80     public static final int TAG_BITS_PER_SAMPLE =
     81         defineTag(IfdId.TYPE_IFD_0, (short) 0x0102);
     82     public static final int TAG_COMPRESSION =
     83         defineTag(IfdId.TYPE_IFD_0, (short) 0x0103);
     84     public static final int TAG_PHOTOMETRIC_INTERPRETATION =
     85         defineTag(IfdId.TYPE_IFD_0, (short) 0x0106);
     86     public static final int TAG_IMAGE_DESCRIPTION =
     87         defineTag(IfdId.TYPE_IFD_0, (short) 0x010E);
     88     public static final int TAG_MAKE =
     89         defineTag(IfdId.TYPE_IFD_0, (short) 0x010F);
     90     public static final int TAG_MODEL =
     91         defineTag(IfdId.TYPE_IFD_0, (short) 0x0110);
     92     public static final int TAG_STRIP_OFFSETS =
     93         defineTag(IfdId.TYPE_IFD_0, (short) 0x0111);
     94     public static final int TAG_ORIENTATION =
     95         defineTag(IfdId.TYPE_IFD_0, (short) 0x0112);
     96     public static final int TAG_SAMPLES_PER_PIXEL =
     97         defineTag(IfdId.TYPE_IFD_0, (short) 0x0115);
     98     public static final int TAG_ROWS_PER_STRIP =
     99         defineTag(IfdId.TYPE_IFD_0, (short) 0x0116);
    100     public static final int TAG_STRIP_BYTE_COUNTS =
    101         defineTag(IfdId.TYPE_IFD_0, (short) 0x0117);
    102     public static final int TAG_X_RESOLUTION =
    103         defineTag(IfdId.TYPE_IFD_0, (short) 0x011A);
    104     public static final int TAG_Y_RESOLUTION =
    105         defineTag(IfdId.TYPE_IFD_0, (short) 0x011B);
    106     public static final int TAG_PLANAR_CONFIGURATION =
    107         defineTag(IfdId.TYPE_IFD_0, (short) 0x011C);
    108     public static final int TAG_RESOLUTION_UNIT =
    109         defineTag(IfdId.TYPE_IFD_0, (short) 0x0128);
    110     public static final int TAG_TRANSFER_FUNCTION =
    111         defineTag(IfdId.TYPE_IFD_0, (short) 0x012D);
    112     public static final int TAG_SOFTWARE =
    113         defineTag(IfdId.TYPE_IFD_0, (short) 0x0131);
    114     public static final int TAG_DATE_TIME =
    115         defineTag(IfdId.TYPE_IFD_0, (short) 0x0132);
    116     public static final int TAG_ARTIST =
    117         defineTag(IfdId.TYPE_IFD_0, (short) 0x013B);
    118     public static final int TAG_WHITE_POINT =
    119         defineTag(IfdId.TYPE_IFD_0, (short) 0x013E);
    120     public static final int TAG_PRIMARY_CHROMATICITIES =
    121         defineTag(IfdId.TYPE_IFD_0, (short) 0x013F);
    122     public static final int TAG_Y_CB_CR_COEFFICIENTS =
    123         defineTag(IfdId.TYPE_IFD_0, (short) 0x0211);
    124     public static final int TAG_Y_CB_CR_SUB_SAMPLING =
    125         defineTag(IfdId.TYPE_IFD_0, (short) 0x0212);
    126     public static final int TAG_Y_CB_CR_POSITIONING =
    127         defineTag(IfdId.TYPE_IFD_0, (short) 0x0213);
    128     public static final int TAG_REFERENCE_BLACK_WHITE =
    129         defineTag(IfdId.TYPE_IFD_0, (short) 0x0214);
    130     public static final int TAG_COPYRIGHT =
    131         defineTag(IfdId.TYPE_IFD_0, (short) 0x8298);
    132     public static final int TAG_EXIF_IFD =
    133         defineTag(IfdId.TYPE_IFD_0, (short) 0x8769);
    134     public static final int TAG_GPS_IFD =
    135         defineTag(IfdId.TYPE_IFD_0, (short) 0x8825);
    136     // IFD 1
    137     public static final int TAG_JPEG_INTERCHANGE_FORMAT =
    138         defineTag(IfdId.TYPE_IFD_1, (short) 0x0201);
    139     public static final int TAG_JPEG_INTERCHANGE_FORMAT_LENGTH =
    140         defineTag(IfdId.TYPE_IFD_1, (short) 0x0202);
    141     // IFD Exif Tags
    142     public static final int TAG_EXPOSURE_TIME =
    143         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829A);
    144     public static final int TAG_F_NUMBER =
    145         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829D);
    146     public static final int TAG_EXPOSURE_PROGRAM =
    147         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8822);
    148     public static final int TAG_SPECTRAL_SENSITIVITY =
    149         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8824);
    150     public static final int TAG_ISO_SPEED_RATINGS =
    151         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8827);
    152     public static final int TAG_OECF =
    153         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8828);
    154     public static final int TAG_EXIF_VERSION =
    155         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9000);
    156     public static final int TAG_DATE_TIME_ORIGINAL =
    157         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9003);
    158     public static final int TAG_DATE_TIME_DIGITIZED =
    159         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9004);
    160     public static final int TAG_COMPONENTS_CONFIGURATION =
    161         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9101);
    162     public static final int TAG_COMPRESSED_BITS_PER_PIXEL =
    163         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9102);
    164     public static final int TAG_SHUTTER_SPEED_VALUE =
    165         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9201);
    166     public static final int TAG_APERTURE_VALUE =
    167         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9202);
    168     public static final int TAG_BRIGHTNESS_VALUE =
    169         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9203);
    170     public static final int TAG_EXPOSURE_BIAS_VALUE =
    171         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9204);
    172     public static final int TAG_MAX_APERTURE_VALUE =
    173         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9205);
    174     public static final int TAG_SUBJECT_DISTANCE =
    175         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9206);
    176     public static final int TAG_METERING_MODE =
    177         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9207);
    178     public static final int TAG_LIGHT_SOURCE =
    179         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9208);
    180     public static final int TAG_FLASH =
    181         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9209);
    182     public static final int TAG_FOCAL_LENGTH =
    183         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x920A);
    184     public static final int TAG_SUBJECT_AREA =
    185         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9214);
    186     public static final int TAG_MAKER_NOTE =
    187         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x927C);
    188     public static final int TAG_USER_COMMENT =
    189         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9286);
    190     public static final int TAG_SUB_SEC_TIME =
    191         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9290);
    192     public static final int TAG_SUB_SEC_TIME_ORIGINAL =
    193         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9291);
    194     public static final int TAG_SUB_SEC_TIME_DIGITIZED =
    195         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9292);
    196     public static final int TAG_FLASHPIX_VERSION =
    197         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA000);
    198     public static final int TAG_COLOR_SPACE =
    199         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA001);
    200     public static final int TAG_PIXEL_X_DIMENSION =
    201         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA002);
    202     public static final int TAG_PIXEL_Y_DIMENSION =
    203         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA003);
    204     public static final int TAG_RELATED_SOUND_FILE =
    205         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA004);
    206     public static final int TAG_INTEROPERABILITY_IFD =
    207         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA005);
    208     public static final int TAG_FLASH_ENERGY =
    209         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20B);
    210     public static final int TAG_SPATIAL_FREQUENCY_RESPONSE =
    211         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20C);
    212     public static final int TAG_FOCAL_PLANE_X_RESOLUTION =
    213         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20E);
    214     public static final int TAG_FOCAL_PLANE_Y_RESOLUTION =
    215         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20F);
    216     public static final int TAG_FOCAL_PLANE_RESOLUTION_UNIT =
    217         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA210);
    218     public static final int TAG_SUBJECT_LOCATION =
    219         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA214);
    220     public static final int TAG_EXPOSURE_INDEX =
    221         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA215);
    222     public static final int TAG_SENSING_METHOD =
    223         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA217);
    224     public static final int TAG_FILE_SOURCE =
    225         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA300);
    226     public static final int TAG_SCENE_TYPE =
    227         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA301);
    228     public static final int TAG_CFA_PATTERN =
    229         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA302);
    230     public static final int TAG_CUSTOM_RENDERED =
    231         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA401);
    232     public static final int TAG_EXPOSURE_MODE =
    233         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA402);
    234     public static final int TAG_WHITE_BALANCE =
    235         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA403);
    236     public static final int TAG_DIGITAL_ZOOM_RATIO =
    237         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA404);
    238     public static final int TAG_FOCAL_LENGTH_IN_35_MM_FILE =
    239         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA405);
    240     public static final int TAG_SCENE_CAPTURE_TYPE =
    241         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA406);
    242     public static final int TAG_GAIN_CONTROL =
    243         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA407);
    244     public static final int TAG_CONTRAST =
    245         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA408);
    246     public static final int TAG_SATURATION =
    247         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA409);
    248     public static final int TAG_SHARPNESS =
    249         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40A);
    250     public static final int TAG_DEVICE_SETTING_DESCRIPTION =
    251         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40B);
    252     public static final int TAG_SUBJECT_DISTANCE_RANGE =
    253         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40C);
    254     public static final int TAG_IMAGE_UNIQUE_ID =
    255         defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA420);
    256     // IFD GPS tags
    257     public static final int TAG_GPS_VERSION_ID =
    258         defineTag(IfdId.TYPE_IFD_GPS, (short) 0);
    259     public static final int TAG_GPS_LATITUDE_REF =
    260         defineTag(IfdId.TYPE_IFD_GPS, (short) 1);
    261     public static final int TAG_GPS_LATITUDE =
    262         defineTag(IfdId.TYPE_IFD_GPS, (short) 2);
    263     public static final int TAG_GPS_LONGITUDE_REF =
    264         defineTag(IfdId.TYPE_IFD_GPS, (short) 3);
    265     public static final int TAG_GPS_LONGITUDE =
    266         defineTag(IfdId.TYPE_IFD_GPS, (short) 4);
    267     public static final int TAG_GPS_ALTITUDE_REF =
    268         defineTag(IfdId.TYPE_IFD_GPS, (short) 5);
    269     public static final int TAG_GPS_ALTITUDE =
    270         defineTag(IfdId.TYPE_IFD_GPS, (short) 6);
    271     public static final int TAG_GPS_TIME_STAMP =
    272         defineTag(IfdId.TYPE_IFD_GPS, (short) 7);
    273     public static final int TAG_GPS_SATTELLITES =
    274         defineTag(IfdId.TYPE_IFD_GPS, (short) 8);
    275     public static final int TAG_GPS_STATUS =
    276         defineTag(IfdId.TYPE_IFD_GPS, (short) 9);
    277     public static final int TAG_GPS_MEASURE_MODE =
    278         defineTag(IfdId.TYPE_IFD_GPS, (short) 10);
    279     public static final int TAG_GPS_DOP =
    280         defineTag(IfdId.TYPE_IFD_GPS, (short) 11);
    281     public static final int TAG_GPS_SPEED_REF =
    282         defineTag(IfdId.TYPE_IFD_GPS, (short) 12);
    283     public static final int TAG_GPS_SPEED =
    284         defineTag(IfdId.TYPE_IFD_GPS, (short) 13);
    285     public static final int TAG_GPS_TRACK_REF =
    286         defineTag(IfdId.TYPE_IFD_GPS, (short) 14);
    287     public static final int TAG_GPS_TRACK =
    288         defineTag(IfdId.TYPE_IFD_GPS, (short) 15);
    289     public static final int TAG_GPS_IMG_DIRECTION_REF =
    290         defineTag(IfdId.TYPE_IFD_GPS, (short) 16);
    291     public static final int TAG_GPS_IMG_DIRECTION =
    292         defineTag(IfdId.TYPE_IFD_GPS, (short) 17);
    293     public static final int TAG_GPS_MAP_DATUM =
    294         defineTag(IfdId.TYPE_IFD_GPS, (short) 18);
    295     public static final int TAG_GPS_DEST_LATITUDE_REF =
    296         defineTag(IfdId.TYPE_IFD_GPS, (short) 19);
    297     public static final int TAG_GPS_DEST_LATITUDE =
    298         defineTag(IfdId.TYPE_IFD_GPS, (short) 20);
    299     public static final int TAG_GPS_DEST_LONGITUDE_REF =
    300         defineTag(IfdId.TYPE_IFD_GPS, (short) 21);
    301     public static final int TAG_GPS_DEST_LONGITUDE =
    302         defineTag(IfdId.TYPE_IFD_GPS, (short) 22);
    303     public static final int TAG_GPS_DEST_BEARING_REF =
    304         defineTag(IfdId.TYPE_IFD_GPS, (short) 23);
    305     public static final int TAG_GPS_DEST_BEARING =
    306         defineTag(IfdId.TYPE_IFD_GPS, (short) 24);
    307     public static final int TAG_GPS_DEST_DISTANCE_REF =
    308         defineTag(IfdId.TYPE_IFD_GPS, (short) 25);
    309     public static final int TAG_GPS_DEST_DISTANCE =
    310         defineTag(IfdId.TYPE_IFD_GPS, (short) 26);
    311     public static final int TAG_GPS_PROCESSING_METHOD =
    312         defineTag(IfdId.TYPE_IFD_GPS, (short) 27);
    313     public static final int TAG_GPS_AREA_INFORMATION =
    314         defineTag(IfdId.TYPE_IFD_GPS, (short) 28);
    315     public static final int TAG_GPS_DATE_STAMP =
    316         defineTag(IfdId.TYPE_IFD_GPS, (short) 29);
    317     public static final int TAG_GPS_DIFFERENTIAL =
    318         defineTag(IfdId.TYPE_IFD_GPS, (short) 30);
    319     // IFD Interoperability tags
    320     public static final int TAG_INTEROPERABILITY_INDEX =
    321         defineTag(IfdId.TYPE_IFD_INTEROPERABILITY, (short) 1);
    322     private static final Log.Tag TAG = new Log.Tag("ExifInterface");
    323 
    324     /**
    325      * Tags that contain offset markers. These are included in the banned
    326      * defines.
    327      */
    328     private static HashSet<Short> sOffsetTags = new HashSet<Short>();
    329     static {
    330         sOffsetTags.add(getTrueTagKey(TAG_GPS_IFD));
    331         sOffsetTags.add(getTrueTagKey(TAG_EXIF_IFD));
    332         sOffsetTags.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT));
    333         sOffsetTags.add(getTrueTagKey(TAG_INTEROPERABILITY_IFD));
    334         sOffsetTags.add(getTrueTagKey(TAG_STRIP_OFFSETS));
    335     }
    336 
    337     /**
    338      * Tags with definitions that cannot be overridden (banned defines).
    339      */
    340     protected static HashSet<Short> sBannedDefines = new HashSet<Short>(sOffsetTags);
    341     static {
    342         sBannedDefines.add(getTrueTagKey(TAG_NULL));
    343         sBannedDefines.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
    344         sBannedDefines.add(getTrueTagKey(TAG_STRIP_BYTE_COUNTS));
    345     }
    346 
    347     /**
    348      * Returns the constant representing a tag with a given TID and default IFD.
    349      */
    350     public static int defineTag(int ifdId, short tagId) {
    351         return (tagId & 0x0000ffff) | (ifdId << 16);
    352     }
    353 
    354     /**
    355      * Returns the TID for a tag constant.
    356      */
    357     public static short getTrueTagKey(int tag) {
    358         // Truncate
    359         return (short) tag;
    360     }
    361 
    362     /**
    363      * Returns the default IFD for a tag constant.
    364      */
    365     public static int getTrueIfd(int tag) {
    366         return tag >>> 16;
    367     }
    368 
    369     /**
    370      * Constants for {@link TAG_ORIENTATION}. They can be interpreted as
    371      * follows:
    372      * <ul>
    373      * <li>TOP_LEFT is the normal orientation.</li>
    374      * <li>TOP_RIGHT is a left-right mirror.</li>
    375      * <li>BOTTOM_LEFT is a 180 degree rotation.</li>
    376      * <li>BOTTOM_RIGHT is a top-bottom mirror.</li>
    377      * <li>LEFT_TOP is mirrored about the top-left<->bottom-right axis.</li>
    378      * <li>RIGHT_TOP is a 90 degree clockwise rotation.</li>
    379      * <li>LEFT_BOTTOM is mirrored about the top-right<->bottom-left axis.</li>
    380      * <li>RIGHT_BOTTOM is a 270 degree clockwise rotation.</li>
    381      * </ul>
    382      */
    383     public static interface Orientation {
    384         public static final short TOP_LEFT = 1;
    385         public static final short TOP_RIGHT = 2;
    386         public static final short BOTTOM_LEFT = 3;
    387         public static final short BOTTOM_RIGHT = 4;
    388         public static final short LEFT_TOP = 5;
    389         public static final short RIGHT_TOP = 6;
    390         public static final short LEFT_BOTTOM = 7;
    391         public static final short RIGHT_BOTTOM = 8;
    392     }
    393 
    394     /**
    395      * Constants for {@link TAG_Y_CB_CR_POSITIONING}
    396      */
    397     public static interface YCbCrPositioning {
    398         public static final short CENTERED = 1;
    399         public static final short CO_SITED = 2;
    400     }
    401 
    402     /**
    403      * Constants for {@link TAG_COMPRESSION}
    404      */
    405     public static interface Compression {
    406         public static final short UNCOMPRESSION = 1;
    407         public static final short JPEG = 6;
    408     }
    409 
    410     /**
    411      * Constants for {@link TAG_RESOLUTION_UNIT}
    412      */
    413     public static interface ResolutionUnit {
    414         public static final short INCHES = 2;
    415         public static final short CENTIMETERS = 3;
    416     }
    417 
    418     /**
    419      * Constants for {@link TAG_PHOTOMETRIC_INTERPRETATION}
    420      */
    421     public static interface PhotometricInterpretation {
    422         public static final short RGB = 2;
    423         public static final short YCBCR = 6;
    424     }
    425 
    426     /**
    427      * Constants for {@link TAG_PLANAR_CONFIGURATION}
    428      */
    429     public static interface PlanarConfiguration {
    430         public static final short CHUNKY = 1;
    431         public static final short PLANAR = 2;
    432     }
    433 
    434     /**
    435      * Constants for {@link TAG_EXPOSURE_PROGRAM}
    436      */
    437     public static interface ExposureProgram {
    438         public static final short NOT_DEFINED = 0;
    439         public static final short MANUAL = 1;
    440         public static final short NORMAL_PROGRAM = 2;
    441         public static final short APERTURE_PRIORITY = 3;
    442         public static final short SHUTTER_PRIORITY = 4;
    443         public static final short CREATIVE_PROGRAM = 5;
    444         public static final short ACTION_PROGRAM = 6;
    445         public static final short PROTRAIT_MODE = 7;
    446         public static final short LANDSCAPE_MODE = 8;
    447     }
    448 
    449     /**
    450      * Constants for {@link TAG_METERING_MODE}
    451      */
    452     public static interface MeteringMode {
    453         public static final short UNKNOWN = 0;
    454         public static final short AVERAGE = 1;
    455         public static final short CENTER_WEIGHTED_AVERAGE = 2;
    456         public static final short SPOT = 3;
    457         public static final short MULTISPOT = 4;
    458         public static final short PATTERN = 5;
    459         public static final short PARTAIL = 6;
    460         public static final short OTHER = 255;
    461     }
    462 
    463     /**
    464      * Constants for {@link TAG_FLASH} As the definition in Jeita EXIF 2.2
    465      * standard, we can treat this constant as bitwise flag.
    466      * <p>
    467      * e.g.
    468      * <p>
    469      * short flash = FIRED | RETURN_STROBE_RETURN_LIGHT_DETECTED |
    470      * MODE_AUTO_MODE
    471      */
    472     public static interface Flash {
    473         // LSB
    474         public static final short DID_NOT_FIRE = 0;
    475         public static final short FIRED = 1;
    476         // 1st~2nd bits
    477         public static final short RETURN_NO_STROBE_RETURN_DETECTION_FUNCTION = 0 << 1;
    478         public static final short RETURN_STROBE_RETURN_LIGHT_NOT_DETECTED = 2 << 1;
    479         public static final short RETURN_STROBE_RETURN_LIGHT_DETECTED = 3 << 1;
    480         // 3rd~4th bits
    481         public static final short MODE_UNKNOWN = 0 << 3;
    482         public static final short MODE_COMPULSORY_FLASH_FIRING = 1 << 3;
    483         public static final short MODE_COMPULSORY_FLASH_SUPPRESSION = 2 << 3;
    484         public static final short MODE_AUTO_MODE = 3 << 3;
    485         // 5th bit
    486         public static final short FUNCTION_PRESENT = 0 << 5;
    487         public static final short FUNCTION_NO_FUNCTION = 1 << 5;
    488         // 6th bit
    489         public static final short RED_EYE_REDUCTION_NO_OR_UNKNOWN = 0 << 6;
    490         public static final short RED_EYE_REDUCTION_SUPPORT = 1 << 6;
    491     }
    492 
    493     /**
    494      * Constants for {@link TAG_COLOR_SPACE}
    495      */
    496     public static interface ColorSpace {
    497         public static final short SRGB = 1;
    498         public static final short UNCALIBRATED = (short) 0xFFFF;
    499     }
    500 
    501     /**
    502      * Constants for {@link TAG_EXPOSURE_MODE}
    503      */
    504     public static interface ExposureMode {
    505         public static final short AUTO_EXPOSURE = 0;
    506         public static final short MANUAL_EXPOSURE = 1;
    507         public static final short AUTO_BRACKET = 2;
    508     }
    509 
    510     /**
    511      * Constants for {@link TAG_WHITE_BALANCE}
    512      */
    513     public static interface WhiteBalance {
    514         public static final short AUTO = 0;
    515         public static final short MANUAL = 1;
    516     }
    517 
    518     /**
    519      * Constants for {@link TAG_SCENE_CAPTURE_TYPE}
    520      */
    521     public static interface SceneCapture {
    522         public static final short STANDARD = 0;
    523         public static final short LANDSCAPE = 1;
    524         public static final short PROTRAIT = 2;
    525         public static final short NIGHT_SCENE = 3;
    526     }
    527 
    528     /**
    529      * Constants for {@link TAG_COMPONENTS_CONFIGURATION}
    530      */
    531     public static interface ComponentsConfiguration {
    532         public static final short NOT_EXIST = 0;
    533         public static final short Y = 1;
    534         public static final short CB = 2;
    535         public static final short CR = 3;
    536         public static final short R = 4;
    537         public static final short G = 5;
    538         public static final short B = 6;
    539     }
    540 
    541     /**
    542      * Constants for {@link TAG_LIGHT_SOURCE}
    543      */
    544     public static interface LightSource {
    545         public static final short UNKNOWN = 0;
    546         public static final short DAYLIGHT = 1;
    547         public static final short FLUORESCENT = 2;
    548         public static final short TUNGSTEN = 3;
    549         public static final short FLASH = 4;
    550         public static final short FINE_WEATHER = 9;
    551         public static final short CLOUDY_WEATHER = 10;
    552         public static final short SHADE = 11;
    553         public static final short DAYLIGHT_FLUORESCENT = 12;
    554         public static final short DAY_WHITE_FLUORESCENT = 13;
    555         public static final short COOL_WHITE_FLUORESCENT = 14;
    556         public static final short WHITE_FLUORESCENT = 15;
    557         public static final short STANDARD_LIGHT_A = 17;
    558         public static final short STANDARD_LIGHT_B = 18;
    559         public static final short STANDARD_LIGHT_C = 19;
    560         public static final short D55 = 20;
    561         public static final short D65 = 21;
    562         public static final short D75 = 22;
    563         public static final short D50 = 23;
    564         public static final short ISO_STUDIO_TUNGSTEN = 24;
    565         public static final short OTHER = 255;
    566     }
    567 
    568     /**
    569      * Constants for {@link TAG_SENSING_METHOD}
    570      */
    571     public static interface SensingMethod {
    572         public static final short NOT_DEFINED = 1;
    573         public static final short ONE_CHIP_COLOR = 2;
    574         public static final short TWO_CHIP_COLOR = 3;
    575         public static final short THREE_CHIP_COLOR = 4;
    576         public static final short COLOR_SEQUENTIAL_AREA = 5;
    577         public static final short TRILINEAR = 7;
    578         public static final short COLOR_SEQUENTIAL_LINEAR = 8;
    579     }
    580 
    581     /**
    582      * Constants for {@link TAG_FILE_SOURCE}
    583      */
    584     public static interface FileSource {
    585         public static final short DSC = 3;
    586     }
    587 
    588     /**
    589      * Constants for {@link TAG_SCENE_TYPE}
    590      */
    591     public static interface SceneType {
    592         public static final short DIRECT_PHOTOGRAPHED = 1;
    593     }
    594 
    595     /**
    596      * Constants for {@link TAG_GAIN_CONTROL}
    597      */
    598     public static interface GainControl {
    599         public static final short NONE = 0;
    600         public static final short LOW_UP = 1;
    601         public static final short HIGH_UP = 2;
    602         public static final short LOW_DOWN = 3;
    603         public static final short HIGH_DOWN = 4;
    604     }
    605 
    606     /**
    607      * Constants for {@link TAG_CONTRAST}
    608      */
    609     public static interface Contrast {
    610         public static final short NORMAL = 0;
    611         public static final short SOFT = 1;
    612         public static final short HARD = 2;
    613     }
    614 
    615     /**
    616      * Constants for {@link TAG_SATURATION}
    617      */
    618     public static interface Saturation {
    619         public static final short NORMAL = 0;
    620         public static final short LOW = 1;
    621         public static final short HIGH = 2;
    622     }
    623 
    624     /**
    625      * Constants for {@link TAG_SHARPNESS}
    626      */
    627     public static interface Sharpness {
    628         public static final short NORMAL = 0;
    629         public static final short SOFT = 1;
    630         public static final short HARD = 2;
    631     }
    632 
    633     /**
    634      * Constants for {@link TAG_SUBJECT_DISTANCE}
    635      */
    636     public static interface SubjectDistance {
    637         public static final short UNKNOWN = 0;
    638         public static final short MACRO = 1;
    639         public static final short CLOSE_VIEW = 2;
    640         public static final short DISTANT_VIEW = 3;
    641     }
    642 
    643     /**
    644      * Constants for {@link TAG_GPS_LATITUDE_REF},
    645      * {@link TAG_GPS_DEST_LATITUDE_REF}
    646      */
    647     public static interface GpsLatitudeRef {
    648         public static final String NORTH = "N";
    649         public static final String SOUTH = "S";
    650     }
    651 
    652     /**
    653      * Constants for {@link TAG_GPS_LONGITUDE_REF},
    654      * {@link TAG_GPS_DEST_LONGITUDE_REF}
    655      */
    656     public static interface GpsLongitudeRef {
    657         public static final String EAST = "E";
    658         public static final String WEST = "W";
    659     }
    660 
    661     /**
    662      * Constants for {@link TAG_GPS_ALTITUDE_REF}
    663      */
    664     public static interface GpsAltitudeRef {
    665         public static final short SEA_LEVEL = 0;
    666         public static final short SEA_LEVEL_NEGATIVE = 1;
    667     }
    668 
    669     /**
    670      * Constants for {@link TAG_GPS_STATUS}
    671      */
    672     public static interface GpsStatus {
    673         public static final String IN_PROGRESS = "A";
    674         public static final String INTEROPERABILITY = "V";
    675     }
    676 
    677     /**
    678      * Constants for {@link TAG_GPS_MEASURE_MODE}
    679      */
    680     public static interface GpsMeasureMode {
    681         public static final String MODE_2_DIMENSIONAL = "2";
    682         public static final String MODE_3_DIMENSIONAL = "3";
    683     }
    684 
    685     /**
    686      * Constants for {@link TAG_GPS_SPEED_REF},
    687      * {@link TAG_GPS_DEST_DISTANCE_REF}
    688      */
    689     public static interface GpsSpeedRef {
    690         public static final String KILOMETERS = "K";
    691         public static final String MILES = "M";
    692         public static final String KNOTS = "N";
    693     }
    694 
    695     /**
    696      * Constants for {@link TAG_GPS_TRACK_REF},
    697      * {@link TAG_GPS_IMG_DIRECTION_REF}, {@link TAG_GPS_DEST_BEARING_REF}
    698      */
    699     public static interface GpsTrackRef {
    700         public static final String TRUE_DIRECTION = "T";
    701         public static final String MAGNETIC_DIRECTION = "M";
    702     }
    703 
    704     /**
    705      * Constants for {@link TAG_GPS_DIFFERENTIAL}
    706      */
    707     public static interface GpsDifferential {
    708         public static final short WITHOUT_DIFFERENTIAL_CORRECTION = 0;
    709         public static final short DIFFERENTIAL_CORRECTION_APPLIED = 1;
    710     }
    711 
    712     private static final String NULL_ARGUMENT_STRING = "Argument is null";
    713     private ExifData mData = new ExifData(DEFAULT_BYTE_ORDER);
    714     public static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
    715 
    716     public ExifInterface() {
    717         mGPSDateStampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    718     }
    719 
    720     /**
    721      * Reads the exif tags from a byte array, clearing this ExifInterface
    722      * object's existing exif tags.
    723      *
    724      * @param jpeg a byte array containing a jpeg compressed image.
    725      * @throws IOException
    726      */
    727     public void readExif(byte[] jpeg) throws IOException {
    728         readExif(new ByteArrayInputStream(jpeg));
    729     }
    730 
    731     /**
    732      * Reads the exif tags from an InputStream, clearing this ExifInterface
    733      * object's existing exif tags.
    734      *
    735      * @param inStream an InputStream containing a jpeg compressed image.
    736      * @throws IOException
    737      */
    738     public void readExif(InputStream inStream) throws IOException {
    739         if (inStream == null) {
    740             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    741         }
    742         ExifData d = null;
    743         try {
    744             d = new ExifReader(this).read(inStream);
    745         } catch (ExifInvalidFormatException e) {
    746             throw new IOException("Invalid exif format : " + e);
    747         }
    748         mData = d;
    749     }
    750 
    751     /**
    752      * Reads the exif tags from a file, clearing this ExifInterface object's
    753      * existing exif tags.
    754      *
    755      * @param inFileName a string representing the filepath to jpeg file.
    756      * @throws FileNotFoundException
    757      * @throws IOException
    758      */
    759     public void readExif(String inFileName) throws FileNotFoundException, IOException {
    760         if (inFileName == null) {
    761             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    762         }
    763         InputStream is = null;
    764 
    765         is = new BufferedInputStream(new FileInputStream(inFileName));
    766         readExif(is);
    767 
    768         is.close();
    769     }
    770 
    771     /**
    772      * Sets the exif tags, clearing this ExifInterface object's existing exif
    773      * tags.
    774      *
    775      * @param tags a collection of exif tags to set.
    776      */
    777     public void setExif(Collection<ExifTag> tags) {
    778         clearExif();
    779         setTags(tags);
    780     }
    781 
    782     /**
    783      * Clears this ExifInterface object's existing exif tags.
    784      */
    785     public void clearExif() {
    786         mData = new ExifData(DEFAULT_BYTE_ORDER);
    787     }
    788 
    789     /**
    790      * Writes the tags from this ExifInterface object into a jpeg image,
    791      * removing prior exif tags.
    792      *
    793      * @param jpeg a byte array containing a jpeg compressed image.
    794      * @param exifOutStream an OutputStream to which the jpeg image with added
    795      *            exif tags will be written.
    796      * @throws IOException
    797      */
    798     public void writeExif(byte[] jpeg, OutputStream exifOutStream) throws IOException {
    799         if (jpeg == null || exifOutStream == null) {
    800             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    801         }
    802         OutputStream s = getExifWriterStream(exifOutStream);
    803         s.write(jpeg, 0, jpeg.length);
    804         s.flush();
    805     }
    806 
    807     /**
    808      * Writes the tags from this ExifInterface object into a jpeg compressed
    809      * bitmap, removing prior exif tags.
    810      *
    811      * @param bmap a bitmap to compress and write exif into.
    812      * @param exifOutStream the OutputStream to which the jpeg image with added
    813      *            exif tags will be written.
    814      * @throws IOException
    815      */
    816     public void writeExif(Bitmap bmap, OutputStream exifOutStream) throws IOException {
    817         if (bmap == null || exifOutStream == null) {
    818             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    819         }
    820         OutputStream s = getExifWriterStream(exifOutStream);
    821         bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
    822         s.flush();
    823     }
    824 
    825     /**
    826      * Writes the tags from this ExifInterface object into a jpeg stream,
    827      * removing prior exif tags.
    828      *
    829      * @param jpegStream an InputStream containing a jpeg compressed image.
    830      * @param exifOutStream an OutputStream to which the jpeg image with added
    831      *            exif tags will be written.
    832      * @throws IOException
    833      */
    834     public void writeExif(InputStream jpegStream, OutputStream exifOutStream) throws IOException {
    835         if (jpegStream == null || exifOutStream == null) {
    836             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    837         }
    838         OutputStream s = getExifWriterStream(exifOutStream);
    839         doExifStreamIO(jpegStream, s);
    840         s.flush();
    841     }
    842 
    843     /**
    844      * Writes the tags from this ExifInterface object into a jpeg image,
    845      * removing prior exif tags.
    846      *
    847      * @param jpeg a byte array containing a jpeg compressed image.
    848      * @param exifOutFileName a String containing the filepath to which the jpeg
    849      *            image with added exif tags will be written.
    850      * @throws FileNotFoundException
    851      * @throws IOException
    852      */
    853     public void writeExif(byte[] jpeg, String exifOutFileName) throws FileNotFoundException,
    854             IOException {
    855         if (jpeg == null || exifOutFileName == null) {
    856             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    857         }
    858         OutputStream s = null;
    859         s = getExifWriterStream(exifOutFileName);
    860         s.write(jpeg, 0, jpeg.length);
    861         s.flush();
    862         s.close();
    863     }
    864 
    865     /**
    866      * Writes the tags from this ExifInterface object into a jpeg compressed
    867      * bitmap, removing prior exif tags.
    868      *
    869      * @param bmap a bitmap to compress and write exif into.
    870      * @param exifOutFileName a String containing the filepath to which the jpeg
    871      *            image with added exif tags will be written.
    872      * @throws FileNotFoundException
    873      * @throws IOException
    874      */
    875     public void writeExif(Bitmap bmap, String exifOutFileName) throws FileNotFoundException,
    876             IOException {
    877         if (bmap == null || exifOutFileName == null) {
    878             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    879         }
    880         OutputStream s = null;
    881 
    882         s = getExifWriterStream(exifOutFileName);
    883         bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
    884         s.flush();
    885         s.close();
    886     }
    887 
    888     /**
    889      * Writes the tags from this ExifInterface object into a jpeg stream,
    890      * removing prior exif tags.
    891      *
    892      * @param jpegStream an InputStream containing a jpeg compressed image.
    893      * @param exifOutFileName a String containing the filepath to which the jpeg
    894      *            image with added exif tags will be written.
    895      * @throws FileNotFoundException
    896      * @throws IOException
    897      */
    898     public void writeExif(InputStream jpegStream, String exifOutFileName)
    899             throws FileNotFoundException, IOException {
    900         if (jpegStream == null || exifOutFileName == null) {
    901             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    902         }
    903         OutputStream s = null;
    904 
    905         s = getExifWriterStream(exifOutFileName);
    906         doExifStreamIO(jpegStream, s);
    907         s.flush();
    908 
    909         s.close();
    910     }
    911 
    912     /**
    913      * Writes the tags from this ExifInterface object into a jpeg file, removing
    914      * prior exif tags.
    915      *
    916      * @param jpegFileName a String containing the filepath for a jpeg file.
    917      * @param exifOutFileName a String containing the filepath to which the jpeg
    918      *            image with added exif tags will be written.
    919      * @throws FileNotFoundException
    920      * @throws IOException
    921      */
    922     public void writeExif(String jpegFileName, String exifOutFileName)
    923             throws FileNotFoundException, IOException {
    924         if (jpegFileName == null || exifOutFileName == null) {
    925             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    926         }
    927         InputStream is = null;
    928 
    929         is = new FileInputStream(jpegFileName);
    930         writeExif(is, exifOutFileName);
    931 
    932         is.close();
    933     }
    934 
    935     /**
    936      * Wraps an OutputStream object with an ExifOutputStream. Exif tags in this
    937      * ExifInterface object will be added to a jpeg image written to this
    938      * stream, removing prior exif tags. Other methods of this ExifInterface
    939      * object should not be called until the returned OutputStream has been
    940      * closed.
    941      *
    942      * @param outStream an OutputStream to wrap.
    943      * @return an OutputStream that wraps the outStream parameter, and adds exif
    944      *         metadata. A jpeg image should be written to this stream.
    945      */
    946     public OutputStream getExifWriterStream(OutputStream outStream) {
    947         if (outStream == null) {
    948             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    949         }
    950         ExifOutputStream eos = new ExifOutputStream(outStream, this);
    951         eos.setExifData(mData);
    952         return eos;
    953     }
    954 
    955     /**
    956      * Returns an OutputStream object that writes to a file. Exif tags in this
    957      * ExifInterface object will be added to a jpeg image written to this
    958      * stream, removing prior exif tags. Other methods of this ExifInterface
    959      * object should not be called until the returned OutputStream has been
    960      * closed.
    961      *
    962      * @param exifOutFileName an String containing a filepath for a jpeg file.
    963      * @return an OutputStream that writes to the exifOutFileName file, and adds
    964      *         exif metadata. A jpeg image should be written to this stream.
    965      * @throws FileNotFoundException
    966      */
    967     public OutputStream getExifWriterStream(String exifOutFileName) throws FileNotFoundException {
    968         if (exifOutFileName == null) {
    969             throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
    970         }
    971         OutputStream out = null;
    972         try {
    973             out = new FileOutputStream(exifOutFileName);
    974         } catch (FileNotFoundException e) {
    975             closeSilently(out);
    976             throw e;
    977         }
    978         return getExifWriterStream(out);
    979     }
    980 
    981     /**
    982      * Attempts to do an in-place rewrite the exif metadata in a file for the
    983      * given tags. If tags do not exist or do not have the same size as the
    984      * existing exif tags, this method will fail.
    985      *
    986      * @param filename a String containing a filepath for a jpeg file with exif
    987      *            tags to rewrite.
    988      * @param tags tags that will be written into the jpeg file over existing
    989      *            tags if possible.
    990      * @return true if success, false if could not overwrite. If false, no
    991      *         changes are made to the file.
    992      * @throws FileNotFoundException
    993      * @throws IOException
    994      */
    995     public boolean rewriteExif(String filename, Collection<ExifTag> tags)
    996             throws FileNotFoundException, IOException {
    997         RandomAccessFile file = null;
    998         InputStream is = null;
    999         boolean ret;
   1000         try {
   1001             File temp = new File(filename);
   1002             is = new BufferedInputStream(new FileInputStream(temp));
   1003 
   1004             // Parse beginning of APP1 in exif to find size of exif header.
   1005             ExifParser parser = null;
   1006             try {
   1007                 parser = ExifParser.parse(is, this);
   1008             } catch (ExifInvalidFormatException e) {
   1009                 throw new IOException("Invalid exif format : ", e);
   1010             }
   1011             long exifSize = parser.getOffsetToExifEndFromSOF();
   1012 
   1013             // Free up resources
   1014             is.close();
   1015             is = null;
   1016 
   1017             // Open file for memory mapping.
   1018             file = new RandomAccessFile(temp, "rw");
   1019             long fileLength = file.length();
   1020             if (fileLength < exifSize) {
   1021                 throw new IOException("Filesize changed during operation");
   1022             }
   1023 
   1024             // Map only exif header into memory.
   1025             ByteBuffer buf = file.getChannel().map(MapMode.READ_WRITE, 0, exifSize);
   1026 
   1027             // Attempt to overwrite tag values without changing lengths (avoids
   1028             // file copy).
   1029             ret = rewriteExif(buf, tags);
   1030         } finally {
   1031             closeSilently(is);
   1032         }
   1033         file.close();
   1034         return ret;
   1035     }
   1036 
   1037     /**
   1038      * Attempts to do an in-place rewrite the exif metadata in a ByteBuffer for
   1039      * the given tags. If tags do not exist or do not have the same size as the
   1040      * existing exif tags, this method will fail.
   1041      *
   1042      * @param buf a ByteBuffer containing a jpeg file with existing exif tags to
   1043      *            rewrite.
   1044      * @param tags tags that will be written into the jpeg ByteBuffer over
   1045      *            existing tags if possible.
   1046      * @return true if success, false if could not overwrite. If false, no
   1047      *         changes are made to the ByteBuffer.
   1048      * @throws IOException
   1049      */
   1050     public boolean rewriteExif(ByteBuffer buf, Collection<ExifTag> tags) throws IOException {
   1051         ExifModifier mod = null;
   1052         try {
   1053             mod = new ExifModifier(buf, this);
   1054             for (ExifTag t : tags) {
   1055                 mod.modifyTag(t);
   1056             }
   1057             return mod.commit();
   1058         } catch (ExifInvalidFormatException e) {
   1059             throw new IOException("Invalid exif format : " + e);
   1060         }
   1061     }
   1062 
   1063     /**
   1064      * Attempts to do an in-place rewrite of the exif metadata. If this fails,
   1065      * fall back to overwriting file. This preserves tags that are not being
   1066      * rewritten.
   1067      *
   1068      * @param filename a String containing a filepath for a jpeg file.
   1069      * @param tags tags that will be written into the jpeg file over existing
   1070      *            tags if possible.
   1071      * @throws FileNotFoundException
   1072      * @throws IOException
   1073      * @see #rewriteExif
   1074      */
   1075     public void forceRewriteExif(String filename, Collection<ExifTag> tags)
   1076             throws FileNotFoundException,
   1077             IOException {
   1078         // Attempt in-place write
   1079         if (!rewriteExif(filename, tags)) {
   1080             // Fall back to doing a copy
   1081             ExifData tempData = mData;
   1082             mData = new ExifData(DEFAULT_BYTE_ORDER);
   1083             FileInputStream is = null;
   1084             ByteArrayOutputStream bytes = null;
   1085             try {
   1086                 is = new FileInputStream(filename);
   1087                 bytes = new ByteArrayOutputStream();
   1088                 doExifStreamIO(is, bytes);
   1089                 byte[] imageBytes = bytes.toByteArray();
   1090                 readExif(imageBytes);
   1091                 setTags(tags);
   1092                 writeExif(imageBytes, filename);
   1093             } finally {
   1094                 is.close();
   1095                 // Prevent clobbering of mData
   1096                 mData = tempData;
   1097             }
   1098         }
   1099     }
   1100 
   1101     /**
   1102      * Attempts to do an in-place rewrite of the exif metadata using the tags in
   1103      * this ExifInterface object. If this fails, fall back to overwriting file.
   1104      * This preserves tags that are not being rewritten.
   1105      *
   1106      * @param filename a String containing a filepath for a jpeg file.
   1107      * @throws FileNotFoundException
   1108      * @throws IOException
   1109      * @see #rewriteExif
   1110      */
   1111     public void forceRewriteExif(String filename) throws FileNotFoundException, IOException {
   1112         forceRewriteExif(filename, getAllTags());
   1113     }
   1114 
   1115     /**
   1116      * Get the exif tags in this ExifInterface object or null if none exist.
   1117      *
   1118      * @return a List of {@link ExifTag}s.
   1119      */
   1120     public List<ExifTag> getAllTags() {
   1121         return mData.getAllTags();
   1122     }
   1123 
   1124     /**
   1125      * Returns a list of ExifTags that share a TID (which can be obtained by
   1126      * calling {@link #getTrueTagKey} on a defined tag constant) or null if none
   1127      * exist.
   1128      *
   1129      * @param tagId a TID as defined in the exif standard (or with
   1130      *            {@link #defineTag}).
   1131      * @return a List of {@link ExifTag}s.
   1132      */
   1133     public List<ExifTag> getTagsForTagId(short tagId) {
   1134         return mData.getAllTagsForTagId(tagId);
   1135     }
   1136 
   1137     /**
   1138      * Returns a list of ExifTags that share an IFD (which can be obtained by
   1139      * calling {@link #getTrueIFD} on a defined tag constant) or null if none
   1140      * exist.
   1141      *
   1142      * @param ifdId an IFD as defined in the exif standard (or with
   1143      *            {@link #defineTag}).
   1144      * @return a List of {@link ExifTag}s.
   1145      */
   1146     public List<ExifTag> getTagsForIfdId(int ifdId) {
   1147         return mData.getAllTagsForIfd(ifdId);
   1148     }
   1149 
   1150     /**
   1151      * Gets an ExifTag for an IFD other than the tag's default.
   1152      *
   1153      * @see #getTag
   1154      */
   1155     public ExifTag getTag(int tagId, int ifdId) {
   1156         if (!ExifTag.isValidIfd(ifdId)) {
   1157             return null;
   1158         }
   1159         return mData.getTag(getTrueTagKey(tagId), ifdId);
   1160     }
   1161 
   1162     /**
   1163      * Returns the ExifTag in that tag's default IFD for a defined tag constant
   1164      * or null if none exists.
   1165      *
   1166      * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1167      * @return an {@link ExifTag} or null if none exists.
   1168      */
   1169     public ExifTag getTag(int tagId) {
   1170         int ifdId = getDefinedTagDefaultIfd(tagId);
   1171         return getTag(tagId, ifdId);
   1172     }
   1173 
   1174     /**
   1175      * Gets a tag value for an IFD other than the tag's default.
   1176      *
   1177      * @see #getTagValue
   1178      */
   1179     public Object getTagValue(int tagId, int ifdId) {
   1180         ExifTag t = getTag(tagId, ifdId);
   1181         return (t == null) ? null : t.getValue();
   1182     }
   1183 
   1184     /**
   1185      * Returns the value of the ExifTag in that tag's default IFD for a defined
   1186      * tag constant or null if none exists or the value could not be cast into
   1187      * the return type.
   1188      *
   1189      * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1190      * @return the value of the ExifTag or null if none exists.
   1191      */
   1192     public Object getTagValue(int tagId) {
   1193         int ifdId = getDefinedTagDefaultIfd(tagId);
   1194         return getTagValue(tagId, ifdId);
   1195     }
   1196 
   1197     /*
   1198      * Getter methods that are similar to getTagValue. Null is returned if the
   1199      * tag value cannot be cast into the return type.
   1200      */
   1201 
   1202     /**
   1203      * @see #getTagValue
   1204      */
   1205     public String getTagStringValue(int tagId, int ifdId) {
   1206         ExifTag t = getTag(tagId, ifdId);
   1207         if (t == null) {
   1208             return null;
   1209         }
   1210         return t.getValueAsString();
   1211     }
   1212 
   1213     /**
   1214      * @see #getTagValue
   1215      */
   1216     public String getTagStringValue(int tagId) {
   1217         int ifdId = getDefinedTagDefaultIfd(tagId);
   1218         return getTagStringValue(tagId, ifdId);
   1219     }
   1220 
   1221     /**
   1222      * @see #getTagValue
   1223      */
   1224     public Long getTagLongValue(int tagId, int ifdId) {
   1225         long[] l = getTagLongValues(tagId, ifdId);
   1226         if (l == null || l.length <= 0) {
   1227             return null;
   1228         }
   1229         return new Long(l[0]);
   1230     }
   1231 
   1232     /**
   1233      * @see #getTagValue
   1234      */
   1235     public Long getTagLongValue(int tagId) {
   1236         int ifdId = getDefinedTagDefaultIfd(tagId);
   1237         return getTagLongValue(tagId, ifdId);
   1238     }
   1239 
   1240     /**
   1241      * @see #getTagValue
   1242      */
   1243     public Integer getTagIntValue(int tagId, int ifdId) {
   1244         int[] l = getTagIntValues(tagId, ifdId);
   1245         if (l == null || l.length <= 0) {
   1246             return null;
   1247         }
   1248         return new Integer(l[0]);
   1249     }
   1250 
   1251     /**
   1252      * @see #getTagValue
   1253      */
   1254     public Integer getTagIntValue(int tagId) {
   1255         int ifdId = getDefinedTagDefaultIfd(tagId);
   1256         return getTagIntValue(tagId, ifdId);
   1257     }
   1258 
   1259     /**
   1260      * @see #getTagValue
   1261      */
   1262     public Byte getTagByteValue(int tagId, int ifdId) {
   1263         byte[] l = getTagByteValues(tagId, ifdId);
   1264         if (l == null || l.length <= 0) {
   1265             return null;
   1266         }
   1267         return new Byte(l[0]);
   1268     }
   1269 
   1270     /**
   1271      * @see #getTagValue
   1272      */
   1273     public Byte getTagByteValue(int tagId) {
   1274         int ifdId = getDefinedTagDefaultIfd(tagId);
   1275         return getTagByteValue(tagId, ifdId);
   1276     }
   1277 
   1278     /**
   1279      * @see #getTagValue
   1280      */
   1281     public Rational getTagRationalValue(int tagId, int ifdId) {
   1282         Rational[] l = getTagRationalValues(tagId, ifdId);
   1283         if (l == null || l.length == 0) {
   1284             return null;
   1285         }
   1286         return new Rational(l[0]);
   1287     }
   1288 
   1289     /**
   1290      * @see #getTagValue
   1291      */
   1292     public Rational getTagRationalValue(int tagId) {
   1293         int ifdId = getDefinedTagDefaultIfd(tagId);
   1294         return getTagRationalValue(tagId, ifdId);
   1295     }
   1296 
   1297     /**
   1298      * @see #getTagValue
   1299      */
   1300     public long[] getTagLongValues(int tagId, int ifdId) {
   1301         ExifTag t = getTag(tagId, ifdId);
   1302         if (t == null) {
   1303             return null;
   1304         }
   1305         return t.getValueAsLongs();
   1306     }
   1307 
   1308     /**
   1309      * @see #getTagValue
   1310      */
   1311     public long[] getTagLongValues(int tagId) {
   1312         int ifdId = getDefinedTagDefaultIfd(tagId);
   1313         return getTagLongValues(tagId, ifdId);
   1314     }
   1315 
   1316     /**
   1317      * @see #getTagValue
   1318      */
   1319     public int[] getTagIntValues(int tagId, int ifdId) {
   1320         ExifTag t = getTag(tagId, ifdId);
   1321         if (t == null) {
   1322             return null;
   1323         }
   1324         return t.getValueAsInts();
   1325     }
   1326 
   1327     /**
   1328      * @see #getTagValue
   1329      */
   1330     public int[] getTagIntValues(int tagId) {
   1331         int ifdId = getDefinedTagDefaultIfd(tagId);
   1332         return getTagIntValues(tagId, ifdId);
   1333     }
   1334 
   1335     /**
   1336      * @see #getTagValue
   1337      */
   1338     public byte[] getTagByteValues(int tagId, int ifdId) {
   1339         ExifTag t = getTag(tagId, ifdId);
   1340         if (t == null) {
   1341             return null;
   1342         }
   1343         return t.getValueAsBytes();
   1344     }
   1345 
   1346     /**
   1347      * @see #getTagValue
   1348      */
   1349     public byte[] getTagByteValues(int tagId) {
   1350         int ifdId = getDefinedTagDefaultIfd(tagId);
   1351         return getTagByteValues(tagId, ifdId);
   1352     }
   1353 
   1354     /**
   1355      * @see #getTagValue
   1356      */
   1357     public Rational[] getTagRationalValues(int tagId, int ifdId) {
   1358         ExifTag t = getTag(tagId, ifdId);
   1359         if (t == null) {
   1360             return null;
   1361         }
   1362         return t.getValueAsRationals();
   1363     }
   1364 
   1365     /**
   1366      * @see #getTagValue
   1367      */
   1368     public Rational[] getTagRationalValues(int tagId) {
   1369         int ifdId = getDefinedTagDefaultIfd(tagId);
   1370         return getTagRationalValues(tagId, ifdId);
   1371     }
   1372 
   1373     /**
   1374      * Checks whether a tag has a defined number of elements.
   1375      *
   1376      * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1377      * @return true if the tag has a defined number of elements.
   1378      */
   1379     public boolean isTagCountDefined(int tagId) {
   1380         int info = getTagInfo().get(tagId);
   1381         // No value in info can be zero, as all tags have a non-zero type
   1382         if (info == 0) {
   1383             return false;
   1384         }
   1385         return getComponentCountFromInfo(info) != ExifTag.SIZE_UNDEFINED;
   1386     }
   1387 
   1388     /**
   1389      * Gets the defined number of elements for a tag.
   1390      *
   1391      * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1392      * @return the number of elements or {@link ExifTag#SIZE_UNDEFINED} if the
   1393      *         tag or the number of elements is not defined.
   1394      */
   1395     public int getDefinedTagCount(int tagId) {
   1396         int info = getTagInfo().get(tagId);
   1397         if (info == 0) {
   1398             return ExifTag.SIZE_UNDEFINED;
   1399         }
   1400         return getComponentCountFromInfo(info);
   1401     }
   1402 
   1403     /**
   1404      * Gets the number of elements for an ExifTag in a given IFD.
   1405      *
   1406      * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1407      * @param ifdId the IFD containing the ExifTag to check.
   1408      * @return the number of elements in the ExifTag, if the tag's size is
   1409      *         undefined this will return the actual number of elements that is
   1410      *         in the ExifTag's value.
   1411      */
   1412     public int getActualTagCount(int tagId, int ifdId) {
   1413         ExifTag t = getTag(tagId, ifdId);
   1414         if (t == null) {
   1415             return 0;
   1416         }
   1417         return t.getComponentCount();
   1418     }
   1419 
   1420     /**
   1421      * Gets the default IFD for a tag.
   1422      *
   1423      * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1424      * @return the default IFD for a tag definition or {@link #IFD_NULL} if no
   1425      *         definition exists.
   1426      */
   1427     public int getDefinedTagDefaultIfd(int tagId) {
   1428         int info = getTagInfo().get(tagId);
   1429         if (info == DEFINITION_NULL) {
   1430             return IFD_NULL;
   1431         }
   1432         return getTrueIfd(tagId);
   1433     }
   1434 
   1435     /**
   1436      * Gets the defined type for a tag.
   1437      *
   1438      * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1439      * @return the type.
   1440      * @see ExifTag#getDataType()
   1441      */
   1442     public short getDefinedTagType(int tagId) {
   1443         int info = getTagInfo().get(tagId);
   1444         if (info == 0) {
   1445             return -1;
   1446         }
   1447         return getTypeFromInfo(info);
   1448     }
   1449 
   1450     /**
   1451      * Returns true if tag TID is one of the following: {@link TAG_EXIF_IFD},
   1452      * {@link TAG_GPS_IFD}, {@link TAG_JPEG_INTERCHANGE_FORMAT},
   1453      * {@link TAG_STRIP_OFFSETS}, {@link TAG_INTEROPERABILITY_IFD}
   1454      * <p>
   1455      * Note: defining tags with these TID's is disallowed.
   1456      *
   1457      * @param tag a tag's TID (can be obtained from a defined tag constant with
   1458      *            {@link #getTrueTagKey}).
   1459      * @return true if the TID is that of an offset tag.
   1460      */
   1461     protected static boolean isOffsetTag(short tag) {
   1462         return sOffsetTags.contains(tag);
   1463     }
   1464 
   1465     /**
   1466      * Creates a tag for a defined tag constant in a given IFD if that IFD is
   1467      * allowed for the tag.  This method will fail anytime the appropriate
   1468      * {@link ExifTag#setValue} for this tag's datatype would fail.
   1469      *
   1470      * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1471      * @param ifdId the IFD that the tag should be in.
   1472      * @param val the value of the tag to set.
   1473      * @return an ExifTag object or null if one could not be constructed.
   1474      * @see #buildTag
   1475      */
   1476     public ExifTag buildTag(int tagId, int ifdId, Object val) {
   1477         int info = getTagInfo().get(tagId);
   1478         if (info == 0 || val == null) {
   1479             return null;
   1480         }
   1481         short type = getTypeFromInfo(info);
   1482         int definedCount = getComponentCountFromInfo(info);
   1483         boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
   1484         if (!ExifInterface.isIfdAllowed(info, ifdId)) {
   1485             return null;
   1486         }
   1487         ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
   1488         if (!t.setValue(val)) {
   1489             return null;
   1490         }
   1491         return t;
   1492     }
   1493 
   1494     /**
   1495      * Creates a tag for a defined tag constant in the tag's default IFD.
   1496      *
   1497      * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1498      * @param val the tag's value.
   1499      * @return an ExifTag object.
   1500      */
   1501     public ExifTag buildTag(int tagId, Object val) {
   1502         int ifdId = getTrueIfd(tagId);
   1503         return buildTag(tagId, ifdId, val);
   1504     }
   1505 
   1506     protected ExifTag buildUninitializedTag(int tagId) {
   1507         int info = getTagInfo().get(tagId);
   1508         if (info == 0) {
   1509             return null;
   1510         }
   1511         short type = getTypeFromInfo(info);
   1512         int definedCount = getComponentCountFromInfo(info);
   1513         boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
   1514         int ifdId = getTrueIfd(tagId);
   1515         ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
   1516         return t;
   1517     }
   1518 
   1519     /**
   1520      * Sets the value of an ExifTag if it exists in the given IFD. The value
   1521      * must be the correct type and length for that ExifTag.
   1522      *
   1523      * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1524      * @param ifdId the IFD that the ExifTag is in.
   1525      * @param val the value to set.
   1526      * @return true if success, false if the ExifTag doesn't exist or the value
   1527      *         is the wrong type/length.
   1528      * @see #setTagValue
   1529      */
   1530     public boolean setTagValue(int tagId, int ifdId, Object val) {
   1531         ExifTag t = getTag(tagId, ifdId);
   1532         if (t == null) {
   1533             return false;
   1534         }
   1535         return t.setValue(val);
   1536     }
   1537 
   1538     /**
   1539      * Sets the value of an ExifTag if it exists it's default IFD. The value
   1540      * must be the correct type and length for that ExifTag.
   1541      *
   1542      * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1543      * @param val the value to set.
   1544      * @return true if success, false if the ExifTag doesn't exist or the value
   1545      *         is the wrong type/length.
   1546      */
   1547     public boolean setTagValue(int tagId, Object val) {
   1548         int ifdId = getDefinedTagDefaultIfd(tagId);
   1549         return setTagValue(tagId, ifdId, val);
   1550     }
   1551 
   1552     /**
   1553      * Puts an ExifTag into this ExifInterface object's tags, removing a
   1554      * previous ExifTag with the same TID and IFD. The IFD it is put into will
   1555      * be the one the tag was created with in {@link #buildTag}.
   1556      *
   1557      * @param tag an ExifTag to put into this ExifInterface's tags.
   1558      * @return the previous ExifTag with the same TID and IFD or null if none
   1559      *         exists.
   1560      */
   1561     public ExifTag setTag(ExifTag tag) {
   1562         return mData.addTag(tag);
   1563     }
   1564 
   1565     /**
   1566      * Puts a collection of ExifTags into this ExifInterface objects's tags. Any
   1567      * previous ExifTags with the same TID and IFDs will be removed.
   1568      *
   1569      * @param tags a Collection of ExifTags.
   1570      * @see #setTag
   1571      */
   1572     public void setTags(Collection<ExifTag> tags) {
   1573         for (ExifTag t : tags) {
   1574             setTag(t);
   1575         }
   1576     }
   1577 
   1578     /**
   1579      * Removes the ExifTag for a tag constant from the given IFD.
   1580      *
   1581      * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1582      * @param ifdId the IFD of the ExifTag to remove.
   1583      */
   1584     public void deleteTag(int tagId, int ifdId) {
   1585         mData.removeTag(getTrueTagKey(tagId), ifdId);
   1586     }
   1587 
   1588     /**
   1589      * Removes the ExifTag for a tag constant from that tag's default IFD.
   1590      *
   1591      * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1592      */
   1593     public void deleteTag(int tagId) {
   1594         int ifdId = getDefinedTagDefaultIfd(tagId);
   1595         deleteTag(tagId, ifdId);
   1596     }
   1597 
   1598     /**
   1599      * Creates a new tag definition in this ExifInterface object for a given TID
   1600      * and default IFD. Creating a definition with the same TID and default IFD
   1601      * as a previous definition will override it.
   1602      *
   1603      * @param tagId the TID for the tag.
   1604      * @param defaultIfd the default IFD for the tag.
   1605      * @param tagType the type of the tag (see {@link ExifTag#getDataType()}).
   1606      * @param defaultComponentCount the number of elements of this tag's type in
   1607      *            the tags value.
   1608      * @param allowedIfds the IFD's this tag is allowed to be put in.
   1609      * @return the defined tag constant (e.g. {@link #TAG_IMAGE_WIDTH}) or
   1610      *         {@link #TAG_NULL} if the definition could not be made.
   1611      */
   1612     public int setTagDefinition(short tagId, int defaultIfd, short tagType,
   1613             short defaultComponentCount, int[] allowedIfds) {
   1614         if (sBannedDefines.contains(tagId)) {
   1615             return TAG_NULL;
   1616         }
   1617         if (ExifTag.isValidType(tagType) && ExifTag.isValidIfd(defaultIfd)) {
   1618             int tagDef = defineTag(defaultIfd, tagId);
   1619             if (tagDef == TAG_NULL) {
   1620                 return TAG_NULL;
   1621             }
   1622             int[] otherDefs = getTagDefinitionsForTagId(tagId);
   1623             SparseIntArray infos = getTagInfo();
   1624             // Make sure defaultIfd is in allowedIfds
   1625             boolean defaultCheck = false;
   1626             for (int i : allowedIfds) {
   1627                 if (defaultIfd == i) {
   1628                     defaultCheck = true;
   1629                 }
   1630                 if (!ExifTag.isValidIfd(i)) {
   1631                     return TAG_NULL;
   1632                 }
   1633             }
   1634             if (!defaultCheck) {
   1635                 return TAG_NULL;
   1636             }
   1637 
   1638             int ifdFlags = getFlagsFromAllowedIfds(allowedIfds);
   1639             // Make sure no identical tags can exist in allowedIfds
   1640             if (otherDefs != null) {
   1641                 for (int def : otherDefs) {
   1642                     int tagInfo = infos.get(def);
   1643                     int allowedFlags = getAllowedIfdFlagsFromInfo(tagInfo);
   1644                     if ((ifdFlags & allowedFlags) != 0) {
   1645                         return TAG_NULL;
   1646                     }
   1647                 }
   1648             }
   1649             getTagInfo().put(tagDef, ifdFlags << 24 | (tagType << 16) | defaultComponentCount);
   1650             return tagDef;
   1651         }
   1652         return TAG_NULL;
   1653     }
   1654 
   1655     protected int getTagDefinition(short tagId, int defaultIfd) {
   1656         return getTagInfo().get(defineTag(defaultIfd, tagId));
   1657     }
   1658 
   1659     protected int[] getTagDefinitionsForTagId(short tagId) {
   1660         int[] ifds = IfdData.getIfds();
   1661         int[] defs = new int[ifds.length];
   1662         int counter = 0;
   1663         SparseIntArray infos = getTagInfo();
   1664         for (int i : ifds) {
   1665             int def = defineTag(i, tagId);
   1666             if (infos.get(def) != DEFINITION_NULL) {
   1667                 defs[counter++] = def;
   1668             }
   1669         }
   1670         if (counter == 0) {
   1671             return null;
   1672         }
   1673 
   1674         return Arrays.copyOfRange(defs, 0, counter);
   1675     }
   1676 
   1677     protected int getTagDefinitionForTag(ExifTag tag) {
   1678         short type = tag.getDataType();
   1679         int count = tag.getComponentCount();
   1680         int ifd = tag.getIfd();
   1681         return getTagDefinitionForTag(tag.getTagId(), type, count, ifd);
   1682     }
   1683 
   1684     protected int getTagDefinitionForTag(short tagId, short type, int count, int ifd) {
   1685         int[] defs = getTagDefinitionsForTagId(tagId);
   1686         if (defs == null) {
   1687             return TAG_NULL;
   1688         }
   1689         SparseIntArray infos = getTagInfo();
   1690         int ret = TAG_NULL;
   1691         for (int i : defs) {
   1692             int info = infos.get(i);
   1693             short def_type = getTypeFromInfo(info);
   1694             int def_count = getComponentCountFromInfo(info);
   1695             int[] def_ifds = getAllowedIfdsFromInfo(info);
   1696             boolean valid_ifd = false;
   1697             for (int j : def_ifds) {
   1698                 if (j == ifd) {
   1699                     valid_ifd = true;
   1700                     break;
   1701                 }
   1702             }
   1703             if (valid_ifd && type == def_type
   1704                     && (count == def_count || def_count == ExifTag.SIZE_UNDEFINED)) {
   1705                 ret = i;
   1706                 break;
   1707             }
   1708         }
   1709         return ret;
   1710     }
   1711 
   1712     /**
   1713      * Removes a tag definition for given defined tag constant.
   1714      *
   1715      * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
   1716      */
   1717     public void removeTagDefinition(int tagId) {
   1718         getTagInfo().delete(tagId);
   1719     }
   1720 
   1721     /**
   1722      * Resets tag definitions to the default ones.
   1723      */
   1724     public void resetTagDefinitions() {
   1725         mTagInfo = null;
   1726     }
   1727 
   1728     /**
   1729      * Returns the thumbnail from IFD1 as a bitmap, or null if none exists.
   1730      *
   1731      * @return the thumbnail as a bitmap.
   1732      */
   1733     public Bitmap getThumbnailBitmap() {
   1734         if (mData.hasCompressedThumbnail()) {
   1735             byte[] thumb = mData.getCompressedThumbnail();
   1736             return BitmapFactory.decodeByteArray(thumb, 0, thumb.length);
   1737         } else if (mData.hasUncompressedStrip()) {
   1738             // TODO: implement uncompressed
   1739         }
   1740         return null;
   1741     }
   1742 
   1743     /**
   1744      * Returns the thumbnail from IFD1 as a byte array, or null if none exists.
   1745      * The bytes may either be an uncompressed strip as specified in the exif
   1746      * standard or a jpeg compressed image.
   1747      *
   1748      * @return the thumbnail as a byte array.
   1749      */
   1750     public byte[] getThumbnailBytes() {
   1751         if (mData.hasCompressedThumbnail()) {
   1752             return mData.getCompressedThumbnail();
   1753         } else if (mData.hasUncompressedStrip()) {
   1754             // TODO: implement this
   1755         }
   1756         return null;
   1757     }
   1758 
   1759     /**
   1760      * Returns the thumbnail if it is jpeg compressed, or null if none exists.
   1761      *
   1762      * @return the thumbnail as a byte array.
   1763      */
   1764     public byte[] getThumbnail() {
   1765         return mData.getCompressedThumbnail();
   1766     }
   1767 
   1768     /**
   1769      * Check if thumbnail is compressed.
   1770      *
   1771      * @return true if the thumbnail is compressed.
   1772      */
   1773     public boolean isThumbnailCompressed() {
   1774         return mData.hasCompressedThumbnail();
   1775     }
   1776 
   1777     /**
   1778      * Check if thumbnail exists.
   1779      *
   1780      * @return true if a compressed thumbnail exists.
   1781      */
   1782     public boolean hasThumbnail() {
   1783         // TODO: add back in uncompressed strip
   1784         return mData.hasCompressedThumbnail();
   1785     }
   1786 
   1787     // TODO: uncompressed thumbnail setters
   1788 
   1789     /**
   1790      * Sets the thumbnail to be a jpeg compressed image. Clears any prior
   1791      * thumbnail.
   1792      *
   1793      * @param thumb a byte array containing a jpeg compressed image.
   1794      * @return true if the thumbnail was set.
   1795      */
   1796     public boolean setCompressedThumbnail(byte[] thumb) {
   1797         mData.clearThumbnailAndStrips();
   1798         mData.setCompressedThumbnail(thumb);
   1799         return true;
   1800     }
   1801 
   1802     /**
   1803      * Sets the thumbnail to be a jpeg compressed bitmap. Clears any prior
   1804      * thumbnail.
   1805      *
   1806      * @param thumb a bitmap to compress to a jpeg thumbnail.
   1807      * @return true if the thumbnail was set.
   1808      */
   1809     public boolean setCompressedThumbnail(Bitmap thumb) {
   1810         ByteArrayOutputStream thumbnail = new ByteArrayOutputStream();
   1811         if (!thumb.compress(Bitmap.CompressFormat.JPEG, 90, thumbnail)) {
   1812             return false;
   1813         }
   1814         return setCompressedThumbnail(thumbnail.toByteArray());
   1815     }
   1816 
   1817     /**
   1818      * Clears the compressed thumbnail if it exists.
   1819      */
   1820     public void removeCompressedThumbnail() {
   1821         mData.setCompressedThumbnail(null);
   1822     }
   1823 
   1824     // Convenience methods:
   1825 
   1826     /**
   1827      * Decodes the user comment tag into string as specified in the EXIF
   1828      * standard. Returns null if decoding failed.
   1829      */
   1830     public String getUserComment() {
   1831         return mData.getUserComment();
   1832     }
   1833 
   1834     /**
   1835      * Returns the Orientation ExifTag value for a given number of degrees.
   1836      *
   1837      * @param degrees the amount an image is rotated in degrees.
   1838      */
   1839     public static short getOrientationValueForRotation(int degrees) {
   1840         degrees %= 360;
   1841         if (degrees < 0) {
   1842             degrees += 360;
   1843         }
   1844         if (degrees < 90) {
   1845             return Orientation.TOP_LEFT; // 0 degrees
   1846         } else if (degrees < 180) {
   1847             return Orientation.RIGHT_TOP; // 90 degrees cw
   1848         } else if (degrees < 270) {
   1849             return Orientation.BOTTOM_LEFT; // 180 degrees
   1850         } else {
   1851             return Orientation.RIGHT_BOTTOM; // 270 degrees cw
   1852         }
   1853     }
   1854 
   1855     /**
   1856      * Returns the rotation degrees corresponding to an ExifTag Orientation
   1857      * value.
   1858      *
   1859      * @param orientation the ExifTag Orientation value.
   1860      */
   1861     public static int getRotationForOrientationValue(short orientation) {
   1862         switch (orientation) {
   1863             case Orientation.TOP_LEFT:
   1864                 return 0;
   1865             case Orientation.RIGHT_TOP:
   1866                 return 90;
   1867             case Orientation.BOTTOM_LEFT:
   1868                 return 180;
   1869             case Orientation.RIGHT_BOTTOM:
   1870                 return 270;
   1871             default:
   1872                 return 0;
   1873         }
   1874     }
   1875 
   1876     /**
   1877      * Gets the double representation of the GPS latitude or longitude
   1878      * coordinate.
   1879      *
   1880      * @param coordinate an array of 3 Rationals representing the degrees,
   1881      *            minutes, and seconds of the GPS location as defined in the
   1882      *            exif specification.
   1883      * @param reference a GPS reference reperesented by a String containing "N",
   1884      *            "S", "E", or "W".
   1885      * @return the GPS coordinate represented as degrees + minutes/60 +
   1886      *         seconds/3600
   1887      */
   1888     public static double convertLatOrLongToDouble(Rational[] coordinate, String reference) {
   1889         try {
   1890             double degrees = coordinate[0].toDouble();
   1891             double minutes = coordinate[1].toDouble();
   1892             double seconds = coordinate[2].toDouble();
   1893             double result = degrees + minutes / 60.0 + seconds / 3600.0;
   1894             if ((reference.equals("S") || reference.equals("W"))) {
   1895                 return -result;
   1896             }
   1897             return result;
   1898         } catch (ArrayIndexOutOfBoundsException e) {
   1899             throw new IllegalArgumentException();
   1900         }
   1901     }
   1902 
   1903     /**
   1904      * Gets the GPS latitude and longitude as a pair of doubles from this
   1905      * ExifInterface object's tags, or null if the necessary tags do not exist.
   1906      *
   1907      * @return an array of 2 doubles containing the latitude, and longitude
   1908      *         respectively.
   1909      * @see #convertLatOrLongToDouble
   1910      */
   1911     public double[] getLatLongAsDoubles() {
   1912         Rational[] latitude = getTagRationalValues(TAG_GPS_LATITUDE);
   1913         String latitudeRef = getTagStringValue(TAG_GPS_LATITUDE_REF);
   1914         Rational[] longitude = getTagRationalValues(TAG_GPS_LONGITUDE);
   1915         String longitudeRef = getTagStringValue(TAG_GPS_LONGITUDE_REF);
   1916         if (latitude == null || longitude == null || latitudeRef == null || longitudeRef == null
   1917                 || latitude.length < 3 || longitude.length < 3) {
   1918             return null;
   1919         }
   1920         double[] latLon = new double[2];
   1921         latLon[0] = convertLatOrLongToDouble(latitude, latitudeRef);
   1922         latLon[1] = convertLatOrLongToDouble(longitude, longitudeRef);
   1923         return latLon;
   1924     }
   1925 
   1926     private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
   1927     private static final String DATETIME_FORMAT_STR = "yyyy:MM:dd kk:mm:ss";
   1928     private final DateFormat mDateTimeStampFormat = new SimpleDateFormat(DATETIME_FORMAT_STR);
   1929     private final DateFormat mGPSDateStampFormat = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
   1930     private final Calendar mGPSTimeStampCalendar = Calendar
   1931             .getInstance(TimeZone.getTimeZone("UTC"));
   1932 
   1933     /**
   1934      * Creates, formats, and sets the DateTimeStamp tag for one of:
   1935      * {@link #TAG_DATE_TIME}, {@link #TAG_DATE_TIME_DIGITIZED},
   1936      * {@link #TAG_DATE_TIME_ORIGINAL}.
   1937      *
   1938      * @param tagId one of the DateTimeStamp tags.
   1939      * @param timestamp a timestamp to format, in ms.
   1940      * @param timezone a TimeZone object.
   1941      * @return true if success, false if the tag could not be set.
   1942      */
   1943     public boolean addDateTimeStampTag(int tagId, long timestamp, TimeZone timezone) {
   1944         if (tagId == TAG_DATE_TIME || tagId == TAG_DATE_TIME_DIGITIZED
   1945                 || tagId == TAG_DATE_TIME_ORIGINAL) {
   1946             mDateTimeStampFormat.setTimeZone(timezone);
   1947             ExifTag t = buildTag(tagId, mDateTimeStampFormat.format(timestamp));
   1948             if (t == null) {
   1949                 return false;
   1950             }
   1951             setTag(t);
   1952         } else {
   1953             return false;
   1954         }
   1955         return true;
   1956     }
   1957 
   1958     /**
   1959      * Creates and sets all to the GPS tags for a give latitude and longitude.
   1960      *
   1961      * @param latitude a GPS latitude coordinate.
   1962      * @param longitude a GPS longitude coordinate.
   1963      * @return true if success, false if they could not be created or set.
   1964      */
   1965     public boolean addGpsTags(double latitude, double longitude) {
   1966         ExifTag latTag = buildTag(TAG_GPS_LATITUDE, toExifLatLong(latitude));
   1967         ExifTag longTag = buildTag(TAG_GPS_LONGITUDE, toExifLatLong(longitude));
   1968         ExifTag latRefTag = buildTag(TAG_GPS_LATITUDE_REF,
   1969                 latitude >= 0 ? ExifInterface.GpsLatitudeRef.NORTH
   1970                         : ExifInterface.GpsLatitudeRef.SOUTH);
   1971         ExifTag longRefTag = buildTag(TAG_GPS_LONGITUDE_REF,
   1972                 longitude >= 0 ? ExifInterface.GpsLongitudeRef.EAST
   1973                         : ExifInterface.GpsLongitudeRef.WEST);
   1974         if (latTag == null || longTag == null || latRefTag == null || longRefTag == null) {
   1975             return false;
   1976         }
   1977         setTag(latTag);
   1978         setTag(longTag);
   1979         setTag(latRefTag);
   1980         setTag(longRefTag);
   1981         return true;
   1982     }
   1983 
   1984     /**
   1985      * Creates and sets the GPS timestamp tag.
   1986      *
   1987      * @param timestamp a GPS timestamp.
   1988      * @return true if success, false if could not be created or set.
   1989      */
   1990     public boolean addGpsDateTimeStampTag(long timestamp) {
   1991         ExifTag t = buildTag(TAG_GPS_DATE_STAMP, mGPSDateStampFormat.format(timestamp));
   1992         if (t == null) {
   1993             return false;
   1994         }
   1995         setTag(t);
   1996         mGPSTimeStampCalendar.setTimeInMillis(timestamp);
   1997         t = buildTag(TAG_GPS_TIME_STAMP, new Rational[] {
   1998                 new Rational(mGPSTimeStampCalendar.get(Calendar.HOUR_OF_DAY), 1),
   1999                 new Rational(mGPSTimeStampCalendar.get(Calendar.MINUTE), 1),
   2000                 new Rational(mGPSTimeStampCalendar.get(Calendar.SECOND), 1)
   2001         });
   2002         if (t == null) {
   2003             return false;
   2004         }
   2005         setTag(t);
   2006         return true;
   2007     }
   2008 
   2009     private static Rational[] toExifLatLong(double value) {
   2010         // convert to the format dd/1 mm/1 ssss/100
   2011         value = Math.abs(value);
   2012         int degrees = (int) value;
   2013         value = (value - degrees) * 60;
   2014         int minutes = (int) value;
   2015         value = (value - minutes) * 6000;
   2016         int seconds = (int) value;
   2017         return new Rational[] {
   2018                 new Rational(degrees, 1), new Rational(minutes, 1), new Rational(seconds, 100)
   2019         };
   2020     }
   2021 
   2022     private void doExifStreamIO(InputStream is, OutputStream os) throws IOException {
   2023         byte[] buf = new byte[1024];
   2024         int ret = is.read(buf, 0, 1024);
   2025         while (ret != -1) {
   2026             os.write(buf, 0, ret);
   2027             ret = is.read(buf, 0, 1024);
   2028         }
   2029     }
   2030 
   2031     protected static void closeSilently(Closeable c) {
   2032         if (c != null) {
   2033             try {
   2034                 c.close();
   2035             } catch (Throwable e) {
   2036                 // ignored
   2037             }
   2038         }
   2039     }
   2040 
   2041     private SparseIntArray mTagInfo = null;
   2042 
   2043     protected SparseIntArray getTagInfo() {
   2044         if (mTagInfo == null) {
   2045             mTagInfo = new SparseIntArray();
   2046             initTagInfo();
   2047         }
   2048         return mTagInfo;
   2049     }
   2050 
   2051     private void initTagInfo() {
   2052         /**
   2053          * We put tag information in a 4-bytes integer. The first byte a bitmask
   2054          * representing the allowed IFDs of the tag, the second byte is the data
   2055          * type, and the last two byte are a short value indicating the default
   2056          * component count of this tag.
   2057          */
   2058         // IFD0 tags
   2059         int[] ifdAllowedIfds = {
   2060                 IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1
   2061         };
   2062         int ifdFlags = getFlagsFromAllowedIfds(ifdAllowedIfds) << 24;
   2063         mTagInfo.put(ExifInterface.TAG_MAKE,
   2064                 ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2065         mTagInfo.put(ExifInterface.TAG_IMAGE_WIDTH,
   2066                 ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2067         mTagInfo.put(ExifInterface.TAG_IMAGE_LENGTH,
   2068                 ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2069         mTagInfo.put(ExifInterface.TAG_BITS_PER_SAMPLE,
   2070                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3);
   2071         mTagInfo.put(ExifInterface.TAG_COMPRESSION,
   2072                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2073         mTagInfo.put(ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION,
   2074                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2075         mTagInfo.put(ExifInterface.TAG_ORIENTATION, ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16
   2076                 | 1);
   2077         mTagInfo.put(ExifInterface.TAG_SAMPLES_PER_PIXEL,
   2078                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2079         mTagInfo.put(ExifInterface.TAG_PLANAR_CONFIGURATION,
   2080                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2081         mTagInfo.put(ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING,
   2082                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
   2083         mTagInfo.put(ExifInterface.TAG_Y_CB_CR_POSITIONING,
   2084                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2085         mTagInfo.put(ExifInterface.TAG_X_RESOLUTION,
   2086                 ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2087         mTagInfo.put(ExifInterface.TAG_Y_RESOLUTION,
   2088                 ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2089         mTagInfo.put(ExifInterface.TAG_RESOLUTION_UNIT,
   2090                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2091         mTagInfo.put(ExifInterface.TAG_STRIP_OFFSETS,
   2092                 ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
   2093         mTagInfo.put(ExifInterface.TAG_ROWS_PER_STRIP,
   2094                 ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2095         mTagInfo.put(ExifInterface.TAG_STRIP_BYTE_COUNTS,
   2096                 ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
   2097         mTagInfo.put(ExifInterface.TAG_TRANSFER_FUNCTION,
   2098                 ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3 * 256);
   2099         mTagInfo.put(ExifInterface.TAG_WHITE_POINT,
   2100                 ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 2);
   2101         mTagInfo.put(ExifInterface.TAG_PRIMARY_CHROMATICITIES,
   2102                 ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
   2103         mTagInfo.put(ExifInterface.TAG_Y_CB_CR_COEFFICIENTS,
   2104                 ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
   2105         mTagInfo.put(ExifInterface.TAG_REFERENCE_BLACK_WHITE,
   2106                 ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
   2107         mTagInfo.put(ExifInterface.TAG_DATE_TIME,
   2108                 ifdFlags | ExifTag.TYPE_ASCII << 16 | 20);
   2109         mTagInfo.put(ExifInterface.TAG_IMAGE_DESCRIPTION,
   2110                 ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2111         mTagInfo.put(ExifInterface.TAG_MAKE,
   2112                 ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2113         mTagInfo.put(ExifInterface.TAG_MODEL,
   2114                 ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2115         mTagInfo.put(ExifInterface.TAG_SOFTWARE,
   2116                 ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2117         mTagInfo.put(ExifInterface.TAG_ARTIST,
   2118                 ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2119         mTagInfo.put(ExifInterface.TAG_COPYRIGHT,
   2120                 ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2121         mTagInfo.put(ExifInterface.TAG_EXIF_IFD,
   2122                 ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2123         mTagInfo.put(ExifInterface.TAG_GPS_IFD,
   2124                 ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2125         // IFD1 tags
   2126         int[] ifd1AllowedIfds = {
   2127             IfdId.TYPE_IFD_1
   2128         };
   2129         int ifdFlags1 = getFlagsFromAllowedIfds(ifd1AllowedIfds) << 24;
   2130         mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT,
   2131                 ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2132         mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
   2133                 ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2134         // Exif tags
   2135         int[] exifAllowedIfds = {
   2136             IfdId.TYPE_IFD_EXIF
   2137         };
   2138         int exifFlags = getFlagsFromAllowedIfds(exifAllowedIfds) << 24;
   2139         mTagInfo.put(ExifInterface.TAG_EXIF_VERSION,
   2140                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
   2141         mTagInfo.put(ExifInterface.TAG_FLASHPIX_VERSION,
   2142                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
   2143         mTagInfo.put(ExifInterface.TAG_COLOR_SPACE,
   2144                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2145         mTagInfo.put(ExifInterface.TAG_COMPONENTS_CONFIGURATION,
   2146                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
   2147         mTagInfo.put(ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL,
   2148                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2149         mTagInfo.put(ExifInterface.TAG_PIXEL_X_DIMENSION,
   2150                 exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2151         mTagInfo.put(ExifInterface.TAG_PIXEL_Y_DIMENSION,
   2152                 exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2153         mTagInfo.put(ExifInterface.TAG_MAKER_NOTE,
   2154                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
   2155         mTagInfo.put(ExifInterface.TAG_USER_COMMENT,
   2156                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
   2157         mTagInfo.put(ExifInterface.TAG_RELATED_SOUND_FILE,
   2158                 exifFlags | ExifTag.TYPE_ASCII << 16 | 13);
   2159         mTagInfo.put(ExifInterface.TAG_DATE_TIME_ORIGINAL,
   2160                 exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
   2161         mTagInfo.put(ExifInterface.TAG_DATE_TIME_DIGITIZED,
   2162                 exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
   2163         mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME,
   2164                 exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2165         mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_ORIGINAL,
   2166                 exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2167         mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_DIGITIZED,
   2168                 exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2169         mTagInfo.put(ExifInterface.TAG_IMAGE_UNIQUE_ID,
   2170                 exifFlags | ExifTag.TYPE_ASCII << 16 | 33);
   2171         mTagInfo.put(ExifInterface.TAG_EXPOSURE_TIME,
   2172                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2173         mTagInfo.put(ExifInterface.TAG_F_NUMBER,
   2174                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2175         mTagInfo.put(ExifInterface.TAG_EXPOSURE_PROGRAM,
   2176                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2177         mTagInfo.put(ExifInterface.TAG_SPECTRAL_SENSITIVITY,
   2178                 exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2179         mTagInfo.put(ExifInterface.TAG_ISO_SPEED_RATINGS,
   2180                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
   2181         mTagInfo.put(ExifInterface.TAG_OECF,
   2182                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
   2183         mTagInfo.put(ExifInterface.TAG_SHUTTER_SPEED_VALUE,
   2184                 exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
   2185         mTagInfo.put(ExifInterface.TAG_APERTURE_VALUE,
   2186                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2187         mTagInfo.put(ExifInterface.TAG_BRIGHTNESS_VALUE,
   2188                 exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
   2189         mTagInfo.put(ExifInterface.TAG_EXPOSURE_BIAS_VALUE,
   2190                 exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
   2191         mTagInfo.put(ExifInterface.TAG_MAX_APERTURE_VALUE,
   2192                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2193         mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE,
   2194                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2195         mTagInfo.put(ExifInterface.TAG_METERING_MODE,
   2196                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2197         mTagInfo.put(ExifInterface.TAG_LIGHT_SOURCE,
   2198                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2199         mTagInfo.put(ExifInterface.TAG_FLASH,
   2200                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2201         mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH,
   2202                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2203         mTagInfo.put(ExifInterface.TAG_SUBJECT_AREA,
   2204                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
   2205         mTagInfo.put(ExifInterface.TAG_FLASH_ENERGY,
   2206                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2207         mTagInfo.put(ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE,
   2208                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
   2209         mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION,
   2210                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2211         mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION,
   2212                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2213         mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT,
   2214                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2215         mTagInfo.put(ExifInterface.TAG_SUBJECT_LOCATION,
   2216                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
   2217         mTagInfo.put(ExifInterface.TAG_EXPOSURE_INDEX,
   2218                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2219         mTagInfo.put(ExifInterface.TAG_SENSING_METHOD,
   2220                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2221         mTagInfo.put(ExifInterface.TAG_FILE_SOURCE,
   2222                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
   2223         mTagInfo.put(ExifInterface.TAG_SCENE_TYPE,
   2224                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
   2225         mTagInfo.put(ExifInterface.TAG_CFA_PATTERN,
   2226                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
   2227         mTagInfo.put(ExifInterface.TAG_CUSTOM_RENDERED,
   2228                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2229         mTagInfo.put(ExifInterface.TAG_EXPOSURE_MODE,
   2230                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2231         mTagInfo.put(ExifInterface.TAG_WHITE_BALANCE,
   2232                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2233         mTagInfo.put(ExifInterface.TAG_DIGITAL_ZOOM_RATIO,
   2234                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2235         mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH_IN_35_MM_FILE,
   2236                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2237         mTagInfo.put(ExifInterface.TAG_SCENE_CAPTURE_TYPE,
   2238                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2239         mTagInfo.put(ExifInterface.TAG_GAIN_CONTROL,
   2240                 exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2241         mTagInfo.put(ExifInterface.TAG_CONTRAST,
   2242                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2243         mTagInfo.put(ExifInterface.TAG_SATURATION,
   2244                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2245         mTagInfo.put(ExifInterface.TAG_SHARPNESS,
   2246                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2247         mTagInfo.put(ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION,
   2248                 exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
   2249         mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE_RANGE,
   2250                 exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
   2251         mTagInfo.put(ExifInterface.TAG_INTEROPERABILITY_IFD, exifFlags
   2252                 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
   2253         // GPS tag
   2254         int[] gpsAllowedIfds = {
   2255             IfdId.TYPE_IFD_GPS
   2256         };
   2257         int gpsFlags = getFlagsFromAllowedIfds(gpsAllowedIfds) << 24;
   2258         mTagInfo.put(ExifInterface.TAG_GPS_VERSION_ID,
   2259                 gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 4);
   2260         mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE_REF,
   2261                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2262         mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE_REF,
   2263                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2264         mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE,
   2265                 gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
   2266         mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE,
   2267                 gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
   2268         mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE_REF,
   2269                 gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 1);
   2270         mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE,
   2271                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2272         mTagInfo.put(ExifInterface.TAG_GPS_TIME_STAMP,
   2273                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
   2274         mTagInfo.put(ExifInterface.TAG_GPS_SATTELLITES,
   2275                 gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2276         mTagInfo.put(ExifInterface.TAG_GPS_STATUS,
   2277                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2278         mTagInfo.put(ExifInterface.TAG_GPS_MEASURE_MODE,
   2279                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2280         mTagInfo.put(ExifInterface.TAG_GPS_DOP,
   2281                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2282         mTagInfo.put(ExifInterface.TAG_GPS_SPEED_REF,
   2283                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2284         mTagInfo.put(ExifInterface.TAG_GPS_SPEED,
   2285                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2286         mTagInfo.put(ExifInterface.TAG_GPS_TRACK_REF,
   2287                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2288         mTagInfo.put(ExifInterface.TAG_GPS_TRACK,
   2289                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2290         mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
   2291                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2292         mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION,
   2293                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2294         mTagInfo.put(ExifInterface.TAG_GPS_MAP_DATUM,
   2295                 gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
   2296         mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE_REF,
   2297                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2298         mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE,
   2299                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2300         mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING_REF,
   2301                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2302         mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING,
   2303                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2304         mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE_REF,
   2305                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
   2306         mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE,
   2307                 gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
   2308         mTagInfo.put(ExifInterface.TAG_GPS_PROCESSING_METHOD,
   2309                 gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
   2310         mTagInfo.put(ExifInterface.TAG_GPS_AREA_INFORMATION,
   2311                 gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
   2312         mTagInfo.put(ExifInterface.TAG_GPS_DATE_STAMP,
   2313                 gpsFlags | ExifTag.TYPE_ASCII << 16 | 11);
   2314         mTagInfo.put(ExifInterface.TAG_GPS_DIFFERENTIAL,
   2315                 gpsFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 11);
   2316         // Interoperability tag
   2317         int[] interopAllowedIfds = {
   2318             IfdId.TYPE_IFD_INTEROPERABILITY
   2319         };
   2320         int interopFlags = getFlagsFromAllowedIfds(interopAllowedIfds) << 24;
   2321         mTagInfo.put(TAG_INTEROPERABILITY_INDEX, interopFlags | ExifTag.TYPE_ASCII << 16
   2322                 | ExifTag.SIZE_UNDEFINED);
   2323     }
   2324 
   2325     protected static int getAllowedIfdFlagsFromInfo(int info) {
   2326         return info >>> 24;
   2327     }
   2328 
   2329     protected static int[] getAllowedIfdsFromInfo(int info) {
   2330         int ifdFlags = getAllowedIfdFlagsFromInfo(info);
   2331         int[] ifds = IfdData.getIfds();
   2332         ArrayList<Integer> l = new ArrayList<Integer>();
   2333         for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
   2334             int flag = (ifdFlags >> i) & 1;
   2335             if (flag == 1) {
   2336                 l.add(ifds[i]);
   2337             }
   2338         }
   2339         if (l.size() <= 0) {
   2340             return null;
   2341         }
   2342         int[] ret = new int[l.size()];
   2343         int j = 0;
   2344         for (int i : l) {
   2345             ret[j++] = i;
   2346         }
   2347         return ret;
   2348     }
   2349 
   2350     protected static boolean isIfdAllowed(int info, int ifd) {
   2351         int[] ifds = IfdData.getIfds();
   2352         int ifdFlags = getAllowedIfdFlagsFromInfo(info);
   2353         for (int i = 0; i < ifds.length; i++) {
   2354             if (ifd == ifds[i] && ((ifdFlags >> i) & 1) == 1) {
   2355                 return true;
   2356             }
   2357         }
   2358         return false;
   2359     }
   2360 
   2361     protected static int getFlagsFromAllowedIfds(int[] allowedIfds) {
   2362         if (allowedIfds == null || allowedIfds.length == 0) {
   2363             return 0;
   2364         }
   2365         int flags = 0;
   2366         int[] ifds = IfdData.getIfds();
   2367         for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
   2368             for (int j : allowedIfds) {
   2369                 if (ifds[i] == j) {
   2370                     flags |= 1 << i;
   2371                     break;
   2372                 }
   2373             }
   2374         }
   2375         return flags;
   2376     }
   2377 
   2378     protected static short getTypeFromInfo(int info) {
   2379         return (short) ((info >> 16) & 0x0ff);
   2380     }
   2381 
   2382     protected static int getComponentCountFromInfo(int info) {
   2383         return info & 0x0ffff;
   2384     }
   2385 
   2386 }
   2387