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