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