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