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