summaryrefslogtreecommitdiffstats
path: root/gallerycommon/src/com/android/gallery3d/exif/ExifTag.java
diff options
context:
space:
mode:
Diffstat (limited to 'gallerycommon/src/com/android/gallery3d/exif/ExifTag.java')
-rw-r--r--gallerycommon/src/com/android/gallery3d/exif/ExifTag.java1441
1 files changed, 1441 insertions, 0 deletions
diff --git a/gallerycommon/src/com/android/gallery3d/exif/ExifTag.java b/gallerycommon/src/com/android/gallery3d/exif/ExifTag.java
new file mode 100644
index 000000000..49cb6edbc
--- /dev/null
+++ b/gallerycommon/src/com/android/gallery3d/exif/ExifTag.java
@@ -0,0 +1,1441 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.exif;
+
+import android.util.SparseArray;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * This class stores information of an EXIF tag.
+ * @see ExifParser
+ * @see ExifReader
+ * @see IfdData
+ * @see ExifData
+ */
+public class ExifTag {
+ // Tiff Tags
+ public static final short TAG_IMAGE_WIDTH = 0x100;
+ /*
+ * The height of the image.
+ */
+ public static final short TAG_IMAGE_LENGTH = 0x101;
+ public static final short TAG_BITS_PER_SAMPLE = 0x102;
+ public static final short TAG_COMPRESSION = 0x103;
+ public static final short TAG_PHOTOMETRIC_INTERPRETATION = 0x106;
+ public static final short TAG_IMAGE_DESCRIPTION = 0x10E;
+ public static final short TAG_MAKE = 0x10F;
+ public static final short TAG_MODEL = 0x110;
+ public static final short TAG_STRIP_OFFSETS = 0x111;
+ public static final short TAG_ORIENTATION = 0x112;
+ public static final short TAG_SAMPLES_PER_PIXEL = 0x115;
+ public static final short TAG_ROWS_PER_STRIP = 0x116;
+ public static final short TAG_STRIP_BYTE_COUNTS = 0x117;
+ public static final short TAG_X_RESOLUTION = 0x11A;
+ public static final short TAG_Y_RESOLUTION = 0x11B;
+ public static final short TAG_PLANAR_CONFIGURATION = 0x11C;
+ public static final short TAG_RESOLUTION_UNIT = 0x128;
+ public static final short TAG_TRANSFER_FUNCTION = 0x12D;
+ public static final short TAG_SOFTWARE = 0x131;
+ public static final short TAG_DATE_TIME = 0x132;
+ public static final short TAG_ARTIST = 0x13B;
+ public static final short TAG_WHITE_POINT = 0x13E;
+ public static final short TAG_PRIMARY_CHROMATICITIES = 0x13F;
+ public static final short TAG_JPEG_INTERCHANGE_FORMAT = 0x201;
+ public static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = 0x202;
+ public static final short TAG_Y_CB_CR_COEFFICIENTS = 0x211;
+ public static final short TAG_Y_CB_CR_SUB_SAMPLING = 0x212;
+ public static final short TAG_Y_CB_CR_POSITIONING = 0x213;
+ public static final short TAG_REFERENCE_BLACK_WHITE = 0x214;
+ public static final short TAG_COPYRIGHT = (short) 0x8298;
+ public static final short TAG_EXIF_IFD = (short) 0x8769;
+ public static final short TAG_GPS_IFD = (short) 0x8825;
+
+ // Exif Tags
+ public static final short TAG_EXPOSURE_TIME = (short) 0x829A;
+ public static final short TAG_F_NUMBER = (short) 0x829D;
+ public static final short TAG_EXPOSURE_PROGRAM = (short) 0x8822;
+ public static final short TAG_SPECTRAL_SENSITIVITY = (short) 0x8824;
+ public static final short TAG_ISO_SPEED_RATINGS = (short) 0x8827;
+ public static final short TAG_OECF = (short) 0x8828;
+ public static final short TAG_EXIF_VERSION = (short) 0x9000;
+ public static final short TAG_DATE_TIME_ORIGINAL = (short) 0x9003;
+ public static final short TAG_DATE_TIME_DIGITIZED = (short) 0x9004;
+ public static final short TAG_COMPONENTS_CONFIGURATION = (short) 0x9101;
+ public static final short TAG_COMPRESSED_BITS_PER_PIXEL = (short) 0x9102;
+ public static final short TAG_SHUTTER_SPEED_VALUE = (short) 0x9201;
+ public static final short TAG_APERTURE_VALUE = (short) 0x9202;
+ public static final short TAG_BRIGHTNESS_VALUE = (short) 0x9203;
+ public static final short TAG_EXPOSURE_BIAS_VALUE = (short) 0x9204;
+ public static final short TAG_MAX_APERTURE_VALUE = (short) 0x9205;
+ public static final short TAG_SUBJECT_DISTANCE = (short) 0x9206;
+ public static final short TAG_METERING_MODE = (short) 0x9207;
+ public static final short TAG_LIGHT_SOURCE = (short) 0x9208;
+ public static final short TAG_FLASH = (short) 0x9209;
+ public static final short TAG_FOCAL_LENGTH = (short) 0x920A;
+ public static final short TAG_SUBJECT_AREA = (short) 0x9214;
+ public static final short TAG_MAKER_NOTE = (short) 0x927C;
+ public static final short TAG_USER_COMMENT = (short) 0x9286;
+ public static final short TAG_SUB_SEC_TIME = (short) 0x9290;
+ public static final short TAG_SUB_SEC_TIME_ORIGINAL = (short) 0x9291;
+ public static final short TAG_SUB_SEC_TIME_DIGITIZED = (short) 0x9292;
+ public static final short TAG_FLASHPIX_VERSION = (short) 0xA000;
+ public static final short TAG_COLOR_SPACE = (short) 0xA001;
+ public static final short TAG_PIXEL_X_DIMENSION = (short) 0xA002;
+ public static final short TAG_PIXEL_Y_DIMENSION = (short) 0xA003;
+ public static final short TAG_RELATED_SOUND_FILE = (short) 0xA004;
+ public static final short TAG_INTEROPERABILITY_IFD = (short) 0xA005;
+ public static final short TAG_FLASH_ENERGY = (short) 0xA20B;
+ public static final short TAG_SPATIAL_FREQUENCY_RESPONSE = (short) 0xA20C;
+ public static final short TAG_FOCAL_PLANE_X_RESOLUTION = (short) 0xA20E;
+ public static final short TAG_FOCAL_PLANE_Y_RESOLUTION = (short) 0xA20F;
+ public static final short TAG_FOCAL_PLANE_RESOLUTION_UNIT = (short) 0xA210;
+ public static final short TAG_SUBJECT_LOCATION = (short) 0xA214;
+ public static final short TAG_EXPOSURE_INDEX = (short) 0xA215;
+ public static final short TAG_SENSING_METHOD = (short) 0xA217;
+ public static final short TAG_FILE_SOURCE = (short) 0xA300;
+ public static final short TAG_SCENE_TYPE = (short) 0xA301;
+ public static final short TAG_CFA_PATTERN = (short) 0xA302;
+ public static final short TAG_CUSTOM_RENDERED = (short) 0xA401;
+ public static final short TAG_EXPOSURE_MODE = (short) 0xA402;
+ public static final short TAG_WHITE_BALANCE = (short) 0xA403;
+ public static final short TAG_DIGITAL_ZOOM_RATIO = (short) 0xA404;
+ public static final short TAG_FOCAL_LENGTH_IN_35_MM_FILE = (short) 0xA405;
+ public static final short TAG_SCENE_CAPTURE_TYPE = (short) 0xA406;
+ public static final short TAG_GAIN_CONTROL = (short) 0xA407;
+ public static final short TAG_CONTRAST = (short) 0xA408;
+ public static final short TAG_SATURATION = (short) 0xA409;
+ public static final short TAG_SHARPNESS = (short) 0xA40A;
+ public static final short TAG_DEVICE_SETTING_DESCRIPTION = (short) 0xA40B;
+ public static final short TAG_SUBJECT_DISTANCE_RANGE = (short) 0xA40C;
+ public static final short TAG_IMAGE_UNIQUE_ID = (short) 0xA420;
+
+ // GPS tags
+ public static final short TAG_GPS_VERSION_ID = 0;
+ public static final short TAG_GPS_LATITUDE_REF = 1;
+ public static final short TAG_GPS_LATITUDE = 2;
+ public static final short TAG_GPS_LONGITUDE_REF = 3;
+ public static final short TAG_GPS_LONGITUDE = 4;
+ public static final short TAG_GPS_ALTITUDE_REF = 5;
+ public static final short TAG_GPS_ALTITUDE = 6;
+ public static final short TAG_GPS_TIME_STAMP = 7;
+ public static final short TAG_GPS_SATTELLITES = 8;
+ public static final short TAG_GPS_STATUS = 9;
+ public static final short TAG_GPS_MEASURE_MODE = 10;
+ public static final short TAG_GPS_DOP = 11;
+ public static final short TAG_GPS_SPEED_REF = 12;
+ public static final short TAG_GPS_SPEED = 13;
+ public static final short TAG_GPS_TRACK_REF = 14;
+ public static final short TAG_GPS_TRACK = 15;
+ public static final short TAG_GPS_IMG_DIRECTION_REF = 16;
+ public static final short TAG_GPS_IMG_DIRECTION = 17;
+ public static final short TAG_GPS_MAP_DATUM = 18;
+ public static final short TAG_GPS_DEST_LATITUDE_REF = 19;
+ public static final short TAG_GPS_DEST_LATITUDE = 20;
+ public static final short TAG_GPS_DEST_LONGITUDE_REF = 21;
+ public static final short TAG_GPS_DEST_LONGITUDE = 22;
+ public static final short TAG_GPS_DEST_BEARING_REF = 23;
+ public static final short TAG_GPS_DEST_BEARING = 24;
+ public static final short TAG_GPS_DEST_DISTANCE_REF = 25;
+ public static final short TAG_GPS_DEST_DISTANCE = 26;
+ public static final short TAG_GPS_PROCESSING_METHOD = 27;
+ public static final short TAG_GPS_AREA_INFORMATION = 28;
+ public static final short TAG_GPS_DATA_STAMP = 29;
+ public static final short TAG_GPS_DIFFERENTIAL = 30;
+
+ // Interoperability tag
+ public static final short TAG_INTEROPERABILITY_INDEX = 1;
+
+ /**
+ * Constants for {@link #TAG_ORIENTATION}
+ */
+ public static interface Orientation {
+ public static final short TOP_LEFT = 1;
+ public static final short TOP_RIGHT = 2;
+ public static final short BOTTOM_LEFT = 3;
+ public static final short BOTTOM_RIGHT = 4;
+ public static final short LEFT_TOP = 5;
+ public static final short RIGHT_TOP = 6;
+ public static final short LEFT_BOTTOM = 7;
+ public static final short RIGHT_BOTTOM = 8;
+ }
+
+ /**
+ * Constants for {@link #TAG_Y_CB_CR_POSITIONING}
+ */
+ public static interface YCbCrPositioning {
+ public static final short CENTERED = 1;
+ public static final short CO_SITED = 2;
+ }
+
+ /**
+ * Constants for {@link #TAG_COMPRESSION}
+ */
+ public static interface Compression {
+ public static final short UNCOMPRESSION = 1;
+ public static final short JPEG = 6;
+ }
+
+ /**
+ * Constants for {@link #TAG_RESOLUTION_UNIT}
+ */
+ public static interface ResolutionUnit {
+ public static final short INCHES = 2;
+ public static final short CENTIMETERS = 3;
+ }
+
+ /**
+ * Constants for {@link #TAG_PHOTOMETRIC_INTERPRETATION}
+ */
+ public static interface PhotometricInterpretation {
+ public static final short RGB = 2;
+ public static final short YCBCR = 6;
+ }
+
+ /**
+ * Constants for {@link #TAG_PLANAR_CONFIGURATION}
+ */
+ public static interface PlanarConfiguration {
+ public static final short CHUNKY = 1;
+ public static final short PLANAR = 2;
+ }
+
+ /**
+ * Constants for {@link #TAG_EXPOSURE_PROGRAM}
+ */
+ public static interface ExposureProgram {
+ public static final short NOT_DEFINED = 0;
+ public static final short MANUAL = 1;
+ public static final short NORMAL_PROGRAM = 2;
+ public static final short APERTURE_PRIORITY = 3;
+ public static final short SHUTTER_PRIORITY = 4;
+ public static final short CREATIVE_PROGRAM = 5;
+ public static final short ACTION_PROGRAM = 6;
+ public static final short PROTRAIT_MODE = 7;
+ public static final short LANDSCAPE_MODE = 8;
+ }
+
+ /**
+ * Constants for {@link #TAG_METERING_MODE}
+ */
+ public static interface MeteringMode {
+ public static final short UNKNOWN = 0;
+ public static final short AVERAGE = 1;
+ public static final short CENTER_WEIGHTED_AVERAGE = 2;
+ public static final short SPOT = 3;
+ public static final short MULTISPOT = 4;
+ public static final short PATTERN = 5;
+ public static final short PARTAIL = 6;
+ public static final short OTHER = 255;
+ }
+
+ /**
+ * Constants for {@link #TAG_FLASH} As the definition in Jeita EXIF 2.2 standard, we can
+ * treat this constant as bitwise flag.
+ * <p>
+ * e.g.
+ * <p>
+ * short flash = FIRED | RETURN_STROBE_RETURN_LIGHT_DETECTED | MODE_AUTO_MODE
+ */
+ public static interface Flash {
+ // LSB
+ public static final short DID_NOT_FIRED = 0;
+ public static final short FIRED = 1;
+ // 1st~2nd bits
+ public static final short RETURN_NO_STROBE_RETURN_DETECTION_FUNCTION = 0 << 1;
+ public static final short RETURN_STROBE_RETURN_LIGHT_NOT_DETECTED = 2 << 1;
+ public static final short RETURN_STROBE_RETURN_LIGHT_DETECTED = 3 << 1;
+ // 3rd~4th bits
+ public static final short MODE_UNKNOWN = 0 << 3;
+ public static final short MODE_COMPULSORY_FLASH_FIRING = 1 << 3;
+ public static final short MODE_COMPULSORY_FLASH_SUPPRESSION = 2 << 3;
+ public static final short MODE_AUTO_MODE = 3 << 3;
+ // 5th bit
+ public static final short FUNCTION_PRESENT = 0 << 5;
+ public static final short FUNCTION_NO_FUNCTION = 1 << 5;
+ // 6th bit
+ public static final short RED_EYE_REDUCTION_NO_OR_UNKNOWN = 0 << 6;
+ public static final short RED_EYE_REDUCTION_SUPPORT = 1 << 6;
+ }
+
+ /**
+ * Constants for {@link #TAG_COLOR_SPACE}
+ */
+ public static interface ColorSpace {
+ public static final short SRGB = 1;
+ public static final short UNCALIBRATED = (short) 0xFFFF;
+ }
+
+ /**
+ * Constants for {@link #TAG_EXPOSURE_MODE}
+ */
+ public static interface ExposureMode {
+ public static final short AUTO_EXPOSURE = 0;
+ public static final short MANUAL_EXPOSURE = 1;
+ public static final short AUTO_BRACKET = 2;
+ }
+
+ /**
+ * Constants for {@link #TAG_WHITE_BALANCE}
+ */
+ public static interface WhiteBalance {
+ public static final short AUTO = 0;
+ public static final short MANUAL = 1;
+ }
+
+ /**
+ * Constants for {@link #TAG_SCENE_CAPTURE_TYPE}
+ */
+ public static interface SceneCapture {
+ public static final short STANDARD = 0;
+ public static final short LANDSCAPE = 1;
+ public static final short PROTRAIT = 2;
+ public static final short NIGHT_SCENE = 3;
+ }
+
+ /**
+ * Constants for {@link #TAG_COMPONENTS_CONFIGURATION}
+ */
+ public static interface ComponentsConfiguration {
+ public static final short NOT_EXIST = 0;
+ public static final short Y = 1;
+ public static final short CB = 2;
+ public static final short CR = 3;
+ public static final short R = 4;
+ public static final short G = 5;
+ public static final short B = 6;
+ }
+
+ /**
+ * Constants for {@link #TAG_LIGHT_SOURCE}
+ */
+ public static interface LightSource {
+ public static final short UNKNOWN = 0;
+ public static final short DAYLIGHT = 1;
+ public static final short FLUORESCENT = 2;
+ public static final short TUNGSTEN = 3;
+ public static final short FLASH = 4;
+ public static final short FINE_WEATHER = 9;
+ public static final short CLOUDY_WEATHER = 10;
+ public static final short SHADE = 11;
+ public static final short DAYLIGHT_FLUORESCENT = 12;
+ public static final short DAY_WHITE_FLUORESCENT = 13;
+ public static final short COOL_WHITE_FLUORESCENT = 14;
+ public static final short WHITE_FLUORESCENT = 15;
+ public static final short STANDARD_LIGHT_A = 17;
+ public static final short STANDARD_LIGHT_B = 18;
+ public static final short STANDARD_LIGHT_C = 19;
+ public static final short D55 = 20;
+ public static final short D65 = 21;
+ public static final short D75 = 22;
+ public static final short D50 = 23;
+ public static final short ISO_STUDIO_TUNGSTEN = 24;
+ public static final short OTHER = 255;
+ }
+
+ /**
+ * Constants for {@link #TAG_SENSING_METHOD}
+ */
+ public static interface SensingMethod {
+ public static final short NOT_DEFINED = 1;
+ public static final short ONE_CHIP_COLOR = 2;
+ public static final short TWO_CHIP_COLOR = 3;
+ public static final short THREE_CHIP_COLOR = 4;
+ public static final short COLOR_SEQUENTIAL_AREA = 5;
+ public static final short TRILINEAR = 7;
+ public static final short COLOR_SEQUENTIAL_LINEAR = 8;
+ }
+
+ /**
+ * Constants for {@link #TAG_FILE_SOURCE}
+ */
+ public static interface FileSource {
+ public static final short DSC = 3;
+ }
+
+ /**
+ * Constants for {@link #TAG_SCENE_TYPE}
+ */
+ public static interface SceneType {
+ public static final short DIRECT_PHOTOGRAPHED = 1;
+ }
+
+ /**
+ * Constants for {@link #TAG_GAIN_CONTROL}
+ */
+ public static interface GainControl {
+ public static final short NONE = 0;
+ public static final short LOW_UP = 1;
+ public static final short HIGH_UP = 2;
+ public static final short LOW_DOWN = 3;
+ public static final short HIGH_DOWN = 4;
+ }
+
+ /**
+ * Constants for {@link #TAG_CONTRAST}
+ */
+ public static interface Contrast {
+ public static final short NORMAL = 0;
+ public static final short SOFT = 1;
+ public static final short HARD = 2;
+ }
+
+ /**
+ * Constants for {@link #TAG_SATURATION}
+ */
+ public static interface Saturation {
+ public static final short NORMAL = 0;
+ public static final short LOW = 1;
+ public static final short HIGH = 2;
+ }
+
+ /**
+ * Constants for {@link #TAG_SHARPNESS}
+ */
+ public static interface Sharpness {
+ public static final short NORMAL = 0;
+ public static final short SOFT = 1;
+ public static final short HARD = 2;
+ }
+
+ /**
+ * Constants for {@link #TAG_SUBJECT_DISTANCE}
+ */
+ public static interface SubjectDistance {
+ public static final short UNKNOWN = 0;
+ public static final short MACRO = 1;
+ public static final short CLOSE_VIEW = 2;
+ public static final short DISTANT_VIEW = 3;
+ }
+
+ /**
+ * Constants for {@link #TAG_GPS_LATITUDE_REF}, {@link #TAG_GPS_DEST_LATITUDE_REF}
+ */
+ public static interface GpsLatitudeRef {
+ public static final String NORTH = "N";
+ public static final String SOUTH = "S";
+ }
+
+ /**
+ * Constants for {@link #TAG_GPS_LONGITUDE_REF}, {@link #TAG_GPS_DEST_LONGITUDE_REF}
+ */
+ public static interface GpsLongitudeRef {
+ public static final String EAST = "E";
+ public static final String WEST = "W";
+ }
+
+ /**
+ * Constants for {@link #TAG_GPS_ALTITUDE_REF}
+ */
+ public static interface GpsAltitudeRef {
+ public static final short SEA_LEVEL = 0;
+ public static final short SEA_LEVEL_NEGATIVE = 1;
+ }
+
+ /**
+ * Constants for {@link #TAG_GPS_STATUS}
+ */
+ public static interface GpsStatus {
+ public static final String IN_PROGRESS = "A";
+ public static final String INTEROPERABILITY = "V";
+ }
+
+ /**
+ * Constants for {@link #TAG_GPS_MEASURE_MODE}
+ */
+ public static interface GpsMeasureMode {
+ public static final String MODE_2_DIMENSIONAL = "2";
+ public static final String MODE_3_DIMENSIONAL = "3";
+ }
+
+ /**
+ * Constants for {@link #TAG_GPS_SPEED_REF}, {@link #TAG_GPS_DEST_DISTANCE_REF}
+ */
+ public static interface GpsSpeedRef {
+ public static final String KILOMETERS = "K";
+ public static final String MILES = "M";
+ public static final String KNOTS = "N";
+ }
+
+ /**
+ * Constants for {@link #TAG_GPS_TRACK_REF}, {@link #TAG_GPS_IMG_DIRECTION_REF},
+ * {@link #TAG_GPS_DEST_BEARING_REF}
+ */
+ public static interface GpsTrackRef {
+ public static final String TRUE_DIRECTION = "T";
+ public static final String MAGNETIC_DIRECTION = "M";
+ }
+
+ /**
+ * Constants for {@link #TAG_GPS_DIFFERENTIAL}
+ */
+ public static interface GpsDifferential {
+ public static final short WITHOUT_DIFFERENTIAL_CORRECTION = 0;
+ public static final short DIFFERENTIAL_CORRECTION_APPLIED = 1;
+ }
+
+ /**
+ * The BYTE type in the EXIF standard. An 8-bit unsigned integer.
+ */
+ public static final short TYPE_UNSIGNED_BYTE = 1;
+ /**
+ * The ASCII type in the EXIF standard. An 8-bit byte containing one 7-bit ASCII code.
+ * The final byte is terminated with NULL.
+ */
+ public static final short TYPE_ASCII = 2;
+ /**
+ * The SHORT type in the EXIF standard. A 16-bit (2-byte) unsigned integer
+ */
+ public static final short TYPE_UNSIGNED_SHORT = 3;
+ /**
+ * The LONG type in the EXIF standard. A 32-bit (4-byte) unsigned integer
+ */
+ public static final short TYPE_UNSIGNED_LONG = 4;
+ /**
+ * The RATIONAL type of EXIF standard. It consists of two LONGs. The first one is the numerator
+ * and the second one expresses the denominator.
+ */
+ public static final short TYPE_UNSIGNED_RATIONAL = 5;
+ /**
+ * The UNDEFINED type in the EXIF standard. An 8-bit byte that can take any value
+ * depending on the field definition.
+ */
+ public static final short TYPE_UNDEFINED = 7;
+ /**
+ * The SLONG type in the EXIF standard. A 32-bit (4-byte) signed integer
+ * (2's complement notation).
+ */
+ public static final short TYPE_LONG = 9;
+ /**
+ * The SRATIONAL type of EXIF standard. It consists of two SLONGs. The first one is the
+ * numerator and the second one is the denominator.
+ */
+ public static final short TYPE_RATIONAL = 10;
+
+ private static final int TYPE_TO_SIZE_MAP[] = new int[11];
+ static {
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_BYTE] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_ASCII] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_SHORT] = 2;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_LONG] = 4;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_RATIONAL] = 8;
+ TYPE_TO_SIZE_MAP[TYPE_UNDEFINED] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_LONG] = 4;
+ TYPE_TO_SIZE_MAP[TYPE_RATIONAL] = 8;
+ }
+
+ /**
+ * Gets the element size of the given data type.
+ *
+ * @see #TYPE_ASCII
+ * @see #TYPE_LONG
+ * @see #TYPE_RATIONAL
+ * @see #TYPE_UNDEFINED
+ * @see #TYPE_UNSIGNED_BYTE
+ * @see #TYPE_UNSIGNED_LONG
+ * @see #TYPE_UNSIGNED_RATIONAL
+ * @see #TYPE_UNSIGNED_SHORT
+ */
+ public static int getElementSize(short type) {
+ return TYPE_TO_SIZE_MAP[type];
+ }
+
+ private static volatile SparseArray<Integer> sTagInfo = null;
+ private static volatile SparseArray<Integer> sInteroperTagInfo = null;
+ private static final int SIZE_UNDEFINED = 0;
+
+ private static SparseArray<Integer> getTagInfo() {
+ if (sTagInfo == null) {
+ synchronized(ExifTag.class) {
+ if (sTagInfo == null) {
+ sTagInfo = new SparseArray<Integer>();
+ initTagInfo();
+ }
+ }
+ }
+ return sTagInfo;
+ }
+
+ private static SparseArray<Integer> getInteroperTagInfo() {
+ if (sInteroperTagInfo == null) {
+ synchronized(ExifTag.class) {
+ if (sInteroperTagInfo == null) {
+ sInteroperTagInfo = new SparseArray<Integer>();
+ sInteroperTagInfo.put(TAG_INTEROPERABILITY_INDEX,
+ (IfdId.TYPE_IFD_INTEROPERABILITY << 24)
+ | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ }
+ }
+ }
+ return sInteroperTagInfo;
+ }
+
+ private static void initTagInfo() {
+ /**
+ * We put tag information in a 4-bytes integer. The first byte is the
+ * IFD of the tag, and the second byte is the default data type. The
+ * last two byte are a short value indicating the component count of this
+ * tag.
+ */
+ sTagInfo.put(TAG_MAKE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_IMAGE_WIDTH,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_IMAGE_LENGTH,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_BITS_PER_SAMPLE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 3);
+ sTagInfo.put(TAG_COMPRESSION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_PHOTOMETRIC_INTERPRETATION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_ORIENTATION, (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SAMPLES_PER_PIXEL,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_PLANAR_CONFIGURATION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_Y_CB_CR_SUB_SAMPLING,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 2);
+ sTagInfo.put(TAG_Y_CB_CR_POSITIONING,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_X_RESOLUTION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_Y_RESOLUTION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_RESOLUTION_UNIT,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_STRIP_OFFSETS,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_ROWS_PER_STRIP,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_STRIP_BYTE_COUNTS,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_JPEG_INTERCHANGE_FORMAT,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_TRANSFER_FUNCTION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_SHORT << 16 | 3 * 256);
+ sTagInfo.put(TAG_WHITE_POINT,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 2);
+ sTagInfo.put(TAG_PRIMARY_CHROMATICITIES,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 6);
+ sTagInfo.put(TAG_Y_CB_CR_COEFFICIENTS,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 3);
+ sTagInfo.put(TAG_REFERENCE_BLACK_WHITE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 6);
+ sTagInfo.put(TAG_DATE_TIME,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | 20);
+ sTagInfo.put(TAG_IMAGE_DESCRIPTION,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_MAKE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_MODEL,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SOFTWARE,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_ARTIST,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_COPYRIGHT,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_EXIF_IFD,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_GPS_IFD,
+ (IfdId.TYPE_IFD_0 << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+
+ // EXIF TAG
+ sTagInfo.put(TAG_EXIF_VERSION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 4);
+ sTagInfo.put(TAG_FLASHPIX_VERSION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 4);
+ sTagInfo.put(TAG_COLOR_SPACE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_COMPONENTS_CONFIGURATION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 4);
+ sTagInfo.put(TAG_COMPRESSED_BITS_PER_PIXEL,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_PIXEL_X_DIMENSION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_PIXEL_Y_DIMENSION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_LONG << 16 | 1);
+ sTagInfo.put(TAG_MAKER_NOTE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_USER_COMMENT,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_RELATED_SOUND_FILE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | 13);
+ sTagInfo.put(TAG_DATE_TIME_ORIGINAL,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | 20);
+ sTagInfo.put(TAG_DATE_TIME_DIGITIZED,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | 20);
+ sTagInfo.put(TAG_SUB_SEC_TIME,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SUB_SEC_TIME_ORIGINAL,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SUB_SEC_TIME_DIGITIZED,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_IMAGE_UNIQUE_ID,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | 33);
+ sTagInfo.put(TAG_EXPOSURE_TIME,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_F_NUMBER,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_EXPOSURE_PROGRAM,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SPECTRAL_SENSITIVITY,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_ISO_SPEED_RATINGS,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_OECF,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SHUTTER_SPEED_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_APERTURE_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_BRIGHTNESS_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_EXPOSURE_BIAS_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_MAX_APERTURE_VALUE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_SUBJECT_DISTANCE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_METERING_MODE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_LIGHT_SOURCE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_FLASH,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_FOCAL_LENGTH,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_SUBJECT_AREA,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_FLASH_ENERGY,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_SPATIAL_FREQUENCY_RESPONSE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_FOCAL_PLANE_X_RESOLUTION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_FOCAL_PLANE_Y_RESOLUTION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_FOCAL_PLANE_RESOLUTION_UNIT,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SUBJECT_LOCATION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 2);
+ sTagInfo.put(TAG_EXPOSURE_INDEX,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_SENSING_METHOD,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_FILE_SOURCE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 1);
+ sTagInfo.put(TAG_SCENE_TYPE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | 1);
+ sTagInfo.put(TAG_CFA_PATTERN,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_CUSTOM_RENDERED,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_EXPOSURE_MODE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_WHITE_BALANCE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_DIGITAL_ZOOM_RATIO,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_FOCAL_LENGTH_IN_35_MM_FILE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SCENE_CAPTURE_TYPE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_GAIN_CONTROL,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_CONTRAST,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SATURATION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_SHARPNESS,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ sTagInfo.put(TAG_DEVICE_SETTING_DESCRIPTION,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_SUBJECT_DISTANCE_RANGE,
+ (IfdId.TYPE_IFD_EXIF << 24) | TYPE_UNSIGNED_SHORT << 16 | 1);
+ // GPS tag
+ sTagInfo.put(TAG_GPS_VERSION_ID,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_BYTE << 16 | 4);
+ sTagInfo.put(TAG_GPS_LATITUDE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_LONGITUDE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_LATITUDE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_RATIONAL << 16 | 3);
+ sTagInfo.put(TAG_GPS_LONGITUDE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_RATIONAL << 16 | 3);
+ sTagInfo.put(TAG_GPS_ALTITUDE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_BYTE << 16 | 1);
+ sTagInfo.put(TAG_GPS_ALTITUDE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_TIME_STAMP,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 3);
+ sTagInfo.put(TAG_GPS_SATTELLITES,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_GPS_STATUS,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_MEASURE_MODE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_DOP,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_SPEED_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_SPEED,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_TRACK_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_TRACK,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_IMG_DIRECTION_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_IMG_DIRECTION,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_MAP_DATUM,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_GPS_DEST_LATITUDE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_DEST_LATITUDE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_DEST_BEARING_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_DEST_BEARING,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_DEST_DISTANCE_REF,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 2);
+ sTagInfo.put(TAG_GPS_DEST_DISTANCE,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ sTagInfo.put(TAG_GPS_PROCESSING_METHOD,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_GPS_AREA_INFORMATION,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNDEFINED << 16 | SIZE_UNDEFINED);
+ sTagInfo.put(TAG_GPS_DATA_STAMP,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_ASCII << 16 | 11);
+ sTagInfo.put(TAG_GPS_DIFFERENTIAL,
+ (IfdId.TYPE_IFD_GPS << 24) | TYPE_UNSIGNED_SHORT << 16 | 11);
+ }
+
+ private final short mTagId;
+ private final short mDataType;
+ private final int mIfd;
+ private final boolean mComponentCountDefined;
+ private int mComponentCount;
+ private Object mValue;
+ private int mOffset;
+
+ static private short getTypeFromInfo(int info) {
+ return (short) ((info >> 16) & 0xff);
+ }
+
+ static private int getComponentCountFromInfo(int info) {
+ return info & 0xffff;
+ }
+
+ static private int getIfdIdFromInfo(int info) {
+ return (info >> 24) & 0xff;
+ }
+
+ static private boolean getComponentCountDefined(short tagId, int ifd) {
+ Integer info = (ifd == IfdId.TYPE_IFD_INTEROPERABILITY) ?
+ getInteroperTagInfo().get(tagId) : getTagInfo().get(tagId);
+ if (info == null) return false;
+ return getComponentCountFromInfo(info) != SIZE_UNDEFINED;
+ }
+
+ static int getIfdIdFromTagId(short tagId) {
+ Integer info = getTagInfo().get(tagId);
+ if (info == null) {
+ throw new IllegalArgumentException("Unknown Tag ID: " + tagId);
+ }
+ return getIfdIdFromInfo(info);
+ }
+
+ /**
+ * Create a tag with given ID. For tags related to interoperability and thumbnail, call
+ * {@link #buildInteroperabilityTag(short)} and {@link #buildThumbnailTag(short)} respectively.
+ * @exception IllegalArgumentException If the ID is invalid.
+ */
+ static public ExifTag buildTag(short tagId) {
+ Integer info = getTagInfo().get(tagId);
+ if (info == null) {
+ throw new IllegalArgumentException("Unknown Tag ID: " + tagId);
+ }
+ return new ExifTag(tagId, getTypeFromInfo(info),
+ getComponentCountFromInfo(info),
+ getIfdIdFromInfo(info));
+ }
+
+ /**
+ * Create a tag related to thumbnail with given ID.
+ * @exception IllegalArgumentException If the ID is invalid.
+ */
+ static public ExifTag buildThumbnailTag(short tagId) {
+ Integer info = getTagInfo().get(tagId);
+ if (info == null || getIfdIdFromInfo(info) != IfdId.TYPE_IFD_0) {
+ throw new IllegalArgumentException("Unknown Thumnail Tag ID: " + tagId);
+ }
+ return new ExifTag(tagId, getTypeFromInfo(info),
+ getComponentCountFromInfo(info),
+ IfdId.TYPE_IFD_1);
+ }
+
+ /**
+ * Create a tag related to interoperability with given ID.
+ * @exception IllegalArgumentException If the ID is invalid.
+ */
+ static public ExifTag buildInteroperabilityTag(short tagId) {
+ Integer info = getInteroperTagInfo().get(tagId);
+ if (info == null || getIfdIdFromInfo(info) != IfdId.TYPE_IFD_INTEROPERABILITY) {
+ throw new RuntimeException("Unknown Interoperability Tag ID: " + tagId);
+ }
+ return new ExifTag(tagId, getTypeFromInfo(info),
+ getComponentCountFromInfo(info),
+ IfdId.TYPE_IFD_INTEROPERABILITY);
+ }
+
+ ExifTag(short tagId, short type, int componentCount, int ifd) {
+ mTagId = tagId;
+ mDataType = type;
+ mComponentCount = componentCount;
+ mComponentCountDefined = getComponentCountDefined(tagId, ifd);
+ mIfd = ifd;
+ }
+
+ /**
+ * Returns the ID of the IFD this tag belongs to.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_EXIF
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ */
+ public int getIfd() {
+ return mIfd;
+ }
+
+ /**
+ * Gets the ID of this tag.
+ */
+ public short getTagId() {
+ return mTagId;
+ }
+
+ /**
+ * Gets the data type of this tag
+ *
+ * @see #TYPE_ASCII
+ * @see #TYPE_LONG
+ * @see #TYPE_RATIONAL
+ * @see #TYPE_UNDEFINED
+ * @see #TYPE_UNSIGNED_BYTE
+ * @see #TYPE_UNSIGNED_LONG
+ * @see #TYPE_UNSIGNED_RATIONAL
+ * @see #TYPE_UNSIGNED_SHORT
+ */
+ public short getDataType() {
+ return mDataType;
+ }
+
+ /**
+ * Gets the total data size in bytes of the value of this tag.
+ */
+ public int getDataSize() {
+ return getComponentCount() * getElementSize(getDataType());
+ }
+
+ /**
+ * Gets the component count of this tag.
+ */
+ public int getComponentCount() {
+ return mComponentCount;
+ }
+
+ /**
+ * Returns true if this ExifTag contains value; otherwise, this tag will contain an offset value
+ * that links to the area where the actual value is located.
+ *
+ * @see #getOffset()
+ */
+ public boolean hasValue() {
+ return mValue != null;
+ }
+
+ /**
+ * Gets the offset of this tag. This is only valid if this data size > 4 and contains an offset
+ * to the location of the actual value.
+ */
+ public int getOffset() {
+ return mOffset;
+ }
+
+ /**
+ * Sets the offset of this tag.
+ */
+ void setOffset(int offset) {
+ mOffset = offset;
+ }
+
+ private void checkComponentCountOrThrow(int count)
+ throws IllegalArgumentException {
+ if (mComponentCountDefined && (mComponentCount != count)) {
+ throw new IllegalArgumentException("Tag " + mTagId + ": Required "
+ + mComponentCount + " components but was given " + count
+ + " component(s)");
+ }
+ }
+
+ private void throwTypeNotMatchedException(String className)
+ throws IllegalArgumentException {
+ throw new IllegalArgumentException("Tag " + mTagId + ": expect type " +
+ convertTypeToString(mDataType) + " but got " + className);
+ }
+
+ private static String convertTypeToString(short type) {
+ switch (type) {
+ case TYPE_UNSIGNED_BYTE:
+ return "UNSIGNED_BYTE";
+ case TYPE_ASCII:
+ return "ASCII";
+ case TYPE_UNSIGNED_SHORT:
+ return "UNSIGNED_SHORT";
+ case TYPE_UNSIGNED_LONG:
+ return "UNSIGNED_LONG";
+ case TYPE_UNSIGNED_RATIONAL:
+ return "UNSIGNED_RATIONAL";
+ case TYPE_UNDEFINED:
+ return "UNDEFINED";
+ case TYPE_LONG:
+ return "LONG";
+ case TYPE_RATIONAL:
+ return "RATIONAL";
+ default:
+ return "";
+ }
+ }
+
+ private static final int UNSIGNED_SHORT_MAX = 65535;
+ private static final long UNSIGNED_LONG_MAX = 4294967295L;
+ private static final long LONG_MAX = Integer.MAX_VALUE;
+ private static final long LONG_MIN = Integer.MIN_VALUE;
+
+ private void checkOverflowForUnsignedShort(int[] value) {
+ for (int v : value) {
+ if (v > UNSIGNED_SHORT_MAX || v < 0) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type UNSIGNED_SHORT");
+ }
+ }
+ }
+
+ private void checkOverflowForUnsignedLong(long[] value) {
+ for (long v: value) {
+ if (v < 0 || v > UNSIGNED_LONG_MAX) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type UNSIGNED_LONG");
+ }
+ }
+ }
+
+ private void checkOverflowForUnsignedLong(int[] value) {
+ for (int v: value) {
+ if (v < 0) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type UNSIGNED_LONG");
+ }
+ }
+ }
+
+ private void checkOverflowForUnsignedRational(Rational[] value) {
+ for (Rational v: value) {
+ if (v.getNominator() < 0 || v.getDenominator() < 0
+ || v.getNominator() > UNSIGNED_LONG_MAX
+ || v.getDenominator() > UNSIGNED_LONG_MAX) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type UNSIGNED_RATIONAL");
+ }
+ }
+ }
+
+ private void checkOverflowForRational(Rational[] value) {
+ for (Rational v: value) {
+ if (v.getNominator() < LONG_MIN || v.getDenominator() < LONG_MIN
+ || v.getNominator() > LONG_MAX
+ || v.getDenominator() > LONG_MAX) {
+ throw new IllegalArgumentException(
+ "Tag " + mTagId+ ": Value" + v +
+ " is illegal for type RATIONAL");
+ }
+ }
+ }
+
+ /**
+ * Sets integer values into this tag.
+ * @exception IllegalArgumentException for the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+ * <li>The value overflows. </li>
+ * <li>The value.length does NOT match the definition of component count in
+ * EXIF standard.</li>
+ * </ul>
+ */
+ public void setValue(int[] value) {
+ checkComponentCountOrThrow(value.length);
+ if (mDataType != TYPE_UNSIGNED_SHORT && mDataType != TYPE_LONG &&
+ mDataType != TYPE_UNSIGNED_LONG) {
+ throwTypeNotMatchedException("int");
+ }
+ if (mDataType == TYPE_UNSIGNED_SHORT) {
+ checkOverflowForUnsignedShort(value);
+ } else if (mDataType == TYPE_UNSIGNED_LONG) {
+ checkOverflowForUnsignedLong(value);
+ }
+
+ long[] data = new long[value.length];
+ for (int i = 0; i < value.length; i++) {
+ data[i] = value[i];
+ }
+ mValue = data;
+ mComponentCount = value.length;
+ }
+
+ /**
+ * Sets integer values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The component count in the definition of EXIF standard is not 1.</li>
+ * </ul>
+ */
+ public void setValue(int value) {
+ checkComponentCountOrThrow(1);
+ setValue(new int[] {value});
+ }
+
+ /**
+ * Sets long values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+ * <li>The value overflows. </li>
+ * <li>The value.length does NOT match the definition of component count in
+ * EXIF standard.</li>
+ * </ul>
+ */
+ public void setValue(long[] value) {
+ checkComponentCountOrThrow(value.length);
+ if (mDataType != TYPE_UNSIGNED_LONG) {
+ throwTypeNotMatchedException("long");
+ }
+ checkOverflowForUnsignedLong(value);
+ mValue = value;
+ mComponentCount = value.length;
+ }
+
+ /**
+ * Sets long values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+ * <li>The value overflows. </li>
+ * <li>The component count in the definition of EXIF standard is not 1.</li>
+ * </ul>
+ */
+ public void setValue(long value) {
+ setValue(new long[] {value});
+ }
+
+ /**
+ * Sets string values into this tag.
+ * @exception IllegalArgumentException If the data type is not {@link #TYPE_ASCII}
+ * or value.length() + 1 does NOT fit the definition of the component count in the
+ * EXIF standard.
+ */
+ public void setValue(String value) {
+ checkComponentCountOrThrow(value.length() + 1);
+ if (mDataType != TYPE_ASCII) {
+ throwTypeNotMatchedException("String");
+ }
+ mComponentCount = value.length() + 1;
+ mValue = value;
+ }
+
+ /**
+ * Sets Rational values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL} or
+ * {@link #TYPE_RATIONAL} .</li>
+ * <li>The value overflows. </li>
+ * <li>The value.length does NOT match the definition of component count in
+ * EXIF standard.</li>
+ * </ul>
+ */
+ public void setValue(Rational[] value) {
+ if (mDataType == TYPE_UNSIGNED_RATIONAL) {
+ checkOverflowForUnsignedRational(value);
+ } else if (mDataType == TYPE_RATIONAL) {
+ checkOverflowForRational(value);
+ } else {
+ throwTypeNotMatchedException("Rational");
+ }
+ checkComponentCountOrThrow(value.length);
+ mValue = value;
+ mComponentCount = value.length;
+ }
+
+ /**
+ * Sets Rational values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL} or
+ * {@link #TYPE_RATIONAL} .</li>
+ * <li>The value overflows. </li>
+ * <li>The component count in the definition of EXIF standard is not 1.</li>
+ * </ul>
+ * */
+ public void setValue(Rational value) {
+ setValue(new Rational[] {value});
+ }
+
+ /**
+ * Sets byte values into this tag.
+ * @exception IllegalArgumentException For the following situation:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
+ * {@link #TYPE_UNDEFINED} .</li>
+ * <li>The length does NOT match the definition of component count in EXIF standard.</li>
+ * </ul>
+ * */
+ public void setValue(byte[] value, int offset, int length) {
+ checkComponentCountOrThrow(length);
+ if (mDataType != TYPE_UNSIGNED_BYTE && mDataType != TYPE_UNDEFINED) {
+ throwTypeNotMatchedException("byte");
+ }
+ mValue = new byte[length];
+ System.arraycopy(value, offset, mValue, 0, length);
+ mComponentCount = length;
+ }
+
+ /**
+ * Equivalent to setValue(value, 0, value.length).
+ */
+ public void setValue(byte[] value) {
+ setValue(value, 0, value.length);
+ }
+
+ private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyy:MM:dd kk:mm:ss");
+
+ /**
+ * Sets a timestamp to this tag. The method converts the timestamp with the format of
+ * "yyyy:MM:dd kk:mm:ss" and calls {@link #setValue(String)}.
+ *
+ * @param time the number of milliseconds since Jan. 1, 1970 GMT
+ * @exception IllegalArgumentException If the data type is not {@link #TYPE_ASCII}
+ * or the component count of this tag is not 20 or undefined
+ */
+ public void setTimeValue(long time) {
+ // synchronized on TIME_FORMAT as SimpleDateFormat is not thread safe
+ synchronized (TIME_FORMAT) {
+ setValue(TIME_FORMAT.format(new Date(time)));
+ }
+ }
+
+ /**
+ * Gets the {@link #TYPE_UNSIGNED_SHORT} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_UNSIGNED_SHORT}.
+ */
+ public int getUnsignedShort(int index) {
+ if (mDataType != TYPE_UNSIGNED_SHORT) {
+ throw new IllegalArgumentException("Cannot get UNSIGNED_SHORT value from "
+ + convertTypeToString(mDataType));
+ }
+ return (int) (((long[]) mValue) [index]);
+ }
+
+ /**
+ * Gets the {@link #TYPE_LONG} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_LONG}.
+ */
+ public int getLong(int index) {
+ if (mDataType != TYPE_LONG) {
+ throw new IllegalArgumentException("Cannot get LONG value from "
+ + convertTypeToString(mDataType));
+ }
+ return (int) (((long[]) mValue) [index]);
+ }
+
+ /**
+ * Gets the {@link #TYPE_UNSIGNED_LONG} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_UNSIGNED_LONG}.
+ */
+ public long getUnsignedLong(int index) {
+ if (mDataType != TYPE_UNSIGNED_LONG) {
+ throw new IllegalArgumentException("Cannot get UNSIGNED LONG value from "
+ + convertTypeToString(mDataType));
+ }
+ return ((long[]) mValue) [index];
+ }
+
+ /**
+ * Gets the {@link #TYPE_ASCII} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_ASCII}.
+ */
+ public String getString() {
+ if (mDataType != TYPE_ASCII) {
+ throw new IllegalArgumentException("Cannot get ASCII value from "
+ + convertTypeToString(mDataType));
+ }
+ return (String) mValue;
+ }
+
+ /**
+ * Gets the {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL} data.
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_RATIONAL} or
+ * {@link #TYPE_UNSIGNED_RATIONAL}.
+ */
+ public Rational getRational(int index) {
+ if ((mDataType != TYPE_RATIONAL) && (mDataType != TYPE_UNSIGNED_RATIONAL)) {
+ throw new IllegalArgumentException("Cannot get RATIONAL value from "
+ + convertTypeToString(mDataType));
+ }
+ return ((Rational[]) mValue) [index];
+ }
+
+ /**
+ * Equivalent to getBytes(buffer, 0, buffer.length).
+ */
+ public void getBytes(byte[] buf) {
+ getBytes(buf, 0, buf.length);
+ }
+
+ /**
+ * Gets the {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE} data.
+ *
+ * @param buf the byte array in which to store the bytes read.
+ * @param offset the initial position in buffer to store the bytes.
+ * @param length the maximum number of bytes to store in buffer. If length > component count,
+ * only the valid bytes will be stored.
+ *
+ * @exception IllegalArgumentException If the type is NOT {@link #TYPE_UNDEFINED} or
+ * {@link #TYPE_UNSIGNED_BYTE}.
+ */
+ public void getBytes(byte[] buf, int offset, int length) {
+ if ((mDataType != TYPE_UNDEFINED) && (mDataType != TYPE_UNSIGNED_BYTE)) {
+ throw new IllegalArgumentException("Cannot get BYTE value from "
+ + convertTypeToString(mDataType));
+ }
+ System.arraycopy(mValue, 0, buf, offset,
+ (length > mComponentCount) ? mComponentCount : length);
+ }
+
+ /**
+ * Returns a string representation of the value of this tag.
+ */
+ public String valueToString() {
+ StringBuilder sbuilder = new StringBuilder();
+ switch (getDataType()) {
+ case ExifTag.TYPE_UNDEFINED:
+ case ExifTag.TYPE_UNSIGNED_BYTE:
+ byte buf[] = new byte[getComponentCount()];
+ getBytes(buf);
+ for(int i = 0, n = getComponentCount(); i < n; i++) {
+ if(i != 0) sbuilder.append(" ");
+ sbuilder.append(String.format("%02x", buf[i]));
+ }
+ break;
+ case ExifTag.TYPE_ASCII:
+ sbuilder.append(getString());
+ break;
+ case ExifTag.TYPE_UNSIGNED_LONG:
+ for(int i = 0, n = getComponentCount(); i < n; i++) {
+ if(i != 0) sbuilder.append(" ");
+ sbuilder.append(getUnsignedLong(i));
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL:
+ case ExifTag.TYPE_UNSIGNED_RATIONAL:
+ for(int i = 0, n = getComponentCount(); i < n; i++) {
+ Rational r = getRational(i);
+ if(i != 0) sbuilder.append(" ");
+ sbuilder.append(r.getNominator()).append("/").append(r.getDenominator());
+ }
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT:
+ for(int i = 0, n = getComponentCount(); i < n; i++) {
+ if(i != 0) sbuilder.append(" ");
+ sbuilder.append(getUnsignedShort(i));
+ }
+ break;
+ case ExifTag.TYPE_LONG:
+ for(int i = 0, n = getComponentCount(); i < n; i++) {
+ if(i != 0) sbuilder.append(" ");
+ sbuilder.append(getLong(i));
+ }
+ break;
+ }
+ return sbuilder.toString();
+ }
+
+ /**
+ * Returns true if the ID is one of the following: {@link #TAG_EXIF_IFD},
+ * {@link #TAG_GPS_IFD}, {@link #TAG_JPEG_INTERCHANGE_FORMAT},
+ * {@link #TAG_STRIP_OFFSETS}, {@link #TAG_INTEROPERABILITY_IFD}
+ */
+ static boolean isOffsetTag(short tagId) {
+ return tagId == TAG_EXIF_IFD
+ || tagId == TAG_GPS_IFD
+ || tagId == TAG_JPEG_INTERCHANGE_FORMAT
+ || tagId == TAG_STRIP_OFFSETS
+ || tagId == TAG_INTEROPERABILITY_IFD;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ExifTag) {
+ ExifTag tag = (ExifTag) obj;
+ if (mValue != null) {
+ if (mValue instanceof long[]) {
+ if (!(tag.mValue instanceof long[])) return false;
+ return Arrays.equals((long[]) mValue, (long[]) tag.mValue);
+ } else if (mValue instanceof Rational[]) {
+ if (!(tag.mValue instanceof Rational[])) return false;
+ return Arrays.equals((Rational[]) mValue, (Rational[]) tag.mValue);
+ } else if (mValue instanceof byte[]) {
+ if (!(tag.mValue instanceof byte[])) return false;
+ return Arrays.equals((byte[]) mValue, (byte[]) tag.mValue);
+ } else {
+ return mValue.equals(tag.mValue);
+ }
+ } else {
+ return tag.mValue == null;
+ }
+ }
+ return false;
+ }
+}