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