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