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