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