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