ExifInterface.java revision 9a03dd10c1334a2998cfb99fead2e5a78dfdee98
1/* 2 * Copyright (C) 2007 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 17package android.media; 18 19import android.annotation.NonNull; 20import android.content.res.AssetManager; 21import android.graphics.Bitmap; 22import android.graphics.BitmapFactory; 23import android.system.ErrnoException; 24import android.system.Os; 25import android.system.OsConstants; 26import android.util.Log; 27import android.util.Pair; 28import android.annotation.IntDef; 29 30import java.io.BufferedInputStream; 31import java.io.ByteArrayInputStream; 32import java.io.DataInputStream; 33import java.io.EOFException; 34import java.io.File; 35import java.io.FileDescriptor; 36import java.io.FileInputStream; 37import java.io.FileNotFoundException; 38import java.io.FileOutputStream; 39import java.io.FilterOutputStream; 40import java.io.IOException; 41import java.io.InputStream; 42import java.io.OutputStream; 43import java.nio.ByteBuffer; 44import java.nio.ByteOrder; 45import java.nio.charset.Charset; 46import java.nio.charset.StandardCharsets; 47import java.text.ParsePosition; 48import java.text.SimpleDateFormat; 49import java.util.Arrays; 50import java.util.LinkedList; 51import java.util.Date; 52import java.util.HashMap; 53import java.util.HashSet; 54import java.util.Map; 55import java.util.Set; 56import java.util.TimeZone; 57import java.util.regex.Matcher; 58import java.util.regex.Pattern; 59import java.lang.annotation.Retention; 60import java.lang.annotation.RetentionPolicy; 61 62import libcore.io.IoUtils; 63import libcore.io.Streams; 64 65/** 66 * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file. 67 * <p> 68 * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW and RAF. 69 * <p> 70 * Attribute mutation is supported for JPEG image files. 71 */ 72public class ExifInterface { 73 private static final String TAG = "ExifInterface"; 74 private static final boolean DEBUG = false; 75 76 // The Exif tag names. See Tiff 6.0 Section 3 and Section 8. 77 /** Type is String. */ 78 public static final String TAG_ARTIST = "Artist"; 79 /** Type is int. */ 80 public static final String TAG_BITS_PER_SAMPLE = "BitsPerSample"; 81 /** Type is int. */ 82 public static final String TAG_COMPRESSION = "Compression"; 83 /** Type is String. */ 84 public static final String TAG_COPYRIGHT = "Copyright"; 85 /** Type is String. */ 86 public static final String TAG_DATETIME = "DateTime"; 87 /** Type is String. */ 88 public static final String TAG_IMAGE_DESCRIPTION = "ImageDescription"; 89 /** Type is int. */ 90 public static final String TAG_IMAGE_LENGTH = "ImageLength"; 91 /** Type is int. */ 92 public static final String TAG_IMAGE_WIDTH = "ImageWidth"; 93 /** Type is int. */ 94 public static final String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat"; 95 /** Type is int. */ 96 public static final String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength"; 97 /** Type is String. */ 98 public static final String TAG_MAKE = "Make"; 99 /** Type is String. */ 100 public static final String TAG_MODEL = "Model"; 101 /** Type is int. */ 102 public static final String TAG_ORIENTATION = "Orientation"; 103 /** Type is int. */ 104 public static final String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation"; 105 /** Type is int. */ 106 public static final String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration"; 107 /** Type is rational. */ 108 public static final String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities"; 109 /** Type is rational. */ 110 public static final String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite"; 111 /** Type is int. */ 112 public static final String TAG_RESOLUTION_UNIT = "ResolutionUnit"; 113 /** Type is int. */ 114 public static final String TAG_ROWS_PER_STRIP = "RowsPerStrip"; 115 /** Type is int. */ 116 public static final String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel"; 117 /** Type is String. */ 118 public static final String TAG_SOFTWARE = "Software"; 119 /** Type is int. */ 120 public static final String TAG_STRIP_BYTE_COUNTS = "StripByteCounts"; 121 /** Type is int. */ 122 public static final String TAG_STRIP_OFFSETS = "StripOffsets"; 123 /** Type is int. */ 124 public static final String TAG_TRANSFER_FUNCTION = "TransferFunction"; 125 /** Type is rational. */ 126 public static final String TAG_WHITE_POINT = "WhitePoint"; 127 /** Type is rational. */ 128 public static final String TAG_X_RESOLUTION = "XResolution"; 129 /** Type is rational. */ 130 public static final String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients"; 131 /** Type is int. */ 132 public static final String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning"; 133 /** Type is int. */ 134 public static final String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling"; 135 /** Type is rational. */ 136 public static final String TAG_Y_RESOLUTION = "YResolution"; 137 /** Type is rational. */ 138 public static final String TAG_APERTURE_VALUE = "ApertureValue"; 139 /** Type is rational. */ 140 public static final String TAG_BRIGHTNESS_VALUE = "BrightnessValue"; 141 /** Type is String. */ 142 public static final String TAG_CFA_PATTERN = "CFAPattern"; 143 /** Type is int. */ 144 public static final String TAG_COLOR_SPACE = "ColorSpace"; 145 /** Type is String. */ 146 public static final String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration"; 147 /** Type is rational. */ 148 public static final String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel"; 149 /** Type is int. */ 150 public static final String TAG_CONTRAST = "Contrast"; 151 /** Type is int. */ 152 public static final String TAG_CUSTOM_RENDERED = "CustomRendered"; 153 /** Type is String. */ 154 public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized"; 155 /** Type is String. */ 156 public static final String TAG_DATETIME_ORIGINAL = "DateTimeOriginal"; 157 /** Type is String. */ 158 public static final String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription"; 159 /** Type is double. */ 160 public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio"; 161 /** Type is String. */ 162 public static final String TAG_EXIF_VERSION = "ExifVersion"; 163 /** Type is double. */ 164 public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue"; 165 /** Type is rational. */ 166 public static final String TAG_EXPOSURE_INDEX = "ExposureIndex"; 167 /** Type is int. */ 168 public static final String TAG_EXPOSURE_MODE = "ExposureMode"; 169 /** Type is int. */ 170 public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram"; 171 /** Type is double. */ 172 public static final String TAG_EXPOSURE_TIME = "ExposureTime"; 173 /** Type is double. */ 174 public static final String TAG_F_NUMBER = "FNumber"; 175 /** 176 * Type is double. 177 * 178 * @deprecated use {@link #TAG_F_NUMBER} instead 179 */ 180 @Deprecated 181 public static final String TAG_APERTURE = "FNumber"; 182 /** Type is String. */ 183 public static final String TAG_FILE_SOURCE = "FileSource"; 184 /** Type is int. */ 185 public static final String TAG_FLASH = "Flash"; 186 /** Type is rational. */ 187 public static final String TAG_FLASH_ENERGY = "FlashEnergy"; 188 /** Type is String. */ 189 public static final String TAG_FLASHPIX_VERSION = "FlashpixVersion"; 190 /** Type is rational. */ 191 public static final String TAG_FOCAL_LENGTH = "FocalLength"; 192 /** Type is int. */ 193 public static final String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm"; 194 /** Type is int. */ 195 public static final String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit"; 196 /** Type is rational. */ 197 public static final String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution"; 198 /** Type is rational. */ 199 public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution"; 200 /** Type is int. */ 201 public static final String TAG_GAIN_CONTROL = "GainControl"; 202 /** Type is int. */ 203 public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings"; 204 /** 205 * Type is int. 206 * 207 * @deprecated use {@link #TAG_ISO_SPEED_RATINGS} instead 208 */ 209 @Deprecated 210 public static final String TAG_ISO = "ISOSpeedRatings"; 211 /** Type is String. */ 212 public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID"; 213 /** Type is int. */ 214 public static final String TAG_LIGHT_SOURCE = "LightSource"; 215 /** Type is String. */ 216 public static final String TAG_MAKER_NOTE = "MakerNote"; 217 /** Type is rational. */ 218 public static final String TAG_MAX_APERTURE_VALUE = "MaxApertureValue"; 219 /** Type is int. */ 220 public static final String TAG_METERING_MODE = "MeteringMode"; 221 /** Type is int. */ 222 public static final String TAG_NEW_SUBFILE_TYPE = "NewSubfileType"; 223 /** Type is String. */ 224 public static final String TAG_OECF = "OECF"; 225 /** Type is int. */ 226 public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension"; 227 /** Type is int. */ 228 public static final String TAG_PIXEL_Y_DIMENSION = "PixelYDimension"; 229 /** Type is String. */ 230 public static final String TAG_RELATED_SOUND_FILE = "RelatedSoundFile"; 231 /** Type is int. */ 232 public static final String TAG_SATURATION = "Saturation"; 233 /** Type is int. */ 234 public static final String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType"; 235 /** Type is String. */ 236 public static final String TAG_SCENE_TYPE = "SceneType"; 237 /** Type is int. */ 238 public static final String TAG_SENSING_METHOD = "SensingMethod"; 239 /** Type is int. */ 240 public static final String TAG_SHARPNESS = "Sharpness"; 241 /** Type is rational. */ 242 public static final String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue"; 243 /** Type is String. */ 244 public static final String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse"; 245 /** Type is String. */ 246 public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity"; 247 /** Type is int. */ 248 public static final String TAG_SUBFILE_TYPE = "SubfileType"; 249 /** Type is String. */ 250 public static final String TAG_SUBSEC_TIME = "SubSecTime"; 251 /** 252 * Type is String. 253 * 254 * @deprecated use {@link #TAG_SUBSEC_TIME_DIGITIZED} instead 255 */ 256 public static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized"; 257 /** Type is String. */ 258 public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized"; 259 /** 260 * Type is String. 261 * 262 * @deprecated use {@link #TAG_SUBSEC_TIME_ORIGINAL} instead 263 */ 264 public static final String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal"; 265 /** Type is String. */ 266 public static final String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal"; 267 /** Type is int. */ 268 public static final String TAG_SUBJECT_AREA = "SubjectArea"; 269 /** Type is double. */ 270 public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance"; 271 /** Type is int. */ 272 public static final String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange"; 273 /** Type is int. */ 274 public static final String TAG_SUBJECT_LOCATION = "SubjectLocation"; 275 /** Type is String. */ 276 public static final String TAG_USER_COMMENT = "UserComment"; 277 /** Type is int. */ 278 public static final String TAG_WHITE_BALANCE = "WhiteBalance"; 279 /** 280 * The altitude (in meters) based on the reference in TAG_GPS_ALTITUDE_REF. 281 * Type is rational. 282 */ 283 public static final String TAG_GPS_ALTITUDE = "GPSAltitude"; 284 /** 285 * 0 if the altitude is above sea level. 1 if the altitude is below sea 286 * level. Type is int. 287 */ 288 public static final String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef"; 289 /** Type is String. */ 290 public static final String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation"; 291 /** Type is rational. */ 292 public static final String TAG_GPS_DOP = "GPSDOP"; 293 /** Type is String. */ 294 public static final String TAG_GPS_DATESTAMP = "GPSDateStamp"; 295 /** Type is rational. */ 296 public static final String TAG_GPS_DEST_BEARING = "GPSDestBearing"; 297 /** Type is String. */ 298 public static final String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef"; 299 /** Type is rational. */ 300 public static final String TAG_GPS_DEST_DISTANCE = "GPSDestDistance"; 301 /** Type is String. */ 302 public static final String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef"; 303 /** Type is rational. */ 304 public static final String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude"; 305 /** Type is String. */ 306 public static final String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef"; 307 /** Type is rational. */ 308 public static final String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude"; 309 /** Type is String. */ 310 public static final String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef"; 311 /** Type is int. */ 312 public static final String TAG_GPS_DIFFERENTIAL = "GPSDifferential"; 313 /** Type is rational. */ 314 public static final String TAG_GPS_IMG_DIRECTION = "GPSImgDirection"; 315 /** Type is String. */ 316 public static final String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef"; 317 /** Type is rational. Format is "num1/denom1,num2/denom2,num3/denom3". */ 318 public static final String TAG_GPS_LATITUDE = "GPSLatitude"; 319 /** Type is String. */ 320 public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef"; 321 /** Type is rational. Format is "num1/denom1,num2/denom2,num3/denom3". */ 322 public static final String TAG_GPS_LONGITUDE = "GPSLongitude"; 323 /** Type is String. */ 324 public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef"; 325 /** Type is String. */ 326 public static final String TAG_GPS_MAP_DATUM = "GPSMapDatum"; 327 /** Type is String. */ 328 public static final String TAG_GPS_MEASURE_MODE = "GPSMeasureMode"; 329 /** Type is String. Name of GPS processing method used for location finding. */ 330 public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod"; 331 /** Type is String. */ 332 public static final String TAG_GPS_SATELLITES = "GPSSatellites"; 333 /** Type is rational. */ 334 public static final String TAG_GPS_SPEED = "GPSSpeed"; 335 /** Type is String. */ 336 public static final String TAG_GPS_SPEED_REF = "GPSSpeedRef"; 337 /** Type is String. */ 338 public static final String TAG_GPS_STATUS = "GPSStatus"; 339 /** Type is String. Format is "hh:mm:ss". */ 340 public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp"; 341 /** Type is rational. */ 342 public static final String TAG_GPS_TRACK = "GPSTrack"; 343 /** Type is String. */ 344 public static final String TAG_GPS_TRACK_REF = "GPSTrackRef"; 345 /** Type is String. */ 346 public static final String TAG_GPS_VERSION_ID = "GPSVersionID"; 347 /** Type is String. */ 348 public static final String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex"; 349 /** Type is int. */ 350 public static final String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength"; 351 /** Type is int. */ 352 public static final String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth"; 353 /** Type is int. DNG Specification 1.4.0.0. Section 4 */ 354 public static final String TAG_DNG_VERSION = "DNGVersion"; 355 /** Type is int. DNG Specification 1.4.0.0. Section 4 */ 356 public static final String TAG_DEFAULT_CROP_SIZE = "DefaultCropSize"; 357 /** Type is undefined. See Olympus MakerNote tags in http://www.exiv2.org/tags-olympus.html. */ 358 public static final String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage"; 359 /** Type is int. See Olympus Camera Settings tags in http://www.exiv2.org/tags-olympus.html. */ 360 public static final String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart"; 361 /** Type is int. See Olympus Camera Settings tags in http://www.exiv2.org/tags-olympus.html. */ 362 public static final String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength"; 363 /** Type is int. See Olympus Image Processing tags in http://www.exiv2.org/tags-olympus.html. */ 364 public static final String TAG_ORF_ASPECT_FRAME = "AspectFrame"; 365 /** 366 * Type is int. See PanasonicRaw tags in 367 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 368 */ 369 public static final String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder"; 370 /** 371 * Type is int. See PanasonicRaw tags in 372 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 373 */ 374 public static final String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder"; 375 /** 376 * Type is int. See PanasonicRaw tags in 377 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 378 */ 379 public static final String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder"; 380 /** 381 * Type is int. See PanasonicRaw tags in 382 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 383 */ 384 public static final String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder"; 385 /** 386 * Type is int. See PanasonicRaw tags in 387 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 388 */ 389 public static final String TAG_RW2_ISO = "ISO"; 390 /** 391 * Type is undefined. See PanasonicRaw tags in 392 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 393 */ 394 public static final String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw"; 395 396 /** 397 * Private tags used for pointing the other IFD offsets. 398 * The types of the following tags are int. 399 * See JEITA CP-3451C Section 4.6.3: Exif-specific IFD. 400 * For SubIFD, see Note 1 of Adobe PageMaker® 6.0 TIFF Technical Notes. 401 */ 402 private static final String TAG_EXIF_IFD_POINTER = "ExifIFDPointer"; 403 private static final String TAG_GPS_INFO_IFD_POINTER = "GPSInfoIFDPointer"; 404 private static final String TAG_INTEROPERABILITY_IFD_POINTER = "InteroperabilityIFDPointer"; 405 private static final String TAG_SUB_IFD_POINTER = "SubIFDPointer"; 406 // Proprietary pointer tags used for ORF files. 407 // See http://www.exiv2.org/tags-olympus.html 408 private static final String TAG_ORF_CAMERA_SETTINGS_IFD_POINTER = "CameraSettingsIFDPointer"; 409 private static final String TAG_ORF_IMAGE_PROCESSING_IFD_POINTER = "ImageProcessingIFDPointer"; 410 411 // Private tags used for thumbnail information. 412 private static final String TAG_HAS_THUMBNAIL = "HasThumbnail"; 413 private static final String TAG_THUMBNAIL_OFFSET = "ThumbnailOffset"; 414 private static final String TAG_THUMBNAIL_LENGTH = "ThumbnailLength"; 415 private static final String TAG_THUMBNAIL_DATA = "ThumbnailData"; 416 private static final int MAX_THUMBNAIL_SIZE = 512; 417 418 // Constants used for the Orientation Exif tag. 419 public static final int ORIENTATION_UNDEFINED = 0; 420 public static final int ORIENTATION_NORMAL = 1; 421 public static final int ORIENTATION_FLIP_HORIZONTAL = 2; // left right reversed mirror 422 public static final int ORIENTATION_ROTATE_180 = 3; 423 public static final int ORIENTATION_FLIP_VERTICAL = 4; // upside down mirror 424 // flipped about top-left <--> bottom-right axis 425 public static final int ORIENTATION_TRANSPOSE = 5; 426 public static final int ORIENTATION_ROTATE_90 = 6; // rotate 90 cw to right it 427 // flipped about top-right <--> bottom-left axis 428 public static final int ORIENTATION_TRANSVERSE = 7; 429 public static final int ORIENTATION_ROTATE_270 = 8; // rotate 270 to right it 430 431 // Constants used for white balance 432 public static final int WHITEBALANCE_AUTO = 0; 433 public static final int WHITEBALANCE_MANUAL = 1; 434 435 // Maximum size for checking file type signature (see image_type_recognition_lite.cc) 436 private static final int SIGNATURE_CHECK_SIZE = 5000; 437 438 private static final byte[] JPEG_SIGNATURE = new byte[] {(byte) 0xff, (byte) 0xd8, (byte) 0xff}; 439 private static final String RAF_SIGNATURE = "FUJIFILMCCD-RAW"; 440 private static final int RAF_OFFSET_TO_JPEG_IMAGE_OFFSET = 84; 441 private static final int RAF_INFO_SIZE = 160; 442 private static final int RAF_JPEG_LENGTH_VALUE_SIZE = 4; 443 444 // See http://fileformats.archiveteam.org/wiki/Olympus_ORF 445 private static final short ORF_SIGNATURE_1 = 0x4f52; 446 private static final short ORF_SIGNATURE_2 = 0x5352; 447 // There are two formats for Olympus Makernote Headers. Each has different identifiers and 448 // offsets to the actual data. 449 // See http://www.exiv2.org/makernote.html#R1 450 private static final byte[] ORF_MAKER_NOTE_HEADER_1 = new byte[] {(byte) 0x4f, (byte) 0x4c, 451 (byte) 0x59, (byte) 0x4d, (byte) 0x50, (byte) 0x00}; // "OLYMP\0" 452 private static final byte[] ORF_MAKER_NOTE_HEADER_2 = new byte[] {(byte) 0x4f, (byte) 0x4c, 453 (byte) 0x59, (byte) 0x4d, (byte) 0x50, (byte) 0x55, (byte) 0x53, (byte) 0x00, 454 (byte) 0x49, (byte) 0x49}; // "OLYMPUS\0II" 455 private static final int ORF_MAKER_NOTE_HEADER_1_SIZE = 8; 456 private static final int ORF_MAKER_NOTE_HEADER_2_SIZE = 12; 457 458 // See http://fileformats.archiveteam.org/wiki/RW2 459 private static final short RW2_SIGNATURE = 0x0055; 460 461 // See http://fileformats.archiveteam.org/wiki/Pentax_PEF 462 private static final String PEF_SIGNATURE = "PENTAX"; 463 // See http://www.exiv2.org/makernote.html#R11 464 private static final int PEF_MAKER_NOTE_SKIP_SIZE = 6; 465 466 private static SimpleDateFormat sFormatter; 467 468 // See Exchangeable image file format for digital still cameras: Exif version 2.2. 469 // The following values are for parsing EXIF data area. There are tag groups in EXIF data area. 470 // They are called "Image File Directory". They have multiple data formats to cover various 471 // image metadata from GPS longitude to camera model name. 472 473 // Types of Exif byte alignments (see JEITA CP-3451C Section 4.5.2) 474 private static final short BYTE_ALIGN_II = 0x4949; // II: Intel order 475 private static final short BYTE_ALIGN_MM = 0x4d4d; // MM: Motorola order 476 477 // TIFF Header Fixed Constant (see JEITA CP-3451C Section 4.5.2) 478 private static final byte START_CODE = 0x2a; // 42 479 private static final int IFD_OFFSET = 8; 480 481 // Formats for the value in IFD entry (See TIFF 6.0 Section 2, "Image File Directory".) 482 private static final int IFD_FORMAT_BYTE = 1; 483 private static final int IFD_FORMAT_STRING = 2; 484 private static final int IFD_FORMAT_USHORT = 3; 485 private static final int IFD_FORMAT_ULONG = 4; 486 private static final int IFD_FORMAT_URATIONAL = 5; 487 private static final int IFD_FORMAT_SBYTE = 6; 488 private static final int IFD_FORMAT_UNDEFINED = 7; 489 private static final int IFD_FORMAT_SSHORT = 8; 490 private static final int IFD_FORMAT_SLONG = 9; 491 private static final int IFD_FORMAT_SRATIONAL = 10; 492 private static final int IFD_FORMAT_SINGLE = 11; 493 private static final int IFD_FORMAT_DOUBLE = 12; 494 // Format indicating a new IFD entry (See Adobe PageMaker® 6.0 TIFF Technical Notes, "New Tag") 495 private static final int IFD_FORMAT_IFD = 13; 496 // Names for the data formats for debugging purpose. 497 private static final String[] IFD_FORMAT_NAMES = new String[] { 498 "", "BYTE", "STRING", "USHORT", "ULONG", "URATIONAL", "SBYTE", "UNDEFINED", "SSHORT", 499 "SLONG", "SRATIONAL", "SINGLE", "DOUBLE" 500 }; 501 // Sizes of the components of each IFD value format 502 private static final int[] IFD_FORMAT_BYTES_PER_FORMAT = new int[] { 503 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 1 504 }; 505 private static final byte[] EXIF_ASCII_PREFIX = new byte[] { 506 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 507 }; 508 509 /** 510 * Constants used for Compression tag. 511 * For Value 1, 2, 32773, see TIFF 6.0 Spec Section 3: Bilevel Images, Compression 512 * For Value 6, see TIFF 6.0 Spec Section 22: JPEG Compression, Extensions to Existing Fields 513 * For Value 7, 8, 34892, see DNG Specification 1.4.0.0. Section 3, Compression 514 */ 515 private static final int DATA_UNCOMPRESSED = 1; 516 private static final int DATA_HUFFMAN_COMPRESSED = 2; 517 private static final int DATA_JPEG = 6; 518 private static final int DATA_JPEG_COMPRESSED = 7; 519 private static final int DATA_DEFLATE_ZIP = 8; 520 private static final int DATA_PACK_BITS_COMPRESSED = 32773; 521 private static final int DATA_LOSSY_JPEG = 34892; 522 523 /** 524 * Constants used for BitsPerSample tag. 525 * For RGB, see TIFF 6.0 Spec Section 6, Differences from Palette Color Images 526 * For Greyscale, see TIFF 6.0 Spec Section 4, Differences from Bilevel Images 527 */ 528 private static final int[] BITS_PER_SAMPLE_RGB = new int[] { 8, 8, 8 }; 529 private static final int[] BITS_PER_SAMPLE_GREYSCALE_1 = new int[] { 4 }; 530 private static final int[] BITS_PER_SAMPLE_GREYSCALE_2 = new int[] { 8 }; 531 532 /** 533 * Constants used for PhotometricInterpretation tag. 534 * For White/Black, see Section 3, Color. 535 * See TIFF 6.0 Spec Section 22, Minimum Requirements for TIFF with JPEG Compression. 536 */ 537 private static final int PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO = 0; 538 private static final int PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO = 1; 539 private static final int PHOTOMETRIC_INTERPRETATION_RGB = 2; 540 private static final int PHOTOMETRIC_INTERPRETATION_YCBCR = 6; 541 542 /** 543 * Constants used for NewSubfileType tag. 544 * See TIFF 6.0 Spec Section 8 545 * */ 546 private static final int ORIGINAL_RESOLUTION_IMAGE = 0; 547 private static final int REDUCED_RESOLUTION_IMAGE = 1; 548 549 // A class for indicating EXIF rational type. 550 private static class Rational { 551 public final long numerator; 552 public final long denominator; 553 554 private Rational(long numerator, long denominator) { 555 // Handle erroneous case 556 if (denominator == 0) { 557 this.numerator = 0; 558 this.denominator = 1; 559 return; 560 } 561 this.numerator = numerator; 562 this.denominator = denominator; 563 } 564 565 @Override 566 public String toString() { 567 return numerator + "/" + denominator; 568 } 569 570 public double calculate() { 571 return (double) numerator / denominator; 572 } 573 } 574 575 // A class for indicating EXIF attribute. 576 private static class ExifAttribute { 577 public final int format; 578 public final int numberOfComponents; 579 public final byte[] bytes; 580 581 private ExifAttribute(int format, int numberOfComponents, byte[] bytes) { 582 this.format = format; 583 this.numberOfComponents = numberOfComponents; 584 this.bytes = bytes; 585 } 586 587 public static ExifAttribute createUShort(int[] values, ByteOrder byteOrder) { 588 final ByteBuffer buffer = ByteBuffer.wrap( 589 new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_USHORT] * values.length]); 590 buffer.order(byteOrder); 591 for (int value : values) { 592 buffer.putShort((short) value); 593 } 594 return new ExifAttribute(IFD_FORMAT_USHORT, values.length, buffer.array()); 595 } 596 597 public static ExifAttribute createUShort(int value, ByteOrder byteOrder) { 598 return createUShort(new int[] {value}, byteOrder); 599 } 600 601 public static ExifAttribute createULong(long[] values, ByteOrder byteOrder) { 602 final ByteBuffer buffer = ByteBuffer.wrap( 603 new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_ULONG] * values.length]); 604 buffer.order(byteOrder); 605 for (long value : values) { 606 buffer.putInt((int) value); 607 } 608 return new ExifAttribute(IFD_FORMAT_ULONG, values.length, buffer.array()); 609 } 610 611 public static ExifAttribute createULong(long value, ByteOrder byteOrder) { 612 return createULong(new long[] {value}, byteOrder); 613 } 614 615 public static ExifAttribute createSLong(int[] values, ByteOrder byteOrder) { 616 final ByteBuffer buffer = ByteBuffer.wrap( 617 new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_SLONG] * values.length]); 618 buffer.order(byteOrder); 619 for (int value : values) { 620 buffer.putInt(value); 621 } 622 return new ExifAttribute(IFD_FORMAT_SLONG, values.length, buffer.array()); 623 } 624 625 public static ExifAttribute createSLong(int value, ByteOrder byteOrder) { 626 return createSLong(new int[] {value}, byteOrder); 627 } 628 629 public static ExifAttribute createByte(String value) { 630 // Exception for GPSAltitudeRef tag 631 if (value.length() == 1 && value.charAt(0) >= '0' && value.charAt(0) <= '1') { 632 final byte[] bytes = new byte[] { (byte) (value.charAt(0) - '0') }; 633 return new ExifAttribute(IFD_FORMAT_BYTE, bytes.length, bytes); 634 } 635 final byte[] ascii = value.getBytes(ASCII); 636 return new ExifAttribute(IFD_FORMAT_BYTE, ascii.length, ascii); 637 } 638 639 public static ExifAttribute createString(String value) { 640 final byte[] ascii = (value + '\0').getBytes(ASCII); 641 return new ExifAttribute(IFD_FORMAT_STRING, ascii.length, ascii); 642 } 643 644 public static ExifAttribute createURational(Rational[] values, ByteOrder byteOrder) { 645 final ByteBuffer buffer = ByteBuffer.wrap( 646 new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_URATIONAL] * values.length]); 647 buffer.order(byteOrder); 648 for (Rational value : values) { 649 buffer.putInt((int) value.numerator); 650 buffer.putInt((int) value.denominator); 651 } 652 return new ExifAttribute(IFD_FORMAT_URATIONAL, values.length, buffer.array()); 653 } 654 655 public static ExifAttribute createURational(Rational value, ByteOrder byteOrder) { 656 return createURational(new Rational[] {value}, byteOrder); 657 } 658 659 public static ExifAttribute createSRational(Rational[] values, ByteOrder byteOrder) { 660 final ByteBuffer buffer = ByteBuffer.wrap( 661 new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_SRATIONAL] * values.length]); 662 buffer.order(byteOrder); 663 for (Rational value : values) { 664 buffer.putInt((int) value.numerator); 665 buffer.putInt((int) value.denominator); 666 } 667 return new ExifAttribute(IFD_FORMAT_SRATIONAL, values.length, buffer.array()); 668 } 669 670 public static ExifAttribute createSRational(Rational value, ByteOrder byteOrder) { 671 return createSRational(new Rational[] {value}, byteOrder); 672 } 673 674 public static ExifAttribute createDouble(double[] values, ByteOrder byteOrder) { 675 final ByteBuffer buffer = ByteBuffer.wrap( 676 new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_DOUBLE] * values.length]); 677 buffer.order(byteOrder); 678 for (double value : values) { 679 buffer.putDouble(value); 680 } 681 return new ExifAttribute(IFD_FORMAT_DOUBLE, values.length, buffer.array()); 682 } 683 684 public static ExifAttribute createDouble(double value, ByteOrder byteOrder) { 685 return createDouble(new double[] {value}, byteOrder); 686 } 687 688 @Override 689 public String toString() { 690 return "(" + IFD_FORMAT_NAMES[format] + ", data length:" + bytes.length + ")"; 691 } 692 693 private Object getValue(ByteOrder byteOrder) { 694 try { 695 ByteOrderAwarenessDataInputStream inputStream = 696 new ByteOrderAwarenessDataInputStream(bytes); 697 inputStream.setByteOrder(byteOrder); 698 switch (format) { 699 case IFD_FORMAT_BYTE: 700 case IFD_FORMAT_SBYTE: { 701 // Exception for GPSAltitudeRef tag 702 if (bytes.length == 1 && bytes[0] >= 0 && bytes[0] <= 1) { 703 return new String(new char[] { (char) (bytes[0] + '0') }); 704 } 705 return new String(bytes, ASCII); 706 } 707 case IFD_FORMAT_UNDEFINED: 708 case IFD_FORMAT_STRING: { 709 int index = 0; 710 if (numberOfComponents >= EXIF_ASCII_PREFIX.length) { 711 boolean same = true; 712 for (int i = 0; i < EXIF_ASCII_PREFIX.length; ++i) { 713 if (bytes[i] != EXIF_ASCII_PREFIX[i]) { 714 same = false; 715 break; 716 } 717 } 718 if (same) { 719 index = EXIF_ASCII_PREFIX.length; 720 } 721 } 722 723 StringBuilder stringBuilder = new StringBuilder(); 724 while (index < numberOfComponents) { 725 int ch = bytes[index]; 726 if (ch == 0) { 727 break; 728 } 729 if (ch >= 32) { 730 stringBuilder.append((char) ch); 731 } else { 732 stringBuilder.append('?'); 733 } 734 ++index; 735 } 736 return stringBuilder.toString(); 737 } 738 case IFD_FORMAT_USHORT: { 739 final int[] values = new int[numberOfComponents]; 740 for (int i = 0; i < numberOfComponents; ++i) { 741 values[i] = inputStream.readUnsignedShort(); 742 } 743 return values; 744 } 745 case IFD_FORMAT_ULONG: { 746 final long[] values = new long[numberOfComponents]; 747 for (int i = 0; i < numberOfComponents; ++i) { 748 values[i] = inputStream.readUnsignedInt(); 749 } 750 return values; 751 } 752 case IFD_FORMAT_URATIONAL: { 753 final Rational[] values = new Rational[numberOfComponents]; 754 for (int i = 0; i < numberOfComponents; ++i) { 755 final long numerator = inputStream.readUnsignedInt(); 756 final long denominator = inputStream.readUnsignedInt(); 757 values[i] = new Rational(numerator, denominator); 758 } 759 return values; 760 } 761 case IFD_FORMAT_SSHORT: { 762 final int[] values = new int[numberOfComponents]; 763 for (int i = 0; i < numberOfComponents; ++i) { 764 values[i] = inputStream.readShort(); 765 } 766 return values; 767 } 768 case IFD_FORMAT_SLONG: { 769 final int[] values = new int[numberOfComponents]; 770 for (int i = 0; i < numberOfComponents; ++i) { 771 values[i] = inputStream.readInt(); 772 } 773 return values; 774 } 775 case IFD_FORMAT_SRATIONAL: { 776 final Rational[] values = new Rational[numberOfComponents]; 777 for (int i = 0; i < numberOfComponents; ++i) { 778 final long numerator = inputStream.readInt(); 779 final long denominator = inputStream.readInt(); 780 values[i] = new Rational(numerator, denominator); 781 } 782 return values; 783 } 784 case IFD_FORMAT_SINGLE: { 785 final double[] values = new double[numberOfComponents]; 786 for (int i = 0; i < numberOfComponents; ++i) { 787 values[i] = inputStream.readFloat(); 788 } 789 return values; 790 } 791 case IFD_FORMAT_DOUBLE: { 792 final double[] values = new double[numberOfComponents]; 793 for (int i = 0; i < numberOfComponents; ++i) { 794 values[i] = inputStream.readDouble(); 795 } 796 return values; 797 } 798 default: 799 return null; 800 } 801 } catch (IOException e) { 802 Log.w(TAG, "IOException occurred during reading a value", e); 803 return null; 804 } 805 } 806 807 public double getDoubleValue(ByteOrder byteOrder) { 808 Object value = getValue(byteOrder); 809 if (value == null) { 810 throw new NumberFormatException("NULL can't be converted to a double value"); 811 } 812 if (value instanceof String) { 813 return Double.parseDouble((String) value); 814 } 815 if (value instanceof long[]) { 816 long[] array = (long[]) value; 817 if (array.length == 1) { 818 return (double) array[0]; 819 } 820 throw new NumberFormatException("There are more than one component"); 821 } 822 if (value instanceof int[]) { 823 int[] array = (int[]) value; 824 if (array.length == 1) { 825 return (double) array[0]; 826 } 827 throw new NumberFormatException("There are more than one component"); 828 } 829 if (value instanceof double[]) { 830 double[] array = (double[]) value; 831 if (array.length == 1) { 832 return array[0]; 833 } 834 throw new NumberFormatException("There are more than one component"); 835 } 836 if (value instanceof Rational[]) { 837 Rational[] array = (Rational[]) value; 838 if (array.length == 1) { 839 return array[0].calculate(); 840 } 841 throw new NumberFormatException("There are more than one component"); 842 } 843 throw new NumberFormatException("Couldn't find a double value"); 844 } 845 846 public int getIntValue(ByteOrder byteOrder) { 847 Object value = getValue(byteOrder); 848 if (value == null) { 849 throw new NumberFormatException("NULL can't be converted to a integer value"); 850 } 851 if (value instanceof String) { 852 return Integer.parseInt((String) value); 853 } 854 if (value instanceof long[]) { 855 long[] array = (long[]) value; 856 if (array.length == 1) { 857 return (int) array[0]; 858 } 859 throw new NumberFormatException("There are more than one component"); 860 } 861 if (value instanceof int[]) { 862 int[] array = (int[]) value; 863 if (array.length == 1) { 864 return array[0]; 865 } 866 throw new NumberFormatException("There are more than one component"); 867 } 868 throw new NumberFormatException("Couldn't find a integer value"); 869 } 870 871 public String getStringValue(ByteOrder byteOrder) { 872 Object value = getValue(byteOrder); 873 if (value == null) { 874 return null; 875 } 876 if (value instanceof String) { 877 return (String) value; 878 } 879 880 final StringBuilder stringBuilder = new StringBuilder(); 881 if (value instanceof long[]) { 882 long[] array = (long[]) value; 883 for (int i = 0; i < array.length; ++i) { 884 stringBuilder.append(array[i]); 885 if (i + 1 != array.length) { 886 stringBuilder.append(","); 887 } 888 } 889 return stringBuilder.toString(); 890 } 891 if (value instanceof int[]) { 892 int[] array = (int[]) value; 893 for (int i = 0; i < array.length; ++i) { 894 stringBuilder.append(array[i]); 895 if (i + 1 != array.length) { 896 stringBuilder.append(","); 897 } 898 } 899 return stringBuilder.toString(); 900 } 901 if (value instanceof double[]) { 902 double[] array = (double[]) value; 903 for (int i = 0; i < array.length; ++i) { 904 stringBuilder.append(array[i]); 905 if (i + 1 != array.length) { 906 stringBuilder.append(","); 907 } 908 } 909 return stringBuilder.toString(); 910 } 911 if (value instanceof Rational[]) { 912 Rational[] array = (Rational[]) value; 913 for (int i = 0; i < array.length; ++i) { 914 stringBuilder.append(array[i].numerator); 915 stringBuilder.append('/'); 916 stringBuilder.append(array[i].denominator); 917 if (i + 1 != array.length) { 918 stringBuilder.append(","); 919 } 920 } 921 return stringBuilder.toString(); 922 } 923 return null; 924 } 925 926 public int size() { 927 return IFD_FORMAT_BYTES_PER_FORMAT[format] * numberOfComponents; 928 } 929 } 930 931 // A class for indicating EXIF tag. 932 private static class ExifTag { 933 public final int number; 934 public final String name; 935 public final int primaryFormat; 936 public final int secondaryFormat; 937 938 private ExifTag(String name, int number, int format) { 939 this.name = name; 940 this.number = number; 941 this.primaryFormat = format; 942 this.secondaryFormat = -1; 943 } 944 945 private ExifTag(String name, int number, int primaryFormat, int secondaryFormat) { 946 this.name = name; 947 this.number = number; 948 this.primaryFormat = primaryFormat; 949 this.secondaryFormat = secondaryFormat; 950 } 951 } 952 953 // Primary image IFD TIFF tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 954 private static final ExifTag[] IFD_TIFF_TAGS = new ExifTag[] { 955 // For below two, see TIFF 6.0 Spec Section 3: Bilevel Images. 956 new ExifTag(TAG_NEW_SUBFILE_TYPE, 254, IFD_FORMAT_ULONG), 957 new ExifTag(TAG_SUBFILE_TYPE, 255, IFD_FORMAT_ULONG), 958 new ExifTag(TAG_IMAGE_WIDTH, 256, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 959 new ExifTag(TAG_IMAGE_LENGTH, 257, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 960 new ExifTag(TAG_BITS_PER_SAMPLE, 258, IFD_FORMAT_USHORT), 961 new ExifTag(TAG_COMPRESSION, 259, IFD_FORMAT_USHORT), 962 new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262, IFD_FORMAT_USHORT), 963 new ExifTag(TAG_IMAGE_DESCRIPTION, 270, IFD_FORMAT_STRING), 964 new ExifTag(TAG_MAKE, 271, IFD_FORMAT_STRING), 965 new ExifTag(TAG_MODEL, 272, IFD_FORMAT_STRING), 966 new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 967 new ExifTag(TAG_ORIENTATION, 274, IFD_FORMAT_USHORT), 968 new ExifTag(TAG_SAMPLES_PER_PIXEL, 277, IFD_FORMAT_USHORT), 969 new ExifTag(TAG_ROWS_PER_STRIP, 278, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 970 new ExifTag(TAG_STRIP_BYTE_COUNTS, 279, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 971 new ExifTag(TAG_X_RESOLUTION, 282, IFD_FORMAT_URATIONAL), 972 new ExifTag(TAG_Y_RESOLUTION, 283, IFD_FORMAT_URATIONAL), 973 new ExifTag(TAG_PLANAR_CONFIGURATION, 284, IFD_FORMAT_USHORT), 974 new ExifTag(TAG_RESOLUTION_UNIT, 296, IFD_FORMAT_USHORT), 975 new ExifTag(TAG_TRANSFER_FUNCTION, 301, IFD_FORMAT_USHORT), 976 new ExifTag(TAG_SOFTWARE, 305, IFD_FORMAT_STRING), 977 new ExifTag(TAG_DATETIME, 306, IFD_FORMAT_STRING), 978 new ExifTag(TAG_ARTIST, 315, IFD_FORMAT_STRING), 979 new ExifTag(TAG_WHITE_POINT, 318, IFD_FORMAT_URATIONAL), 980 new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319, IFD_FORMAT_URATIONAL), 981 // See Adobe PageMaker® 6.0 TIFF Technical Notes, Note 1. 982 new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG), 983 new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG), 984 new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG), 985 new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529, IFD_FORMAT_URATIONAL), 986 new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT), 987 new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT), 988 new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL), 989 new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING), 990 new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG), 991 new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG), 992 // RW2 file tags 993 // See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html) 994 new ExifTag(TAG_RW2_SENSOR_TOP_BORDER, 4, IFD_FORMAT_ULONG), 995 new ExifTag(TAG_RW2_SENSOR_LEFT_BORDER, 5, IFD_FORMAT_ULONG), 996 new ExifTag(TAG_RW2_SENSOR_BOTTOM_BORDER, 6, IFD_FORMAT_ULONG), 997 new ExifTag(TAG_RW2_SENSOR_RIGHT_BORDER, 7, IFD_FORMAT_ULONG), 998 new ExifTag(TAG_RW2_ISO, 23, IFD_FORMAT_USHORT), 999 new ExifTag(TAG_RW2_JPG_FROM_RAW, 46, IFD_FORMAT_UNDEFINED) 1000 }; 1001 1002 // Primary image IFD Exif Private tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 1003 private static final ExifTag[] IFD_EXIF_TAGS = new ExifTag[] { 1004 new ExifTag(TAG_EXPOSURE_TIME, 33434, IFD_FORMAT_URATIONAL), 1005 new ExifTag(TAG_F_NUMBER, 33437, IFD_FORMAT_URATIONAL), 1006 new ExifTag(TAG_EXPOSURE_PROGRAM, 34850, IFD_FORMAT_USHORT), 1007 new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852, IFD_FORMAT_STRING), 1008 new ExifTag(TAG_ISO_SPEED_RATINGS, 34855, IFD_FORMAT_USHORT), 1009 new ExifTag(TAG_OECF, 34856, IFD_FORMAT_UNDEFINED), 1010 new ExifTag(TAG_EXIF_VERSION, 36864, IFD_FORMAT_STRING), 1011 new ExifTag(TAG_DATETIME_ORIGINAL, 36867, IFD_FORMAT_STRING), 1012 new ExifTag(TAG_DATETIME_DIGITIZED, 36868, IFD_FORMAT_STRING), 1013 new ExifTag(TAG_COMPONENTS_CONFIGURATION, 37121, IFD_FORMAT_UNDEFINED), 1014 new ExifTag(TAG_COMPRESSED_BITS_PER_PIXEL, 37122, IFD_FORMAT_URATIONAL), 1015 new ExifTag(TAG_SHUTTER_SPEED_VALUE, 37377, IFD_FORMAT_SRATIONAL), 1016 new ExifTag(TAG_APERTURE_VALUE, 37378, IFD_FORMAT_URATIONAL), 1017 new ExifTag(TAG_BRIGHTNESS_VALUE, 37379, IFD_FORMAT_SRATIONAL), 1018 new ExifTag(TAG_EXPOSURE_BIAS_VALUE, 37380, IFD_FORMAT_SRATIONAL), 1019 new ExifTag(TAG_MAX_APERTURE_VALUE, 37381, IFD_FORMAT_URATIONAL), 1020 new ExifTag(TAG_SUBJECT_DISTANCE, 37382, IFD_FORMAT_URATIONAL), 1021 new ExifTag(TAG_METERING_MODE, 37383, IFD_FORMAT_USHORT), 1022 new ExifTag(TAG_LIGHT_SOURCE, 37384, IFD_FORMAT_USHORT), 1023 new ExifTag(TAG_FLASH, 37385, IFD_FORMAT_USHORT), 1024 new ExifTag(TAG_FOCAL_LENGTH, 37386, IFD_FORMAT_URATIONAL), 1025 new ExifTag(TAG_SUBJECT_AREA, 37396, IFD_FORMAT_USHORT), 1026 new ExifTag(TAG_MAKER_NOTE, 37500, IFD_FORMAT_UNDEFINED), 1027 new ExifTag(TAG_USER_COMMENT, 37510, IFD_FORMAT_UNDEFINED), 1028 new ExifTag(TAG_SUBSEC_TIME, 37520, IFD_FORMAT_STRING), 1029 new ExifTag(TAG_SUBSEC_TIME_ORIG, 37521, IFD_FORMAT_STRING), 1030 new ExifTag(TAG_SUBSEC_TIME_DIG, 37522, IFD_FORMAT_STRING), 1031 new ExifTag(TAG_FLASHPIX_VERSION, 40960, IFD_FORMAT_UNDEFINED), 1032 new ExifTag(TAG_COLOR_SPACE, 40961, IFD_FORMAT_USHORT), 1033 new ExifTag(TAG_PIXEL_X_DIMENSION, 40962, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 1034 new ExifTag(TAG_PIXEL_Y_DIMENSION, 40963, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 1035 new ExifTag(TAG_RELATED_SOUND_FILE, 40964, IFD_FORMAT_STRING), 1036 new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG), 1037 new ExifTag(TAG_FLASH_ENERGY, 41483, IFD_FORMAT_URATIONAL), 1038 new ExifTag(TAG_SPATIAL_FREQUENCY_RESPONSE, 41484, IFD_FORMAT_UNDEFINED), 1039 new ExifTag(TAG_FOCAL_PLANE_X_RESOLUTION, 41486, IFD_FORMAT_URATIONAL), 1040 new ExifTag(TAG_FOCAL_PLANE_Y_RESOLUTION, 41487, IFD_FORMAT_URATIONAL), 1041 new ExifTag(TAG_FOCAL_PLANE_RESOLUTION_UNIT, 41488, IFD_FORMAT_USHORT), 1042 new ExifTag(TAG_SUBJECT_LOCATION, 41492, IFD_FORMAT_USHORT), 1043 new ExifTag(TAG_EXPOSURE_INDEX, 41493, IFD_FORMAT_URATIONAL), 1044 new ExifTag(TAG_SENSING_METHOD, 41495, IFD_FORMAT_USHORT), 1045 new ExifTag(TAG_FILE_SOURCE, 41728, IFD_FORMAT_UNDEFINED), 1046 new ExifTag(TAG_SCENE_TYPE, 41729, IFD_FORMAT_UNDEFINED), 1047 new ExifTag(TAG_CFA_PATTERN, 41730, IFD_FORMAT_UNDEFINED), 1048 new ExifTag(TAG_CUSTOM_RENDERED, 41985, IFD_FORMAT_USHORT), 1049 new ExifTag(TAG_EXPOSURE_MODE, 41986, IFD_FORMAT_USHORT), 1050 new ExifTag(TAG_WHITE_BALANCE, 41987, IFD_FORMAT_USHORT), 1051 new ExifTag(TAG_DIGITAL_ZOOM_RATIO, 41988, IFD_FORMAT_URATIONAL), 1052 new ExifTag(TAG_FOCAL_LENGTH_IN_35MM_FILM, 41989, IFD_FORMAT_USHORT), 1053 new ExifTag(TAG_SCENE_CAPTURE_TYPE, 41990, IFD_FORMAT_USHORT), 1054 new ExifTag(TAG_GAIN_CONTROL, 41991, IFD_FORMAT_USHORT), 1055 new ExifTag(TAG_CONTRAST, 41992, IFD_FORMAT_USHORT), 1056 new ExifTag(TAG_SATURATION, 41993, IFD_FORMAT_USHORT), 1057 new ExifTag(TAG_SHARPNESS, 41994, IFD_FORMAT_USHORT), 1058 new ExifTag(TAG_DEVICE_SETTING_DESCRIPTION, 41995, IFD_FORMAT_UNDEFINED), 1059 new ExifTag(TAG_SUBJECT_DISTANCE_RANGE, 41996, IFD_FORMAT_USHORT), 1060 new ExifTag(TAG_IMAGE_UNIQUE_ID, 42016, IFD_FORMAT_STRING), 1061 new ExifTag(TAG_DNG_VERSION, 50706, IFD_FORMAT_BYTE), 1062 new ExifTag(TAG_DEFAULT_CROP_SIZE, 50720, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG) 1063 }; 1064 1065 // Primary image IFD GPS Info tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 1066 private static final ExifTag[] IFD_GPS_TAGS = new ExifTag[] { 1067 new ExifTag(TAG_GPS_VERSION_ID, 0, IFD_FORMAT_BYTE), 1068 new ExifTag(TAG_GPS_LATITUDE_REF, 1, IFD_FORMAT_STRING), 1069 new ExifTag(TAG_GPS_LATITUDE, 2, IFD_FORMAT_URATIONAL), 1070 new ExifTag(TAG_GPS_LONGITUDE_REF, 3, IFD_FORMAT_STRING), 1071 new ExifTag(TAG_GPS_LONGITUDE, 4, IFD_FORMAT_URATIONAL), 1072 new ExifTag(TAG_GPS_ALTITUDE_REF, 5, IFD_FORMAT_BYTE), 1073 new ExifTag(TAG_GPS_ALTITUDE, 6, IFD_FORMAT_URATIONAL), 1074 new ExifTag(TAG_GPS_TIMESTAMP, 7, IFD_FORMAT_URATIONAL), 1075 new ExifTag(TAG_GPS_SATELLITES, 8, IFD_FORMAT_STRING), 1076 new ExifTag(TAG_GPS_STATUS, 9, IFD_FORMAT_STRING), 1077 new ExifTag(TAG_GPS_MEASURE_MODE, 10, IFD_FORMAT_STRING), 1078 new ExifTag(TAG_GPS_DOP, 11, IFD_FORMAT_URATIONAL), 1079 new ExifTag(TAG_GPS_SPEED_REF, 12, IFD_FORMAT_STRING), 1080 new ExifTag(TAG_GPS_SPEED, 13, IFD_FORMAT_URATIONAL), 1081 new ExifTag(TAG_GPS_TRACK_REF, 14, IFD_FORMAT_STRING), 1082 new ExifTag(TAG_GPS_TRACK, 15, IFD_FORMAT_URATIONAL), 1083 new ExifTag(TAG_GPS_IMG_DIRECTION_REF, 16, IFD_FORMAT_STRING), 1084 new ExifTag(TAG_GPS_IMG_DIRECTION, 17, IFD_FORMAT_URATIONAL), 1085 new ExifTag(TAG_GPS_MAP_DATUM, 18, IFD_FORMAT_STRING), 1086 new ExifTag(TAG_GPS_DEST_LATITUDE_REF, 19, IFD_FORMAT_STRING), 1087 new ExifTag(TAG_GPS_DEST_LATITUDE, 20, IFD_FORMAT_URATIONAL), 1088 new ExifTag(TAG_GPS_DEST_LONGITUDE_REF, 21, IFD_FORMAT_STRING), 1089 new ExifTag(TAG_GPS_DEST_LONGITUDE, 22, IFD_FORMAT_URATIONAL), 1090 new ExifTag(TAG_GPS_DEST_BEARING_REF, 23, IFD_FORMAT_STRING), 1091 new ExifTag(TAG_GPS_DEST_BEARING, 24, IFD_FORMAT_URATIONAL), 1092 new ExifTag(TAG_GPS_DEST_DISTANCE_REF, 25, IFD_FORMAT_STRING), 1093 new ExifTag(TAG_GPS_DEST_DISTANCE, 26, IFD_FORMAT_URATIONAL), 1094 new ExifTag(TAG_GPS_PROCESSING_METHOD, 27, IFD_FORMAT_UNDEFINED), 1095 new ExifTag(TAG_GPS_AREA_INFORMATION, 28, IFD_FORMAT_UNDEFINED), 1096 new ExifTag(TAG_GPS_DATESTAMP, 29, IFD_FORMAT_STRING), 1097 new ExifTag(TAG_GPS_DIFFERENTIAL, 30, IFD_FORMAT_USHORT) 1098 }; 1099 // Primary image IFD Interoperability tag (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 1100 private static final ExifTag[] IFD_INTEROPERABILITY_TAGS = new ExifTag[] { 1101 new ExifTag(TAG_INTEROPERABILITY_INDEX, 1, IFD_FORMAT_STRING) 1102 }; 1103 // IFD Thumbnail tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 1104 private static final ExifTag[] IFD_THUMBNAIL_TAGS = new ExifTag[] { 1105 // For below two, see TIFF 6.0 Spec Section 3: Bilevel Images. 1106 new ExifTag(TAG_NEW_SUBFILE_TYPE, 254, IFD_FORMAT_ULONG), 1107 new ExifTag(TAG_SUBFILE_TYPE, 255, IFD_FORMAT_ULONG), 1108 new ExifTag(TAG_THUMBNAIL_IMAGE_WIDTH, 256, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 1109 new ExifTag(TAG_THUMBNAIL_IMAGE_LENGTH, 257, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 1110 new ExifTag(TAG_BITS_PER_SAMPLE, 258, IFD_FORMAT_USHORT), 1111 new ExifTag(TAG_COMPRESSION, 259, IFD_FORMAT_USHORT), 1112 new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262, IFD_FORMAT_USHORT), 1113 new ExifTag(TAG_IMAGE_DESCRIPTION, 270, IFD_FORMAT_STRING), 1114 new ExifTag(TAG_MAKE, 271, IFD_FORMAT_STRING), 1115 new ExifTag(TAG_MODEL, 272, IFD_FORMAT_STRING), 1116 new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 1117 new ExifTag(TAG_ORIENTATION, 274, IFD_FORMAT_USHORT), 1118 new ExifTag(TAG_SAMPLES_PER_PIXEL, 277, IFD_FORMAT_USHORT), 1119 new ExifTag(TAG_ROWS_PER_STRIP, 278, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 1120 new ExifTag(TAG_STRIP_BYTE_COUNTS, 279, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 1121 new ExifTag(TAG_X_RESOLUTION, 282, IFD_FORMAT_URATIONAL), 1122 new ExifTag(TAG_Y_RESOLUTION, 283, IFD_FORMAT_URATIONAL), 1123 new ExifTag(TAG_PLANAR_CONFIGURATION, 284, IFD_FORMAT_USHORT), 1124 new ExifTag(TAG_RESOLUTION_UNIT, 296, IFD_FORMAT_USHORT), 1125 new ExifTag(TAG_TRANSFER_FUNCTION, 301, IFD_FORMAT_USHORT), 1126 new ExifTag(TAG_SOFTWARE, 305, IFD_FORMAT_STRING), 1127 new ExifTag(TAG_DATETIME, 306, IFD_FORMAT_STRING), 1128 new ExifTag(TAG_ARTIST, 315, IFD_FORMAT_STRING), 1129 new ExifTag(TAG_WHITE_POINT, 318, IFD_FORMAT_URATIONAL), 1130 new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319, IFD_FORMAT_URATIONAL), 1131 // See Adobe PageMaker® 6.0 TIFF Technical Notes, Note 1. 1132 new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG), 1133 new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG), 1134 new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG), 1135 new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529, IFD_FORMAT_URATIONAL), 1136 new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT), 1137 new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT), 1138 new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL), 1139 new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING), 1140 new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG), 1141 new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG), 1142 new ExifTag(TAG_DNG_VERSION, 50706, IFD_FORMAT_BYTE), 1143 new ExifTag(TAG_DEFAULT_CROP_SIZE, 50720, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG) 1144 }; 1145 1146 // RAF file tag (See piex.cc line 372) 1147 private static final ExifTag TAG_RAF_IMAGE_SIZE = 1148 new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT); 1149 1150 // ORF file tags (See http://www.exiv2.org/tags-olympus.html) 1151 private static final ExifTag[] ORF_MAKER_NOTE_TAGS = new ExifTag[] { 1152 new ExifTag(TAG_ORF_THUMBNAIL_IMAGE, 256, IFD_FORMAT_UNDEFINED), 1153 new ExifTag(TAG_ORF_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_ULONG), 1154 new ExifTag(TAG_ORF_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_ULONG) 1155 }; 1156 private static final ExifTag[] ORF_CAMERA_SETTINGS_TAGS = new ExifTag[] { 1157 new ExifTag(TAG_ORF_PREVIEW_IMAGE_START, 257, IFD_FORMAT_ULONG), 1158 new ExifTag(TAG_ORF_PREVIEW_IMAGE_LENGTH, 258, IFD_FORMAT_ULONG) 1159 }; 1160 private static final ExifTag[] ORF_IMAGE_PROCESSING_TAGS = new ExifTag[] { 1161 new ExifTag(TAG_ORF_ASPECT_FRAME, 4371, IFD_FORMAT_USHORT) 1162 }; 1163 // PEF file tag (See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Pentax.html) 1164 private static final ExifTag[] PEF_TAGS = new ExifTag[] { 1165 new ExifTag(TAG_COLOR_SPACE, 55, IFD_FORMAT_USHORT) 1166 }; 1167 1168 // See JEITA CP-3451C Section 4.6.3: Exif-specific IFD. 1169 // The following values are used for indicating pointers to the other Image File Directories. 1170 1171 // Indices of Exif Ifd tag groups 1172 /** @hide */ 1173 @Retention(RetentionPolicy.SOURCE) 1174 @IntDef({IFD_TYPE_PRIMARY, IFD_TYPE_EXIF, IFD_TYPE_GPS, IFD_TYPE_INTEROPERABILITY, 1175 IFD_TYPE_THUMBNAIL, IFD_TYPE_PREVIEW, IFD_TYPE_ORF_MAKER_NOTE, 1176 IFD_TYPE_ORF_CAMERA_SETTINGS, IFD_TYPE_ORF_IMAGE_PROCESSING, IFD_TYPE_PEF}) 1177 public @interface IfdType {} 1178 1179 private static final int IFD_TYPE_PRIMARY = 0; 1180 private static final int IFD_TYPE_EXIF = 1; 1181 private static final int IFD_TYPE_GPS = 2; 1182 private static final int IFD_TYPE_INTEROPERABILITY = 3; 1183 private static final int IFD_TYPE_THUMBNAIL = 4; 1184 private static final int IFD_TYPE_PREVIEW = 5; 1185 private static final int IFD_TYPE_ORF_MAKER_NOTE = 6; 1186 private static final int IFD_TYPE_ORF_CAMERA_SETTINGS = 7; 1187 private static final int IFD_TYPE_ORF_IMAGE_PROCESSING = 8; 1188 private static final int IFD_TYPE_PEF = 9; 1189 1190 // List of Exif tag groups 1191 private static final ExifTag[][] EXIF_TAGS = new ExifTag[][] { 1192 IFD_TIFF_TAGS, IFD_EXIF_TAGS, IFD_GPS_TAGS, IFD_INTEROPERABILITY_TAGS, 1193 IFD_THUMBNAIL_TAGS, IFD_TIFF_TAGS, ORF_MAKER_NOTE_TAGS, ORF_CAMERA_SETTINGS_TAGS, 1194 ORF_IMAGE_PROCESSING_TAGS, PEF_TAGS 1195 }; 1196 // List of tags for pointing to the other image file directory offset. 1197 private static final ExifTag[] EXIF_POINTER_TAGS = new ExifTag[] { 1198 new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG), 1199 new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG), 1200 new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG), 1201 new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG), 1202 new ExifTag(TAG_ORF_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_BYTE), 1203 new ExifTag(TAG_ORF_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_BYTE) 1204 }; 1205 1206 // Tags for indicating the thumbnail offset and length 1207 private static final ExifTag JPEG_INTERCHANGE_FORMAT_TAG = 1208 new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG); 1209 private static final ExifTag JPEG_INTERCHANGE_FORMAT_LENGTH_TAG = 1210 new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG); 1211 1212 // Mappings from tag number to tag name and each item represents one IFD tag group. 1213 private static final HashMap[] sExifTagMapsForReading = new HashMap[EXIF_TAGS.length]; 1214 // Mappings from tag name to tag number and each item represents one IFD tag group. 1215 private static final HashMap[] sExifTagMapsForWriting = new HashMap[EXIF_TAGS.length]; 1216 private static final HashSet<String> sTagSetForCompatibility = new HashSet<>(Arrays.asList( 1217 TAG_F_NUMBER, TAG_DIGITAL_ZOOM_RATIO, TAG_EXPOSURE_TIME, TAG_SUBJECT_DISTANCE, 1218 TAG_GPS_TIMESTAMP)); 1219 // Mappings from tag number to IFD type for pointer tags. 1220 private static final HashMap sExifPointerTagMap = new HashMap(); 1221 1222 // See JPEG File Interchange Format Version 1.02. 1223 // The following values are defined for handling JPEG streams. In this implementation, we are 1224 // not only getting information from EXIF but also from some JPEG special segments such as 1225 // MARKER_COM for user comment and MARKER_SOFx for image width and height. 1226 1227 private static final Charset ASCII = Charset.forName("US-ASCII"); 1228 // Identifier for EXIF APP1 segment in JPEG 1229 private static final byte[] IDENTIFIER_EXIF_APP1 = "Exif\0\0".getBytes(ASCII); 1230 // JPEG segment markers, that each marker consumes two bytes beginning with 0xff and ending with 1231 // the indicator. There is no SOF4, SOF8, SOF16 markers in JPEG and SOFx markers indicates start 1232 // of frame(baseline DCT) and the image size info exists in its beginning part. 1233 private static final byte MARKER = (byte) 0xff; 1234 private static final byte MARKER_SOI = (byte) 0xd8; 1235 private static final byte MARKER_SOF0 = (byte) 0xc0; 1236 private static final byte MARKER_SOF1 = (byte) 0xc1; 1237 private static final byte MARKER_SOF2 = (byte) 0xc2; 1238 private static final byte MARKER_SOF3 = (byte) 0xc3; 1239 private static final byte MARKER_SOF5 = (byte) 0xc5; 1240 private static final byte MARKER_SOF6 = (byte) 0xc6; 1241 private static final byte MARKER_SOF7 = (byte) 0xc7; 1242 private static final byte MARKER_SOF9 = (byte) 0xc9; 1243 private static final byte MARKER_SOF10 = (byte) 0xca; 1244 private static final byte MARKER_SOF11 = (byte) 0xcb; 1245 private static final byte MARKER_SOF13 = (byte) 0xcd; 1246 private static final byte MARKER_SOF14 = (byte) 0xce; 1247 private static final byte MARKER_SOF15 = (byte) 0xcf; 1248 private static final byte MARKER_SOS = (byte) 0xda; 1249 private static final byte MARKER_APP1 = (byte) 0xe1; 1250 private static final byte MARKER_COM = (byte) 0xfe; 1251 private static final byte MARKER_EOI = (byte) 0xd9; 1252 1253 // Supported Image File Types 1254 private static final int IMAGE_TYPE_UNKNOWN = 0; 1255 private static final int IMAGE_TYPE_ARW = 1; 1256 private static final int IMAGE_TYPE_CR2 = 2; 1257 private static final int IMAGE_TYPE_DNG = 3; 1258 private static final int IMAGE_TYPE_JPEG = 4; 1259 private static final int IMAGE_TYPE_NEF = 5; 1260 private static final int IMAGE_TYPE_NRW = 6; 1261 private static final int IMAGE_TYPE_ORF = 7; 1262 private static final int IMAGE_TYPE_PEF = 8; 1263 private static final int IMAGE_TYPE_RAF = 9; 1264 private static final int IMAGE_TYPE_RW2 = 10; 1265 private static final int IMAGE_TYPE_SRW = 11; 1266 1267 static { 1268 sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); 1269 sFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); 1270 1271 // Build up the hash tables to look up Exif tags for reading Exif tags. 1272 for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) { 1273 sExifTagMapsForReading[ifdType] = new HashMap(); 1274 sExifTagMapsForWriting[ifdType] = new HashMap(); 1275 for (ExifTag tag : EXIF_TAGS[ifdType]) { 1276 sExifTagMapsForReading[ifdType].put(tag.number, tag); 1277 sExifTagMapsForWriting[ifdType].put(tag.name, tag); 1278 } 1279 } 1280 1281 // Build up the hash table to look up Exif pointer tags. 1282 sExifPointerTagMap.put(EXIF_POINTER_TAGS[0].number, IFD_TYPE_PREVIEW); // 330 1283 sExifPointerTagMap.put(EXIF_POINTER_TAGS[1].number, IFD_TYPE_EXIF); // 34665 1284 sExifPointerTagMap.put(EXIF_POINTER_TAGS[2].number, IFD_TYPE_GPS); // 34853 1285 sExifPointerTagMap.put(EXIF_POINTER_TAGS[3].number, IFD_TYPE_INTEROPERABILITY); // 40965 1286 sExifPointerTagMap.put(EXIF_POINTER_TAGS[4].number, IFD_TYPE_ORF_CAMERA_SETTINGS); // 8224 1287 sExifPointerTagMap.put(EXIF_POINTER_TAGS[5].number, IFD_TYPE_ORF_IMAGE_PROCESSING); // 8256 1288 } 1289 1290 private final String mFilename; 1291 private final FileDescriptor mSeekableFileDescriptor; 1292 private final AssetManager.AssetInputStream mAssetInputStream; 1293 private final boolean mIsInputStream; 1294 private int mMimeType; 1295 private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length]; 1296 private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN; 1297 private boolean mHasThumbnail; 1298 // The following values used for indicating a thumbnail position. 1299 private int mThumbnailOffset; 1300 private int mThumbnailLength; 1301 private byte[] mThumbnailBytes; 1302 private int mThumbnailCompression; 1303 private int mExifOffset; 1304 private int mOrfMakerNoteOffset; 1305 private int mOrfThumbnailOffset; 1306 private int mOrfThumbnailLength; 1307 private int mRw2JpgFromRawOffset; 1308 1309 // Pattern to check non zero timestamp 1310 private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*"); 1311 // Pattern to check gps timestamp 1312 private static final Pattern sGpsTimestampPattern = 1313 Pattern.compile("^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$"); 1314 1315 /** 1316 * Reads Exif tags from the specified image file. 1317 */ 1318 public ExifInterface(String filename) throws IOException { 1319 if (filename == null) { 1320 throw new IllegalArgumentException("filename cannot be null"); 1321 } 1322 FileInputStream in = null; 1323 mAssetInputStream = null; 1324 mFilename = filename; 1325 mIsInputStream = false; 1326 try { 1327 in = new FileInputStream(filename); 1328 if (isSeekableFD(in.getFD())) { 1329 mSeekableFileDescriptor = in.getFD(); 1330 } else { 1331 mSeekableFileDescriptor = null; 1332 } 1333 loadAttributes(in); 1334 } finally { 1335 IoUtils.closeQuietly(in); 1336 } 1337 } 1338 1339 /** 1340 * Reads Exif tags from the specified image file descriptor. Attribute mutation is supported 1341 * for writable and seekable file descriptors only. This constructor will not rewind the offset 1342 * of the given file descriptor. Developers should close the file descriptor after use. 1343 */ 1344 public ExifInterface(FileDescriptor fileDescriptor) throws IOException { 1345 if (fileDescriptor == null) { 1346 throw new IllegalArgumentException("fileDescriptor cannot be null"); 1347 } 1348 mAssetInputStream = null; 1349 mFilename = null; 1350 if (isSeekableFD(fileDescriptor)) { 1351 mSeekableFileDescriptor = fileDescriptor; 1352 // Keep the original file descriptor in order to save attributes when it's seekable. 1353 // Otherwise, just close the given file descriptor after reading it because the save 1354 // feature won't be working. 1355 try { 1356 fileDescriptor = Os.dup(fileDescriptor); 1357 } catch (ErrnoException e) { 1358 throw e.rethrowAsIOException(); 1359 } 1360 } else { 1361 mSeekableFileDescriptor = null; 1362 } 1363 mIsInputStream = false; 1364 FileInputStream in = null; 1365 try { 1366 in = new FileInputStream(fileDescriptor); 1367 loadAttributes(in); 1368 } finally { 1369 IoUtils.closeQuietly(in); 1370 } 1371 } 1372 1373 /** 1374 * Reads Exif tags from the specified image input stream. Attribute mutation is not supported 1375 * for input streams. The given input stream will proceed its current position. Developers 1376 * should close the input stream after use. 1377 */ 1378 public ExifInterface(InputStream inputStream) throws IOException { 1379 if (inputStream == null) { 1380 throw new IllegalArgumentException("inputStream cannot be null"); 1381 } 1382 mFilename = null; 1383 if (inputStream instanceof AssetManager.AssetInputStream) { 1384 mAssetInputStream = (AssetManager.AssetInputStream) inputStream; 1385 mSeekableFileDescriptor = null; 1386 } else if (inputStream instanceof FileInputStream 1387 && isSeekableFD(((FileInputStream) inputStream).getFD())) { 1388 mAssetInputStream = null; 1389 mSeekableFileDescriptor = ((FileInputStream) inputStream).getFD(); 1390 } else { 1391 mAssetInputStream = null; 1392 mSeekableFileDescriptor = null; 1393 } 1394 mIsInputStream = true; 1395 loadAttributes(inputStream); 1396 } 1397 1398 /** 1399 * Returns the EXIF attribute of the specified tag or {@code null} if there is no such tag in 1400 * the image file. 1401 * 1402 * @param tag the name of the tag. 1403 */ 1404 private ExifAttribute getExifAttribute(String tag) { 1405 // Retrieves all tag groups. The value from primary image tag group has a higher priority 1406 // than the value from the thumbnail tag group if there are more than one candidates. 1407 for (int i = 0; i < EXIF_TAGS.length; ++i) { 1408 Object value = mAttributes[i].get(tag); 1409 if (value != null) { 1410 return (ExifAttribute) value; 1411 } 1412 } 1413 return null; 1414 } 1415 1416 /** 1417 * Returns the value of the specified tag or {@code null} if there 1418 * is no such tag in the image file. 1419 * 1420 * @param tag the name of the tag. 1421 */ 1422 public String getAttribute(String tag) { 1423 ExifAttribute attribute = getExifAttribute(tag); 1424 if (attribute != null) { 1425 if (!sTagSetForCompatibility.contains(tag)) { 1426 return attribute.getStringValue(mExifByteOrder); 1427 } 1428 if (tag.equals(TAG_GPS_TIMESTAMP)) { 1429 // Convert the rational values to the custom formats for backwards compatibility. 1430 if (attribute.format != IFD_FORMAT_URATIONAL 1431 && attribute.format != IFD_FORMAT_SRATIONAL) { 1432 return null; 1433 } 1434 Rational[] array = (Rational[]) attribute.getValue(mExifByteOrder); 1435 if (array.length != 3) { 1436 return null; 1437 } 1438 return String.format("%02d:%02d:%02d", 1439 (int) ((float) array[0].numerator / array[0].denominator), 1440 (int) ((float) array[1].numerator / array[1].denominator), 1441 (int) ((float) array[2].numerator / array[2].denominator)); 1442 } 1443 try { 1444 return Double.toString(attribute.getDoubleValue(mExifByteOrder)); 1445 } catch (NumberFormatException e) { 1446 return null; 1447 } 1448 } 1449 return null; 1450 } 1451 1452 /** 1453 * Returns the integer value of the specified tag. If there is no such tag 1454 * in the image file or the value cannot be parsed as integer, return 1455 * <var>defaultValue</var>. 1456 * 1457 * @param tag the name of the tag. 1458 * @param defaultValue the value to return if the tag is not available. 1459 */ 1460 public int getAttributeInt(String tag, int defaultValue) { 1461 ExifAttribute exifAttribute = getExifAttribute(tag); 1462 if (exifAttribute == null) { 1463 return defaultValue; 1464 } 1465 1466 try { 1467 return exifAttribute.getIntValue(mExifByteOrder); 1468 } catch (NumberFormatException e) { 1469 return defaultValue; 1470 } 1471 } 1472 1473 /** 1474 * Returns the double value of the tag that is specified as rational or contains a 1475 * double-formatted value. If there is no such tag in the image file or the value cannot be 1476 * parsed as double, return <var>defaultValue</var>. 1477 * 1478 * @param tag the name of the tag. 1479 * @param defaultValue the value to return if the tag is not available. 1480 */ 1481 public double getAttributeDouble(String tag, double defaultValue) { 1482 ExifAttribute exifAttribute = getExifAttribute(tag); 1483 if (exifAttribute == null) { 1484 return defaultValue; 1485 } 1486 1487 try { 1488 return exifAttribute.getDoubleValue(mExifByteOrder); 1489 } catch (NumberFormatException e) { 1490 return defaultValue; 1491 } 1492 } 1493 1494 /** 1495 * Set the value of the specified tag. 1496 * 1497 * @param tag the name of the tag. 1498 * @param value the value of the tag. 1499 */ 1500 public void setAttribute(String tag, String value) { 1501 // Convert the given value to rational values for backwards compatibility. 1502 if (value != null && sTagSetForCompatibility.contains(tag)) { 1503 if (tag.equals(TAG_GPS_TIMESTAMP)) { 1504 Matcher m = sGpsTimestampPattern.matcher(value); 1505 if (!m.find()) { 1506 Log.w(TAG, "Invalid value for " + tag + " : " + value); 1507 return; 1508 } 1509 value = Integer.parseInt(m.group(1)) + "/1," + Integer.parseInt(m.group(2)) + "/1," 1510 + Integer.parseInt(m.group(3)) + "/1"; 1511 } else { 1512 try { 1513 double doubleValue = Double.parseDouble(value); 1514 value = (long) (doubleValue * 10000L) + "/10000"; 1515 } catch (NumberFormatException e) { 1516 Log.w(TAG, "Invalid value for " + tag + " : " + value); 1517 return; 1518 } 1519 } 1520 } 1521 1522 for (int i = 0 ; i < EXIF_TAGS.length; ++i) { 1523 if (i == IFD_TYPE_THUMBNAIL && !mHasThumbnail) { 1524 continue; 1525 } 1526 final Object obj = sExifTagMapsForWriting[i].get(tag); 1527 if (obj != null) { 1528 if (value == null) { 1529 mAttributes[i].remove(tag); 1530 continue; 1531 } 1532 final ExifTag exifTag = (ExifTag) obj; 1533 Pair<Integer, Integer> guess = guessDataFormat(value); 1534 int dataFormat; 1535 if (exifTag.primaryFormat == guess.first || exifTag.primaryFormat == guess.second) { 1536 dataFormat = exifTag.primaryFormat; 1537 } else if (exifTag.secondaryFormat != -1 && (exifTag.secondaryFormat == guess.first 1538 || exifTag.secondaryFormat == guess.second)) { 1539 dataFormat = exifTag.secondaryFormat; 1540 } else if (exifTag.primaryFormat == IFD_FORMAT_BYTE 1541 || exifTag.primaryFormat == IFD_FORMAT_UNDEFINED 1542 || exifTag.primaryFormat == IFD_FORMAT_STRING) { 1543 dataFormat = exifTag.primaryFormat; 1544 } else { 1545 Log.w(TAG, "Given tag (" + tag + ") value didn't match with one of expected " 1546 + "formats: " + IFD_FORMAT_NAMES[exifTag.primaryFormat] 1547 + (exifTag.secondaryFormat == -1 ? "" : ", " 1548 + IFD_FORMAT_NAMES[exifTag.secondaryFormat]) + " (guess: " 1549 + IFD_FORMAT_NAMES[guess.first] + (guess.second == -1 ? "" : ", " 1550 + IFD_FORMAT_NAMES[guess.second]) + ")"); 1551 continue; 1552 } 1553 switch (dataFormat) { 1554 case IFD_FORMAT_BYTE: { 1555 mAttributes[i].put(tag, ExifAttribute.createByte(value)); 1556 break; 1557 } 1558 case IFD_FORMAT_UNDEFINED: 1559 case IFD_FORMAT_STRING: { 1560 mAttributes[i].put(tag, ExifAttribute.createString(value)); 1561 break; 1562 } 1563 case IFD_FORMAT_USHORT: { 1564 final String[] values = value.split(","); 1565 final int[] intArray = new int[values.length]; 1566 for (int j = 0; j < values.length; ++j) { 1567 intArray[j] = Integer.parseInt(values[j]); 1568 } 1569 mAttributes[i].put(tag, 1570 ExifAttribute.createUShort(intArray, mExifByteOrder)); 1571 break; 1572 } 1573 case IFD_FORMAT_SLONG: { 1574 final String[] values = value.split(","); 1575 final int[] intArray = new int[values.length]; 1576 for (int j = 0; j < values.length; ++j) { 1577 intArray[j] = Integer.parseInt(values[j]); 1578 } 1579 mAttributes[i].put(tag, 1580 ExifAttribute.createSLong(intArray, mExifByteOrder)); 1581 break; 1582 } 1583 case IFD_FORMAT_ULONG: { 1584 final String[] values = value.split(","); 1585 final long[] longArray = new long[values.length]; 1586 for (int j = 0; j < values.length; ++j) { 1587 longArray[j] = Long.parseLong(values[j]); 1588 } 1589 mAttributes[i].put(tag, 1590 ExifAttribute.createULong(longArray, mExifByteOrder)); 1591 break; 1592 } 1593 case IFD_FORMAT_URATIONAL: { 1594 final String[] values = value.split(","); 1595 final Rational[] rationalArray = new Rational[values.length]; 1596 for (int j = 0; j < values.length; ++j) { 1597 final String[] numbers = values[j].split("/"); 1598 rationalArray[j] = new Rational(Long.parseLong(numbers[0]), 1599 Long.parseLong(numbers[1])); 1600 } 1601 mAttributes[i].put(tag, 1602 ExifAttribute.createURational(rationalArray, mExifByteOrder)); 1603 break; 1604 } 1605 case IFD_FORMAT_SRATIONAL: { 1606 final String[] values = value.split(","); 1607 final Rational[] rationalArray = new Rational[values.length]; 1608 for (int j = 0; j < values.length; ++j) { 1609 final String[] numbers = values[j].split("/"); 1610 rationalArray[j] = new Rational(Long.parseLong(numbers[0]), 1611 Long.parseLong(numbers[1])); 1612 } 1613 mAttributes[i].put(tag, 1614 ExifAttribute.createSRational(rationalArray, mExifByteOrder)); 1615 break; 1616 } 1617 case IFD_FORMAT_DOUBLE: { 1618 final String[] values = value.split(","); 1619 final double[] doubleArray = new double[values.length]; 1620 for (int j = 0; j < values.length; ++j) { 1621 doubleArray[j] = Double.parseDouble(values[j]); 1622 } 1623 mAttributes[i].put(tag, 1624 ExifAttribute.createDouble(doubleArray, mExifByteOrder)); 1625 break; 1626 } 1627 default: 1628 Log.w(TAG, "Data format isn't one of expected formats: " + dataFormat); 1629 continue; 1630 } 1631 } 1632 } 1633 } 1634 1635 /** 1636 * Update the values of the tags in the tag groups if any value for the tag already was stored. 1637 * 1638 * @param tag the name of the tag. 1639 * @param value the value of the tag in a form of {@link ExifAttribute}. 1640 * @return Returns {@code true} if updating is placed. 1641 */ 1642 private boolean updateAttribute(String tag, ExifAttribute value) { 1643 boolean updated = false; 1644 for (int i = 0 ; i < EXIF_TAGS.length; ++i) { 1645 if (mAttributes[i].containsKey(tag)) { 1646 mAttributes[i].put(tag, value); 1647 updated = true; 1648 } 1649 } 1650 return updated; 1651 } 1652 1653 /** 1654 * Remove any values of the specified tag. 1655 * 1656 * @param tag the name of the tag. 1657 */ 1658 private void removeAttribute(String tag) { 1659 for (int i = 0 ; i < EXIF_TAGS.length; ++i) { 1660 mAttributes[i].remove(tag); 1661 } 1662 } 1663 1664 /** 1665 * This function decides which parser to read the image data according to the given input stream 1666 * type and the content of the input stream. In each case, it reads the first three bytes to 1667 * determine whether the image data format is JPEG or not. 1668 */ 1669 private void loadAttributes(@NonNull InputStream in) throws IOException { 1670 try { 1671 // Initialize mAttributes. 1672 for (int i = 0; i < EXIF_TAGS.length; ++i) { 1673 mAttributes[i] = new HashMap(); 1674 } 1675 1676 // Check file type 1677 in = new BufferedInputStream(in, SIGNATURE_CHECK_SIZE); 1678 mMimeType = getMimeType((BufferedInputStream) in); 1679 1680 switch (mMimeType) { 1681 case IMAGE_TYPE_JPEG: { 1682 getJpegAttributes(in, 0, IFD_TYPE_PRIMARY); // 0 is offset 1683 break; 1684 } 1685 case IMAGE_TYPE_RAF: { 1686 getRafAttributes(in); 1687 break; 1688 } 1689 case IMAGE_TYPE_ORF: { 1690 getOrfAttributes(in); 1691 break; 1692 } 1693 case IMAGE_TYPE_RW2: { 1694 getRw2Attributes(in); 1695 break; 1696 } 1697 case IMAGE_TYPE_ARW: 1698 case IMAGE_TYPE_CR2: 1699 case IMAGE_TYPE_DNG: 1700 case IMAGE_TYPE_NEF: 1701 case IMAGE_TYPE_NRW: 1702 case IMAGE_TYPE_PEF: 1703 case IMAGE_TYPE_SRW: 1704 case IMAGE_TYPE_UNKNOWN: { 1705 getRawAttributes(in); 1706 break; 1707 } 1708 default: { 1709 break; 1710 } 1711 } 1712 // Set thumbnail image offset and length 1713 setThumbnailData(in); 1714 } catch (IOException e) { 1715 // Ignore exceptions in order to keep the compatibility with the old versions of 1716 // ExifInterface. 1717 if (DEBUG) { 1718 Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file" 1719 + "(ExifInterface supports JPEG and some RAW image formats only) " 1720 + "or a corrupted JPEG file to ExifInterface.", e); 1721 } 1722 } finally { 1723 addDefaultValuesForCompatibility(); 1724 1725 if (DEBUG) { 1726 printAttributes(); 1727 } 1728 } 1729 } 1730 1731 private static boolean isSeekableFD(FileDescriptor fd) throws IOException { 1732 try { 1733 Os.lseek(fd, 0, OsConstants.SEEK_CUR); 1734 return true; 1735 } catch (ErrnoException e) { 1736 return false; 1737 } 1738 } 1739 1740 // Prints out attributes for debugging. 1741 private void printAttributes() { 1742 for (int i = 0; i < mAttributes.length; ++i) { 1743 Log.d(TAG, "The size of tag group[" + i + "]: " + mAttributes[i].size()); 1744 for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) { 1745 final ExifAttribute tagValue = (ExifAttribute) entry.getValue(); 1746 Log.d(TAG, "tagName: " + entry.getKey() + ", tagType: " + tagValue.toString() 1747 + ", tagValue: '" + tagValue.getStringValue(mExifByteOrder) + "'"); 1748 } 1749 } 1750 } 1751 1752 /** 1753 * Save the tag data into the original image file. This is expensive because it involves 1754 * copying all the data from one file to another and deleting the old file and renaming the 1755 * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write 1756 * and make a single call rather than multiple calls for each attribute. 1757 */ 1758 public void saveAttributes() throws IOException { 1759 if (mMimeType != IMAGE_TYPE_JPEG) { 1760 throw new UnsupportedOperationException( 1761 "ExifInterface only supports saving attributes on JPEG formats."); 1762 } 1763 if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) { 1764 throw new UnsupportedOperationException( 1765 "ExifInterface does not support saving attributes for the current input."); 1766 } 1767 1768 // Keep the thumbnail in memory 1769 mThumbnailBytes = getThumbnail(); 1770 1771 FileInputStream in = null; 1772 FileOutputStream out = null; 1773 File tempFile = null; 1774 try { 1775 // Move the original file to temporary file. 1776 if (mFilename != null) { 1777 tempFile = new File(mFilename + ".tmp"); 1778 File originalFile = new File(mFilename); 1779 if (!originalFile.renameTo(tempFile)) { 1780 throw new IOException("Could'nt rename to " + tempFile.getAbsolutePath()); 1781 } 1782 } else if (mSeekableFileDescriptor != null) { 1783 tempFile = File.createTempFile("temp", "jpg"); 1784 Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET); 1785 in = new FileInputStream(mSeekableFileDescriptor); 1786 out = new FileOutputStream(tempFile); 1787 Streams.copy(in, out); 1788 } 1789 } catch (ErrnoException e) { 1790 throw e.rethrowAsIOException(); 1791 } finally { 1792 IoUtils.closeQuietly(in); 1793 IoUtils.closeQuietly(out); 1794 } 1795 1796 in = null; 1797 out = null; 1798 try { 1799 // Save the new file. 1800 in = new FileInputStream(tempFile); 1801 if (mFilename != null) { 1802 out = new FileOutputStream(mFilename); 1803 } else if (mSeekableFileDescriptor != null) { 1804 Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET); 1805 out = new FileOutputStream(mSeekableFileDescriptor); 1806 } 1807 saveJpegAttributes(in, out); 1808 } catch (ErrnoException e) { 1809 throw e.rethrowAsIOException(); 1810 } finally { 1811 IoUtils.closeQuietly(in); 1812 IoUtils.closeQuietly(out); 1813 tempFile.delete(); 1814 } 1815 1816 // Discard the thumbnail in memory 1817 mThumbnailBytes = null; 1818 } 1819 1820 /** 1821 * Returns true if the image file has a thumbnail. 1822 */ 1823 public boolean hasThumbnail() { 1824 return mHasThumbnail; 1825 } 1826 1827 /** 1828 * Returns the JPEG compressed thumbnail inside the image file, or {@code null} if there is no 1829 * JPEG compressed thumbnail. 1830 * The returned data can be decoded using 1831 * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)} 1832 */ 1833 public byte[] getThumbnail() { 1834 if (mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED) { 1835 return getThumbnailBytes(); 1836 } 1837 return null; 1838 } 1839 1840 /** 1841 * Returns the thumbnail bytes inside the image file, regardless of the compression type of the 1842 * thumbnail image. 1843 */ 1844 public byte[] getThumbnailBytes() { 1845 if (!mHasThumbnail) { 1846 return null; 1847 } 1848 if (mThumbnailBytes != null) { 1849 return mThumbnailBytes; 1850 } 1851 1852 // Read the thumbnail. 1853 InputStream in = null; 1854 try { 1855 if (mAssetInputStream != null) { 1856 in = mAssetInputStream; 1857 if (in.markSupported()) { 1858 in.reset(); 1859 } else { 1860 Log.d(TAG, "Cannot read thumbnail from inputstream without mark/reset support"); 1861 return null; 1862 } 1863 } else if (mFilename != null) { 1864 in = new FileInputStream(mFilename); 1865 } else if (mSeekableFileDescriptor != null) { 1866 FileDescriptor fileDescriptor = Os.dup(mSeekableFileDescriptor); 1867 Os.lseek(fileDescriptor, 0, OsConstants.SEEK_SET); 1868 in = new FileInputStream(fileDescriptor); 1869 } 1870 if (in == null) { 1871 // Should not be reached this. 1872 throw new FileNotFoundException(); 1873 } 1874 if (in.skip(mThumbnailOffset) != mThumbnailOffset) { 1875 throw new IOException("Corrupted image"); 1876 } 1877 byte[] buffer = new byte[mThumbnailLength]; 1878 if (in.read(buffer) != mThumbnailLength) { 1879 throw new IOException("Corrupted image"); 1880 } 1881 mThumbnailBytes = buffer; 1882 return buffer; 1883 } catch (IOException | ErrnoException e) { 1884 // Couldn't get a thumbnail image. 1885 Log.d(TAG, "Encountered exception while getting thumbnail", e); 1886 } finally { 1887 IoUtils.closeQuietly(in); 1888 } 1889 return null; 1890 } 1891 1892 /** 1893 * Creates and returns a Bitmap object of the thumbnail image based on the byte array and the 1894 * thumbnail compression value, or {@code null} if the compression type is unsupported. 1895 */ 1896 public Bitmap getThumbnailBitmap() { 1897 if (!mHasThumbnail) { 1898 return null; 1899 } else if (mThumbnailBytes == null) { 1900 mThumbnailBytes = getThumbnailBytes(); 1901 } 1902 1903 if (mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED) { 1904 return BitmapFactory.decodeByteArray(mThumbnailBytes, 0, mThumbnailLength); 1905 } else if (mThumbnailCompression == DATA_UNCOMPRESSED) { 1906 int[] rgbValues = new int[mThumbnailBytes.length / 3]; 1907 byte alpha = (byte) 0xff000000; 1908 for (int i = 0; i < rgbValues.length; i++) { 1909 rgbValues[i] = alpha + (mThumbnailBytes[3 * i] << 16) 1910 + (mThumbnailBytes[3 * i + 1] << 8) + mThumbnailBytes[3 * i + 2]; 1911 } 1912 1913 ExifAttribute imageLengthAttribute = 1914 (ExifAttribute) mAttributes[IFD_TYPE_THUMBNAIL].get(TAG_IMAGE_LENGTH); 1915 ExifAttribute imageWidthAttribute = 1916 (ExifAttribute) mAttributes[IFD_TYPE_THUMBNAIL].get(TAG_IMAGE_WIDTH); 1917 if (imageLengthAttribute != null && imageWidthAttribute != null) { 1918 int imageLength = imageLengthAttribute.getIntValue(mExifByteOrder); 1919 int imageWidth = imageWidthAttribute.getIntValue(mExifByteOrder); 1920 return Bitmap.createBitmap( 1921 rgbValues, imageWidth, imageLength, Bitmap.Config.ARGB_8888); 1922 } 1923 } 1924 return null; 1925 } 1926 1927 /** 1928 * Returns true if thumbnail image is JPEG Compressed, or false if either thumbnail image does 1929 * not exist or thumbnail image is uncompressed. 1930 */ 1931 public boolean isThumbnailCompressed() { 1932 if (mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED) { 1933 return true; 1934 } 1935 return false; 1936 } 1937 1938 /** 1939 * Returns the offset and length of thumbnail inside the image file, or 1940 * {@code null} if there is no thumbnail. 1941 * 1942 * @return two-element array, the offset in the first value, and length in 1943 * the second, or {@code null} if no thumbnail was found. 1944 */ 1945 public long[] getThumbnailRange() { 1946 if (!mHasThumbnail) { 1947 return null; 1948 } 1949 1950 long[] range = new long[2]; 1951 range[0] = mThumbnailOffset; 1952 range[1] = mThumbnailLength; 1953 1954 return range; 1955 } 1956 1957 /** 1958 * Stores the latitude and longitude value in a float array. The first element is 1959 * the latitude, and the second element is the longitude. Returns false if the 1960 * Exif tags are not available. 1961 */ 1962 public boolean getLatLong(float output[]) { 1963 String latValue = getAttribute(TAG_GPS_LATITUDE); 1964 String latRef = getAttribute(TAG_GPS_LATITUDE_REF); 1965 String lngValue = getAttribute(TAG_GPS_LONGITUDE); 1966 String lngRef = getAttribute(TAG_GPS_LONGITUDE_REF); 1967 1968 if (latValue != null && latRef != null && lngValue != null && lngRef != null) { 1969 try { 1970 output[0] = convertRationalLatLonToFloat(latValue, latRef); 1971 output[1] = convertRationalLatLonToFloat(lngValue, lngRef); 1972 return true; 1973 } catch (IllegalArgumentException e) { 1974 // if values are not parseable 1975 } 1976 } 1977 1978 return false; 1979 } 1980 1981 /** 1982 * Return the altitude in meters. If the exif tag does not exist, return 1983 * <var>defaultValue</var>. 1984 * 1985 * @param defaultValue the value to return if the tag is not available. 1986 */ 1987 public double getAltitude(double defaultValue) { 1988 double altitude = getAttributeDouble(TAG_GPS_ALTITUDE, -1); 1989 int ref = getAttributeInt(TAG_GPS_ALTITUDE_REF, -1); 1990 1991 if (altitude >= 0 && ref >= 0) { 1992 return (altitude * ((ref == 1) ? -1 : 1)); 1993 } else { 1994 return defaultValue; 1995 } 1996 } 1997 1998 /** 1999 * Returns number of milliseconds since Jan. 1, 1970, midnight local time. 2000 * Returns -1 if the date time information if not available. 2001 * @hide 2002 */ 2003 public long getDateTime() { 2004 String dateTimeString = getAttribute(TAG_DATETIME); 2005 if (dateTimeString == null 2006 || !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1; 2007 2008 ParsePosition pos = new ParsePosition(0); 2009 try { 2010 // The exif field is in local time. Parsing it as if it is UTC will yield time 2011 // since 1/1/1970 local time 2012 Date datetime = sFormatter.parse(dateTimeString, pos); 2013 if (datetime == null) return -1; 2014 long msecs = datetime.getTime(); 2015 2016 String subSecs = getAttribute(TAG_SUBSEC_TIME); 2017 if (subSecs != null) { 2018 try { 2019 long sub = Long.parseLong(subSecs); 2020 while (sub > 1000) { 2021 sub /= 10; 2022 } 2023 msecs += sub; 2024 } catch (NumberFormatException e) { 2025 // Ignored 2026 } 2027 } 2028 return msecs; 2029 } catch (IllegalArgumentException e) { 2030 return -1; 2031 } 2032 } 2033 2034 /** 2035 * Returns number of milliseconds since Jan. 1, 1970, midnight UTC. 2036 * Returns -1 if the date time information if not available. 2037 * @hide 2038 */ 2039 public long getGpsDateTime() { 2040 String date = getAttribute(TAG_GPS_DATESTAMP); 2041 String time = getAttribute(TAG_GPS_TIMESTAMP); 2042 if (date == null || time == null 2043 || (!sNonZeroTimePattern.matcher(date).matches() 2044 && !sNonZeroTimePattern.matcher(time).matches())) { 2045 return -1; 2046 } 2047 2048 String dateTimeString = date + ' ' + time; 2049 2050 ParsePosition pos = new ParsePosition(0); 2051 try { 2052 Date datetime = sFormatter.parse(dateTimeString, pos); 2053 if (datetime == null) return -1; 2054 return datetime.getTime(); 2055 } catch (IllegalArgumentException e) { 2056 return -1; 2057 } 2058 } 2059 2060 private static float convertRationalLatLonToFloat(String rationalString, String ref) { 2061 try { 2062 String [] parts = rationalString.split(","); 2063 2064 String [] pair; 2065 pair = parts[0].split("/"); 2066 double degrees = Double.parseDouble(pair[0].trim()) 2067 / Double.parseDouble(pair[1].trim()); 2068 2069 pair = parts[1].split("/"); 2070 double minutes = Double.parseDouble(pair[0].trim()) 2071 / Double.parseDouble(pair[1].trim()); 2072 2073 pair = parts[2].split("/"); 2074 double seconds = Double.parseDouble(pair[0].trim()) 2075 / Double.parseDouble(pair[1].trim()); 2076 2077 double result = degrees + (minutes / 60.0) + (seconds / 3600.0); 2078 if ((ref.equals("S") || ref.equals("W"))) { 2079 return (float) -result; 2080 } 2081 return (float) result; 2082 } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { 2083 // Not valid 2084 throw new IllegalArgumentException(); 2085 } 2086 } 2087 2088 // Checks the type of image file 2089 private int getMimeType(BufferedInputStream in) throws IOException { 2090 in.mark(SIGNATURE_CHECK_SIZE); 2091 byte[] signatureCheckBytes = new byte[SIGNATURE_CHECK_SIZE]; 2092 if (in.read(signatureCheckBytes) != SIGNATURE_CHECK_SIZE) { 2093 throw new EOFException(); 2094 } 2095 in.reset(); 2096 if (isJpegFormat(signatureCheckBytes)) { 2097 return IMAGE_TYPE_JPEG; 2098 } else if (isRafFormat(signatureCheckBytes)) { 2099 return IMAGE_TYPE_RAF; 2100 } else if (isOrfFormat(signatureCheckBytes)) { 2101 return IMAGE_TYPE_ORF; 2102 } else if (isRw2Format(signatureCheckBytes)) { 2103 return IMAGE_TYPE_RW2; 2104 } 2105 // Certain file formats (PEF) are identified in readImageFileDirectory() 2106 return IMAGE_TYPE_UNKNOWN; 2107 } 2108 2109 /** 2110 * This method looks at the first 3 bytes to determine if this file is a JPEG file. 2111 * See http://www.media.mit.edu/pia/Research/deepview/exif.html, "JPEG format and Marker" 2112 */ 2113 private static boolean isJpegFormat(byte[] signatureCheckBytes) throws IOException { 2114 for (int i = 0; i < JPEG_SIGNATURE.length; i++) { 2115 if (signatureCheckBytes[i] != JPEG_SIGNATURE[i]) { 2116 return false; 2117 } 2118 } 2119 return true; 2120 } 2121 2122 /** 2123 * This method looks at the first 15 bytes to determine if this file is a RAF file. 2124 * There is no official specification for RAF files from Fuji, but there is an online archive of 2125 * image file specifications: 2126 * http://fileformats.archiveteam.org/wiki/Fujifilm_RAF 2127 */ 2128 private boolean isRafFormat(byte[] signatureCheckBytes) throws IOException { 2129 byte[] rafSignatureBytes = RAF_SIGNATURE.getBytes(); 2130 for (int i = 0; i < rafSignatureBytes.length; i++) { 2131 if (signatureCheckBytes[i] != rafSignatureBytes[i]) { 2132 return false; 2133 } 2134 } 2135 return true; 2136 } 2137 2138 /** 2139 * ORF has a similar structure to TIFF but it contains a different signature at the TIFF Header. 2140 * This method looks at the 2 bytes following the Byte Order bytes to determine if this file is 2141 * an ORF file. 2142 * There is no official specification for ORF files from Olympus, but there is an online archive 2143 * of image file specifications: 2144 * http://fileformats.archiveteam.org/wiki/Olympus_ORF 2145 */ 2146 private boolean isOrfFormat(byte[] signatureCheckBytes) throws IOException { 2147 ByteOrderAwarenessDataInputStream signatureInputStream = 2148 new ByteOrderAwarenessDataInputStream(signatureCheckBytes); 2149 // Read byte order 2150 mExifByteOrder = readByteOrder(signatureInputStream); 2151 // Set byte order 2152 signatureInputStream.setByteOrder(mExifByteOrder); 2153 2154 short orfSignature = signatureInputStream.readShort(); 2155 if (orfSignature == ORF_SIGNATURE_1 || orfSignature == ORF_SIGNATURE_2) { 2156 return true; 2157 } 2158 return false; 2159 } 2160 2161 /** 2162 * RW2 is TIFF-based, but stores 0x55 signature byte instead of 0x42 at the header 2163 * See http://lclevy.free.fr/raw/ 2164 */ 2165 private boolean isRw2Format(byte[] signatureCheckBytes) throws IOException { 2166 ByteOrderAwarenessDataInputStream signatureInputStream = 2167 new ByteOrderAwarenessDataInputStream(signatureCheckBytes); 2168 // Read byte order 2169 mExifByteOrder = readByteOrder(signatureInputStream); 2170 // Set byte order 2171 signatureInputStream.setByteOrder(mExifByteOrder); 2172 2173 short signatureByte = signatureInputStream.readShort(); 2174 if (signatureByte == RW2_SIGNATURE) { 2175 return true; 2176 } 2177 return false; 2178 } 2179 2180 /** 2181 * Loads EXIF attributes from a JPEG input stream. 2182 * 2183 * @param inputStream The input stream that starts with the JPEG data. 2184 * @param jpegOffset The offset value in input stream for JPEG data. 2185 * @param imageTypes The image type from which to retrieve metadata. Use IFD_TYPE_PRIMARY for 2186 * primary image, IFD_TYPE_PREVIEW for preview image, and 2187 * IFD_TYPE_THUMBNAIL for thumbnail image. 2188 * @throws IOException If the data contains invalid JPEG markers, offsets, or length values. 2189 */ 2190 private void getJpegAttributes(InputStream inputStream, int jpegOffset, int imageType) 2191 throws IOException { 2192 // See JPEG File Interchange Format Specification, "JFIF Specification" 2193 if (DEBUG) { 2194 Log.d(TAG, "getJpegAttributes starting with: " + inputStream); 2195 } 2196 2197 DataInputStream dataInputStream = new DataInputStream(inputStream); 2198 // Mark current position to reset after retrieving data 2199 dataInputStream.mark(dataInputStream.available()); 2200 2201 // Skip to JPEG data 2202 if (dataInputStream.skip(jpegOffset) != jpegOffset) { 2203 throw new IOException("Invalid JPEG offset"); 2204 } 2205 int bytesRead = jpegOffset; 2206 2207 byte marker; 2208 if ((marker = dataInputStream.readByte()) != MARKER) { 2209 throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff)); 2210 } 2211 ++bytesRead; 2212 if (dataInputStream.readByte() != MARKER_SOI) { 2213 throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff)); 2214 } 2215 ++bytesRead; 2216 while (true) { 2217 marker = dataInputStream.readByte(); 2218 if (marker != MARKER) { 2219 throw new IOException("Invalid marker:" + Integer.toHexString(marker & 0xff)); 2220 } 2221 ++bytesRead; 2222 marker = dataInputStream.readByte(); 2223 if (DEBUG) { 2224 Log.d(TAG, "Found JPEG segment indicator: " + Integer.toHexString(marker & 0xff)); 2225 } 2226 ++bytesRead; 2227 2228 // EOI indicates the end of an image and in case of SOS, JPEG image stream starts and 2229 // the image data will terminate right after. 2230 if (marker == MARKER_EOI || marker == MARKER_SOS) { 2231 break; 2232 } 2233 int length = dataInputStream.readUnsignedShort() - 2; 2234 bytesRead += 2; 2235 if (DEBUG) { 2236 Log.d(TAG, "JPEG segment: " + Integer.toHexString(marker & 0xff) + " (length: " 2237 + (length + 2) + ")"); 2238 } 2239 if (length < 0) { 2240 throw new IOException("Invalid length"); 2241 } 2242 switch (marker) { 2243 case MARKER_APP1: { 2244 if (DEBUG) { 2245 Log.d(TAG, "MARKER_APP1"); 2246 } 2247 if (length < 6) { 2248 // Skip if it's not an EXIF APP1 segment. 2249 break; 2250 } 2251 byte[] identifier = new byte[6]; 2252 if (inputStream.read(identifier) != 6) { 2253 throw new IOException("Invalid exif"); 2254 } 2255 bytesRead += 6; 2256 length -= 6; 2257 if (!Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) { 2258 // Skip if it's not an EXIF APP1 segment. 2259 break; 2260 } 2261 if (length <= 0) { 2262 throw new IOException("Invalid exif"); 2263 } 2264 if (DEBUG) { 2265 Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")"); 2266 } 2267 // Save offset values for createJpegThumbnailBitmap() function 2268 mExifOffset = bytesRead; 2269 2270 byte[] bytes = new byte[length]; 2271 if (dataInputStream.read(bytes) != length) { 2272 throw new IOException("Invalid exif"); 2273 } 2274 bytesRead += length; 2275 length = 0; 2276 2277 readExifSegment(bytes, imageType); 2278 break; 2279 } 2280 2281 case MARKER_COM: { 2282 byte[] bytes = new byte[length]; 2283 if (dataInputStream.read(bytes) != length) { 2284 throw new IOException("Invalid exif"); 2285 } 2286 length = 0; 2287 if (getAttribute(TAG_USER_COMMENT) == null) { 2288 mAttributes[IFD_TYPE_EXIF].put(TAG_USER_COMMENT, ExifAttribute.createString( 2289 new String(bytes, ASCII))); 2290 } 2291 break; 2292 } 2293 2294 case MARKER_SOF0: 2295 case MARKER_SOF1: 2296 case MARKER_SOF2: 2297 case MARKER_SOF3: 2298 case MARKER_SOF5: 2299 case MARKER_SOF6: 2300 case MARKER_SOF7: 2301 case MARKER_SOF9: 2302 case MARKER_SOF10: 2303 case MARKER_SOF11: 2304 case MARKER_SOF13: 2305 case MARKER_SOF14: 2306 case MARKER_SOF15: { 2307 if (dataInputStream.skipBytes(1) != 1) { 2308 throw new IOException("Invalid SOFx"); 2309 } 2310 mAttributes[imageType].put(TAG_IMAGE_LENGTH, ExifAttribute.createULong( 2311 dataInputStream.readUnsignedShort(), mExifByteOrder)); 2312 mAttributes[imageType].put(TAG_IMAGE_WIDTH, ExifAttribute.createULong( 2313 dataInputStream.readUnsignedShort(), mExifByteOrder)); 2314 length -= 5; 2315 break; 2316 } 2317 2318 default: { 2319 break; 2320 } 2321 } 2322 if (length < 0) { 2323 throw new IOException("Invalid length"); 2324 } 2325 if (dataInputStream.skipBytes(length) != length) { 2326 throw new IOException("Invalid JPEG segment"); 2327 } 2328 bytesRead += length; 2329 } 2330 // Reset dataInputStream to marked position 2331 dataInputStream.reset(); 2332 } 2333 2334 private void getRawAttributes(InputStream in) throws IOException { 2335 int totalBytes = in.available(); 2336 byte[] exifBytes = new byte[totalBytes]; 2337 in.mark(in.available()); 2338 in.read(exifBytes); 2339 in.reset(); 2340 2341 ByteOrderAwarenessDataInputStream dataInputStream = 2342 new ByteOrderAwarenessDataInputStream(exifBytes); 2343 2344 // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1. 2345 parseTiffHeaders(dataInputStream, exifBytes.length); 2346 2347 // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6. 2348 readImageFileDirectory(dataInputStream, IFD_TYPE_PRIMARY); 2349 2350 // Update ImageLength/Width tags for all image data. 2351 updateImageSizeValues(in, IFD_TYPE_PRIMARY); 2352 updateImageSizeValues(in, IFD_TYPE_PREVIEW); 2353 updateImageSizeValues(in, IFD_TYPE_THUMBNAIL); 2354 2355 // Check if each image data is in valid position. 2356 validateImages(in); 2357 2358 if (mMimeType == IMAGE_TYPE_PEF) { 2359 // PEF files contain a MakerNote data, which contains the data for ColorSpace tag. 2360 // See http://lclevy.free.fr/raw/ and piex.cc PefGetPreviewData() 2361 ExifAttribute makerNoteAttribute = 2362 (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE); 2363 if (makerNoteAttribute != null) { 2364 // Create an ordered DataInputStream for MakerNote 2365 ByteOrderAwarenessDataInputStream makerNoteDataInputStream = 2366 new ByteOrderAwarenessDataInputStream(makerNoteAttribute.bytes); 2367 makerNoteDataInputStream.setByteOrder(mExifByteOrder); 2368 2369 // Seek to MakerNote data 2370 makerNoteDataInputStream.seek(PEF_MAKER_NOTE_SKIP_SIZE); 2371 2372 // Read IFD data from MakerNote 2373 readImageFileDirectory(makerNoteDataInputStream, IFD_TYPE_PEF); 2374 2375 // Update ColorSpace tag 2376 ExifAttribute colorSpaceAttribute = 2377 (ExifAttribute) mAttributes[IFD_TYPE_PEF].get(TAG_COLOR_SPACE); 2378 if (colorSpaceAttribute != null) { 2379 mAttributes[IFD_TYPE_EXIF].put(TAG_COLOR_SPACE, colorSpaceAttribute); 2380 } 2381 } 2382 } 2383 } 2384 2385 /** 2386 * RAF files contains a JPEG and a CFA data. 2387 * The JPEG contains two images, a preview and a thumbnail, while the CFA contains a RAW image. 2388 * This method looks at the first 160 bytes of a RAF file to retrieve the offset and length 2389 * values for the JPEG and CFA data. 2390 * Using that data, it parses the JPEG data to retrieve the preview and thumbnail image data, 2391 * then parses the CFA metadata to retrieve the primary image length/width values. 2392 * For data format details, see http://fileformats.archiveteam.org/wiki/Fujifilm_RAF 2393 */ 2394 private void getRafAttributes(InputStream in) throws IOException { 2395 // Retrieve offset & length values 2396 in.mark(RAF_INFO_SIZE); 2397 in.skip(RAF_OFFSET_TO_JPEG_IMAGE_OFFSET); 2398 byte[] jpegOffsetBytes = new byte[4]; 2399 byte[] cfaHeaderOffsetBytes = new byte[4]; 2400 byte[] cfaHeaderLengthBytes = new byte[4]; 2401 in.read(jpegOffsetBytes); 2402 // Skip JPEG length value since it is not needed 2403 in.skip(RAF_JPEG_LENGTH_VALUE_SIZE); 2404 in.read(cfaHeaderOffsetBytes); 2405 in.read(cfaHeaderLengthBytes); 2406 int rafJpegOffset = ByteBuffer.wrap(jpegOffsetBytes).getInt(); 2407 int rafCfaHeaderOffset = ByteBuffer.wrap(cfaHeaderOffsetBytes).getInt(); 2408 int rafCfaHeaderLength = ByteBuffer.wrap(cfaHeaderLengthBytes).getInt(); 2409 in.reset(); 2410 2411 // Retrieve JPEG image metadata 2412 getJpegAttributes(in, rafJpegOffset, IFD_TYPE_PREVIEW); 2413 2414 // Skip to CFA header offset. 2415 // A while loop is used because the skip method may not be able to skip the requested amount 2416 // at once because the size of the buffer may be restricted. 2417 in.mark(rafCfaHeaderOffset + rafCfaHeaderLength); 2418 int totalSkip = rafCfaHeaderOffset; 2419 while (totalSkip > 0) { 2420 long skipped = in.skip(totalSkip); 2421 totalSkip -= skipped; 2422 } 2423 2424 // Retrieve primary image length/width values, if TAG_RAF_IMAGE_SIZE exists 2425 byte[] exifBytes = new byte[rafCfaHeaderLength]; 2426 if (in.read(exifBytes) != rafCfaHeaderLength) { 2427 throw new EOFException(); 2428 } 2429 in.reset(); 2430 ByteOrderAwarenessDataInputStream dataInputStream = 2431 new ByteOrderAwarenessDataInputStream(exifBytes); 2432 int numberOfDirectoryEntry = dataInputStream.readInt(); 2433 if (DEBUG) { 2434 Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry); 2435 } 2436 // CFA stores some metadata about the RAW image. Since CFA uses proprietary tags, can only 2437 // find and retrieve image size information tags, while skipping others. 2438 // See piex.cc RafGetDimension() 2439 for (int i = 0; i < numberOfDirectoryEntry; ++i) { 2440 int tagNumber = dataInputStream.readUnsignedShort(); 2441 int numberOfBytes = dataInputStream.readUnsignedShort(); 2442 if (tagNumber == TAG_RAF_IMAGE_SIZE.number) { 2443 int imageLength = dataInputStream.readShort(); 2444 int imageWidth = dataInputStream.readShort(); 2445 ExifAttribute imageLengthAttribute = 2446 ExifAttribute.createUShort(imageLength, mExifByteOrder); 2447 ExifAttribute imageWidthAttribute = 2448 ExifAttribute.createUShort(imageWidth, mExifByteOrder); 2449 mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, imageLengthAttribute); 2450 mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, imageWidthAttribute); 2451 if (DEBUG) { 2452 Log.d(TAG, "Updated to length: " + imageLength + ", width: " + imageWidth); 2453 } 2454 return; 2455 } 2456 dataInputStream.skip(numberOfBytes); 2457 } 2458 } 2459 2460 /** 2461 * ORF files contains a primary image data and a MakerNote data that contains preview/thumbnail 2462 * images. Both data takes the form of IFDs and can therefore be read with the 2463 * readImageFileDirectory() method. 2464 * This method reads all the necessary data and updates the primary/preview/thumbnail image 2465 * information according to the GetOlympusPreviewImage() method in piex.cc. 2466 * For data format details, see the following: 2467 * http://fileformats.archiveteam.org/wiki/Olympus_ORF 2468 * https://libopenraw.freedesktop.org/wiki/Olympus_ORF 2469 */ 2470 private void getOrfAttributes(InputStream in) throws IOException { 2471 // Retrieve primary image data 2472 // Other Exif data will be located in the Makernote. 2473 getRawAttributes(in); 2474 2475 // Additionally retrieve preview/thumbnail information from MakerNote tag, which contains 2476 // proprietary tags and therefore does not have offical documentation 2477 // See GetOlympusPreviewImage() in piex.cc & http://www.exiv2.org/tags-olympus.html 2478 ExifAttribute makerNoteAttribute = 2479 (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE); 2480 if (makerNoteAttribute != null) { 2481 // Create an ordered DataInputStream for MakerNote 2482 ByteOrderAwarenessDataInputStream makerNoteDataInputStream = 2483 new ByteOrderAwarenessDataInputStream(makerNoteAttribute.bytes); 2484 makerNoteDataInputStream.setByteOrder(mExifByteOrder); 2485 2486 // There are two types of headers for Olympus MakerNotes 2487 // See http://www.exiv2.org/makernote.html#R1 2488 byte[] makerNoteHeader1Bytes = new byte[ORF_MAKER_NOTE_HEADER_1.length]; 2489 makerNoteDataInputStream.readFully(makerNoteHeader1Bytes); 2490 makerNoteDataInputStream.seek(0); 2491 byte[] makerNoteHeader2Bytes = new byte[ORF_MAKER_NOTE_HEADER_2.length]; 2492 makerNoteDataInputStream.readFully(makerNoteHeader2Bytes); 2493 // Skip the corresponding amount of bytes for each header type 2494 if (Arrays.equals(makerNoteHeader1Bytes, ORF_MAKER_NOTE_HEADER_1)) { 2495 makerNoteDataInputStream.seek(ORF_MAKER_NOTE_HEADER_1_SIZE); 2496 } else if (Arrays.equals(makerNoteHeader2Bytes, ORF_MAKER_NOTE_HEADER_2)) { 2497 makerNoteDataInputStream.seek(ORF_MAKER_NOTE_HEADER_2_SIZE); 2498 } 2499 2500 // Read IFD data from MakerNote 2501 readImageFileDirectory(makerNoteDataInputStream, IFD_TYPE_ORF_MAKER_NOTE); 2502 2503 // Retrieve & update preview image offset & length values 2504 ExifAttribute imageLengthAttribute = (ExifAttribute) 2505 mAttributes[IFD_TYPE_ORF_CAMERA_SETTINGS].get(TAG_ORF_PREVIEW_IMAGE_START); 2506 ExifAttribute bitsPerSampleAttribute = (ExifAttribute) 2507 mAttributes[IFD_TYPE_ORF_CAMERA_SETTINGS].get(TAG_ORF_PREVIEW_IMAGE_LENGTH); 2508 2509 if (imageLengthAttribute != null && bitsPerSampleAttribute != null) { 2510 mAttributes[IFD_TYPE_PREVIEW].put(TAG_JPEG_INTERCHANGE_FORMAT, 2511 imageLengthAttribute); 2512 mAttributes[IFD_TYPE_PREVIEW].put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 2513 bitsPerSampleAttribute); 2514 } 2515 2516 // TODO: Check this behavior in other ORF files 2517 // Retrieve primary image length & width values 2518 // See piex.cc GetOlympusPreviewImage() 2519 ExifAttribute aspectFrameAttribute = (ExifAttribute) 2520 mAttributes[IFD_TYPE_ORF_IMAGE_PROCESSING].get(TAG_ORF_ASPECT_FRAME); 2521 if (aspectFrameAttribute != null) { 2522 int[] aspectFrameValues = new int[4]; 2523 aspectFrameValues = (int[]) aspectFrameAttribute.getValue(mExifByteOrder); 2524 if (aspectFrameValues[2] > aspectFrameValues[0] && 2525 aspectFrameValues[3] > aspectFrameValues[1]) { 2526 int primaryImageWidth = aspectFrameValues[2] - aspectFrameValues[0] + 1; 2527 int primaryImageLength = aspectFrameValues[3] - aspectFrameValues[1] + 1; 2528 // Swap width & length values 2529 if (primaryImageWidth < primaryImageLength) { 2530 primaryImageWidth += primaryImageLength; 2531 primaryImageLength = primaryImageWidth - primaryImageLength; 2532 primaryImageWidth -= primaryImageLength; 2533 } 2534 ExifAttribute primaryImageWidthAttribute = 2535 ExifAttribute.createUShort(primaryImageWidth, mExifByteOrder); 2536 ExifAttribute primaryImageLengthAttribute = 2537 ExifAttribute.createUShort(primaryImageLength, mExifByteOrder); 2538 2539 mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, primaryImageWidthAttribute); 2540 mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, primaryImageLengthAttribute); 2541 } 2542 } 2543 } 2544 } 2545 2546 // RW2 contains the primary image data in IFD0 and the preview and/or thumbnail image data in 2547 // the JpgFromRaw tag 2548 // See https://libopenraw.freedesktop.org/wiki/Panasonic_RAW/ and piex.cc Rw2GetPreviewData() 2549 private void getRw2Attributes(InputStream in) throws IOException { 2550 // Retrieve primary image data 2551 getRawAttributes(in); 2552 2553 // Retrieve preview and/or thumbnail image data 2554 ExifAttribute jpgFromRawAttribute = 2555 (ExifAttribute) mAttributes[IFD_TYPE_PRIMARY].get(TAG_RW2_JPG_FROM_RAW); 2556 if (jpgFromRawAttribute != null) { 2557 getJpegAttributes(in, mRw2JpgFromRawOffset, IFD_TYPE_PREVIEW); 2558 } 2559 2560 // Set ISO tag value if necessary 2561 ExifAttribute rw2IsoAttribute = 2562 (ExifAttribute) mAttributes[IFD_TYPE_PRIMARY].get(TAG_RW2_ISO); 2563 ExifAttribute exifIsoAttribute = 2564 (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_ISO_SPEED_RATINGS); 2565 if (rw2IsoAttribute != null && exifIsoAttribute == null) { 2566 // Place this attribute only if it doesn't exist 2567 mAttributes[IFD_TYPE_EXIF].put(TAG_ISO_SPEED_RATINGS, rw2IsoAttribute); 2568 } 2569 } 2570 2571 // Stores a new JPEG image with EXIF attributes into a given output stream. 2572 private void saveJpegAttributes(InputStream inputStream, OutputStream outputStream) 2573 throws IOException { 2574 // See JPEG File Interchange Format Specification, "JFIF Specification" 2575 if (DEBUG) { 2576 Log.d(TAG, "saveJpegAttributes starting with (inputStream: " + inputStream 2577 + ", outputStream: " + outputStream + ")"); 2578 } 2579 DataInputStream dataInputStream = new DataInputStream(inputStream); 2580 ByteOrderAwarenessDataOutputStream dataOutputStream = 2581 new ByteOrderAwarenessDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN); 2582 if (dataInputStream.readByte() != MARKER) { 2583 throw new IOException("Invalid marker"); 2584 } 2585 dataOutputStream.writeByte(MARKER); 2586 if (dataInputStream.readByte() != MARKER_SOI) { 2587 throw new IOException("Invalid marker"); 2588 } 2589 dataOutputStream.writeByte(MARKER_SOI); 2590 2591 // Write EXIF APP1 segment 2592 dataOutputStream.writeByte(MARKER); 2593 dataOutputStream.writeByte(MARKER_APP1); 2594 writeExifSegment(dataOutputStream, 6); 2595 2596 byte[] bytes = new byte[4096]; 2597 2598 while (true) { 2599 byte marker = dataInputStream.readByte(); 2600 if (marker != MARKER) { 2601 throw new IOException("Invalid marker"); 2602 } 2603 marker = dataInputStream.readByte(); 2604 switch (marker) { 2605 case MARKER_APP1: { 2606 int length = dataInputStream.readUnsignedShort() - 2; 2607 if (length < 0) { 2608 throw new IOException("Invalid length"); 2609 } 2610 byte[] identifier = new byte[6]; 2611 if (length >= 6) { 2612 if (dataInputStream.read(identifier) != 6) { 2613 throw new IOException("Invalid exif"); 2614 } 2615 if (Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) { 2616 // Skip the original EXIF APP1 segment. 2617 if (dataInputStream.skip(length - 6) != length - 6) { 2618 throw new IOException("Invalid length"); 2619 } 2620 break; 2621 } 2622 } 2623 // Copy non-EXIF APP1 segment. 2624 dataOutputStream.writeByte(MARKER); 2625 dataOutputStream.writeByte(marker); 2626 dataOutputStream.writeUnsignedShort(length + 2); 2627 if (length >= 6) { 2628 length -= 6; 2629 dataOutputStream.write(identifier); 2630 } 2631 int read; 2632 while (length > 0 && (read = dataInputStream.read( 2633 bytes, 0, Math.min(length, bytes.length))) >= 0) { 2634 dataOutputStream.write(bytes, 0, read); 2635 length -= read; 2636 } 2637 break; 2638 } 2639 case MARKER_EOI: 2640 case MARKER_SOS: { 2641 dataOutputStream.writeByte(MARKER); 2642 dataOutputStream.writeByte(marker); 2643 // Copy all the remaining data 2644 Streams.copy(dataInputStream, dataOutputStream); 2645 return; 2646 } 2647 default: { 2648 // Copy JPEG segment 2649 dataOutputStream.writeByte(MARKER); 2650 dataOutputStream.writeByte(marker); 2651 int length = dataInputStream.readUnsignedShort(); 2652 dataOutputStream.writeUnsignedShort(length); 2653 length -= 2; 2654 if (length < 0) { 2655 throw new IOException("Invalid length"); 2656 } 2657 int read; 2658 while (length > 0 && (read = dataInputStream.read( 2659 bytes, 0, Math.min(length, bytes.length))) >= 0) { 2660 dataOutputStream.write(bytes, 0, read); 2661 length -= read; 2662 } 2663 break; 2664 } 2665 } 2666 } 2667 } 2668 2669 // Reads the given EXIF byte area and save its tag data into attributes. 2670 private void readExifSegment(byte[] exifBytes, int imageType) throws IOException { 2671 ByteOrderAwarenessDataInputStream dataInputStream = 2672 new ByteOrderAwarenessDataInputStream(exifBytes); 2673 2674 // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1. 2675 parseTiffHeaders(dataInputStream, exifBytes.length); 2676 2677 // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6. 2678 readImageFileDirectory(dataInputStream, imageType); 2679 } 2680 2681 private void addDefaultValuesForCompatibility() { 2682 // The value of DATETIME tag has the same value of DATETIME_ORIGINAL tag. 2683 String valueOfDateTimeOriginal = getAttribute(TAG_DATETIME_ORIGINAL); 2684 if (valueOfDateTimeOriginal != null) { 2685 mAttributes[IFD_TYPE_PRIMARY].put(TAG_DATETIME, 2686 ExifAttribute.createString(valueOfDateTimeOriginal)); 2687 } 2688 2689 // Add the default value. 2690 if (getAttribute(TAG_IMAGE_WIDTH) == null) { 2691 mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, 2692 ExifAttribute.createULong(0, mExifByteOrder)); 2693 } 2694 if (getAttribute(TAG_IMAGE_LENGTH) == null) { 2695 mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, 2696 ExifAttribute.createULong(0, mExifByteOrder)); 2697 } 2698 if (getAttribute(TAG_ORIENTATION) == null) { 2699 mAttributes[IFD_TYPE_PRIMARY].put(TAG_ORIENTATION, 2700 ExifAttribute.createULong(0, mExifByteOrder)); 2701 } 2702 if (getAttribute(TAG_LIGHT_SOURCE) == null) { 2703 mAttributes[IFD_TYPE_EXIF].put(TAG_LIGHT_SOURCE, 2704 ExifAttribute.createULong(0, mExifByteOrder)); 2705 } 2706 } 2707 2708 private ByteOrder readByteOrder(ByteOrderAwarenessDataInputStream dataInputStream) 2709 throws IOException { 2710 // Read byte order. 2711 short byteOrder = dataInputStream.readShort(); 2712 switch (byteOrder) { 2713 case BYTE_ALIGN_II: 2714 if (DEBUG) { 2715 Log.d(TAG, "readExifSegment: Byte Align II"); 2716 } 2717 return ByteOrder.LITTLE_ENDIAN; 2718 case BYTE_ALIGN_MM: 2719 if (DEBUG) { 2720 Log.d(TAG, "readExifSegment: Byte Align MM"); 2721 } 2722 return ByteOrder.BIG_ENDIAN; 2723 default: 2724 throw new IOException("Invalid byte order: " + Integer.toHexString(byteOrder)); 2725 } 2726 } 2727 2728 private void parseTiffHeaders(ByteOrderAwarenessDataInputStream dataInputStream, 2729 int exifBytesLength) throws IOException { 2730 // Read byte order 2731 mExifByteOrder = readByteOrder(dataInputStream); 2732 // Set byte order 2733 dataInputStream.setByteOrder(mExifByteOrder); 2734 2735 // Check start code 2736 int startCode = dataInputStream.readUnsignedShort(); 2737 if (mMimeType != IMAGE_TYPE_ORF && mMimeType != IMAGE_TYPE_RW2 && startCode != START_CODE) { 2738 throw new IOException("Invalid start code: " + Integer.toHexString(startCode)); 2739 } 2740 2741 // Read and skip to first ifd offset 2742 int firstIfdOffset = dataInputStream.readInt(); 2743 if (firstIfdOffset < 8 || firstIfdOffset >= exifBytesLength) { 2744 throw new IOException("Invalid first Ifd offset: " + firstIfdOffset); 2745 } 2746 firstIfdOffset -= 8; 2747 if (firstIfdOffset > 0) { 2748 if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset) { 2749 throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset); 2750 } 2751 } 2752 } 2753 2754 // Reads image file directory, which is a tag group in EXIF. 2755 private void readImageFileDirectory(ByteOrderAwarenessDataInputStream dataInputStream, 2756 @IfdType int ifdType) throws IOException { 2757 if (dataInputStream.peek() + 2 > dataInputStream.mLength) { 2758 // Return if there is no data from the offset. 2759 return; 2760 } 2761 // See TIFF 6.0 Section 2: TIFF Structure, Figure 1. 2762 short numberOfDirectoryEntry = dataInputStream.readShort(); 2763 if (dataInputStream.peek() + 12 * numberOfDirectoryEntry > dataInputStream.mLength) { 2764 // Return if the size of entries is too big. 2765 return; 2766 } 2767 2768 if (DEBUG) { 2769 Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry); 2770 } 2771 2772 // See TIFF 6.0 Section 2: TIFF Structure, "Image File Directory". 2773 for (short i = 0; i < numberOfDirectoryEntry; ++i) { 2774 int tagNumber = dataInputStream.readUnsignedShort(); 2775 int dataFormat = dataInputStream.readUnsignedShort(); 2776 int numberOfComponents = dataInputStream.readInt(); 2777 // Next four bytes is for data offset or value. 2778 long nextEntryOffset = dataInputStream.peek() + 4; 2779 2780 // Look up a corresponding tag from tag number 2781 ExifTag tag = (ExifTag) sExifTagMapsForReading[ifdType].get(tagNumber); 2782 2783 if (DEBUG) { 2784 Log.d(TAG, String.format("ifdType: %d, tagNumber: %d, tagName: %s, dataFormat: %d, " 2785 + "numberOfComponents: %d", ifdType, tagNumber, 2786 tag != null ? tag.name : null, dataFormat, numberOfComponents)); 2787 } 2788 2789 if (tag == null || dataFormat <= 0 || 2790 dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) { 2791 // Skip if the parsed tag number is not defined or invalid data format. 2792 if (tag == null) { 2793 Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber); 2794 } else { 2795 Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat); 2796 } 2797 dataInputStream.seek(nextEntryOffset); 2798 continue; 2799 } 2800 2801 // Read a value from data field or seek to the value offset which is stored in data 2802 // field if the size of the entry value is bigger than 4. 2803 int byteCount = numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat]; 2804 if (byteCount > 4) { 2805 int offset = dataInputStream.readInt(); 2806 if (DEBUG) { 2807 Log.d(TAG, "seek to data offset: " + offset); 2808 } 2809 if (mMimeType == IMAGE_TYPE_ORF) { 2810 if (tag.name == TAG_MAKER_NOTE) { 2811 // Save offset value for reading thumbnail 2812 mOrfMakerNoteOffset = offset; 2813 } else if (ifdType == IFD_TYPE_ORF_MAKER_NOTE 2814 && tag.name == TAG_ORF_THUMBNAIL_IMAGE) { 2815 // Retrieve & update values for thumbnail offset and length values for ORF 2816 mOrfThumbnailOffset = offset; 2817 mOrfThumbnailLength = numberOfComponents; 2818 2819 ExifAttribute compressionAttribute = 2820 ExifAttribute.createUShort(DATA_JPEG, mExifByteOrder); 2821 ExifAttribute jpegInterchangeFormatAttribute = 2822 ExifAttribute.createULong(mOrfThumbnailOffset, mExifByteOrder); 2823 ExifAttribute jpegInterchangeFormatLengthAttribute = 2824 ExifAttribute.createULong(mOrfThumbnailLength, mExifByteOrder); 2825 2826 mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_COMPRESSION, compressionAttribute); 2827 mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_JPEG_INTERCHANGE_FORMAT, 2828 jpegInterchangeFormatAttribute); 2829 mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 2830 jpegInterchangeFormatLengthAttribute); 2831 } 2832 } else if (mMimeType == IMAGE_TYPE_RW2) { 2833 if (tag.name == TAG_RW2_JPG_FROM_RAW) { 2834 mRw2JpgFromRawOffset = offset; 2835 } 2836 } 2837 if (offset + byteCount <= dataInputStream.mLength) { 2838 dataInputStream.seek(offset); 2839 } else { 2840 // Skip if invalid data offset. 2841 Log.w(TAG, "Skip the tag entry since data offset is invalid: " + offset); 2842 dataInputStream.seek(nextEntryOffset); 2843 continue; 2844 } 2845 } 2846 2847 // Recursively parse IFD when a IFD pointer tag appears. 2848 Object nextIfdType = sExifPointerTagMap.get(tagNumber); 2849 if (DEBUG) { 2850 Log.d(TAG, "nextIfdType: " + nextIfdType + " byteCount: " + byteCount); 2851 } 2852 2853 if (nextIfdType != null) { 2854 long offset = -1L; 2855 // Get offset from data field 2856 switch (dataFormat) { 2857 case IFD_FORMAT_USHORT: { 2858 offset = dataInputStream.readUnsignedShort(); 2859 break; 2860 } 2861 case IFD_FORMAT_SSHORT: { 2862 offset = dataInputStream.readShort(); 2863 break; 2864 } 2865 case IFD_FORMAT_ULONG: { 2866 offset = dataInputStream.readUnsignedInt(); 2867 break; 2868 } 2869 case IFD_FORMAT_SLONG: 2870 case IFD_FORMAT_IFD: { 2871 offset = dataInputStream.readInt(); 2872 break; 2873 } 2874 default: { 2875 // Nothing to do 2876 break; 2877 } 2878 } 2879 if (DEBUG) { 2880 Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tag.name)); 2881 } 2882 if (offset > 0L && offset < dataInputStream.mLength) { 2883 dataInputStream.seek(offset); 2884 readImageFileDirectory(dataInputStream, (int) nextIfdType); 2885 } else { 2886 Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset); 2887 } 2888 2889 dataInputStream.seek(nextEntryOffset); 2890 continue; 2891 } 2892 2893 byte[] bytes = new byte[byteCount]; 2894 dataInputStream.readFully(bytes); 2895 ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents, bytes); 2896 mAttributes[ifdType].put(tag.name, attribute); 2897 2898 // DNG files have a DNG Version tag specifying the version of specifications that the 2899 // image file is following. 2900 // See http://fileformats.archiveteam.org/wiki/DNG 2901 if (tag.name == TAG_DNG_VERSION) { 2902 mMimeType = IMAGE_TYPE_DNG; 2903 } 2904 2905 // PEF files have a Make or Model tag that begins with "PENTAX" or a compression tag 2906 // that is 65535. 2907 // See http://fileformats.archiveteam.org/wiki/Pentax_PEF 2908 if (((tag.name == TAG_MAKE || tag.name == TAG_MODEL) 2909 && attribute.getStringValue(mExifByteOrder).contains(PEF_SIGNATURE)) 2910 || (tag.name == TAG_COMPRESSION 2911 && attribute.getIntValue(mExifByteOrder) == 65535)) { 2912 mMimeType = IMAGE_TYPE_PEF; 2913 } 2914 2915 // Seek to next tag offset 2916 if (dataInputStream.peek() != nextEntryOffset) { 2917 dataInputStream.seek(nextEntryOffset); 2918 } 2919 } 2920 2921 if (dataInputStream.peek() + 4 <= dataInputStream.mLength) { 2922 int nextIfdOffset = dataInputStream.readInt(); 2923 if (DEBUG) { 2924 Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset)); 2925 } 2926 // The next IFD offset needs to be bigger than 8 2927 // since the first IFD offset is at least 8. 2928 if (nextIfdOffset > 8 && nextIfdOffset < dataInputStream.mLength) { 2929 dataInputStream.seek(nextIfdOffset); 2930 if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) { 2931 // Do not overwrite thumbnail IFD data if it alreay exists. 2932 readImageFileDirectory(dataInputStream, IFD_TYPE_THUMBNAIL); 2933 } else if (mAttributes[IFD_TYPE_PREVIEW].isEmpty()) { 2934 readImageFileDirectory(dataInputStream, IFD_TYPE_PREVIEW); 2935 } 2936 } 2937 } 2938 } 2939 2940 /** 2941 * JPEG compressed images do not contain IMAGE_LENGTH & IMAGE_WIDTH tags. 2942 * This value uses JpegInterchangeFormat(JPEG data offset) value, and calls getJpegAttributes() 2943 * to locate SOF(Start of Frame) marker and update the image length & width values. 2944 * See JEITA CP-3451C Table 5 and Section 4.8.1. B. 2945 */ 2946 private void retrieveJpegImageSize(InputStream in, int imageType) throws IOException { 2947 // Check if image already has IMAGE_LENGTH & IMAGE_WIDTH values 2948 ExifAttribute imageLengthAttribute = 2949 (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_LENGTH); 2950 ExifAttribute imageWidthAttribute = 2951 (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_WIDTH); 2952 2953 if (imageLengthAttribute == null || imageWidthAttribute == null) { 2954 // Find if offset for JPEG data exists 2955 ExifAttribute jpegInterchangeFormatAttribute = 2956 (ExifAttribute) mAttributes[imageType].get(TAG_JPEG_INTERCHANGE_FORMAT); 2957 if (jpegInterchangeFormatAttribute != null) { 2958 int jpegInterchangeFormat = 2959 jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder); 2960 2961 // Searches for SOF marker in JPEG data and updates IMAGE_LENGTH & IMAGE_WIDTH tags 2962 getJpegAttributes(in, jpegInterchangeFormat, imageType); 2963 } 2964 } 2965 } 2966 2967 // Sets thumbnail offset & length attributes based on JpegInterchangeFormat or StripOffsets tags 2968 private void setThumbnailData(InputStream in) throws IOException { 2969 HashMap thumbnailData = mAttributes[IFD_TYPE_THUMBNAIL]; 2970 2971 ExifAttribute compressionAttribute = 2972 (ExifAttribute) thumbnailData.get(TAG_COMPRESSION); 2973 if (compressionAttribute != null) { 2974 mThumbnailCompression = compressionAttribute.getIntValue(mExifByteOrder); 2975 switch (mThumbnailCompression) { 2976 case DATA_JPEG: { 2977 handleThumbnailFromJfif(in, thumbnailData); 2978 break; 2979 } 2980 case DATA_UNCOMPRESSED: 2981 case DATA_JPEG_COMPRESSED: { 2982 if (isSupportedDataType(thumbnailData)) { 2983 handleThumbnailFromStrips(in, thumbnailData); 2984 } 2985 break; 2986 } 2987 } 2988 } else { 2989 // Thumbnail data may not contain Compression tag value 2990 mThumbnailCompression = DATA_JPEG; 2991 handleThumbnailFromJfif(in, thumbnailData); 2992 } 2993 } 2994 2995 // Check JpegInterchangeFormat(JFIF) tags to retrieve thumbnail offset & length values 2996 // and reads the corresponding bytes if stream does not support seek function 2997 private void handleThumbnailFromJfif(InputStream in, HashMap thumbnailData) throws IOException { 2998 ExifAttribute jpegInterchangeFormatAttribute = 2999 (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT); 3000 ExifAttribute jpegInterchangeFormatLengthAttribute = 3001 (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH); 3002 if (jpegInterchangeFormatAttribute != null 3003 && jpegInterchangeFormatLengthAttribute != null) { 3004 int thumbnailOffset = jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder); 3005 int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder); 3006 3007 // The following code limits the size of thumbnail size not to overflow EXIF data area. 3008 thumbnailLength = Math.min(thumbnailLength, in.available() - thumbnailOffset); 3009 if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF 3010 || mMimeType == IMAGE_TYPE_RW2) { 3011 thumbnailOffset += mExifOffset; 3012 } else if (mMimeType == IMAGE_TYPE_ORF) { 3013 // Update offset value since RAF files have IFD data preceding MakerNote data. 3014 thumbnailOffset += mOrfMakerNoteOffset; 3015 } 3016 if (DEBUG) { 3017 Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset 3018 + ", length: " + thumbnailLength); 3019 } 3020 if (thumbnailOffset > 0 && thumbnailLength > 0) { 3021 mHasThumbnail = true; 3022 mThumbnailOffset = thumbnailOffset; 3023 mThumbnailLength = thumbnailLength; 3024 if (mFilename == null && mAssetInputStream == null 3025 && mSeekableFileDescriptor == null) { 3026 // Save the thumbnail in memory if the input doesn't support reading again. 3027 byte[] thumbnailBytes = new byte[thumbnailLength]; 3028 in.skip(thumbnailOffset); 3029 in.read(thumbnailBytes); 3030 mThumbnailBytes = thumbnailBytes; 3031 } 3032 } 3033 } 3034 } 3035 3036 // Check StripOffsets & StripByteCounts tags to retrieve thumbnail offset & length values 3037 private void handleThumbnailFromStrips(InputStream in, HashMap thumbnailData) 3038 throws IOException { 3039 ExifAttribute stripOffsetsAttribute = 3040 (ExifAttribute) thumbnailData.get(TAG_STRIP_OFFSETS); 3041 ExifAttribute stripByteCountsAttribute = 3042 (ExifAttribute) thumbnailData.get(TAG_STRIP_BYTE_COUNTS); 3043 3044 if (stripOffsetsAttribute != null && stripByteCountsAttribute != null) { 3045 long[] stripOffsets = 3046 (long[]) stripOffsetsAttribute.getValue(mExifByteOrder); 3047 long[] stripByteCounts = 3048 (long[]) stripByteCountsAttribute.getValue(mExifByteOrder); 3049 3050 // Set thumbnail byte array data for non-consecutive strip bytes 3051 byte[] totalStripBytes = 3052 new byte[(int) Arrays.stream(stripByteCounts).sum()]; 3053 3054 int bytesRead = 0; 3055 int bytesAdded = 0; 3056 for (int i = 0; i < stripOffsets.length; i++) { 3057 int stripOffset = (int) stripOffsets[i]; 3058 int stripByteCount = (int) stripByteCounts[i]; 3059 3060 // Skip to offset 3061 int skipBytes = stripOffset - bytesRead; 3062 if (skipBytes < 0) { 3063 Log.d(TAG, "Invalid strip offset value"); 3064 } 3065 in.skip(skipBytes); 3066 bytesRead += skipBytes; 3067 3068 // Read strip bytes 3069 byte[] stripBytes = new byte[stripByteCount]; 3070 in.read(stripBytes); 3071 bytesRead += stripByteCount; 3072 3073 // Add bytes to array 3074 System.arraycopy(stripBytes, 0, totalStripBytes, bytesAdded, 3075 stripBytes.length); 3076 bytesAdded += stripBytes.length; 3077 } 3078 3079 mHasThumbnail = true; 3080 mThumbnailBytes = totalStripBytes; 3081 mThumbnailLength = totalStripBytes.length; 3082 } 3083 } 3084 3085 // Check if thumbnail data type is currently supported or not 3086 private boolean isSupportedDataType(HashMap thumbnailData) throws IOException { 3087 ExifAttribute bitsPerSampleAttribute = 3088 (ExifAttribute) thumbnailData.get(TAG_BITS_PER_SAMPLE); 3089 if (bitsPerSampleAttribute != null) { 3090 int[] bitsPerSampleValue = (int[]) bitsPerSampleAttribute.getValue(mExifByteOrder); 3091 3092 if (Arrays.equals(BITS_PER_SAMPLE_RGB, bitsPerSampleValue)) { 3093 return true; 3094 } 3095 3096 // See DNG Specification 1.4.0.0. Section 3, Compression. 3097 if (mMimeType == IMAGE_TYPE_DNG) { 3098 ExifAttribute photometricInterpretationAttribute = 3099 (ExifAttribute) thumbnailData.get(TAG_PHOTOMETRIC_INTERPRETATION); 3100 if (photometricInterpretationAttribute != null) { 3101 int photometricInterpretationValue 3102 = photometricInterpretationAttribute.getIntValue(mExifByteOrder); 3103 if ((photometricInterpretationValue == PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO 3104 && Arrays.equals(bitsPerSampleValue, BITS_PER_SAMPLE_GREYSCALE_2)) 3105 || ((photometricInterpretationValue == PHOTOMETRIC_INTERPRETATION_YCBCR) 3106 && (Arrays.equals(bitsPerSampleValue, BITS_PER_SAMPLE_RGB)))) { 3107 return true; 3108 } else { 3109 // TODO: Add support for lossless Huffman JPEG data 3110 } 3111 } 3112 } 3113 } 3114 if (DEBUG) { 3115 Log.d(TAG, "Unsupported data type value"); 3116 } 3117 return false; 3118 } 3119 3120 // Returns true if the image length and width values are <= 512. 3121 // See Section 4.8 of http://standardsproposals.bsigroup.com/Home/getPDF/567 3122 private boolean isThumbnail(HashMap map) throws IOException { 3123 ExifAttribute imageLengthAttribute = (ExifAttribute) map.get(TAG_IMAGE_LENGTH); 3124 ExifAttribute imageWidthAttribute = (ExifAttribute) map.get(TAG_IMAGE_WIDTH); 3125 3126 if (imageLengthAttribute != null && imageWidthAttribute != null) { 3127 int imageLengthValue = imageLengthAttribute.getIntValue(mExifByteOrder); 3128 int imageWidthValue = imageWidthAttribute.getIntValue(mExifByteOrder); 3129 if (imageLengthValue <= MAX_THUMBNAIL_SIZE && imageWidthValue <= MAX_THUMBNAIL_SIZE) { 3130 return true; 3131 } 3132 } 3133 return false; 3134 } 3135 3136 // Validate primary, preview, thumbnail image data by comparing image size 3137 private void validateImages(InputStream in) throws IOException { 3138 // Swap images based on size (primary > preview > thumbnail) 3139 swapBasedOnImageSize(IFD_TYPE_PRIMARY, IFD_TYPE_PREVIEW); 3140 swapBasedOnImageSize(IFD_TYPE_PRIMARY, IFD_TYPE_THUMBNAIL); 3141 swapBasedOnImageSize(IFD_TYPE_PREVIEW, IFD_TYPE_THUMBNAIL); 3142 3143 // Check whether thumbnail image exists and whether preview image satisfies the thumbnail 3144 // image requirements 3145 if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) { 3146 if (isThumbnail(mAttributes[IFD_TYPE_PREVIEW])) { 3147 mAttributes[IFD_TYPE_THUMBNAIL] = mAttributes[IFD_TYPE_PREVIEW]; 3148 mAttributes[IFD_TYPE_PREVIEW] = new HashMap(); 3149 } 3150 } 3151 3152 // Check if the thumbnail image satisfies the thumbnail size requirements 3153 if (!isThumbnail(mAttributes[IFD_TYPE_THUMBNAIL])) { 3154 Log.d(TAG, "No image meets the size requirements of a thumbnail image."); 3155 } 3156 } 3157 3158 /** 3159 * If image is uncompressed, ImageWidth/Length tags are used to store size info. 3160 * However, uncompressed images often store extra pixels around the edges of the final image, 3161 * which results in larger values for TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH tags. 3162 * This method corrects those tag values by checking first the values of TAG_DEFAULT_CROP_SIZE 3163 * See DNG Specification 1.4.0.0. Section 4. (DefaultCropSize) 3164 * 3165 * If image is JPEG compressed, PixelXDimension/PixelYDimension tags are used for size info. 3166 * However, an image may have padding at the right end or bottom end of the image to make sure 3167 * that the values are multiples of 64. If so, the increased value will be saved in the 3168 * SOF(Start of Frame). In order to assure that valid image size values are stored, this method 3169 * checks TAG_PIXEL_X_DIMENSION & TAG_PIXEL_Y_DIMENSION and updates values if necessary. 3170 * See JEITA CP-3451C Table 5 and Section 4.8.1. B. 3171 * 3172 * If image is a RW2 file, valid image sizes are stored in SensorBorder tags. 3173 * See tiff_parser.cc GetFullDimension32() 3174 * */ 3175 private void updateImageSizeValues(InputStream in, int imageType) throws IOException { 3176 // Uncompressed image valid image size values 3177 ExifAttribute defaultCropSizeAttribute = 3178 (ExifAttribute) mAttributes[imageType].get(TAG_DEFAULT_CROP_SIZE); 3179 // RW2 image valid image size values 3180 ExifAttribute topBorderAttribute = 3181 (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_TOP_BORDER); 3182 ExifAttribute leftBorderAttribute = 3183 (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_LEFT_BORDER); 3184 ExifAttribute bottomBorderAttribute = 3185 (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_BOTTOM_BORDER); 3186 ExifAttribute rightBorderAttribute = 3187 (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_RIGHT_BORDER); 3188 3189 if (defaultCropSizeAttribute != null) { 3190 // Update for uncompressed image 3191 ExifAttribute defaultCropSizeXAttribute, defaultCropSizeYAttribute; 3192 if (defaultCropSizeAttribute.format == IFD_FORMAT_URATIONAL) { 3193 Rational[] defaultCropSizeValue = 3194 (Rational[]) defaultCropSizeAttribute.getValue(mExifByteOrder); 3195 defaultCropSizeXAttribute = 3196 ExifAttribute.createURational(defaultCropSizeValue[0], mExifByteOrder); 3197 defaultCropSizeYAttribute = 3198 ExifAttribute.createURational(defaultCropSizeValue[1], mExifByteOrder); 3199 } else { 3200 int[] defaultCropSizeValue = 3201 (int[]) defaultCropSizeAttribute.getValue(mExifByteOrder); 3202 defaultCropSizeXAttribute = 3203 ExifAttribute.createUShort(defaultCropSizeValue[0], mExifByteOrder); 3204 defaultCropSizeYAttribute = 3205 ExifAttribute.createUShort(defaultCropSizeValue[1], mExifByteOrder); 3206 } 3207 mAttributes[imageType].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute); 3208 mAttributes[imageType].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute); 3209 } else if (topBorderAttribute != null && leftBorderAttribute != null && 3210 bottomBorderAttribute != null && rightBorderAttribute != null) { 3211 // Update for RW2 image 3212 int topBorderValue = topBorderAttribute.getIntValue(mExifByteOrder); 3213 int bottomBorderValue = bottomBorderAttribute.getIntValue(mExifByteOrder); 3214 int rightBorderValue = rightBorderAttribute.getIntValue(mExifByteOrder); 3215 int leftBorderValue = leftBorderAttribute.getIntValue(mExifByteOrder); 3216 if (bottomBorderValue > topBorderValue && rightBorderValue > leftBorderValue) { 3217 int length = bottomBorderValue - topBorderValue; 3218 int width = rightBorderValue - leftBorderValue; 3219 ExifAttribute imageLengthAttribute = 3220 ExifAttribute.createUShort(length, mExifByteOrder); 3221 ExifAttribute imageWidthAttribute = 3222 ExifAttribute.createUShort(width, mExifByteOrder); 3223 mAttributes[imageType].put(TAG_IMAGE_LENGTH, imageLengthAttribute); 3224 mAttributes[imageType].put(TAG_IMAGE_WIDTH, imageWidthAttribute); 3225 } 3226 } else { 3227 // Update for JPEG image 3228 ExifAttribute newSubfileTypeAttribute = 3229 (ExifAttribute) mAttributes[imageType].get(TAG_NEW_SUBFILE_TYPE); 3230 3231 if (newSubfileTypeAttribute != null) { 3232 int newSubfileTypeValue = newSubfileTypeAttribute.getIntValue(mExifByteOrder); 3233 3234 if (newSubfileTypeValue == ORIGINAL_RESOLUTION_IMAGE) { 3235 // Update only for the primary image (OriginalResolutionImage) 3236 ExifAttribute pixelXDimAttribute = 3237 (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_X_DIMENSION); 3238 ExifAttribute pixelYDimAttribute = 3239 (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_Y_DIMENSION); 3240 3241 if (pixelXDimAttribute != null && pixelYDimAttribute != null) { 3242 mAttributes[imageType].put(TAG_IMAGE_WIDTH, pixelXDimAttribute); 3243 mAttributes[imageType].put(TAG_IMAGE_LENGTH, pixelYDimAttribute); 3244 return; 3245 } 3246 } 3247 } 3248 retrieveJpegImageSize(in, imageType); 3249 } 3250 } 3251 3252 // Writes an Exif segment into the given output stream. 3253 private int writeExifSegment(ByteOrderAwarenessDataOutputStream dataOutputStream, 3254 int exifOffsetFromBeginning) throws IOException { 3255 // The following variables are for calculating each IFD tag group size in bytes. 3256 int[] ifdOffsets = new int[EXIF_TAGS.length]; 3257 int[] ifdDataSizes = new int[EXIF_TAGS.length]; 3258 3259 // Remove IFD pointer tags (we'll re-add it later.) 3260 for (ExifTag tag : EXIF_POINTER_TAGS) { 3261 removeAttribute(tag.name); 3262 } 3263 // Remove old thumbnail data 3264 removeAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name); 3265 removeAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name); 3266 3267 // Remove null value tags. 3268 for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) { 3269 for (Object obj : mAttributes[ifdType].entrySet().toArray()) { 3270 final Map.Entry entry = (Map.Entry) obj; 3271 if (entry.getValue() == null) { 3272 mAttributes[ifdType].remove(entry.getKey()); 3273 } 3274 } 3275 } 3276 3277 // Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD 3278 // offset when there is one or more tags in the thumbnail IFD. 3279 if (!mAttributes[IFD_TYPE_EXIF].isEmpty()) { 3280 mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[1].name, 3281 ExifAttribute.createULong(0, mExifByteOrder)); 3282 } 3283 if (!mAttributes[IFD_TYPE_GPS].isEmpty()) { 3284 mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[2].name, 3285 ExifAttribute.createULong(0, mExifByteOrder)); 3286 } 3287 if (!mAttributes[IFD_TYPE_INTEROPERABILITY].isEmpty()) { 3288 mAttributes[IFD_TYPE_EXIF].put(EXIF_POINTER_TAGS[3].name, 3289 ExifAttribute.createULong(0, mExifByteOrder)); 3290 } 3291 if (mHasThumbnail) { 3292 mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name, 3293 ExifAttribute.createULong(0, mExifByteOrder)); 3294 mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, 3295 ExifAttribute.createULong(mThumbnailLength, mExifByteOrder)); 3296 } 3297 3298 // Calculate IFD group data area sizes. IFD group data area is assigned to save the entry 3299 // value which has a bigger size than 4 bytes. 3300 for (int i = 0; i < EXIF_TAGS.length; ++i) { 3301 int sum = 0; 3302 for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) { 3303 final ExifAttribute exifAttribute = (ExifAttribute) ((Map.Entry) entry).getValue(); 3304 final int size = exifAttribute.size(); 3305 if (size > 4) { 3306 sum += size; 3307 } 3308 } 3309 ifdDataSizes[i] += sum; 3310 } 3311 3312 // Calculate IFD offsets. 3313 int position = 8; 3314 for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) { 3315 if (!mAttributes[ifdType].isEmpty()) { 3316 ifdOffsets[ifdType] = position; 3317 position += 2 + mAttributes[ifdType].size() * 12 + 4 + ifdDataSizes[ifdType]; 3318 } 3319 } 3320 if (mHasThumbnail) { 3321 int thumbnailOffset = position; 3322 mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name, 3323 ExifAttribute.createULong(thumbnailOffset, mExifByteOrder)); 3324 mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset; 3325 position += mThumbnailLength; 3326 } 3327 3328 // Calculate the total size 3329 int totalSize = position + 8; // eight bytes is for header part. 3330 if (DEBUG) { 3331 Log.d(TAG, "totalSize length: " + totalSize); 3332 for (int i = 0; i < EXIF_TAGS.length; ++i) { 3333 Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d", 3334 i, ifdOffsets[i], mAttributes[i].size(), ifdDataSizes[i])); 3335 } 3336 } 3337 3338 // Update IFD pointer tags with the calculated offsets. 3339 if (!mAttributes[IFD_TYPE_EXIF].isEmpty()) { 3340 mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[1].name, 3341 ExifAttribute.createULong(ifdOffsets[IFD_TYPE_EXIF], mExifByteOrder)); 3342 } 3343 if (!mAttributes[IFD_TYPE_GPS].isEmpty()) { 3344 mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[2].name, 3345 ExifAttribute.createULong(ifdOffsets[IFD_TYPE_GPS], mExifByteOrder)); 3346 } 3347 if (!mAttributes[IFD_TYPE_INTEROPERABILITY].isEmpty()) { 3348 mAttributes[IFD_TYPE_EXIF].put(EXIF_POINTER_TAGS[3].name, ExifAttribute.createULong( 3349 ifdOffsets[IFD_TYPE_INTEROPERABILITY], mExifByteOrder)); 3350 } 3351 3352 // Write TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1. 3353 dataOutputStream.writeUnsignedShort(totalSize); 3354 dataOutputStream.write(IDENTIFIER_EXIF_APP1); 3355 dataOutputStream.writeShort(mExifByteOrder == ByteOrder.BIG_ENDIAN 3356 ? BYTE_ALIGN_MM : BYTE_ALIGN_II); 3357 dataOutputStream.setByteOrder(mExifByteOrder); 3358 dataOutputStream.writeUnsignedShort(START_CODE); 3359 dataOutputStream.writeUnsignedInt(IFD_OFFSET); 3360 3361 // Write IFD groups. See JEITA CP-3451C Section 4.5.8. Figure 9. 3362 for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) { 3363 if (!mAttributes[ifdType].isEmpty()) { 3364 // See JEITA CP-3451C Section 4.6.2: IFD structure. 3365 // Write entry count 3366 dataOutputStream.writeUnsignedShort(mAttributes[ifdType].size()); 3367 3368 // Write entry info 3369 int dataOffset = ifdOffsets[ifdType] + 2 + mAttributes[ifdType].size() * 12 + 4; 3370 for (Map.Entry entry : (Set<Map.Entry>) mAttributes[ifdType].entrySet()) { 3371 // Convert tag name to tag number. 3372 final ExifTag tag = 3373 (ExifTag) sExifTagMapsForWriting[ifdType].get(entry.getKey()); 3374 final int tagNumber = tag.number; 3375 final ExifAttribute attribute = (ExifAttribute) entry.getValue(); 3376 final int size = attribute.size(); 3377 3378 dataOutputStream.writeUnsignedShort(tagNumber); 3379 dataOutputStream.writeUnsignedShort(attribute.format); 3380 dataOutputStream.writeInt(attribute.numberOfComponents); 3381 if (size > 4) { 3382 dataOutputStream.writeUnsignedInt(dataOffset); 3383 dataOffset += size; 3384 } else { 3385 dataOutputStream.write(attribute.bytes); 3386 // Fill zero up to 4 bytes 3387 if (size < 4) { 3388 for (int i = size; i < 4; ++i) { 3389 dataOutputStream.writeByte(0); 3390 } 3391 } 3392 } 3393 } 3394 3395 // Write the next offset. It writes the offset of thumbnail IFD if there is one or 3396 // more tags in the thumbnail IFD when the current IFD is the primary image TIFF 3397 // IFD; Otherwise 0. 3398 if (ifdType == 0 && !mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) { 3399 dataOutputStream.writeUnsignedInt(ifdOffsets[IFD_TYPE_THUMBNAIL]); 3400 } else { 3401 dataOutputStream.writeUnsignedInt(0); 3402 } 3403 3404 // Write values of data field exceeding 4 bytes after the next offset. 3405 for (Map.Entry entry : (Set<Map.Entry>) mAttributes[ifdType].entrySet()) { 3406 ExifAttribute attribute = (ExifAttribute) entry.getValue(); 3407 3408 if (attribute.bytes.length > 4) { 3409 dataOutputStream.write(attribute.bytes, 0, attribute.bytes.length); 3410 } 3411 } 3412 } 3413 } 3414 3415 // Write thumbnail 3416 if (mHasThumbnail) { 3417 dataOutputStream.write(getThumbnail()); 3418 } 3419 3420 // Reset the byte order to big endian in order to write remaining parts of the JPEG file. 3421 dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN); 3422 3423 return totalSize; 3424 } 3425 3426 /** 3427 * Determines the data format of EXIF entry value. 3428 * 3429 * @param entryValue The value to be determined. 3430 * @return Returns two data formats gussed as a pair in integer. If there is no two candidate 3431 data formats for the given entry value, returns {@code -1} in the second of the pair. 3432 */ 3433 private static Pair<Integer, Integer> guessDataFormat(String entryValue) { 3434 // See TIFF 6.0 Section 2, "Image File Directory". 3435 // Take the first component if there are more than one component. 3436 if (entryValue.contains(",")) { 3437 String[] entryValues = entryValue.split(","); 3438 Pair<Integer, Integer> dataFormat = guessDataFormat(entryValues[0]); 3439 if (dataFormat.first == IFD_FORMAT_STRING) { 3440 return dataFormat; 3441 } 3442 for (int i = 1; i < entryValues.length; ++i) { 3443 final Pair<Integer, Integer> guessDataFormat = guessDataFormat(entryValues[i]); 3444 int first = -1, second = -1; 3445 if (guessDataFormat.first == dataFormat.first 3446 || guessDataFormat.second == dataFormat.first) { 3447 first = dataFormat.first; 3448 } 3449 if (dataFormat.second != -1 && (guessDataFormat.first == dataFormat.second 3450 || guessDataFormat.second == dataFormat.second)) { 3451 second = dataFormat.second; 3452 } 3453 if (first == -1 && second == -1) { 3454 return new Pair<>(IFD_FORMAT_STRING, -1); 3455 } 3456 if (first == -1) { 3457 dataFormat = new Pair<>(second, -1); 3458 continue; 3459 } 3460 if (second == -1) { 3461 dataFormat = new Pair<>(first, -1); 3462 continue; 3463 } 3464 } 3465 return dataFormat; 3466 } 3467 3468 if (entryValue.contains("/")) { 3469 String[] rationalNumber = entryValue.split("/"); 3470 if (rationalNumber.length == 2) { 3471 try { 3472 long numerator = Long.parseLong(rationalNumber[0]); 3473 long denominator = Long.parseLong(rationalNumber[1]); 3474 if (numerator < 0L || denominator < 0L) { 3475 return new Pair<>(IFD_FORMAT_SRATIONAL, -1); 3476 } 3477 if (numerator > Integer.MAX_VALUE || denominator > Integer.MAX_VALUE) { 3478 return new Pair<>(IFD_FORMAT_URATIONAL, -1); 3479 } 3480 return new Pair<>(IFD_FORMAT_SRATIONAL, IFD_FORMAT_URATIONAL); 3481 } catch (NumberFormatException e) { 3482 // Ignored 3483 } 3484 } 3485 return new Pair<>(IFD_FORMAT_STRING, -1); 3486 } 3487 try { 3488 Long longValue = Long.parseLong(entryValue); 3489 if (longValue >= 0 && longValue <= 65535) { 3490 return new Pair<>(IFD_FORMAT_USHORT, IFD_FORMAT_ULONG); 3491 } 3492 if (longValue < 0) { 3493 return new Pair<>(IFD_FORMAT_SLONG, -1); 3494 } 3495 return new Pair<>(IFD_FORMAT_ULONG, -1); 3496 } catch (NumberFormatException e) { 3497 // Ignored 3498 } 3499 try { 3500 Double.parseDouble(entryValue); 3501 return new Pair<>(IFD_FORMAT_DOUBLE, -1); 3502 } catch (NumberFormatException e) { 3503 // Ignored 3504 } 3505 return new Pair<>(IFD_FORMAT_STRING, -1); 3506 } 3507 3508 // An input stream to parse EXIF data area, which can be written in either little or big endian 3509 // order. 3510 private static class ByteOrderAwarenessDataInputStream extends ByteArrayInputStream { 3511 private static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN; 3512 private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN; 3513 3514 private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN; 3515 private final long mLength; 3516 private long mPosition; 3517 3518 public ByteOrderAwarenessDataInputStream(byte[] bytes) { 3519 super(bytes); 3520 mLength = bytes.length; 3521 mPosition = 0L; 3522 } 3523 3524 public void setByteOrder(ByteOrder byteOrder) { 3525 mByteOrder = byteOrder; 3526 } 3527 3528 public void seek(long byteCount) throws IOException { 3529 if (mPosition > byteCount) { 3530 mPosition = 0L; 3531 reset(); 3532 } else { 3533 byteCount -= mPosition; 3534 } 3535 if (skip(byteCount) != byteCount) { 3536 throw new IOException("Couldn't seek up to the byteCount"); 3537 } 3538 } 3539 3540 public long peek() { 3541 return mPosition; 3542 } 3543 3544 public void readFully(byte[] buffer) throws IOException { 3545 mPosition += buffer.length; 3546 if (mPosition > mLength) { 3547 throw new EOFException(); 3548 } 3549 if (super.read(buffer, 0, buffer.length) != buffer.length) { 3550 throw new IOException("Couldn't read up to the length of buffer"); 3551 } 3552 } 3553 3554 public byte readByte() throws IOException { 3555 ++mPosition; 3556 if (mPosition > mLength) { 3557 throw new EOFException(); 3558 } 3559 int ch = super.read(); 3560 if (ch < 0) { 3561 throw new EOFException(); 3562 } 3563 return (byte) ch; 3564 } 3565 3566 public short readShort() throws IOException { 3567 mPosition += 2; 3568 if (mPosition > mLength) { 3569 throw new EOFException(); 3570 } 3571 int ch1 = super.read(); 3572 int ch2 = super.read(); 3573 if ((ch1 | ch2) < 0) { 3574 throw new EOFException(); 3575 } 3576 if (mByteOrder == LITTLE_ENDIAN) { 3577 return (short) ((ch2 << 8) + (ch1)); 3578 } else if (mByteOrder == BIG_ENDIAN) { 3579 return (short) ((ch1 << 8) + (ch2)); 3580 } 3581 throw new IOException("Invalid byte order: " + mByteOrder); 3582 } 3583 3584 public int readInt() throws IOException { 3585 mPosition += 4; 3586 if (mPosition > mLength) { 3587 throw new EOFException(); 3588 } 3589 int ch1 = super.read(); 3590 int ch2 = super.read(); 3591 int ch3 = super.read(); 3592 int ch4 = super.read(); 3593 if ((ch1 | ch2 | ch3 | ch4) < 0) { 3594 throw new EOFException(); 3595 } 3596 if (mByteOrder == LITTLE_ENDIAN) { 3597 return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1); 3598 } else if (mByteOrder == BIG_ENDIAN) { 3599 return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); 3600 } 3601 throw new IOException("Invalid byte order: " + mByteOrder); 3602 } 3603 3604 @Override 3605 public long skip(long byteCount) { 3606 long skipped = super.skip(Math.min(byteCount, mLength - mPosition)); 3607 mPosition += skipped; 3608 return skipped; 3609 } 3610 3611 public int readUnsignedShort() throws IOException { 3612 mPosition += 2; 3613 if (mPosition > mLength) { 3614 throw new EOFException(); 3615 } 3616 int ch1 = super.read(); 3617 int ch2 = super.read(); 3618 if ((ch1 | ch2) < 0) { 3619 throw new EOFException(); 3620 } 3621 if (mByteOrder == LITTLE_ENDIAN) { 3622 return ((ch2 << 8) + (ch1)); 3623 } else if (mByteOrder == BIG_ENDIAN) { 3624 return ((ch1 << 8) + (ch2)); 3625 } 3626 throw new IOException("Invalid byte order: " + mByteOrder); 3627 } 3628 3629 public long readUnsignedInt() throws IOException { 3630 return readInt() & 0xffffffffL; 3631 } 3632 3633 public long readLong() throws IOException { 3634 mPosition += 8; 3635 if (mPosition > mLength) { 3636 throw new EOFException(); 3637 } 3638 int ch1 = super.read(); 3639 int ch2 = super.read(); 3640 int ch3 = super.read(); 3641 int ch4 = super.read(); 3642 int ch5 = super.read(); 3643 int ch6 = super.read(); 3644 int ch7 = super.read(); 3645 int ch8 = super.read(); 3646 if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) { 3647 throw new EOFException(); 3648 } 3649 if (mByteOrder == LITTLE_ENDIAN) { 3650 return (((long) ch8 << 56) + ((long) ch7 << 48) + ((long) ch6 << 40) 3651 + ((long) ch5 << 32) + ((long) ch4 << 24) + ((long) ch3 << 16) 3652 + ((long) ch2 << 8) + (long) ch1); 3653 } else if (mByteOrder == BIG_ENDIAN) { 3654 return (((long) ch1 << 56) + ((long) ch2 << 48) + ((long) ch3 << 40) 3655 + ((long) ch4 << 32) + ((long) ch5 << 24) + ((long) ch6 << 16) 3656 + ((long) ch7 << 8) + (long) ch8); 3657 } 3658 throw new IOException("Invalid byte order: " + mByteOrder); 3659 } 3660 3661 public float readFloat() throws IOException { 3662 return Float.intBitsToFloat(readInt()); 3663 } 3664 3665 public double readDouble() throws IOException { 3666 return Double.longBitsToDouble(readLong()); 3667 } 3668 } 3669 3670 // An output stream to write EXIF data area, which can be written in either little or big endian 3671 // order. 3672 private static class ByteOrderAwarenessDataOutputStream extends FilterOutputStream { 3673 private final OutputStream mOutputStream; 3674 private ByteOrder mByteOrder; 3675 3676 public ByteOrderAwarenessDataOutputStream(OutputStream out, ByteOrder byteOrder) { 3677 super(out); 3678 mOutputStream = out; 3679 mByteOrder = byteOrder; 3680 } 3681 3682 public void setByteOrder(ByteOrder byteOrder) { 3683 mByteOrder = byteOrder; 3684 } 3685 3686 public void write(byte[] bytes) throws IOException { 3687 mOutputStream.write(bytes); 3688 } 3689 3690 public void write(byte[] bytes, int offset, int length) throws IOException { 3691 mOutputStream.write(bytes, offset, length); 3692 } 3693 3694 public void writeByte(int val) throws IOException { 3695 mOutputStream.write(val); 3696 } 3697 3698 public void writeShort(short val) throws IOException { 3699 if (mByteOrder == ByteOrder.LITTLE_ENDIAN) { 3700 mOutputStream.write((val >>> 0) & 0xFF); 3701 mOutputStream.write((val >>> 8) & 0xFF); 3702 } else if (mByteOrder == ByteOrder.BIG_ENDIAN) { 3703 mOutputStream.write((val >>> 8) & 0xFF); 3704 mOutputStream.write((val >>> 0) & 0xFF); 3705 } 3706 } 3707 3708 public void writeInt(int val) throws IOException { 3709 if (mByteOrder == ByteOrder.LITTLE_ENDIAN) { 3710 mOutputStream.write((val >>> 0) & 0xFF); 3711 mOutputStream.write((val >>> 8) & 0xFF); 3712 mOutputStream.write((val >>> 16) & 0xFF); 3713 mOutputStream.write((val >>> 24) & 0xFF); 3714 } else if (mByteOrder == ByteOrder.BIG_ENDIAN) { 3715 mOutputStream.write((val >>> 24) & 0xFF); 3716 mOutputStream.write((val >>> 16) & 0xFF); 3717 mOutputStream.write((val >>> 8) & 0xFF); 3718 mOutputStream.write((val >>> 0) & 0xFF); 3719 } 3720 } 3721 3722 public void writeUnsignedShort(int val) throws IOException { 3723 writeShort((short) val); 3724 } 3725 3726 public void writeUnsignedInt(long val) throws IOException { 3727 writeInt((int) val); 3728 } 3729 } 3730 3731 // Swaps image data based on image size 3732 private void swapBasedOnImageSize(@IfdType int firstIfdType, @IfdType int secondIfdType) 3733 throws IOException { 3734 if (mAttributes[firstIfdType].isEmpty() || mAttributes[secondIfdType].isEmpty()) { 3735 if (DEBUG) { 3736 Log.d(TAG, "Cannot perform swap since only one image data exists"); 3737 } 3738 return; 3739 } 3740 3741 ExifAttribute firstImageLengthAttribute = 3742 (ExifAttribute) mAttributes[firstIfdType].get(TAG_IMAGE_LENGTH); 3743 ExifAttribute firstImageWidthAttribute = 3744 (ExifAttribute) mAttributes[firstIfdType].get(TAG_IMAGE_WIDTH); 3745 ExifAttribute secondImageLengthAttribute = 3746 (ExifAttribute) mAttributes[secondIfdType].get(TAG_IMAGE_LENGTH); 3747 ExifAttribute secondImageWidthAttribute = 3748 (ExifAttribute) mAttributes[secondIfdType].get(TAG_IMAGE_WIDTH); 3749 3750 if (firstImageLengthAttribute == null || firstImageWidthAttribute == null) { 3751 if (DEBUG) { 3752 Log.d(TAG, "First image does not contain valid size information"); 3753 } 3754 } else if (secondImageLengthAttribute == null || secondImageWidthAttribute == null) { 3755 if (DEBUG) { 3756 Log.d(TAG, "Second image does not contain valid size information"); 3757 } 3758 } else { 3759 int firstImageLengthValue = firstImageLengthAttribute.getIntValue(mExifByteOrder); 3760 int firstImageWidthValue = firstImageWidthAttribute.getIntValue(mExifByteOrder); 3761 int secondImageLengthValue = secondImageLengthAttribute.getIntValue(mExifByteOrder); 3762 int secondImageWidthValue = secondImageWidthAttribute.getIntValue(mExifByteOrder); 3763 3764 if (firstImageLengthValue < secondImageLengthValue && 3765 firstImageWidthValue < secondImageWidthValue) { 3766 HashMap tempMap = mAttributes[firstIfdType]; 3767 mAttributes[firstIfdType] = mAttributes[secondIfdType]; 3768 mAttributes[secondIfdType] = tempMap; 3769 } 3770 } 3771 } 3772 3773 // Checks if there is a match 3774 private boolean containsMatch(byte[] mainBytes, byte[] findBytes) { 3775 for (int i = 0; i < mainBytes.length - findBytes.length; i++) { 3776 for (int j = 0; j < findBytes.length; j++) { 3777 if (mainBytes[i + j] != findBytes[j]) { 3778 break; 3779 } 3780 if (j == findBytes.length - 1) { 3781 return true; 3782 } 3783 } 3784 } 3785 return false; 3786 } 3787}