ExifInterface.java revision bc4fd2c642f7db0a091fe6e9179b0380eda16b36
114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon/* 214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Copyright (C) 2007 The Android Open Source Project 314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Licensed under the Apache License, Version 2.0 (the "License"); 514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * you may not use this file except in compliance with the License. 614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * You may obtain a copy of the License at 714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://www.apache.org/licenses/LICENSE-2.0 914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 1014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Unless required by applicable law or agreed to in writing, software 1114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * distributed under the License is distributed on an "AS IS" BASIS, 1214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See the License for the specific language governing permissions and 1414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * limitations under the License. 1514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 1614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 1714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonpackage android.support.media; 1814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 1914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.content.res.AssetManager; 2014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.graphics.Bitmap; 2114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.graphics.BitmapFactory; 22c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chenimport android.location.Location; 2314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.support.annotation.IntDef; 2414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.support.annotation.NonNull; 2514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.util.Log; 2614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.util.Pair; 2714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 2814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.BufferedInputStream; 2914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.ByteArrayInputStream; 3014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.Closeable; 3114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.DataInput; 3214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.DataInputStream; 3314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.EOFException; 3414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.File; 3514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.FileInputStream; 3614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.FileNotFoundException; 3714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.FileOutputStream; 3814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.FilterOutputStream; 3914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.IOException; 4014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.InputStream; 4114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.OutputStream; 4214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.lang.annotation.Retention; 4314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.lang.annotation.RetentionPolicy; 4414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.nio.ByteBuffer; 4514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.nio.ByteOrder; 4614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.nio.charset.Charset; 4714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.text.ParsePosition; 4814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.text.SimpleDateFormat; 4914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.Arrays; 5014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.Date; 5114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.HashMap; 5214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.HashSet; 53bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangrenimport java.util.List; 5414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.Map; 5514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.TimeZone; 56c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chenimport java.util.concurrent.TimeUnit; 5714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.regex.Matcher; 5814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.regex.Pattern; 5914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 6014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon/** 6114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file. 6214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * <p> 6314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW and RAF. 6414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * <p> 6514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Attribute mutation is supported for JPEG image files. 6614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 6714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonpublic class ExifInterface { 6814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG = "ExifInterface"; 6914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final boolean DEBUG = false; 7014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 7114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The Exif tag names. See Tiff 6.0 Section 3 and Section 8. 7214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 7314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_ARTIST = "Artist"; 7414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 7514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_BITS_PER_SAMPLE = "BitsPerSample"; 7614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 7714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_COMPRESSION = "Compression"; 7814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 7914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_COPYRIGHT = "Copyright"; 8014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 8114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_DATETIME = "DateTime"; 8214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 8314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_IMAGE_DESCRIPTION = "ImageDescription"; 8414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 8514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_IMAGE_LENGTH = "ImageLength"; 8614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 8714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_IMAGE_WIDTH = "ImageWidth"; 8814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 8914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat"; 9014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 9114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength"; 9214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 9314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_MAKE = "Make"; 9414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 9514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_MODEL = "Model"; 9614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 9714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_ORIENTATION = "Orientation"; 9814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 9914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation"; 10014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 10114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration"; 10214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 10314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities"; 10414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 10514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite"; 10614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 10714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_RESOLUTION_UNIT = "ResolutionUnit"; 10814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 10914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_ROWS_PER_STRIP = "RowsPerStrip"; 11014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 11114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel"; 11214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 11314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SOFTWARE = "Software"; 11414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 11514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_STRIP_BYTE_COUNTS = "StripByteCounts"; 11614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 11714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_STRIP_OFFSETS = "StripOffsets"; 11814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 11914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_TRANSFER_FUNCTION = "TransferFunction"; 12014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 12114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_WHITE_POINT = "WhitePoint"; 12214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 12314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_X_RESOLUTION = "XResolution"; 12414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 12514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients"; 12614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 12714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning"; 12814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 12914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling"; 13014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 13114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_Y_RESOLUTION = "YResolution"; 13214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 13314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_APERTURE_VALUE = "ApertureValue"; 13414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 13514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_BRIGHTNESS_VALUE = "BrightnessValue"; 13614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 13714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_CFA_PATTERN = "CFAPattern"; 13814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 13914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_COLOR_SPACE = "ColorSpace"; 14014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 14114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration"; 14214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 14314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel"; 14414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 14514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_CONTRAST = "Contrast"; 14614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 14714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_CUSTOM_RENDERED = "CustomRendered"; 14814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 14914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized"; 15014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 15114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_DATETIME_ORIGINAL = "DateTimeOriginal"; 15214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 15314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription"; 15414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is double. */ 15514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio"; 15614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 15714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_EXIF_VERSION = "ExifVersion"; 15814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is double. */ 15914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue"; 16014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 16114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_EXPOSURE_INDEX = "ExposureIndex"; 16214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 16314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_EXPOSURE_MODE = "ExposureMode"; 16414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 16514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram"; 16614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is double. */ 16714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_EXPOSURE_TIME = "ExposureTime"; 16814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is double. */ 16914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_F_NUMBER = "FNumber"; 17014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 17114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FILE_SOURCE = "FileSource"; 17214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 17314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FLASH = "Flash"; 17414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 17514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FLASH_ENERGY = "FlashEnergy"; 17614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 17714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FLASHPIX_VERSION = "FlashpixVersion"; 17814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 17914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FOCAL_LENGTH = "FocalLength"; 18014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 18114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm"; 18214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 18314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit"; 18414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 18514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution"; 18614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 18714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution"; 18814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 18914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GAIN_CONTROL = "GainControl"; 19014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 19114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings"; 19214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 19314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID"; 19414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 19514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_LIGHT_SOURCE = "LightSource"; 19614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 19714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_MAKER_NOTE = "MakerNote"; 19814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 19914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_MAX_APERTURE_VALUE = "MaxApertureValue"; 20014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 20114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_METERING_MODE = "MeteringMode"; 20214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 20314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_NEW_SUBFILE_TYPE = "NewSubfileType"; 20414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 20514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_OECF = "OECF"; 20614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 20714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension"; 20814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 20914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_PIXEL_Y_DIMENSION = "PixelYDimension"; 21014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 21114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_RELATED_SOUND_FILE = "RelatedSoundFile"; 21214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 21314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SATURATION = "Saturation"; 21414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 21514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType"; 21614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 21714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SCENE_TYPE = "SceneType"; 21814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 21914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SENSING_METHOD = "SensingMethod"; 22014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 22114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SHARPNESS = "Sharpness"; 22214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 22314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue"; 22414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 22514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse"; 22614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 22714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity"; 22814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 22914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SUBFILE_TYPE = "SubfileType"; 23014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 23114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SUBSEC_TIME = "SubSecTime"; 23214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 23314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized"; 23414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 23514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal"; 23614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 23714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SUBJECT_AREA = "SubjectArea"; 23814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is double. */ 23914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance"; 24014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 24114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange"; 24214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 24314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_SUBJECT_LOCATION = "SubjectLocation"; 24414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 24514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_USER_COMMENT = "UserComment"; 24614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 24714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_WHITE_BALANCE = "WhiteBalance"; 24814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 24914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * The altitude (in meters) based on the reference in TAG_GPS_ALTITUDE_REF. 25014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Type is rational. 25114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 25214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_ALTITUDE = "GPSAltitude"; 25314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 25414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 0 if the altitude is above sea level. 1 if the altitude is below sea 25514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * level. Type is int. 25614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 25714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef"; 25814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 25914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation"; 26014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 26114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DOP = "GPSDOP"; 26214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 26314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DATESTAMP = "GPSDateStamp"; 26414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 26514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DEST_BEARING = "GPSDestBearing"; 26614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 26714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef"; 26814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 26914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DEST_DISTANCE = "GPSDestDistance"; 27014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 27114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef"; 27214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 27314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude"; 27414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 27514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef"; 27614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 27714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude"; 27814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 27914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef"; 28014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 28114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_DIFFERENTIAL = "GPSDifferential"; 28214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 28314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_IMG_DIRECTION = "GPSImgDirection"; 28414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 28514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef"; 28614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. Format is "num1/denom1,num2/denom2,num3/denom3". */ 28714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_LATITUDE = "GPSLatitude"; 28814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 28914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef"; 29014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. Format is "num1/denom1,num2/denom2,num3/denom3". */ 29114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_LONGITUDE = "GPSLongitude"; 29214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 29314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef"; 29414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 29514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_MAP_DATUM = "GPSMapDatum"; 29614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 29714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_MEASURE_MODE = "GPSMeasureMode"; 29814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. Name of GPS processing method used for location finding. */ 29914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod"; 30014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 30114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_SATELLITES = "GPSSatellites"; 30214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 30314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_SPEED = "GPSSpeed"; 30414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 30514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_SPEED_REF = "GPSSpeedRef"; 30614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 30714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_STATUS = "GPSStatus"; 30814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. Format is "hh:mm:ss". */ 30914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp"; 31014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is rational. */ 31114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_TRACK = "GPSTrack"; 31214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 31314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_TRACK_REF = "GPSTrackRef"; 31414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 31514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_GPS_VERSION_ID = "GPSVersionID"; 31614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is String. */ 31714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex"; 31814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 31914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength"; 32014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. */ 32114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth"; 32214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. DNG Specification 1.4.0.0. Section 4 */ 32314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_DNG_VERSION = "DNGVersion"; 32414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. DNG Specification 1.4.0.0. Section 4 */ 32514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_DEFAULT_CROP_SIZE = "DefaultCropSize"; 32614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is undefined. See Olympus MakerNote tags in http://www.exiv2.org/tags-olympus.html. */ 32714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage"; 32814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. See Olympus Camera Settings tags in http://www.exiv2.org/tags-olympus.html. */ 32914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart"; 33014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. See Olympus Camera Settings tags in http://www.exiv2.org/tags-olympus.html. */ 33114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength"; 33214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** Type is int. See Olympus Image Processing tags in http://www.exiv2.org/tags-olympus.html. */ 33314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_ORF_ASPECT_FRAME = "AspectFrame"; 33414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 33514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Type is int. See PanasonicRaw tags in 33614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 33714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 33814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder"; 33914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 34014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Type is int. See PanasonicRaw tags in 34114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 34214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 34314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder"; 34414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 34514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Type is int. See PanasonicRaw tags in 34614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 34714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 34814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder"; 34914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 35014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Type is int. See PanasonicRaw tags in 35114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 35214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 35314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder"; 35414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 35514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Type is int. See PanasonicRaw tags in 35614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 35714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 35814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_RW2_ISO = "ISO"; 35914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 36014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Type is undefined. See PanasonicRaw tags in 36114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html 36214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 36314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw"; 36414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 36514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 36614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Private tags used for pointing the other IFD offsets. 36714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * The types of the following tags are int. 36814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See JEITA CP-3451C Section 4.6.3: Exif-specific IFD. 36914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For SubIFD, see Note 1 of Adobe PageMaker® 6.0 TIFF Technical Notes. 37014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 37114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_EXIF_IFD_POINTER = "ExifIFDPointer"; 37214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_GPS_INFO_IFD_POINTER = "GPSInfoIFDPointer"; 37314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_INTEROPERABILITY_IFD_POINTER = "InteroperabilityIFDPointer"; 37414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_SUB_IFD_POINTER = "SubIFDPointer"; 37514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Proprietary pointer tags used for ORF files. 37614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://www.exiv2.org/tags-olympus.html 37714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_ORF_CAMERA_SETTINGS_IFD_POINTER = "CameraSettingsIFDPointer"; 37814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_ORF_IMAGE_PROCESSING_IFD_POINTER = "ImageProcessingIFDPointer"; 37914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 38014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Private tags used for thumbnail information. 38114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_HAS_THUMBNAIL = "HasThumbnail"; 38214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_THUMBNAIL_OFFSET = "ThumbnailOffset"; 38314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_THUMBNAIL_LENGTH = "ThumbnailLength"; 38414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String TAG_THUMBNAIL_DATA = "ThumbnailData"; 38514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int MAX_THUMBNAIL_SIZE = 512; 38614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 38714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Constants used for the Orientation Exif tag. 38814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int ORIENTATION_UNDEFINED = 0; 38914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int ORIENTATION_NORMAL = 1; 39014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int ORIENTATION_FLIP_HORIZONTAL = 2; // left right reversed mirror 39114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int ORIENTATION_ROTATE_180 = 3; 39214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int ORIENTATION_FLIP_VERTICAL = 4; // upside down mirror 39314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // flipped about top-left <--> bottom-right axis 39414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int ORIENTATION_TRANSPOSE = 5; 395bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren public static final int ORIENTATION_ROTATE_90 = 6; // rotate 90 degree clockwise 39614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // flipped about top-right <--> bottom-left axis 39714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int ORIENTATION_TRANSVERSE = 7; 398bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren public static final int ORIENTATION_ROTATE_270 = 8; // rotate 270 degree clockwise 399bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren private static final List<Integer> ROTATION_ORDER = Arrays.asList(ORIENTATION_NORMAL, 400bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren ORIENTATION_ROTATE_90, ORIENTATION_ROTATE_180, ORIENTATION_ROTATE_270); 401bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren private static final List<Integer> FLIPPED_ROTATION_ORDER = Arrays.asList( 402bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren ORIENTATION_FLIP_HORIZONTAL, ORIENTATION_TRANSVERSE, ORIENTATION_FLIP_VERTICAL, 403bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren ORIENTATION_TRANSPOSE); 40414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 40514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Constants used for white balance 40614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int WHITEBALANCE_AUTO = 0; 40714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static final int WHITEBALANCE_MANUAL = 1; 40814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 40914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Maximum size for checking file type signature (see image_type_recognition_lite.cc) 41014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int SIGNATURE_CHECK_SIZE = 5000; 41114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 41214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte[] JPEG_SIGNATURE = new byte[] {(byte) 0xff, (byte) 0xd8, (byte) 0xff}; 41314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String RAF_SIGNATURE = "FUJIFILMCCD-RAW"; 41414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int RAF_OFFSET_TO_JPEG_IMAGE_OFFSET = 84; 41514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int RAF_INFO_SIZE = 160; 41614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int RAF_JPEG_LENGTH_VALUE_SIZE = 4; 41714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 41814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://fileformats.archiveteam.org/wiki/Olympus_ORF 41914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final short ORF_SIGNATURE_1 = 0x4f52; 42014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final short ORF_SIGNATURE_2 = 0x5352; 42114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // There are two formats for Olympus Makernote Headers. Each has different identifiers and 42214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // offsets to the actual data. 42314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://www.exiv2.org/makernote.html#R1 42414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte[] ORF_MAKER_NOTE_HEADER_1 = new byte[] {(byte) 0x4f, (byte) 0x4c, 42514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (byte) 0x59, (byte) 0x4d, (byte) 0x50, (byte) 0x00}; // "OLYMP\0" 42614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte[] ORF_MAKER_NOTE_HEADER_2 = new byte[] {(byte) 0x4f, (byte) 0x4c, 42714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (byte) 0x59, (byte) 0x4d, (byte) 0x50, (byte) 0x55, (byte) 0x53, (byte) 0x00, 42814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (byte) 0x49, (byte) 0x49}; // "OLYMPUS\0II" 42914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int ORF_MAKER_NOTE_HEADER_1_SIZE = 8; 43014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int ORF_MAKER_NOTE_HEADER_2_SIZE = 12; 43114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 43214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://fileformats.archiveteam.org/wiki/RW2 43314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final short RW2_SIGNATURE = 0x0055; 43414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 43514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://fileformats.archiveteam.org/wiki/Pentax_PEF 43614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String PEF_SIGNATURE = "PENTAX"; 43714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://www.exiv2.org/makernote.html#R11 43814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int PEF_MAKER_NOTE_SKIP_SIZE = 6; 43914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 44014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static SimpleDateFormat sFormatter; 44114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 44214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See Exchangeable image file format for digital still cameras: Exif version 2.2. 44314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The following values are for parsing EXIF data area. There are tag groups in EXIF data area. 44414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // They are called "Image File Directory". They have multiple data formats to cover various 44514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // image metadata from GPS longitude to camera model name. 44614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 44714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Types of Exif byte alignments (see JEITA CP-3451C Section 4.5.2) 44814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final short BYTE_ALIGN_II = 0x4949; // II: Intel order 44914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final short BYTE_ALIGN_MM = 0x4d4d; // MM: Motorola order 45014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 45114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // TIFF Header Fixed Constant (see JEITA CP-3451C Section 4.5.2) 45214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte START_CODE = 0x2a; // 42 45314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_OFFSET = 8; 45414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 45514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Formats for the value in IFD entry (See TIFF 6.0 Section 2, "Image File Directory".) 45614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_BYTE = 1; 45714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_STRING = 2; 45814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_USHORT = 3; 45914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_ULONG = 4; 46014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_URATIONAL = 5; 46114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_SBYTE = 6; 46214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_UNDEFINED = 7; 46314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_SSHORT = 8; 46414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_SLONG = 9; 46514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_SRATIONAL = 10; 46614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_SINGLE = 11; 46714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_DOUBLE = 12; 46814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Format indicating a new IFD entry (See Adobe PageMaker® 6.0 TIFF Technical Notes, "New Tag") 46914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_FORMAT_IFD = 13; 47014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Names for the data formats for debugging purpose. 47114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final String[] IFD_FORMAT_NAMES = new String[] { 47214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon "", "BYTE", "STRING", "USHORT", "ULONG", "URATIONAL", "SBYTE", "UNDEFINED", "SSHORT", 47314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon "SLONG", "SRATIONAL", "SINGLE", "DOUBLE" 47414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 47514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Sizes of the components of each IFD value format 47614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int[] IFD_FORMAT_BYTES_PER_FORMAT = new int[] { 47714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 1 47814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 47914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte[] EXIF_ASCII_PREFIX = new byte[] { 48014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 48114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 48214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 48314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 48414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Constants used for Compression tag. 48514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For Value 1, 2, 32773, see TIFF 6.0 Spec Section 3: Bilevel Images, Compression 48614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For Value 6, see TIFF 6.0 Spec Section 22: JPEG Compression, Extensions to Existing Fields 48714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For Value 7, 8, 34892, see DNG Specification 1.4.0.0. Section 3, Compression 48814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 48914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int DATA_UNCOMPRESSED = 1; 49014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int DATA_HUFFMAN_COMPRESSED = 2; 49114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int DATA_JPEG = 6; 49214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int DATA_JPEG_COMPRESSED = 7; 49314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int DATA_DEFLATE_ZIP = 8; 49414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int DATA_PACK_BITS_COMPRESSED = 32773; 49514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int DATA_LOSSY_JPEG = 34892; 49614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 49714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 49814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Constants used for BitsPerSample tag. 49914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For RGB, see TIFF 6.0 Spec Section 6, Differences from Palette Color Images 50014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For Greyscale, see TIFF 6.0 Spec Section 4, Differences from Bilevel Images 50114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 50214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int[] BITS_PER_SAMPLE_RGB = new int[] { 8, 8, 8 }; 50314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int[] BITS_PER_SAMPLE_GREYSCALE_1 = new int[] { 4 }; 50414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int[] BITS_PER_SAMPLE_GREYSCALE_2 = new int[] { 8 }; 50514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 50614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 50714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Constants used for PhotometricInterpretation tag. 50814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For White/Black, see Section 3, Color. 50914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See TIFF 6.0 Spec Section 22, Minimum Requirements for TIFF with JPEG Compression. 51014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 51114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO = 0; 51214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO = 1; 51314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int PHOTOMETRIC_INTERPRETATION_RGB = 2; 51414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int PHOTOMETRIC_INTERPRETATION_YCBCR = 6; 51514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 51614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 51714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Constants used for NewSubfileType tag. 51814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See TIFF 6.0 Spec Section 8 51914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * */ 52014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int ORIGINAL_RESOLUTION_IMAGE = 0; 52114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int REDUCED_RESOLUTION_IMAGE = 1; 52214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 52314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // A class for indicating EXIF rational type. 52414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static class Rational { 52514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final long numerator; 52614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final long denominator; 52714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 528c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen private Rational(double value) { 529c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen this((long) (value * 10000), 10000); 530c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen } 531c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen 53214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private Rational(long numerator, long denominator) { 53314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Handle erroneous case 53414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (denominator == 0) { 53514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.numerator = 0; 53614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.denominator = 1; 53714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 53814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 53914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.numerator = numerator; 54014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.denominator = denominator; 54114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 54214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 54314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 54414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public String toString() { 54514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return numerator + "/" + denominator; 54614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 54714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 54814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public double calculate() { 54914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (double) numerator / denominator; 55014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 55114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 55214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 55314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // A class for indicating EXIF attribute. 55414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static class ExifAttribute { 55514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final int format; 55614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final int numberOfComponents; 55714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final byte[] bytes; 55814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 55914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private ExifAttribute(int format, int numberOfComponents, byte[] bytes) { 56014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.format = format; 56114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.numberOfComponents = numberOfComponents; 56214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.bytes = bytes; 56314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 56414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 56514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createUShort(int[] values, ByteOrder byteOrder) { 56614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final ByteBuffer buffer = ByteBuffer.wrap( 56714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_USHORT] * values.length]); 56814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.order(byteOrder); 56914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int value : values) { 57014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.putShort((short) value); 57114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 57214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_USHORT, values.length, buffer.array()); 57314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 57414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 57514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createUShort(int value, ByteOrder byteOrder) { 57614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return createUShort(new int[] {value}, byteOrder); 57714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 57814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 57914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createULong(long[] values, ByteOrder byteOrder) { 58014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final ByteBuffer buffer = ByteBuffer.wrap( 58114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_ULONG] * values.length]); 58214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.order(byteOrder); 58314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (long value : values) { 58414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.putInt((int) value); 58514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 58614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_ULONG, values.length, buffer.array()); 58714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 58814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 58914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createULong(long value, ByteOrder byteOrder) { 59014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return createULong(new long[] {value}, byteOrder); 59114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 59214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 59314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createSLong(int[] values, ByteOrder byteOrder) { 59414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final ByteBuffer buffer = ByteBuffer.wrap( 59514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_SLONG] * values.length]); 59614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.order(byteOrder); 59714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int value : values) { 59814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.putInt(value); 59914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 60014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_SLONG, values.length, buffer.array()); 60114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 60214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 60314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createSLong(int value, ByteOrder byteOrder) { 60414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return createSLong(new int[] {value}, byteOrder); 60514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 60614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 60714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createByte(String value) { 60814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Exception for GPSAltitudeRef tag 60914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value.length() == 1 && value.charAt(0) >= '0' && value.charAt(0) <= '1') { 61014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final byte[] bytes = new byte[] { (byte) (value.charAt(0) - '0') }; 61114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_BYTE, bytes.length, bytes); 61214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 61314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final byte[] ascii = value.getBytes(ASCII); 61414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_BYTE, ascii.length, ascii); 61514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 61614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 61714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createString(String value) { 61814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final byte[] ascii = (value + '\0').getBytes(ASCII); 61914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_STRING, ascii.length, ascii); 62014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 62114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 62214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createURational(Rational[] values, ByteOrder byteOrder) { 62314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final ByteBuffer buffer = ByteBuffer.wrap( 62414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_URATIONAL] * values.length]); 62514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.order(byteOrder); 62614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (Rational value : values) { 62714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.putInt((int) value.numerator); 62814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.putInt((int) value.denominator); 62914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 63014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_URATIONAL, values.length, buffer.array()); 63114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 63214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 63314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createURational(Rational value, ByteOrder byteOrder) { 63414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return createURational(new Rational[] {value}, byteOrder); 63514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 63614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 63714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createSRational(Rational[] values, ByteOrder byteOrder) { 63814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final ByteBuffer buffer = ByteBuffer.wrap( 63914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_SRATIONAL] * values.length]); 64014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.order(byteOrder); 64114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (Rational value : values) { 64214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.putInt((int) value.numerator); 64314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.putInt((int) value.denominator); 64414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 64514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_SRATIONAL, values.length, buffer.array()); 64614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 64714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 64814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createSRational(Rational value, ByteOrder byteOrder) { 64914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return createSRational(new Rational[] {value}, byteOrder); 65014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 65114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 65214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createDouble(double[] values, ByteOrder byteOrder) { 65314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final ByteBuffer buffer = ByteBuffer.wrap( 65414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_DOUBLE] * values.length]); 65514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.order(byteOrder); 65614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (double value : values) { 65714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon buffer.putDouble(value); 65814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 65914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new ExifAttribute(IFD_FORMAT_DOUBLE, values.length, buffer.array()); 66014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 66114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 66214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public static ExifAttribute createDouble(double value, ByteOrder byteOrder) { 66314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return createDouble(new double[] {value}, byteOrder); 66414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 66514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 66614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 66714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public String toString() { 66814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return "(" + IFD_FORMAT_NAMES[format] + ", data length:" + bytes.length + ")"; 66914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 67014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 67114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private Object getValue(ByteOrder byteOrder) { 672f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes ByteOrderedDataInputStream inputStream = null; 67314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 674f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes inputStream = new ByteOrderedDataInputStream(bytes); 67514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon inputStream.setByteOrder(byteOrder); 67614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon switch (format) { 67714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_BYTE: 67814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SBYTE: { 67914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Exception for GPSAltitudeRef tag 68014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (bytes.length == 1 && bytes[0] >= 0 && bytes[0] <= 1) { 68114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new String(new char[] { (char) (bytes[0] + '0') }); 68214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 68314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new String(bytes, ASCII); 68414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 68514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_UNDEFINED: 68614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_STRING: { 68714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int index = 0; 68814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (numberOfComponents >= EXIF_ASCII_PREFIX.length) { 68914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon boolean same = true; 69014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < EXIF_ASCII_PREFIX.length; ++i) { 69114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (bytes[i] != EXIF_ASCII_PREFIX[i]) { 69214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon same = false; 69314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 69414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 69514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 69614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (same) { 69714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon index = EXIF_ASCII_PREFIX.length; 69814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 69914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 70014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 70114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon StringBuilder stringBuilder = new StringBuilder(); 70214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon while (index < numberOfComponents) { 70314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch = bytes[index]; 70414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (ch == 0) { 70514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 70614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 70714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (ch >= 32) { 70814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append((char) ch); 70914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 71014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append('?'); 71114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 71214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++index; 71314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 71414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return stringBuilder.toString(); 71514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 71614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_USHORT: { 71714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final int[] values = new int[numberOfComponents]; 71814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfComponents; ++i) { 71914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon values[i] = inputStream.readUnsignedShort(); 72014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 72114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return values; 72214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 72314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_ULONG: { 72414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final long[] values = new long[numberOfComponents]; 72514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfComponents; ++i) { 72614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon values[i] = inputStream.readUnsignedInt(); 72714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 72814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return values; 72914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 73014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_URATIONAL: { 73114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final Rational[] values = new Rational[numberOfComponents]; 73214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfComponents; ++i) { 73314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final long numerator = inputStream.readUnsignedInt(); 73414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final long denominator = inputStream.readUnsignedInt(); 73514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon values[i] = new Rational(numerator, denominator); 73614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 73714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return values; 73814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 73914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SSHORT: { 74014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final int[] values = new int[numberOfComponents]; 74114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfComponents; ++i) { 74214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon values[i] = inputStream.readShort(); 74314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 74414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return values; 74514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 74614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SLONG: { 74714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final int[] values = new int[numberOfComponents]; 74814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfComponents; ++i) { 74914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon values[i] = inputStream.readInt(); 75014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 75114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return values; 75214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 75314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SRATIONAL: { 75414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final Rational[] values = new Rational[numberOfComponents]; 75514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfComponents; ++i) { 75614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final long numerator = inputStream.readInt(); 75714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final long denominator = inputStream.readInt(); 75814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon values[i] = new Rational(numerator, denominator); 75914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 76014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return values; 76114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 76214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SINGLE: { 76314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final double[] values = new double[numberOfComponents]; 76414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfComponents; ++i) { 76514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon values[i] = inputStream.readFloat(); 76614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 76714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return values; 76814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 76914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_DOUBLE: { 77014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final double[] values = new double[numberOfComponents]; 77114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfComponents; ++i) { 77214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon values[i] = inputStream.readDouble(); 77314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 77414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return values; 77514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 77614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon default: 77714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 77814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 77914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (IOException e) { 78014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "IOException occurred during reading a value", e); 78114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 782f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes } finally { 783f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes if (inputStream != null) { 784f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes try { 785f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes inputStream.close(); 786f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes } catch (IOException e) { 787f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes Log.e(TAG, "IOException occurred while closing InputStream", e); 788f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes } 789f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes } 79014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 79114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 79214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 79314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public double getDoubleValue(ByteOrder byteOrder) { 79414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Object value = getValue(byteOrder); 79514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value == null) { 79614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("NULL can't be converted to a double value"); 79714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 79814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof String) { 79914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return Double.parseDouble((String) value); 80014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 80114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof long[]) { 80214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long[] array = (long[]) value; 80314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (array.length == 1) { 80414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return array[0]; 80514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 80614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("There are more than one component"); 80714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 80814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof int[]) { 80914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] array = (int[]) value; 81014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (array.length == 1) { 81114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return array[0]; 81214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 81314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("There are more than one component"); 81414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 81514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof double[]) { 81614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon double[] array = (double[]) value; 81714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (array.length == 1) { 81814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return array[0]; 81914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 82014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("There are more than one component"); 82114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 82214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof Rational[]) { 82314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Rational[] array = (Rational[]) value; 82414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (array.length == 1) { 82514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return array[0].calculate(); 82614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 82714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("There are more than one component"); 82814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 82914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("Couldn't find a double value"); 83014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 83114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 83214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int getIntValue(ByteOrder byteOrder) { 83314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Object value = getValue(byteOrder); 83414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value == null) { 83514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("NULL can't be converted to a integer value"); 83614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 83714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof String) { 83814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return Integer.parseInt((String) value); 83914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 84014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof long[]) { 84114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long[] array = (long[]) value; 84214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (array.length == 1) { 84314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (int) array[0]; 84414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 84514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("There are more than one component"); 84614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 84714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof int[]) { 84814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] array = (int[]) value; 84914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (array.length == 1) { 85014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return array[0]; 85114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 85214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("There are more than one component"); 85314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 85414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new NumberFormatException("Couldn't find a integer value"); 85514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 85614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 85714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public String getStringValue(ByteOrder byteOrder) { 85814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Object value = getValue(byteOrder); 85914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value == null) { 86014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 86114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 86214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof String) { 86314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (String) value; 86414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 86514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 86614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final StringBuilder stringBuilder = new StringBuilder(); 86714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof long[]) { 86814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long[] array = (long[]) value; 86914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < array.length; ++i) { 87014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(array[i]); 87114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (i + 1 != array.length) { 87214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(","); 87314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 87414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 87514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return stringBuilder.toString(); 87614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 87714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof int[]) { 87814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] array = (int[]) value; 87914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < array.length; ++i) { 88014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(array[i]); 88114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (i + 1 != array.length) { 88214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(","); 88314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 88414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 88514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return stringBuilder.toString(); 88614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 88714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof double[]) { 88814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon double[] array = (double[]) value; 88914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < array.length; ++i) { 89014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(array[i]); 89114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (i + 1 != array.length) { 89214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(","); 89314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 89414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 89514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return stringBuilder.toString(); 89614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 89714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value instanceof Rational[]) { 89814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Rational[] array = (Rational[]) value; 89914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < array.length; ++i) { 90014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(array[i].numerator); 90114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append('/'); 90214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(array[i].denominator); 90314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (i + 1 != array.length) { 90414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stringBuilder.append(","); 90514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 90614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 90714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return stringBuilder.toString(); 90814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 90914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 91014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 91114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 91214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int size() { 91314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return IFD_FORMAT_BYTES_PER_FORMAT[format] * numberOfComponents; 91414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 91514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 91614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 91714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // A class for indicating EXIF tag. 91814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static class ExifTag { 91914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final int number; 92014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final String name; 92114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final int primaryFormat; 92214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public final int secondaryFormat; 92314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 92414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private ExifTag(String name, int number, int format) { 92514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.name = name; 92614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.number = number; 92714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.primaryFormat = format; 92814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.secondaryFormat = -1; 92914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 93014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 93114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private ExifTag(String name, int number, int primaryFormat, int secondaryFormat) { 93214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.name = name; 93314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.number = number; 93414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.primaryFormat = primaryFormat; 93514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this.secondaryFormat = secondaryFormat; 93614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 93714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 93814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 93914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Primary image IFD TIFF tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 94014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] IFD_TIFF_TAGS = new ExifTag[] { 94114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // For below two, see TIFF 6.0 Spec Section 3: Bilevel Images. 94214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_NEW_SUBFILE_TYPE, 254, IFD_FORMAT_ULONG), 94314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBFILE_TYPE, 255, IFD_FORMAT_ULONG), 94414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_IMAGE_WIDTH, 256, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 94514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_IMAGE_LENGTH, 257, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 94614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_BITS_PER_SAMPLE, 258, IFD_FORMAT_USHORT), 94714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_COMPRESSION, 259, IFD_FORMAT_USHORT), 94814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262, IFD_FORMAT_USHORT), 94914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_IMAGE_DESCRIPTION, 270, IFD_FORMAT_STRING), 95014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_MAKE, 271, IFD_FORMAT_STRING), 95114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_MODEL, 272, IFD_FORMAT_STRING), 95214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 95314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORIENTATION, 274, IFD_FORMAT_USHORT), 95414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SAMPLES_PER_PIXEL, 277, IFD_FORMAT_USHORT), 95514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ROWS_PER_STRIP, 278, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 95614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_STRIP_BYTE_COUNTS, 279, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 95714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_X_RESOLUTION, 282, IFD_FORMAT_URATIONAL), 95814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_Y_RESOLUTION, 283, IFD_FORMAT_URATIONAL), 95914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_PLANAR_CONFIGURATION, 284, IFD_FORMAT_USHORT), 96014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RESOLUTION_UNIT, 296, IFD_FORMAT_USHORT), 96114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_TRANSFER_FUNCTION, 301, IFD_FORMAT_USHORT), 96214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SOFTWARE, 305, IFD_FORMAT_STRING), 96314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DATETIME, 306, IFD_FORMAT_STRING), 96414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ARTIST, 315, IFD_FORMAT_STRING), 96514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_WHITE_POINT, 318, IFD_FORMAT_URATIONAL), 96614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319, IFD_FORMAT_URATIONAL), 96714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See Adobe PageMaker® 6.0 TIFF Technical Notes, Note 1. 96814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG), 96914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG), 97014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG), 97114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529, IFD_FORMAT_URATIONAL), 97214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT), 97314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT), 97414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL), 97514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING), 97614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG), 97714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG), 97814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // RW2 file tags 97914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html) 98014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RW2_SENSOR_TOP_BORDER, 4, IFD_FORMAT_ULONG), 98114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RW2_SENSOR_LEFT_BORDER, 5, IFD_FORMAT_ULONG), 98214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RW2_SENSOR_BOTTOM_BORDER, 6, IFD_FORMAT_ULONG), 98314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RW2_SENSOR_RIGHT_BORDER, 7, IFD_FORMAT_ULONG), 98414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RW2_ISO, 23, IFD_FORMAT_USHORT), 98514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RW2_JPG_FROM_RAW, 46, IFD_FORMAT_UNDEFINED) 98614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 98714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 98814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Primary image IFD Exif Private tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 98914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] IFD_EXIF_TAGS = new ExifTag[] { 99014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXPOSURE_TIME, 33434, IFD_FORMAT_URATIONAL), 99114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_F_NUMBER, 33437, IFD_FORMAT_URATIONAL), 99214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXPOSURE_PROGRAM, 34850, IFD_FORMAT_USHORT), 99314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852, IFD_FORMAT_STRING), 99414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ISO_SPEED_RATINGS, 34855, IFD_FORMAT_USHORT), 99514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_OECF, 34856, IFD_FORMAT_UNDEFINED), 99614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXIF_VERSION, 36864, IFD_FORMAT_STRING), 99714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DATETIME_ORIGINAL, 36867, IFD_FORMAT_STRING), 99814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DATETIME_DIGITIZED, 36868, IFD_FORMAT_STRING), 99914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_COMPONENTS_CONFIGURATION, 37121, IFD_FORMAT_UNDEFINED), 100014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_COMPRESSED_BITS_PER_PIXEL, 37122, IFD_FORMAT_URATIONAL), 100114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SHUTTER_SPEED_VALUE, 37377, IFD_FORMAT_SRATIONAL), 100214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_APERTURE_VALUE, 37378, IFD_FORMAT_URATIONAL), 100314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_BRIGHTNESS_VALUE, 37379, IFD_FORMAT_SRATIONAL), 100414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXPOSURE_BIAS_VALUE, 37380, IFD_FORMAT_SRATIONAL), 100514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_MAX_APERTURE_VALUE, 37381, IFD_FORMAT_URATIONAL), 100614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBJECT_DISTANCE, 37382, IFD_FORMAT_URATIONAL), 100714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_METERING_MODE, 37383, IFD_FORMAT_USHORT), 100814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_LIGHT_SOURCE, 37384, IFD_FORMAT_USHORT), 100914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FLASH, 37385, IFD_FORMAT_USHORT), 101014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FOCAL_LENGTH, 37386, IFD_FORMAT_URATIONAL), 101114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBJECT_AREA, 37396, IFD_FORMAT_USHORT), 101214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_MAKER_NOTE, 37500, IFD_FORMAT_UNDEFINED), 101314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_USER_COMMENT, 37510, IFD_FORMAT_UNDEFINED), 101414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBSEC_TIME, 37520, IFD_FORMAT_STRING), 101514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBSEC_TIME_ORIGINAL, 37521, IFD_FORMAT_STRING), 101614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBSEC_TIME_DIGITIZED, 37522, IFD_FORMAT_STRING), 101714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FLASHPIX_VERSION, 40960, IFD_FORMAT_UNDEFINED), 101814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_COLOR_SPACE, 40961, IFD_FORMAT_USHORT), 101914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_PIXEL_X_DIMENSION, 40962, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 102014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_PIXEL_Y_DIMENSION, 40963, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 102114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RELATED_SOUND_FILE, 40964, IFD_FORMAT_STRING), 102214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG), 102314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FLASH_ENERGY, 41483, IFD_FORMAT_URATIONAL), 102414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SPATIAL_FREQUENCY_RESPONSE, 41484, IFD_FORMAT_UNDEFINED), 102514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FOCAL_PLANE_X_RESOLUTION, 41486, IFD_FORMAT_URATIONAL), 102614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FOCAL_PLANE_Y_RESOLUTION, 41487, IFD_FORMAT_URATIONAL), 102714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FOCAL_PLANE_RESOLUTION_UNIT, 41488, IFD_FORMAT_USHORT), 102814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBJECT_LOCATION, 41492, IFD_FORMAT_USHORT), 102914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXPOSURE_INDEX, 41493, IFD_FORMAT_URATIONAL), 103014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SENSING_METHOD, 41495, IFD_FORMAT_USHORT), 103114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FILE_SOURCE, 41728, IFD_FORMAT_UNDEFINED), 103214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SCENE_TYPE, 41729, IFD_FORMAT_UNDEFINED), 103314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_CFA_PATTERN, 41730, IFD_FORMAT_UNDEFINED), 103414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_CUSTOM_RENDERED, 41985, IFD_FORMAT_USHORT), 103514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXPOSURE_MODE, 41986, IFD_FORMAT_USHORT), 103614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_WHITE_BALANCE, 41987, IFD_FORMAT_USHORT), 103714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DIGITAL_ZOOM_RATIO, 41988, IFD_FORMAT_URATIONAL), 103814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_FOCAL_LENGTH_IN_35MM_FILM, 41989, IFD_FORMAT_USHORT), 103914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SCENE_CAPTURE_TYPE, 41990, IFD_FORMAT_USHORT), 104014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GAIN_CONTROL, 41991, IFD_FORMAT_USHORT), 104114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_CONTRAST, 41992, IFD_FORMAT_USHORT), 104214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SATURATION, 41993, IFD_FORMAT_USHORT), 104314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SHARPNESS, 41994, IFD_FORMAT_USHORT), 104414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DEVICE_SETTING_DESCRIPTION, 41995, IFD_FORMAT_UNDEFINED), 104514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBJECT_DISTANCE_RANGE, 41996, IFD_FORMAT_USHORT), 104614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_IMAGE_UNIQUE_ID, 42016, IFD_FORMAT_STRING), 104714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DNG_VERSION, 50706, IFD_FORMAT_BYTE), 104814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DEFAULT_CROP_SIZE, 50720, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG) 104914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 105014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 105114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Primary image IFD GPS Info tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 105214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] IFD_GPS_TAGS = new ExifTag[] { 105314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_VERSION_ID, 0, IFD_FORMAT_BYTE), 105414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_LATITUDE_REF, 1, IFD_FORMAT_STRING), 105514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_LATITUDE, 2, IFD_FORMAT_URATIONAL), 105614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_LONGITUDE_REF, 3, IFD_FORMAT_STRING), 105714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_LONGITUDE, 4, IFD_FORMAT_URATIONAL), 105814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_ALTITUDE_REF, 5, IFD_FORMAT_BYTE), 105914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_ALTITUDE, 6, IFD_FORMAT_URATIONAL), 106014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_TIMESTAMP, 7, IFD_FORMAT_URATIONAL), 106114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_SATELLITES, 8, IFD_FORMAT_STRING), 106214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_STATUS, 9, IFD_FORMAT_STRING), 106314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_MEASURE_MODE, 10, IFD_FORMAT_STRING), 106414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DOP, 11, IFD_FORMAT_URATIONAL), 106514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_SPEED_REF, 12, IFD_FORMAT_STRING), 106614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_SPEED, 13, IFD_FORMAT_URATIONAL), 106714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_TRACK_REF, 14, IFD_FORMAT_STRING), 106814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_TRACK, 15, IFD_FORMAT_URATIONAL), 106914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_IMG_DIRECTION_REF, 16, IFD_FORMAT_STRING), 107014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_IMG_DIRECTION, 17, IFD_FORMAT_URATIONAL), 107114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_MAP_DATUM, 18, IFD_FORMAT_STRING), 107214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DEST_LATITUDE_REF, 19, IFD_FORMAT_STRING), 107314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DEST_LATITUDE, 20, IFD_FORMAT_URATIONAL), 107414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DEST_LONGITUDE_REF, 21, IFD_FORMAT_STRING), 107514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DEST_LONGITUDE, 22, IFD_FORMAT_URATIONAL), 107614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DEST_BEARING_REF, 23, IFD_FORMAT_STRING), 107714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DEST_BEARING, 24, IFD_FORMAT_URATIONAL), 107814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DEST_DISTANCE_REF, 25, IFD_FORMAT_STRING), 107914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DEST_DISTANCE, 26, IFD_FORMAT_URATIONAL), 108014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_PROCESSING_METHOD, 27, IFD_FORMAT_UNDEFINED), 108114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_AREA_INFORMATION, 28, IFD_FORMAT_UNDEFINED), 108214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DATESTAMP, 29, IFD_FORMAT_STRING), 108314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_DIFFERENTIAL, 30, IFD_FORMAT_USHORT) 108414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 108514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Primary image IFD Interoperability tag (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 108614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] IFD_INTEROPERABILITY_TAGS = new ExifTag[] { 108714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_INTEROPERABILITY_INDEX, 1, IFD_FORMAT_STRING) 108814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 108914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // IFD Thumbnail tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels) 109014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] IFD_THUMBNAIL_TAGS = new ExifTag[] { 109114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // For below two, see TIFF 6.0 Spec Section 3: Bilevel Images. 109214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_NEW_SUBFILE_TYPE, 254, IFD_FORMAT_ULONG), 109314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUBFILE_TYPE, 255, IFD_FORMAT_ULONG), 109414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_THUMBNAIL_IMAGE_WIDTH, 256, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 109514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_THUMBNAIL_IMAGE_LENGTH, 257, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 109614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_BITS_PER_SAMPLE, 258, IFD_FORMAT_USHORT), 109714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_COMPRESSION, 259, IFD_FORMAT_USHORT), 109814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262, IFD_FORMAT_USHORT), 109914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_IMAGE_DESCRIPTION, 270, IFD_FORMAT_STRING), 110014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_MAKE, 271, IFD_FORMAT_STRING), 110114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_MODEL, 272, IFD_FORMAT_STRING), 110214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 110314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORIENTATION, 274, IFD_FORMAT_USHORT), 110414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SAMPLES_PER_PIXEL, 277, IFD_FORMAT_USHORT), 110514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ROWS_PER_STRIP, 278, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 110614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_STRIP_BYTE_COUNTS, 279, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG), 110714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_X_RESOLUTION, 282, IFD_FORMAT_URATIONAL), 110814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_Y_RESOLUTION, 283, IFD_FORMAT_URATIONAL), 110914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_PLANAR_CONFIGURATION, 284, IFD_FORMAT_USHORT), 111014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_RESOLUTION_UNIT, 296, IFD_FORMAT_USHORT), 111114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_TRANSFER_FUNCTION, 301, IFD_FORMAT_USHORT), 111214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SOFTWARE, 305, IFD_FORMAT_STRING), 111314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DATETIME, 306, IFD_FORMAT_STRING), 111414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ARTIST, 315, IFD_FORMAT_STRING), 111514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_WHITE_POINT, 318, IFD_FORMAT_URATIONAL), 111614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319, IFD_FORMAT_URATIONAL), 111714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See Adobe PageMaker® 6.0 TIFF Technical Notes, Note 1. 111814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG), 111914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG), 112014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG), 112114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529, IFD_FORMAT_URATIONAL), 112214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT), 112314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT), 112414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL), 112514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING), 112614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG), 112714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG), 112814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DNG_VERSION, 50706, IFD_FORMAT_BYTE), 112914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_DEFAULT_CROP_SIZE, 50720, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG) 113014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 113114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 113214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // RAF file tag (See piex.cc line 372) 113314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag TAG_RAF_IMAGE_SIZE = 113414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT); 113514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 113614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // ORF file tags (See http://www.exiv2.org/tags-olympus.html) 113714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] ORF_MAKER_NOTE_TAGS = new ExifTag[] { 113814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORF_THUMBNAIL_IMAGE, 256, IFD_FORMAT_UNDEFINED), 113914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORF_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_ULONG), 114014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORF_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_ULONG) 114114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 114214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] ORF_CAMERA_SETTINGS_TAGS = new ExifTag[] { 114314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORF_PREVIEW_IMAGE_START, 257, IFD_FORMAT_ULONG), 114414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORF_PREVIEW_IMAGE_LENGTH, 258, IFD_FORMAT_ULONG) 114514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 114614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] ORF_IMAGE_PROCESSING_TAGS = new ExifTag[] { 114714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORF_ASPECT_FRAME, 4371, IFD_FORMAT_USHORT) 114814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 114914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // PEF file tag (See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Pentax.html) 115014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] PEF_TAGS = new ExifTag[] { 115114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_COLOR_SPACE, 55, IFD_FORMAT_USHORT) 115214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 115314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 115414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See JEITA CP-3451C Section 4.6.3: Exif-specific IFD. 115514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The following values are used for indicating pointers to the other Image File Directories. 115614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 115714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Indices of Exif Ifd tag groups 115814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** @hide */ 115914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Retention(RetentionPolicy.SOURCE) 116014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @IntDef({IFD_TYPE_PRIMARY, IFD_TYPE_EXIF, IFD_TYPE_GPS, IFD_TYPE_INTEROPERABILITY, 116114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon IFD_TYPE_THUMBNAIL, IFD_TYPE_PREVIEW, IFD_TYPE_ORF_MAKER_NOTE, 116214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon IFD_TYPE_ORF_CAMERA_SETTINGS, IFD_TYPE_ORF_IMAGE_PROCESSING, IFD_TYPE_PEF}) 116314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public @interface IfdType {} 116414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 116514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_PRIMARY = 0; 116614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_EXIF = 1; 116714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_GPS = 2; 116814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_INTEROPERABILITY = 3; 116914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_THUMBNAIL = 4; 117014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_PREVIEW = 5; 117114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_ORF_MAKER_NOTE = 6; 117214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_ORF_CAMERA_SETTINGS = 7; 117314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_ORF_IMAGE_PROCESSING = 8; 117414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IFD_TYPE_PEF = 9; 117514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 117614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // List of Exif tag groups 117714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[][] EXIF_TAGS = new ExifTag[][] { 117814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon IFD_TIFF_TAGS, IFD_EXIF_TAGS, IFD_GPS_TAGS, IFD_INTEROPERABILITY_TAGS, 117914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon IFD_THUMBNAIL_TAGS, IFD_TIFF_TAGS, ORF_MAKER_NOTE_TAGS, ORF_CAMERA_SETTINGS_TAGS, 118014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ORF_IMAGE_PROCESSING_TAGS, PEF_TAGS 118114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 118214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // List of tags for pointing to the other image file directory offset. 118314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag[] EXIF_POINTER_TAGS = new ExifTag[] { 118414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG), 118514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG), 118614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG), 118714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG), 118814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORF_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_BYTE), 118914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_ORF_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_BYTE) 119014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon }; 119114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 119214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Tags for indicating the thumbnail offset and length 119314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag JPEG_INTERCHANGE_FORMAT_TAG = 119414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG); 119514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ExifTag JPEG_INTERCHANGE_FORMAT_LENGTH_TAG = 119614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG); 119714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 119814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Mappings from tag number to tag name and each item represents one IFD tag group. 1199abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas @SuppressWarnings("unchecked") 1200abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas private static final HashMap<Integer, ExifTag>[] sExifTagMapsForReading = 1201abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas new HashMap[EXIF_TAGS.length]; 120214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Mappings from tag name to tag number and each item represents one IFD tag group. 1203abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas @SuppressWarnings("unchecked") 1204abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas private static final HashMap<String, ExifTag>[] sExifTagMapsForWriting = 1205abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas new HashMap[EXIF_TAGS.length]; 120614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final HashSet<String> sTagSetForCompatibility = new HashSet<>(Arrays.asList( 120714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon TAG_F_NUMBER, TAG_DIGITAL_ZOOM_RATIO, TAG_EXPOSURE_TIME, TAG_SUBJECT_DISTANCE, 120814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon TAG_GPS_TIMESTAMP)); 120914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Mappings from tag number to IFD type for pointer tags. 1210abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas @SuppressWarnings("unchecked") 1211abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas private static final HashMap<Integer, Integer> sExifPointerTagMap = new HashMap(); 121214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 121314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See JPEG File Interchange Format Version 1.02. 121414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The following values are defined for handling JPEG streams. In this implementation, we are 121514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // not only getting information from EXIF but also from some JPEG special segments such as 121614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // MARKER_COM for user comment and MARKER_SOFx for image width and height. 121714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 121814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final Charset ASCII = Charset.forName("US-ASCII"); 121914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Identifier for EXIF APP1 segment in JPEG 122014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte[] IDENTIFIER_EXIF_APP1 = "Exif\0\0".getBytes(ASCII); 122114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // JPEG segment markers, that each marker consumes two bytes beginning with 0xff and ending with 122214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // the indicator. There is no SOF4, SOF8, SOF16 markers in JPEG and SOFx markers indicates start 122314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // of frame(baseline DCT) and the image size info exists in its beginning part. 122414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER = (byte) 0xff; 122514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOI = (byte) 0xd8; 122614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF0 = (byte) 0xc0; 122714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF1 = (byte) 0xc1; 122814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF2 = (byte) 0xc2; 122914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF3 = (byte) 0xc3; 123014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF5 = (byte) 0xc5; 123114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF6 = (byte) 0xc6; 123214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF7 = (byte) 0xc7; 123314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF9 = (byte) 0xc9; 123414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF10 = (byte) 0xca; 123514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF11 = (byte) 0xcb; 123614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF13 = (byte) 0xcd; 123714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF14 = (byte) 0xce; 123814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOF15 = (byte) 0xcf; 123914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_SOS = (byte) 0xda; 124014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_APP1 = (byte) 0xe1; 124114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_COM = (byte) 0xfe; 124214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final byte MARKER_EOI = (byte) 0xd9; 124314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 124414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Supported Image File Types 124514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_UNKNOWN = 0; 124614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_ARW = 1; 124714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_CR2 = 2; 124814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_DNG = 3; 124914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_JPEG = 4; 125014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_NEF = 5; 125114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_NRW = 6; 125214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_ORF = 7; 125314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_PEF = 8; 125414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_RAF = 9; 125514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_RW2 = 10; 125614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final int IMAGE_TYPE_SRW = 11; 125714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 125814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon static { 125914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); 126014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); 126114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 126214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Build up the hash tables to look up Exif tags for reading Exif tags. 126314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) { 1264abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas sExifTagMapsForReading[ifdType] = new HashMap<>(); 1265abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas sExifTagMapsForWriting[ifdType] = new HashMap<>(); 126614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (ExifTag tag : EXIF_TAGS[ifdType]) { 126714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sExifTagMapsForReading[ifdType].put(tag.number, tag); 126814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sExifTagMapsForWriting[ifdType].put(tag.name, tag); 126914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 127014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 127114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 127214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Build up the hash table to look up Exif pointer tags. 127314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sExifPointerTagMap.put(EXIF_POINTER_TAGS[0].number, IFD_TYPE_PREVIEW); // 330 127414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sExifPointerTagMap.put(EXIF_POINTER_TAGS[1].number, IFD_TYPE_EXIF); // 34665 127514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sExifPointerTagMap.put(EXIF_POINTER_TAGS[2].number, IFD_TYPE_GPS); // 34853 127614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sExifPointerTagMap.put(EXIF_POINTER_TAGS[3].number, IFD_TYPE_INTEROPERABILITY); // 40965 127714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sExifPointerTagMap.put(EXIF_POINTER_TAGS[4].number, IFD_TYPE_ORF_CAMERA_SETTINGS); // 8224 127814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sExifPointerTagMap.put(EXIF_POINTER_TAGS[5].number, IFD_TYPE_ORF_IMAGE_PROCESSING); // 8256 127914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 128014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 128114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private final String mFilename; 128214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private final AssetManager.AssetInputStream mAssetInputStream; 128314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mMimeType; 1284abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas @SuppressWarnings("unchecked") 1285abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas private final HashMap<String, ExifAttribute>[] mAttributes = new HashMap[EXIF_TAGS.length]; 128614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN; 128714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private boolean mHasThumbnail; 128814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The following values used for indicating a thumbnail position. 128914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mThumbnailOffset; 129014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mThumbnailLength; 129114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private byte[] mThumbnailBytes; 129214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mThumbnailCompression; 129314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mExifOffset; 129414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mOrfMakerNoteOffset; 129514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mOrfThumbnailOffset; 129614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mOrfThumbnailLength; 129714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mRw2JpgFromRawOffset; 129814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private boolean mIsSupportedFile; 129914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 130014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Pattern to check non zero timestamp 130114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*"); 130214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Pattern to check gps timestamp 130314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final Pattern sGpsTimestampPattern = 130414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Pattern.compile("^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$"); 130514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 130614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 130714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Reads Exif tags from the specified image file. 130814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 130914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public ExifInterface(String filename) throws IOException { 131014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (filename == null) { 131114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IllegalArgumentException("filename cannot be null"); 131214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 131314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon FileInputStream in = null; 131414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAssetInputStream = null; 131514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mFilename = filename; 131614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 131714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in = new FileInputStream(filename); 131814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon loadAttributes(in); 131914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } finally { 132014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon closeQuietly(in); 132114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 132214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 132314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 132414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 132514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Reads Exif tags from the specified image input stream. Attribute mutation is not supported 132614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * for input streams. The given input stream will proceed its current position. Developers 132746ffc16f1c2e80e8fc401a5a440c3c3a847b4ba7Hyundo Moon * should close the input stream after use. This constructor is not intended to be used with 132846ffc16f1c2e80e8fc401a5a440c3c3a847b4ba7Hyundo Moon * an input stream that performs any networking operations. 132914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 133014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public ExifInterface(InputStream inputStream) throws IOException { 133114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (inputStream == null) { 133214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IllegalArgumentException("inputStream cannot be null"); 133314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 133414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mFilename = null; 133514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (inputStream instanceof AssetManager.AssetInputStream) { 133614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAssetInputStream = (AssetManager.AssetInputStream) inputStream; 133714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 133814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAssetInputStream = null; 133914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 134014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon loadAttributes(inputStream); 134114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 134214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 134314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 134414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns the EXIF attribute of the specified tag or {@code null} if there is no such tag in 134514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * the image file. 134614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 134714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param tag the name of the tag. 134814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 134914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private ExifAttribute getExifAttribute(String tag) { 135014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieves all tag groups. The value from primary image tag group has a higher priority 135114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // than the value from the thumbnail tag group if there are more than one candidates. 135214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < EXIF_TAGS.length; ++i) { 1353abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas ExifAttribute value = mAttributes[i].get(tag); 135414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value != null) { 1355abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas return value; 135614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 135714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 135814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 135914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 136014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 136114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 136214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns the value of the specified tag or {@code null} if there 136314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * is no such tag in the image file. 136414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 136514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param tag the name of the tag. 136614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 136714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public String getAttribute(String tag) { 136814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute attribute = getExifAttribute(tag); 136914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (attribute != null) { 137014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!sTagSetForCompatibility.contains(tag)) { 137114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return attribute.getStringValue(mExifByteOrder); 137214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 137314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (tag.equals(TAG_GPS_TIMESTAMP)) { 137414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Convert the rational values to the custom formats for backwards compatibility. 137514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (attribute.format != IFD_FORMAT_URATIONAL 137614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon && attribute.format != IFD_FORMAT_SRATIONAL) { 137714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "GPS Timestamp format is not rational. format=" + attribute.format); 137814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 137914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 138014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Rational[] array = (Rational[]) attribute.getValue(mExifByteOrder); 138114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (array == null || array.length != 3) { 138214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Invalid GPS Timestamp array. array=" + Arrays.toString(array)); 138314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 138414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 138514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return String.format("%02d:%02d:%02d", 138614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (int) ((float) array[0].numerator / array[0].denominator), 138714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (int) ((float) array[1].numerator / array[1].denominator), 138814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (int) ((float) array[2].numerator / array[2].denominator)); 138914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 139014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 139114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return Double.toString(attribute.getDoubleValue(mExifByteOrder)); 139214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException e) { 139314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 139414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 139514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 139614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 139714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 139814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 139914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 140014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns the integer value of the specified tag. If there is no such tag 140114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * in the image file or the value cannot be parsed as integer, return 140214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * <var>defaultValue</var>. 140314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 140414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param tag the name of the tag. 140514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param defaultValue the value to return if the tag is not available. 140614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 140714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int getAttributeInt(String tag, int defaultValue) { 140814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute exifAttribute = getExifAttribute(tag); 140914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (exifAttribute == null) { 141014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return defaultValue; 141114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 141214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 141314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 141414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return exifAttribute.getIntValue(mExifByteOrder); 141514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException e) { 141614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return defaultValue; 141714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 141814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 141914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 142014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 142114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns the double value of the tag that is specified as rational or contains a 142214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * double-formatted value. If there is no such tag in the image file or the value cannot be 142314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * parsed as double, return <var>defaultValue</var>. 142414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 142514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param tag the name of the tag. 142614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param defaultValue the value to return if the tag is not available. 142714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 142814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public double getAttributeDouble(String tag, double defaultValue) { 142914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute exifAttribute = getExifAttribute(tag); 143014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (exifAttribute == null) { 143114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return defaultValue; 143214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 143314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 143414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 143514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return exifAttribute.getDoubleValue(mExifByteOrder); 143614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException e) { 143714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return defaultValue; 143814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 143914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 144014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 144114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 1442bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren * Sets the value of the specified tag. 144314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 144414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param tag the name of the tag. 144514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param value the value of the tag. 144614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 144714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void setAttribute(String tag, String value) { 144814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Convert the given value to rational values for backwards compatibility. 144914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value != null && sTagSetForCompatibility.contains(tag)) { 145014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (tag.equals(TAG_GPS_TIMESTAMP)) { 145114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Matcher m = sGpsTimestampPattern.matcher(value); 145214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!m.find()) { 145314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Invalid value for " + tag + " : " + value); 145414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 145514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 145614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon value = Integer.parseInt(m.group(1)) + "/1," + Integer.parseInt(m.group(2)) + "/1," 145714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + Integer.parseInt(m.group(3)) + "/1"; 145814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 145914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 146014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon double doubleValue = Double.parseDouble(value); 1461c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen value = new Rational(doubleValue).toString(); 146214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException e) { 146314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Invalid value for " + tag + " : " + value); 146414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 146514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 146614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 146714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 146814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 146914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0 ; i < EXIF_TAGS.length; ++i) { 147014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (i == IFD_TYPE_THUMBNAIL && !mHasThumbnail) { 147114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 147214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 1473abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas final ExifTag exifTag = sExifTagMapsForWriting[i].get(tag); 1474abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas if (exifTag != null) { 147514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (value == null) { 147614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].remove(tag); 147714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 147814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 147914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Pair<Integer, Integer> guess = guessDataFormat(value); 148014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int dataFormat; 148114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (exifTag.primaryFormat == guess.first || exifTag.primaryFormat == guess.second) { 148214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataFormat = exifTag.primaryFormat; 148314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (exifTag.secondaryFormat != -1 && (exifTag.secondaryFormat == guess.first 148414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon || exifTag.secondaryFormat == guess.second)) { 148514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataFormat = exifTag.secondaryFormat; 148614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (exifTag.primaryFormat == IFD_FORMAT_BYTE 148714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon || exifTag.primaryFormat == IFD_FORMAT_UNDEFINED 148814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon || exifTag.primaryFormat == IFD_FORMAT_STRING) { 148914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataFormat = exifTag.primaryFormat; 149014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 149114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Given tag (" + tag + ") value didn't match with one of expected " 149214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + "formats: " + IFD_FORMAT_NAMES[exifTag.primaryFormat] 149314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + (exifTag.secondaryFormat == -1 ? "" : ", " 149414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + IFD_FORMAT_NAMES[exifTag.secondaryFormat]) + " (guess: " 149514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + IFD_FORMAT_NAMES[guess.first] + (guess.second == -1 ? "" : ", " 149614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + IFD_FORMAT_NAMES[guess.second]) + ")"); 149714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 149814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 149914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon switch (dataFormat) { 150014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_BYTE: { 150114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, ExifAttribute.createByte(value)); 150214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 150314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 150414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_UNDEFINED: 150514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_STRING: { 150614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, ExifAttribute.createString(value)); 150714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 150814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 150914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_USHORT: { 151014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final String[] values = value.split(","); 151114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final int[] intArray = new int[values.length]; 151214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int j = 0; j < values.length; ++j) { 151314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon intArray[j] = Integer.parseInt(values[j]); 151414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 151514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, 151614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(intArray, mExifByteOrder)); 151714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 151814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 151914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SLONG: { 152014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final String[] values = value.split(","); 152114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final int[] intArray = new int[values.length]; 152214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int j = 0; j < values.length; ++j) { 152314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon intArray[j] = Integer.parseInt(values[j]); 152414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 152514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, 152614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createSLong(intArray, mExifByteOrder)); 152714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 152814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 152914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_ULONG: { 153014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final String[] values = value.split(","); 153114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final long[] longArray = new long[values.length]; 153214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int j = 0; j < values.length; ++j) { 153314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon longArray[j] = Long.parseLong(values[j]); 153414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 153514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, 153614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(longArray, mExifByteOrder)); 153714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 153814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 153914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_URATIONAL: { 154014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final String[] values = value.split(","); 154114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final Rational[] rationalArray = new Rational[values.length]; 154214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int j = 0; j < values.length; ++j) { 154314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final String[] numbers = values[j].split("/"); 154477966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]), 154577966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon (long) Double.parseDouble(numbers[1])); 154614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 154714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, 154814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createURational(rationalArray, mExifByteOrder)); 154914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 155014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 155114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SRATIONAL: { 155214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final String[] values = value.split(","); 155314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final Rational[] rationalArray = new Rational[values.length]; 155414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int j = 0; j < values.length; ++j) { 155514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final String[] numbers = values[j].split("/"); 155677966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]), 155777966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon (long) Double.parseDouble(numbers[1])); 155814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 155914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, 156014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createSRational(rationalArray, mExifByteOrder)); 156114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 156214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 156314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_DOUBLE: { 156414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final String[] values = value.split(","); 156514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final double[] doubleArray = new double[values.length]; 156614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int j = 0; j < values.length; ++j) { 156714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon doubleArray[j] = Double.parseDouble(values[j]); 156814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 156914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, 157014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createDouble(doubleArray, mExifByteOrder)); 157114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 157214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 157314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon default: 157414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Data format isn't one of expected formats: " + dataFormat); 157514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 157614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 157714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 157814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 157914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 158014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 158114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 1582bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren * Resets the {@link #TAG_ORIENTATION} of the image to be {@link #ORIENTATION_NORMAL}. 1583bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren */ 1584bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren public void resetOrientation() { 1585bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren setAttribute(TAG_ORIENTATION, Integer.toString(ORIENTATION_NORMAL)); 1586bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } 1587bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren 1588bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren /** 1589bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren * Rotates the image by the given degree clockwise. The degree should be a multiple of 1590bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren * 90 (e.g, 90, 180, -90, etc.). 1591bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren * 1592bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren * @param degree The degree of rotation. 1593bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren */ 1594bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren public void rotate(int degree) { 1595bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren if (degree % 90 !=0) { 1596bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren throw new IllegalArgumentException("degree should be a multiple of 90"); 1597bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } 1598bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren 1599bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren int currentOrientation = getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL); 1600bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren int currentIndex, newIndex; 1601bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren int resultOrientation; 1602bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren if (ROTATION_ORDER.contains(currentOrientation)) { 1603bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren currentIndex = ROTATION_ORDER.indexOf(currentOrientation); 1604bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren newIndex = (currentIndex + degree / 90) % 4; 1605bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren newIndex += newIndex < 0 ? 4 : 0; 1606bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ROTATION_ORDER.get(newIndex); 1607bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } else if (FLIPPED_ROTATION_ORDER.contains(currentOrientation)) { 1608bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren currentIndex = FLIPPED_ROTATION_ORDER.indexOf(currentOrientation); 1609bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren newIndex = (currentIndex + degree / 90) % 4; 1610bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren newIndex += newIndex < 0 ? 4 : 0; 1611bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = FLIPPED_ROTATION_ORDER.get(newIndex); 1612bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } else { 1613bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_UNDEFINED; 1614bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } 1615bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren 1616bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren setAttribute(TAG_ORIENTATION, Integer.toString(resultOrientation)); 1617bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } 1618bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren 1619bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren /** 1620bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren * Flips the image vertically. 1621bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren */ 1622bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren public void flipVertically() { 1623bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren int currentOrientation = getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL); 1624bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren int resultOrientation; 1625bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren switch (currentOrientation) { 1626bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_FLIP_HORIZONTAL: 1627bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_ROTATE_180; 1628bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1629bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_ROTATE_180: 1630bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_FLIP_HORIZONTAL; 1631bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1632bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_FLIP_VERTICAL: 1633bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_NORMAL; 1634bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1635bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_TRANSPOSE: 1636bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_ROTATE_270; 1637bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1638bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_ROTATE_90: 1639bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_TRANSVERSE; 1640bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1641bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_TRANSVERSE: 1642bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_ROTATE_90; 1643bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1644bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_ROTATE_270: 1645bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_TRANSPOSE; 1646bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1647bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_NORMAL: 1648bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_FLIP_VERTICAL; 1649bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1650bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_UNDEFINED: 1651bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren default: 1652bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_UNDEFINED; 1653bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1654bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } 1655bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren setAttribute(TAG_ORIENTATION, Integer.toString(resultOrientation)); 1656bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } 1657bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren 1658bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren /** 1659bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren * Flips the image horizontally. 1660bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren */ 1661bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren public void flipHorizontally() { 1662bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren int currentOrientation = getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL); 1663bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren int resultOrientation; 1664bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren switch (currentOrientation) { 1665bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_FLIP_HORIZONTAL: 1666bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_NORMAL; 1667bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1668bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_ROTATE_180: 1669bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_FLIP_VERTICAL; 1670bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1671bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_FLIP_VERTICAL: 1672bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_ROTATE_180; 1673bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1674bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_TRANSPOSE: 1675bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_ROTATE_90; 1676bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1677bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_ROTATE_90: 1678bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_TRANSPOSE; 1679bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1680bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_TRANSVERSE: 1681bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_ROTATE_270; 1682bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1683bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_ROTATE_270: 1684bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_TRANSVERSE; 1685bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1686bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_NORMAL: 1687bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_FLIP_HORIZONTAL; 1688bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1689bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren case ORIENTATION_UNDEFINED: 1690bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren default: 1691bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren resultOrientation = ORIENTATION_UNDEFINED; 1692bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren break; 1693bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } 1694bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren setAttribute(TAG_ORIENTATION, Integer.toString(resultOrientation)); 1695bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren } 1696bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren 1697bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren /** 169814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Update the values of the tags in the tag groups if any value for the tag already was stored. 169914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 170014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param tag the name of the tag. 170114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param value the value of the tag in a form of {@link ExifAttribute}. 170214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @return Returns {@code true} if updating is placed. 170314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 170414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private boolean updateAttribute(String tag, ExifAttribute value) { 170514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon boolean updated = false; 170614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0 ; i < EXIF_TAGS.length; ++i) { 170714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mAttributes[i].containsKey(tag)) { 170814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].put(tag, value); 170914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon updated = true; 171014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 171114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 171214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return updated; 171314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 171414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 171514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 171614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Remove any values of the specified tag. 171714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 171814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param tag the name of the tag. 171914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 172014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void removeAttribute(String tag) { 172114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0 ; i < EXIF_TAGS.length; ++i) { 172214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[i].remove(tag); 172314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 172414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 172514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 172614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 172714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This function decides which parser to read the image data according to the given input stream 172814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * type and the content of the input stream. In each case, it reads the first three bytes to 172914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * determine whether the image data format is JPEG or not. 173014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 173114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void loadAttributes(@NonNull InputStream in) throws IOException { 173214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 173314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Initialize mAttributes. 173414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < EXIF_TAGS.length; ++i) { 1735abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas mAttributes[i] = new HashMap<>(); 173614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 173714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 173814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check file type 173914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in = new BufferedInputStream(in, SIGNATURE_CHECK_SIZE); 174014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mMimeType = getMimeType((BufferedInputStream) in); 174114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 174214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Create byte-ordered input stream 174314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ByteOrderedDataInputStream inputStream = new ByteOrderedDataInputStream(in); 174414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 174514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon switch (mMimeType) { 174614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_JPEG: { 174714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getJpegAttributes(inputStream, 0, IFD_TYPE_PRIMARY); // 0 is offset 174814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 174914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 175014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_RAF: { 175114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getRafAttributes(inputStream); 175214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 175314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 175414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_ORF: { 175514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getOrfAttributes(inputStream); 175614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 175714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 175814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_RW2: { 175914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getRw2Attributes(inputStream); 176014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 176114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 176214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_ARW: 176314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_CR2: 176414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_DNG: 176514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_NEF: 176614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_NRW: 176714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_PEF: 176814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_SRW: 176914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IMAGE_TYPE_UNKNOWN: { 177014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getRawAttributes(inputStream); 177114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 177214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 177314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon default: { 177414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 177514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 177614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 177714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Set thumbnail image offset and length 177814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon setThumbnailData(inputStream); 177914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mIsSupportedFile = true; 178014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (IOException e) { 178114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Ignore exceptions in order to keep the compatibility with the old versions of 178214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // ExifInterface. 178314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mIsSupportedFile = false; 178414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 178514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file" 178614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + "(ExifInterface supports JPEG and some RAW image formats only) " 178714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + "or a corrupted JPEG file to ExifInterface.", e); 178814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 178914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } finally { 179014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon addDefaultValuesForCompatibility(); 179114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 179214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 179314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon printAttributes(); 179414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 179514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 179614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 179714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 179814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Prints out attributes for debugging. 179914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void printAttributes() { 180014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < mAttributes.length; ++i) { 180114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "The size of tag group[" + i + "]: " + mAttributes[i].size()); 1802abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas for (Map.Entry<String, ExifAttribute> entry : mAttributes[i].entrySet()) { 1803abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas final ExifAttribute tagValue = entry.getValue(); 180414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "tagName: " + entry.getKey() + ", tagType: " + tagValue.toString() 180514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + ", tagValue: '" + tagValue.getStringValue(mExifByteOrder) + "'"); 180614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 180714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 180814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 180914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 181014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 181114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Save the tag data into the original image file. This is expensive because it involves 181214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * copying all the data from one file to another and deleting the old file and renaming the 181314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write 181414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * and make a single call rather than multiple calls for each attribute. 181514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * <p> 181614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This method is only supported for JPEG files. 181714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * </p> 181814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 181914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void saveAttributes() throws IOException { 182014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mIsSupportedFile || mMimeType != IMAGE_TYPE_JPEG) { 182114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("ExifInterface only supports saving attributes on JPEG formats."); 182214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 182314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mFilename == null) { 182414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException( 182514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon "ExifInterface does not support saving attributes for the current input."); 182614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 182714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 182814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Keep the thumbnail in memory 182914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailBytes = getThumbnail(); 183014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 183114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon File tempFile = new File(mFilename + ".tmp"); 183214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon File originalFile = new File(mFilename); 183314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!originalFile.renameTo(tempFile)) { 183414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Could not rename to " + tempFile.getAbsolutePath()); 183514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 183614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 183714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon FileInputStream in = null; 183814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon FileOutputStream out = null; 183914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 184014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Save the new file. 184114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in = new FileInputStream(tempFile); 184214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon out = new FileOutputStream(mFilename); 184314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon saveJpegAttributes(in, out); 184414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } finally { 184514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon closeQuietly(in); 184614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon closeQuietly(out); 184714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon tempFile.delete(); 184814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 184914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 185014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Discard the thumbnail in memory 185114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailBytes = null; 185214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 185314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 185414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 185514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns true if the image file has a thumbnail. 185614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 185714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public boolean hasThumbnail() { 185814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mHasThumbnail; 185914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 186014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 186114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 186214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns the JPEG compressed thumbnail inside the image file, or {@code null} if there is no 186314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * JPEG compressed thumbnail. 186414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * The returned data can be decoded using 186514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)} 186614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 186714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public byte[] getThumbnail() { 186814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED) { 186914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return getThumbnailBytes(); 187014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 187114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 187214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 187314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 187414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 187514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns the thumbnail bytes inside the image file, regardless of the compression type of the 187614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * thumbnail image. 187714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 187814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public byte[] getThumbnailBytes() { 187914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mHasThumbnail) { 188014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 188114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 188214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mThumbnailBytes != null) { 188314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mThumbnailBytes; 188414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 188514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 188614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read the thumbnail. 188714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon InputStream in = null; 188814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 188914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mAssetInputStream != null) { 189014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in = mAssetInputStream; 189114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.markSupported()) { 189214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.reset(); 189314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 189414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Cannot read thumbnail from inputstream without mark/reset support"); 189514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 189614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 189714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mFilename != null) { 189814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in = new FileInputStream(mFilename); 189914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 190014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in == null) { 190114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Should not be reached this. 190214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new FileNotFoundException(); 190314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 190414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.skip(mThumbnailOffset) != mThumbnailOffset) { 190514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Corrupted image"); 190614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 190714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] buffer = new byte[mThumbnailLength]; 190814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.read(buffer) != mThumbnailLength) { 190914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Corrupted image"); 191014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 191114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailBytes = buffer; 191214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return buffer; 191314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (IOException e) { 191414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Couldn't get a thumbnail image. 191514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Encountered exception while getting thumbnail", e); 191614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } finally { 191714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon closeQuietly(in); 191814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 191914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 192014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 192114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 192214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 192314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Creates and returns a Bitmap object of the thumbnail image based on the byte array and the 192414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * thumbnail compression value, or {@code null} if the compression type is unsupported. 192514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 192614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public Bitmap getThumbnailBitmap() { 192714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mHasThumbnail) { 192814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 192914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mThumbnailBytes == null) { 193014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailBytes = getThumbnailBytes(); 193114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 193214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 193314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED) { 193414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return BitmapFactory.decodeByteArray(mThumbnailBytes, 0, mThumbnailLength); 193514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mThumbnailCompression == DATA_UNCOMPRESSED) { 193614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] rgbValues = new int[mThumbnailBytes.length / 3]; 193714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte alpha = (byte) 0xff000000; 193814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < rgbValues.length; i++) { 193914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon rgbValues[i] = alpha + (mThumbnailBytes[3 * i] << 16) 194014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + (mThumbnailBytes[3 * i + 1] << 8) + mThumbnailBytes[3 * i + 2]; 194114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 194214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 194314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageLengthAttribute = 194414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_THUMBNAIL].get(TAG_IMAGE_LENGTH); 194514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageWidthAttribute = 194614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_THUMBNAIL].get(TAG_IMAGE_WIDTH); 194714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (imageLengthAttribute != null && imageWidthAttribute != null) { 194814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int imageLength = imageLengthAttribute.getIntValue(mExifByteOrder); 194914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int imageWidth = imageWidthAttribute.getIntValue(mExifByteOrder); 195014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return Bitmap.createBitmap( 195114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon rgbValues, imageWidth, imageLength, Bitmap.Config.ARGB_8888); 195214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 195314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 195414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 195514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 195614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 195714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 195814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns true if thumbnail image is JPEG Compressed, or false if either thumbnail image does 195914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * not exist or thumbnail image is uncompressed. 196014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 196114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public boolean isThumbnailCompressed() { 196214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED; 196314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 196414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 196514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 196614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns the offset and length of thumbnail inside the image file, or 196714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * {@code null} if there is no thumbnail. 196814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 196914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @return two-element array, the offset in the first value, and length in 197014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * the second, or {@code null} if no thumbnail was found. 197114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 197214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public long[] getThumbnailRange() { 197314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mHasThumbnail) { 197414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 197514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 197614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 197714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long[] range = new long[2]; 197814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon range[0] = mThumbnailOffset; 197914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon range[1] = mThumbnailLength; 198014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 198114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return range; 198214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 198314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 198414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 1985d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * Stores the latitude and longitude value in a float array. The first element is the latitude, 1986d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * and the second element is the longitude. Returns false if the Exif tags are not available. 1987d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * 1988d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * @deprecated Use {@link #getLatLong()} instead. 198914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 1990d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon @Deprecated 199114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public boolean getLatLong(float output[]) { 1992d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon double[] latLong = getLatLong(); 1993d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon if (latLong == null) { 1994d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon return false; 1995d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon } 1996d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon 1997d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon output[0] = (float) latLong[0]; 1998d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon output[1] = (float) latLong[1]; 1999d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon return true; 2000d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon } 2001d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon 2002d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon /** 2003d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * Gets the latitude and longitude values. 2004d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * <p> 2005d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * If there are valid latitude and longitude values in the image, this method returns a double 2006d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * array where the first element is the latitude and the second element is the longitude. 2007d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * Otherwise, it returns null. 2008d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon */ 2009d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon public double[] getLatLong() { 201014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String latValue = getAttribute(TAG_GPS_LATITUDE); 201114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String latRef = getAttribute(TAG_GPS_LATITUDE_REF); 201214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String lngValue = getAttribute(TAG_GPS_LONGITUDE); 201314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String lngRef = getAttribute(TAG_GPS_LONGITUDE_REF); 201414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 201514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (latValue != null && latRef != null && lngValue != null && lngRef != null) { 201614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 2017d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon double latitude = convertRationalLatLonToDouble(latValue, latRef); 2018d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon double longitude = convertRationalLatLonToDouble(lngValue, lngRef); 2019d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon return new double[] {latitude, longitude}; 202014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (IllegalArgumentException e) { 202114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Latitude/longitude values are not parseable. " + 202214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String.format("latValue=%s, latRef=%s, lngValue=%s, lngRef=%s", 202314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon latValue, latRef, lngValue, lngRef)); 202414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 202514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 2026d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon return null; 2027d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon } 2028d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon 2029d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon /** 2030c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen * Sets the GPS-related information. It will set GPS processing method, latitude and longitude 2031c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen * values, GPS timestamp, and speed information at the same time. 2032c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen * 2033c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen * @param location the {@link Location} object returned by GPS service. 2034c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen */ 2035c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen public void setGpsInfo(Location location) { 2036c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen if (location == null) { 2037c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen return; 2038c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen } 2039c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, location.getProvider()); 2040c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setLatLong(location.getLatitude(), location.getLongitude()); 2041c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setAltitude(location.getAltitude()); 2042c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen // Location objects store speeds in m/sec. Translates it to km/hr here. 2043c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setAttribute(TAG_GPS_SPEED_REF, "K"); 2044c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setAttribute(TAG_GPS_SPEED, new Rational(location.getSpeed() 2045c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen * TimeUnit.HOURS.toSeconds(1) / 1000).toString()); 2046c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen String[] dateTime = sFormatter.format(new Date(location.getTime())).split("\\s+"); 2047c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setAttribute(ExifInterface.TAG_GPS_DATESTAMP, dateTime[0]); 2048c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, dateTime[1]); 2049c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen } 2050c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen 2051c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen /** 2052d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * Sets the latitude and longitude values. 2053d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * 2054d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * @param latitude the decimal value of latitude. Must be a valid double value between -90.0 and 2055d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * 90.0. 2056d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * @param longitude the decimal value of longitude. Must be a valid double value between -180.0 2057d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * and 180.0. 2058d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * @throws IllegalArgumentException If {@code latitude} or {@code longitude} is outside the 2059d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon * specified range. 2060d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon */ 2061d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon public void setLatLong(double latitude, double longitude) { 2062d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon if (latitude < -90.0 || latitude > 90.0 || Double.isNaN(latitude)) { 2063d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon throw new IllegalArgumentException("Latitude value " + latitude + " is not valid."); 2064d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon } 2065d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon if (longitude < -180.0 || longitude > 180.0 || Double.isNaN(longitude)) { 2066d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon throw new IllegalArgumentException("Longitude value " + longitude + " is not valid."); 2067d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon } 2068d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon setAttribute(TAG_GPS_LATITUDE_REF, latitude >= 0 ? "N" : "S"); 2069d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon setAttribute(TAG_GPS_LATITUDE, convertDecimalDegree(Math.abs(latitude))); 2070d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon setAttribute(TAG_GPS_LONGITUDE_REF, longitude >= 0 ? "E" : "W"); 2071d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon setAttribute(TAG_GPS_LONGITUDE, convertDecimalDegree(Math.abs(longitude))); 207214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 207314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 207414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 207514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Return the altitude in meters. If the exif tag does not exist, return 207614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * <var>defaultValue</var>. 207714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 207814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param defaultValue the value to return if the tag is not available. 207914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 208014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public double getAltitude(double defaultValue) { 208114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon double altitude = getAttributeDouble(TAG_GPS_ALTITUDE, -1); 208214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ref = getAttributeInt(TAG_GPS_ALTITUDE_REF, -1); 208314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 208414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (altitude >= 0 && ref >= 0) { 208514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (altitude * ((ref == 1) ? -1 : 1)); 208614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 208714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return defaultValue; 208814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 208914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 209014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 209114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 2092c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen * Sets the altitude in meters. 2093c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen */ 2094c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen public void setAltitude(double altitude) { 2095c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen String ref = altitude >= 0 ? "0" : "1"; 2096c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setAttribute(TAG_GPS_ALTITUDE, new Rational(Math.abs(altitude)).toString()); 2097c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen setAttribute(TAG_GPS_ALTITUDE_REF, ref); 2098c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen } 2099c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen 2100c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen /** 21018f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren * Set the date time value. 21028f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren * 21038f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren * @param timeStamp number of milliseconds since Jan. 1, 1970, midnight local time. 21048f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren * @hide 21058f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren */ 21068f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren public void setDateTime(long timeStamp) { 21078f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren long sub = timeStamp % 1000; 21088f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren setAttribute(TAG_DATETIME, sFormatter.format(new Date(timeStamp))); 21098f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren setAttribute(TAG_SUBSEC_TIME, Long.toString(sub)); 21108f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren } 21118f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren 21128f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren /** 211314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns number of milliseconds since Jan. 1, 1970, midnight local time. 211414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns -1 if the date time information if not available. 211514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @hide 211614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 211714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public long getDateTime() { 211814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String dateTimeString = getAttribute(TAG_DATETIME); 211914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dateTimeString == null 212014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon || !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1; 212114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 212214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ParsePosition pos = new ParsePosition(0); 212314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 212414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The exif field is in local time. Parsing it as if it is UTC will yield time 212514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // since 1/1/1970 local time 212614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Date datetime = sFormatter.parse(dateTimeString, pos); 212714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (datetime == null) return -1; 212814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long msecs = datetime.getTime(); 212914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 213014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String subSecs = getAttribute(TAG_SUBSEC_TIME); 213114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (subSecs != null) { 213214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 213314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long sub = Long.parseLong(subSecs); 213414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon while (sub > 1000) { 213514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sub /= 10; 213614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 213714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon msecs += sub; 213814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException e) { 213914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Ignored 214014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 214114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 214214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return msecs; 214314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (IllegalArgumentException e) { 214414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return -1; 214514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 214614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 214714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 214814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 214914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns number of milliseconds since Jan. 1, 1970, midnight UTC. 215014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns -1 if the date time information if not available. 215114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @hide 215214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 215314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public long getGpsDateTime() { 215414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String date = getAttribute(TAG_GPS_DATESTAMP); 215514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String time = getAttribute(TAG_GPS_TIMESTAMP); 215614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (date == null || time == null 215714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon || (!sNonZeroTimePattern.matcher(date).matches() 215814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon && !sNonZeroTimePattern.matcher(time).matches())) { 215914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return -1; 216014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 216114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 216214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String dateTimeString = date + ' ' + time; 216314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 216414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ParsePosition pos = new ParsePosition(0); 216514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 216614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Date datetime = sFormatter.parse(dateTimeString, pos); 216714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (datetime == null) return -1; 216814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return datetime.getTime(); 216914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (IllegalArgumentException e) { 217014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return -1; 217114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 217214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 217314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 2174d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon private static double convertRationalLatLonToDouble(String rationalString, String ref) { 217514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 217614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String [] parts = rationalString.split(","); 217714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 217814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String [] pair; 217914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon pair = parts[0].split("/"); 218014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon double degrees = Double.parseDouble(pair[0].trim()) 218114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon / Double.parseDouble(pair[1].trim()); 218214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 218314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon pair = parts[1].split("/"); 218414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon double minutes = Double.parseDouble(pair[0].trim()) 218514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon / Double.parseDouble(pair[1].trim()); 218614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 218714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon pair = parts[2].split("/"); 218814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon double seconds = Double.parseDouble(pair[0].trim()) 218914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon / Double.parseDouble(pair[1].trim()); 219014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 219114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon double result = degrees + (minutes / 60.0) + (seconds / 3600.0); 219214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if ((ref.equals("S") || ref.equals("W"))) { 2193d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon return -result; 2194d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon } else if (ref.equals("N") || ref.equals("E")) { 2195d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon return result; 2196d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon } else { 2197d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon // Not valid 2198d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon throw new IllegalArgumentException(); 219914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 220014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { 220114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Not valid 220214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IllegalArgumentException(); 220314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 220414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 220514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 2206d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon private String convertDecimalDegree(double decimalDegree) { 2207d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon long degrees = (long) decimalDegree; 2208d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon long minutes = (long) ((decimalDegree - degrees) * 60.0); 2209d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon long seconds = Math.round((decimalDegree - degrees - minutes / 60.0) * 3600.0 * 1e7); 2210d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon return degrees + "/1," + minutes + "/1," + seconds + "/10000000"; 2211d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon } 2212d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon 221314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Checks the type of image file 221414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int getMimeType(BufferedInputStream in) throws IOException { 221514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.mark(SIGNATURE_CHECK_SIZE); 221614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] signatureCheckBytes = new byte[SIGNATURE_CHECK_SIZE]; 221714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.read(signatureCheckBytes) != SIGNATURE_CHECK_SIZE) { 221814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 221914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 222014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.reset(); 222114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (isJpegFormat(signatureCheckBytes)) { 222214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return IMAGE_TYPE_JPEG; 222314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (isRafFormat(signatureCheckBytes)) { 222414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return IMAGE_TYPE_RAF; 222514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (isOrfFormat(signatureCheckBytes)) { 222614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return IMAGE_TYPE_ORF; 222714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (isRw2Format(signatureCheckBytes)) { 222814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return IMAGE_TYPE_RW2; 222914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 223014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Certain file formats (PEF) are identified in readImageFileDirectory() 223114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return IMAGE_TYPE_UNKNOWN; 223214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 223314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 223414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 223514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This method looks at the first 3 bytes to determine if this file is a JPEG file. 223614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See http://www.media.mit.edu/pia/Research/deepview/exif.html, "JPEG format and Marker" 223714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 223814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static boolean isJpegFormat(byte[] signatureCheckBytes) throws IOException { 223914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < JPEG_SIGNATURE.length; i++) { 224014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (signatureCheckBytes[i] != JPEG_SIGNATURE[i]) { 224114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return false; 224214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 224314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 224414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return true; 224514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 224614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 224714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 224814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This method looks at the first 15 bytes to determine if this file is a RAF file. 224914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * There is no official specification for RAF files from Fuji, but there is an online archive of 225014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * image file specifications: 225114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://fileformats.archiveteam.org/wiki/Fujifilm_RAF 225214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 225314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private boolean isRafFormat(byte[] signatureCheckBytes) throws IOException { 225489889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon byte[] rafSignatureBytes = RAF_SIGNATURE.getBytes(Charset.defaultCharset()); 225514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < rafSignatureBytes.length; i++) { 225614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (signatureCheckBytes[i] != rafSignatureBytes[i]) { 225714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return false; 225814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 225914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 226014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return true; 226114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 226214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 226314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 226414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * ORF has a similar structure to TIFF but it contains a different signature at the TIFF Header. 226514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This method looks at the 2 bytes following the Byte Order bytes to determine if this file is 226614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * an ORF file. 226714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * There is no official specification for ORF files from Olympus, but there is an online archive 226814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * of image file specifications: 226914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://fileformats.archiveteam.org/wiki/Olympus_ORF 227014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 227114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private boolean isOrfFormat(byte[] signatureCheckBytes) throws IOException { 227214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ByteOrderedDataInputStream signatureInputStream = 227314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ByteOrderedDataInputStream(signatureCheckBytes); 227414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read byte order 227514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mExifByteOrder = readByteOrder(signatureInputStream); 227614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Set byte order 227714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon signatureInputStream.setByteOrder(mExifByteOrder); 227814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 227914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon short orfSignature = signatureInputStream.readShort(); 2280f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes signatureInputStream.close(); 228114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return orfSignature == ORF_SIGNATURE_1 || orfSignature == ORF_SIGNATURE_2; 228214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 228314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 228414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 228514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * RW2 is TIFF-based, but stores 0x55 signature byte instead of 0x42 at the header 228614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See http://lclevy.free.fr/raw/ 228714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 228814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private boolean isRw2Format(byte[] signatureCheckBytes) throws IOException { 228914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ByteOrderedDataInputStream signatureInputStream = 229014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ByteOrderedDataInputStream(signatureCheckBytes); 229114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read byte order 229214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mExifByteOrder = readByteOrder(signatureInputStream); 229314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Set byte order 229414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon signatureInputStream.setByteOrder(mExifByteOrder); 229514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 229614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon short signatureByte = signatureInputStream.readShort(); 2297f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes signatureInputStream.close(); 229814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return signatureByte == RW2_SIGNATURE; 229914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 230014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 230114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 230214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Loads EXIF attributes from a JPEG input stream. 230314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 230414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param in The input stream that starts with the JPEG data. 230514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param jpegOffset The offset value in input stream for JPEG data. 230614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param imageType The image type from which to retrieve metadata. Use IFD_TYPE_PRIMARY for 230714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * primary image, IFD_TYPE_PREVIEW for preview image, and 230814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * IFD_TYPE_THUMBNAIL for thumbnail image. 230914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @throws IOException If the data contains invalid JPEG markers, offsets, or length values. 231014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 231114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void getJpegAttributes(ByteOrderedDataInputStream in, int jpegOffset, int imageType) 231214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throws IOException { 231314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See JPEG File Interchange Format Specification, "JFIF Specification" 231414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 231514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "getJpegAttributes starting with: " + in); 231614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 231714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 231814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // JPEG uses Big Endian by default. See https://people.cs.umass.edu/~verts/cs32/endian.html 231914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.setByteOrder(ByteOrder.BIG_ENDIAN); 232014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 232114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip to JPEG data 232214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.seek(jpegOffset); 232314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int bytesRead = jpegOffset; 232414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 232514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte marker; 232614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if ((marker = in.readByte()) != MARKER) { 232714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff)); 232814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 232914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++bytesRead; 233014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.readByte() != MARKER_SOI) { 233114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff)); 233214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 233314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++bytesRead; 233414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon while (true) { 233514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon marker = in.readByte(); 233614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (marker != MARKER) { 233714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid marker:" + Integer.toHexString(marker & 0xff)); 233814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 233914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++bytesRead; 234014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon marker = in.readByte(); 234114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 234214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Found JPEG segment indicator: " + Integer.toHexString(marker & 0xff)); 234314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 234414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++bytesRead; 234514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 234614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // EOI indicates the end of an image and in case of SOS, JPEG image stream starts and 234714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // the image data will terminate right after. 234814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (marker == MARKER_EOI || marker == MARKER_SOS) { 234914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 235014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 235114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int length = in.readUnsignedShort() - 2; 235214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytesRead += 2; 235314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 235414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "JPEG segment: " + Integer.toHexString(marker & 0xff) + " (length: " 235514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + (length + 2) + ")"); 235614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 235714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (length < 0) { 235814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid length"); 235914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 236014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon switch (marker) { 236114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_APP1: { 236214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 236314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "MARKER_APP1"); 236414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 236514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (length < 6) { 236614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip if it's not an EXIF APP1 segment. 236714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 236814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 236914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] identifier = new byte[6]; 237014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.read(identifier) != 6) { 237114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid exif"); 237214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 237314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytesRead += 6; 237414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon length -= 6; 237514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) { 237614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip if it's not an EXIF APP1 segment. 237714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 237814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 237914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (length <= 0) { 238014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid exif"); 238114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 238214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 238314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")"); 238414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 238514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Save offset values for createJpegThumbnailBitmap() function 238614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mExifOffset = bytesRead; 238714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 238814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] bytes = new byte[length]; 238914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.read(bytes) != length) { 239014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid exif"); 239114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 239214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytesRead += length; 239314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon length = 0; 239414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 239514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon readExifSegment(bytes, imageType); 239614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 239714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 239814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 239914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_COM: { 240014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] bytes = new byte[length]; 240114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.read(bytes) != length) { 240214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid exif"); 240314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 240414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon length = 0; 240514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (getAttribute(TAG_USER_COMMENT) == null) { 240614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_EXIF].put(TAG_USER_COMMENT, ExifAttribute.createString( 240714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new String(bytes, ASCII))); 240814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 240914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 241014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 241114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 241214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF0: 241314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF1: 241414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF2: 241514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF3: 241614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF5: 241714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF6: 241814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF7: 241914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF9: 242014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF10: 242114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF11: 242214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF13: 242314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF14: 242414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOF15: { 242514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.skipBytes(1) != 1) { 242614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid SOFx"); 242714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 242814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[imageType].put(TAG_IMAGE_LENGTH, ExifAttribute.createULong( 242914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.readUnsignedShort(), mExifByteOrder)); 243014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[imageType].put(TAG_IMAGE_WIDTH, ExifAttribute.createULong( 243114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.readUnsignedShort(), mExifByteOrder)); 243214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon length -= 5; 243314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 243414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 243514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 243614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon default: { 243714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 243814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 243914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 244014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (length < 0) { 244114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid length"); 244214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 244314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (in.skipBytes(length) != length) { 244414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid JPEG segment"); 244514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 244614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytesRead += length; 244714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 244814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Restore original byte order 244914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.setByteOrder(mExifByteOrder); 245014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 245114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 245214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void getRawAttributes(ByteOrderedDataInputStream in) throws IOException { 245314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1. 245414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon parseTiffHeaders(in, in.available()); 245514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 245614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6. 245714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon readImageFileDirectory(in, IFD_TYPE_PRIMARY); 245814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 245914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Update ImageLength/Width tags for all image data. 246014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon updateImageSizeValues(in, IFD_TYPE_PRIMARY); 246114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon updateImageSizeValues(in, IFD_TYPE_PREVIEW); 246214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon updateImageSizeValues(in, IFD_TYPE_THUMBNAIL); 246314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 246414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check if each image data is in valid position. 246514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon validateImages(in); 246614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 246714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mMimeType == IMAGE_TYPE_PEF) { 246814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // PEF files contain a MakerNote data, which contains the data for ColorSpace tag. 246914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://lclevy.free.fr/raw/ and piex.cc PefGetPreviewData() 247014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute makerNoteAttribute = 247114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE); 247214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (makerNoteAttribute != null) { 247314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Create an ordered DataInputStream for MakerNote 247414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ByteOrderedDataInputStream makerNoteDataInputStream = 247514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ByteOrderedDataInputStream(makerNoteAttribute.bytes); 247614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon makerNoteDataInputStream.setByteOrder(mExifByteOrder); 247714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 247814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Seek to MakerNote data 247914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon makerNoteDataInputStream.seek(PEF_MAKER_NOTE_SKIP_SIZE); 248014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 248114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read IFD data from MakerNote 248214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon readImageFileDirectory(makerNoteDataInputStream, IFD_TYPE_PEF); 248314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 248414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Update ColorSpace tag 248514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute colorSpaceAttribute = 248614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_PEF].get(TAG_COLOR_SPACE); 248714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (colorSpaceAttribute != null) { 248814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_EXIF].put(TAG_COLOR_SPACE, colorSpaceAttribute); 248914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 249014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 249114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 249214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 249314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 249414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 249514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * RAF files contains a JPEG and a CFA data. 249614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * The JPEG contains two images, a preview and a thumbnail, while the CFA contains a RAW image. 249714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This method looks at the first 160 bytes of a RAF file to retrieve the offset and length 249814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * values for the JPEG and CFA data. 249914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Using that data, it parses the JPEG data to retrieve the preview and thumbnail image data, 250014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * then parses the CFA metadata to retrieve the primary image length/width values. 250114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For data format details, see http://fileformats.archiveteam.org/wiki/Fujifilm_RAF 250214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 250314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void getRafAttributes(ByteOrderedDataInputStream in) throws IOException { 250414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve offset & length values 250514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.skipBytes(RAF_OFFSET_TO_JPEG_IMAGE_OFFSET); 250614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] jpegOffsetBytes = new byte[4]; 250714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] cfaHeaderOffsetBytes = new byte[4]; 250814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.read(jpegOffsetBytes); 250914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip JPEG length value since it is not needed 251014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.skipBytes(RAF_JPEG_LENGTH_VALUE_SIZE); 251114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.read(cfaHeaderOffsetBytes); 251214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int rafJpegOffset = ByteBuffer.wrap(jpegOffsetBytes).getInt(); 251314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int rafCfaHeaderOffset = ByteBuffer.wrap(cfaHeaderOffsetBytes).getInt(); 251414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 251514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve JPEG image metadata 251614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getJpegAttributes(in, rafJpegOffset, IFD_TYPE_PREVIEW); 251714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 251814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip to CFA header offset. 251914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.seek(rafCfaHeaderOffset); 252014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 252114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve primary image length/width values, if TAG_RAF_IMAGE_SIZE exists 252214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.setByteOrder(ByteOrder.BIG_ENDIAN); 252314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int numberOfDirectoryEntry = in.readInt(); 252414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 252514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry); 252614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 252714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // CFA stores some metadata about the RAW image. Since CFA uses proprietary tags, can only 252814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // find and retrieve image size information tags, while skipping others. 252914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See piex.cc RafGetDimension() 253014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < numberOfDirectoryEntry; ++i) { 253114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int tagNumber = in.readUnsignedShort(); 253214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int numberOfBytes = in.readUnsignedShort(); 253314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (tagNumber == TAG_RAF_IMAGE_SIZE.number) { 253414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int imageLength = in.readShort(); 253514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int imageWidth = in.readShort(); 253614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageLengthAttribute = 253714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(imageLength, mExifByteOrder); 253814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageWidthAttribute = 253914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(imageWidth, mExifByteOrder); 254014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, imageLengthAttribute); 254114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, imageWidthAttribute); 254214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 254314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Updated to length: " + imageLength + ", width: " + imageWidth); 254414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 254514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 254614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 254714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.skipBytes(numberOfBytes); 254814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 254914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 255014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 255114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 255214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * ORF files contains a primary image data and a MakerNote data that contains preview/thumbnail 255314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * images. Both data takes the form of IFDs and can therefore be read with the 255414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * readImageFileDirectory() method. 255514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This method reads all the necessary data and updates the primary/preview/thumbnail image 255614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * information according to the GetOlympusPreviewImage() method in piex.cc. 255714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * For data format details, see the following: 255814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * http://fileformats.archiveteam.org/wiki/Olympus_ORF 255914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * https://libopenraw.freedesktop.org/wiki/Olympus_ORF 256014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 256114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void getOrfAttributes(ByteOrderedDataInputStream in) throws IOException { 256214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve primary image data 256314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Other Exif data will be located in the Makernote. 256414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getRawAttributes(in); 256514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 256614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Additionally retrieve preview/thumbnail information from MakerNote tag, which contains 256714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // proprietary tags and therefore does not have offical documentation 256814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See GetOlympusPreviewImage() in piex.cc & http://www.exiv2.org/tags-olympus.html 256914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute makerNoteAttribute = 257014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE); 257114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (makerNoteAttribute != null) { 257214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Create an ordered DataInputStream for MakerNote 257314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ByteOrderedDataInputStream makerNoteDataInputStream = 257414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ByteOrderedDataInputStream(makerNoteAttribute.bytes); 257514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon makerNoteDataInputStream.setByteOrder(mExifByteOrder); 257614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 257714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // There are two types of headers for Olympus MakerNotes 257814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://www.exiv2.org/makernote.html#R1 257914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] makerNoteHeader1Bytes = new byte[ORF_MAKER_NOTE_HEADER_1.length]; 258014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon makerNoteDataInputStream.readFully(makerNoteHeader1Bytes); 258114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon makerNoteDataInputStream.seek(0); 258214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] makerNoteHeader2Bytes = new byte[ORF_MAKER_NOTE_HEADER_2.length]; 258314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon makerNoteDataInputStream.readFully(makerNoteHeader2Bytes); 258414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip the corresponding amount of bytes for each header type 258514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (Arrays.equals(makerNoteHeader1Bytes, ORF_MAKER_NOTE_HEADER_1)) { 258614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon makerNoteDataInputStream.seek(ORF_MAKER_NOTE_HEADER_1_SIZE); 258714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (Arrays.equals(makerNoteHeader2Bytes, ORF_MAKER_NOTE_HEADER_2)) { 258814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon makerNoteDataInputStream.seek(ORF_MAKER_NOTE_HEADER_2_SIZE); 258914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 259014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 259114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read IFD data from MakerNote 259214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon readImageFileDirectory(makerNoteDataInputStream, IFD_TYPE_ORF_MAKER_NOTE); 259314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 259414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve & update preview image offset & length values 259514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageLengthAttribute = (ExifAttribute) 259614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_ORF_CAMERA_SETTINGS].get(TAG_ORF_PREVIEW_IMAGE_START); 259714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute bitsPerSampleAttribute = (ExifAttribute) 259814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_ORF_CAMERA_SETTINGS].get(TAG_ORF_PREVIEW_IMAGE_LENGTH); 259914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 260014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (imageLengthAttribute != null && bitsPerSampleAttribute != null) { 260114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PREVIEW].put(TAG_JPEG_INTERCHANGE_FORMAT, 260214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon imageLengthAttribute); 260314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PREVIEW].put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 260414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bitsPerSampleAttribute); 260514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 260614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 260714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // TODO: Check this behavior in other ORF files 260814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve primary image length & width values 260914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See piex.cc GetOlympusPreviewImage() 261014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute aspectFrameAttribute = (ExifAttribute) 261114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_ORF_IMAGE_PROCESSING].get(TAG_ORF_ASPECT_FRAME); 261214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (aspectFrameAttribute != null) { 261314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] aspectFrameValues = (int[]) aspectFrameAttribute.getValue(mExifByteOrder); 261414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (aspectFrameValues == null || aspectFrameValues.length != 4) { 261514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Invalid aspect frame values. frame=" 261614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + Arrays.toString(aspectFrameValues)); 261714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 261814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 261914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (aspectFrameValues[2] > aspectFrameValues[0] && 262014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon aspectFrameValues[3] > aspectFrameValues[1]) { 262114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int primaryImageWidth = aspectFrameValues[2] - aspectFrameValues[0] + 1; 262214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int primaryImageLength = aspectFrameValues[3] - aspectFrameValues[1] + 1; 262314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Swap width & length values 262414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (primaryImageWidth < primaryImageLength) { 262514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon primaryImageWidth += primaryImageLength; 262614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon primaryImageLength = primaryImageWidth - primaryImageLength; 262714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon primaryImageWidth -= primaryImageLength; 262814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 262914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute primaryImageWidthAttribute = 263014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(primaryImageWidth, mExifByteOrder); 263114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute primaryImageLengthAttribute = 263214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(primaryImageLength, mExifByteOrder); 263314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 263414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, primaryImageWidthAttribute); 263514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, primaryImageLengthAttribute); 263614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 263714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 263814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 263914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 264014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 264114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // RW2 contains the primary image data in IFD0 and the preview and/or thumbnail image data in 264214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // the JpgFromRaw tag 264314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See https://libopenraw.freedesktop.org/wiki/Panasonic_RAW/ and piex.cc Rw2GetPreviewData() 264414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void getRw2Attributes(ByteOrderedDataInputStream in) throws IOException { 264514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve primary image data 264614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getRawAttributes(in); 264714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 264814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve preview and/or thumbnail image data 264914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute jpgFromRawAttribute = 265014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_PRIMARY].get(TAG_RW2_JPG_FROM_RAW); 265114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (jpgFromRawAttribute != null) { 265214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getJpegAttributes(in, mRw2JpgFromRawOffset, IFD_TYPE_PREVIEW); 265314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 265414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 265514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Set ISO tag value if necessary 265614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute rw2IsoAttribute = 265714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_PRIMARY].get(TAG_RW2_ISO); 265814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute exifIsoAttribute = 265914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_ISO_SPEED_RATINGS); 266014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (rw2IsoAttribute != null && exifIsoAttribute == null) { 266114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Place this attribute only if it doesn't exist 266214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_EXIF].put(TAG_ISO_SPEED_RATINGS, rw2IsoAttribute); 266314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 266414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 266514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 266614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Stores a new JPEG image with EXIF attributes into a given output stream. 266714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void saveJpegAttributes(InputStream inputStream, OutputStream outputStream) 266814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throws IOException { 266914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See JPEG File Interchange Format Specification, "JFIF Specification" 267014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 267114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "saveJpegAttributes starting with (inputStream: " + inputStream 267214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + ", outputStream: " + outputStream + ")"); 267314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 267414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon DataInputStream dataInputStream = new DataInputStream(inputStream); 267514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ByteOrderedDataOutputStream dataOutputStream = 267614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ByteOrderedDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN); 267714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.readByte() != MARKER) { 267814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid marker"); 267914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 268014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(MARKER); 268114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.readByte() != MARKER_SOI) { 268214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid marker"); 268314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 268414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(MARKER_SOI); 268514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 268614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Write EXIF APP1 segment 268714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(MARKER); 268814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(MARKER_APP1); 268914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon writeExifSegment(dataOutputStream, 6); 269014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 269114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] bytes = new byte[4096]; 269214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 269314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon while (true) { 269414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte marker = dataInputStream.readByte(); 269514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (marker != MARKER) { 269614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid marker"); 269714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 269814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon marker = dataInputStream.readByte(); 269914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon switch (marker) { 270014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_APP1: { 270114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int length = dataInputStream.readUnsignedShort() - 2; 270214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (length < 0) { 270314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid length"); 270414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 270514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] identifier = new byte[6]; 270614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (length >= 6) { 270714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.read(identifier) != 6) { 270814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid exif"); 270914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 271014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) { 271114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip the original EXIF APP1 segment. 271214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.skipBytes(length - 6) != length - 6) { 271314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid length"); 271414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 271514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 271614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 271714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 271814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Copy non-EXIF APP1 segment. 271914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(MARKER); 272014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(marker); 272114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedShort(length + 2); 272214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (length >= 6) { 272314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon length -= 6; 272414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.write(identifier); 272514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 272614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int read; 272714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon while (length > 0 && (read = dataInputStream.read( 272814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytes, 0, Math.min(length, bytes.length))) >= 0) { 272914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.write(bytes, 0, read); 273014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon length -= read; 273114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 273214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 273314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 273414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_EOI: 273514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case MARKER_SOS: { 273614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(MARKER); 273714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(marker); 273814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Copy all the remaining data 273914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon copy(dataInputStream, dataOutputStream); 274014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 274114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 274214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon default: { 274314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Copy JPEG segment 274414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(MARKER); 274514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(marker); 274614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int length = dataInputStream.readUnsignedShort(); 274714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedShort(length); 274814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon length -= 2; 274914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (length < 0) { 275014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid length"); 275114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 275214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int read; 275314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon while (length > 0 && (read = dataInputStream.read( 275414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytes, 0, Math.min(length, bytes.length))) >= 0) { 275514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.write(bytes, 0, read); 275614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon length -= read; 275714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 275814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 275914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 276014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 276114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 276214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 276314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 276414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Reads the given EXIF byte area and save its tag data into attributes. 276514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void readExifSegment(byte[] exifBytes, int imageType) throws IOException { 276614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ByteOrderedDataInputStream dataInputStream = 276714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon new ByteOrderedDataInputStream(exifBytes); 276814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 276914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1. 277014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon parseTiffHeaders(dataInputStream, exifBytes.length); 277114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 277214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6. 277314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon readImageFileDirectory(dataInputStream, imageType); 277414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 277514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 277614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void addDefaultValuesForCompatibility() { 2777a39fc6268fbf33ad5d39829cacebf49b11f35c3eHyundo Moon // If DATETIME tag has no value, then set the value to DATETIME_ORIGINAL tag's. 277814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String valueOfDateTimeOriginal = getAttribute(TAG_DATETIME_ORIGINAL); 2779a39fc6268fbf33ad5d39829cacebf49b11f35c3eHyundo Moon if (valueOfDateTimeOriginal != null && getAttribute(TAG_DATETIME) == null) { 278014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_DATETIME, 278114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createString(valueOfDateTimeOriginal)); 278214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 278314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 278414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Add the default value. 278514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (getAttribute(TAG_IMAGE_WIDTH) == null) { 278614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, 278714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(0, mExifByteOrder)); 278814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 278914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (getAttribute(TAG_IMAGE_LENGTH) == null) { 279014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, 279114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(0, mExifByteOrder)); 279214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 279314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (getAttribute(TAG_ORIENTATION) == null) { 279414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_ORIENTATION, 279514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(0, mExifByteOrder)); 279614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 279714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (getAttribute(TAG_LIGHT_SOURCE) == null) { 279814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_EXIF].put(TAG_LIGHT_SOURCE, 279914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(0, mExifByteOrder)); 280014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 280114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 280214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 280314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private ByteOrder readByteOrder(ByteOrderedDataInputStream dataInputStream) 280414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throws IOException { 280514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read byte order. 280614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon short byteOrder = dataInputStream.readShort(); 280714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon switch (byteOrder) { 280814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case BYTE_ALIGN_II: 280914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 281014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "readExifSegment: Byte Align II"); 281114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 281214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return ByteOrder.LITTLE_ENDIAN; 281314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case BYTE_ALIGN_MM: 281414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 281514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "readExifSegment: Byte Align MM"); 281614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 281714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return ByteOrder.BIG_ENDIAN; 281814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon default: 281914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid byte order: " + Integer.toHexString(byteOrder)); 282014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 282114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 282214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 282314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void parseTiffHeaders(ByteOrderedDataInputStream dataInputStream, 282414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int exifBytesLength) throws IOException { 282514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read byte order 282614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mExifByteOrder = readByteOrder(dataInputStream); 282714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Set byte order 282814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.setByteOrder(mExifByteOrder); 282914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 283014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check start code 283114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int startCode = dataInputStream.readUnsignedShort(); 283214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mMimeType != IMAGE_TYPE_ORF && mMimeType != IMAGE_TYPE_RW2 && startCode != START_CODE) { 283314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid start code: " + Integer.toHexString(startCode)); 283414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 283514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 283614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read and skip to first ifd offset 283714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int firstIfdOffset = dataInputStream.readInt(); 283814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (firstIfdOffset < 8 || firstIfdOffset >= exifBytesLength) { 283914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid first Ifd offset: " + firstIfdOffset); 284014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 284114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon firstIfdOffset -= 8; 284214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (firstIfdOffset > 0) { 284314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.skipBytes(firstIfdOffset) != firstIfdOffset) { 284414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset); 284514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 284614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 284714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 284814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 284914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Reads image file directory, which is a tag group in EXIF. 285014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void readImageFileDirectory(ByteOrderedDataInputStream dataInputStream, 285114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @IfdType int ifdType) throws IOException { 285214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.mPosition + 2 > dataInputStream.mLength) { 285314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Return if there is no data from the offset. 285414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 285514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 285614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See TIFF 6.0 Section 2: TIFF Structure, Figure 1. 285714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon short numberOfDirectoryEntry = dataInputStream.readShort(); 285814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.mPosition + 12 * numberOfDirectoryEntry > dataInputStream.mLength) { 285914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Return if the size of entries is too big. 286014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 286114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 286214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 286314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 286414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry); 286514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 286614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 286714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See TIFF 6.0 Section 2: TIFF Structure, "Image File Directory". 286814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (short i = 0; i < numberOfDirectoryEntry; ++i) { 286914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int tagNumber = dataInputStream.readUnsignedShort(); 287014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int dataFormat = dataInputStream.readUnsignedShort(); 287114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int numberOfComponents = dataInputStream.readInt(); 287214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Next four bytes is for data offset or value. 287314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long nextEntryOffset = dataInputStream.peek() + 4; 287414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 287514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Look up a corresponding tag from tag number 287614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifTag tag = (ExifTag) sExifTagMapsForReading[ifdType].get(tagNumber); 287714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 287814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 287914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, String.format("ifdType: %d, tagNumber: %d, tagName: %s, dataFormat: %d, " 288014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + "numberOfComponents: %d", ifdType, tagNumber, 288114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon tag != null ? tag.name : null, dataFormat, numberOfComponents)); 288214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 288314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 288414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long byteCount = 0; 288514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon boolean valid = false; 288614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (tag == null) { 288714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber); 288814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (dataFormat <= 0 || dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) { 288914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat); 289014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 289114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byteCount = (long) numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat]; 289214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (byteCount < 0 || byteCount > Integer.MAX_VALUE) { 289314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Skip the tag entry since the number of components is invalid: " 289414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + numberOfComponents); 289514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 289614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon valid = true; 289714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 289814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 289914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!valid) { 290014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.seek(nextEntryOffset); 290114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 290214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 290314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 290414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read a value from data field or seek to the value offset which is stored in data 290514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // field if the size of the entry value is bigger than 4. 290614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (byteCount > 4) { 290714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int offset = dataInputStream.readInt(); 290814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 290914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "seek to data offset: " + offset); 291014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 291114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mMimeType == IMAGE_TYPE_ORF) { 291289889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon if (TAG_MAKER_NOTE.equals(tag.name)) { 291314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Save offset value for reading thumbnail 291414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOrfMakerNoteOffset = offset; 291514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (ifdType == IFD_TYPE_ORF_MAKER_NOTE 291689889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon && TAG_ORF_THUMBNAIL_IMAGE.equals(tag.name)) { 291714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Retrieve & update values for thumbnail offset and length values for ORF 291814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOrfThumbnailOffset = offset; 291914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOrfThumbnailLength = numberOfComponents; 292014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 292114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute compressionAttribute = 292214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(DATA_JPEG, mExifByteOrder); 292314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute jpegInterchangeFormatAttribute = 292414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(mOrfThumbnailOffset, mExifByteOrder); 292514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute jpegInterchangeFormatLengthAttribute = 292614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(mOrfThumbnailLength, mExifByteOrder); 292714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 292814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_COMPRESSION, compressionAttribute); 292914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_JPEG_INTERCHANGE_FORMAT, 293014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon jpegInterchangeFormatAttribute); 293114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 293214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon jpegInterchangeFormatLengthAttribute); 293314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 293414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mMimeType == IMAGE_TYPE_RW2) { 293589889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon if (TAG_RW2_JPG_FROM_RAW.equals(tag.name)) { 293614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mRw2JpgFromRawOffset = offset; 293714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 293814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 293914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (offset + byteCount <= dataInputStream.mLength) { 294014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.seek(offset); 294114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 294214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip if invalid data offset. 294314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Skip the tag entry since data offset is invalid: " + offset); 294414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.seek(nextEntryOffset); 294514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 294614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 294714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 294814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 294914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Recursively parse IFD when a IFD pointer tag appears. 2950abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas Integer nextIfdType = sExifPointerTagMap.get(tagNumber); 295114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 295214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "nextIfdType: " + nextIfdType + " byteCount: " + byteCount); 295314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 295414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 295514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (nextIfdType != null) { 295614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long offset = -1L; 295714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Get offset from data field 295814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon switch (dataFormat) { 295914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_USHORT: { 296014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon offset = dataInputStream.readUnsignedShort(); 296114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 296214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 296314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SSHORT: { 296414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon offset = dataInputStream.readShort(); 296514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 296614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 296714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_ULONG: { 296814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon offset = dataInputStream.readUnsignedInt(); 296914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 297014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 297114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_SLONG: 297214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case IFD_FORMAT_IFD: { 297314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon offset = dataInputStream.readInt(); 297414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 297514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 297614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon default: { 297714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Nothing to do 297814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 297914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 298014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 298114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 298214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tag.name)); 298314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 298414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (offset > 0L && offset < dataInputStream.mLength) { 298514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.seek(offset); 2986abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas readImageFileDirectory(dataInputStream, nextIfdType); 298714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 298814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset); 298914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 299014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 299114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.seek(nextEntryOffset); 299214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 299314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 299414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 299514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] bytes = new byte[(int) byteCount]; 299614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.readFully(bytes); 299714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents, bytes); 299814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[ifdType].put(tag.name, attribute); 299914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 300014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // DNG files have a DNG Version tag specifying the version of specifications that the 300114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // image file is following. 300214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://fileformats.archiveteam.org/wiki/DNG 300389889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon if (TAG_DNG_VERSION.equals(tag.name)) { 300414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mMimeType = IMAGE_TYPE_DNG; 300514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 300614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 300714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // PEF files have a Make or Model tag that begins with "PENTAX" or a compression tag 300814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // that is 65535. 300914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See http://fileformats.archiveteam.org/wiki/Pentax_PEF 301089889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon if (((TAG_MAKE.equals(tag.name) || TAG_MODEL.equals(tag.name)) 301114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon && attribute.getStringValue(mExifByteOrder).contains(PEF_SIGNATURE)) 301289889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon || (TAG_COMPRESSION.equals(tag.name) 301314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon && attribute.getIntValue(mExifByteOrder) == 65535)) { 301414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mMimeType = IMAGE_TYPE_PEF; 301514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 301614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 301714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Seek to next tag offset 301814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.peek() != nextEntryOffset) { 301914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.seek(nextEntryOffset); 302014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 302114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 302214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 302314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataInputStream.peek() + 4 <= dataInputStream.mLength) { 302414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int nextIfdOffset = dataInputStream.readInt(); 302514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 302614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset)); 302714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 302814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The next IFD offset needs to be bigger than 8 302914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // since the first IFD offset is at least 8. 303014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (nextIfdOffset > 8 && nextIfdOffset < dataInputStream.mLength) { 303114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataInputStream.seek(nextIfdOffset); 303214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) { 303314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Do not overwrite thumbnail IFD data if it alreay exists. 303414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon readImageFileDirectory(dataInputStream, IFD_TYPE_THUMBNAIL); 303514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mAttributes[IFD_TYPE_PREVIEW].isEmpty()) { 303614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon readImageFileDirectory(dataInputStream, IFD_TYPE_PREVIEW); 303714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 303814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 303914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 304014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 304114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 304214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 304314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * JPEG compressed images do not contain IMAGE_LENGTH & IMAGE_WIDTH tags. 304414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This value uses JpegInterchangeFormat(JPEG data offset) value, and calls getJpegAttributes() 304514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * to locate SOF(Start of Frame) marker and update the image length & width values. 304614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See JEITA CP-3451C Table 5 and Section 4.8.1. B. 304714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 304814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void retrieveJpegImageSize(ByteOrderedDataInputStream in, int imageType) 304914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throws IOException { 305014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check if image already has IMAGE_LENGTH & IMAGE_WIDTH values 305114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageLengthAttribute = 305214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_LENGTH); 305314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageWidthAttribute = 305414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_WIDTH); 305514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 305614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (imageLengthAttribute == null || imageWidthAttribute == null) { 305714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Find if offset for JPEG data exists 305814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute jpegInterchangeFormatAttribute = 305914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[imageType].get(TAG_JPEG_INTERCHANGE_FORMAT); 306014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (jpegInterchangeFormatAttribute != null) { 306114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int jpegInterchangeFormat = 306214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder); 306314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 306414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Searches for SOF marker in JPEG data and updates IMAGE_LENGTH & IMAGE_WIDTH tags 306514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon getJpegAttributes(in, jpegInterchangeFormat, imageType); 306614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 306714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 306814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 306914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 307014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Sets thumbnail offset & length attributes based on JpegInterchangeFormat or StripOffsets tags 307114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void setThumbnailData(ByteOrderedDataInputStream in) throws IOException { 307214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon HashMap thumbnailData = mAttributes[IFD_TYPE_THUMBNAIL]; 307314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 307414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute compressionAttribute = 307514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) thumbnailData.get(TAG_COMPRESSION); 307614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (compressionAttribute != null) { 307714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailCompression = compressionAttribute.getIntValue(mExifByteOrder); 307814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon switch (mThumbnailCompression) { 307914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case DATA_JPEG: { 308014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon handleThumbnailFromJfif(in, thumbnailData); 308114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 308214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 308314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case DATA_UNCOMPRESSED: 308414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon case DATA_JPEG_COMPRESSED: { 308514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (isSupportedDataType(thumbnailData)) { 308614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon handleThumbnailFromStrips(in, thumbnailData); 308714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 308814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon break; 308914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 309014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 309114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 309214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Thumbnail data may not contain Compression tag value 309314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailCompression = DATA_JPEG; 309414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon handleThumbnailFromJfif(in, thumbnailData); 309514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 309614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 309714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 309814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check JpegInterchangeFormat(JFIF) tags to retrieve thumbnail offset & length values 309914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // and reads the corresponding bytes if stream does not support seek function 310014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void handleThumbnailFromJfif(ByteOrderedDataInputStream in, HashMap thumbnailData) 310114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throws IOException { 310214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute jpegInterchangeFormatAttribute = 310314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT); 310414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute jpegInterchangeFormatLengthAttribute = 310514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH); 310614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (jpegInterchangeFormatAttribute != null 310714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon && jpegInterchangeFormatLengthAttribute != null) { 310814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int thumbnailOffset = jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder); 310914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder); 311014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 311114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The following code limits the size of thumbnail size not to overflow EXIF data area. 311214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon thumbnailLength = Math.min(thumbnailLength, in.available() - thumbnailOffset); 311314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF 311414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon || mMimeType == IMAGE_TYPE_RW2) { 311514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon thumbnailOffset += mExifOffset; 311614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mMimeType == IMAGE_TYPE_ORF) { 311714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Update offset value since RAF files have IFD data preceding MakerNote data. 311814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon thumbnailOffset += mOrfMakerNoteOffset; 311914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 312014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 312114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset 312214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + ", length: " + thumbnailLength); 312314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 312414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (thumbnailOffset > 0 && thumbnailLength > 0) { 312514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mHasThumbnail = true; 312614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailOffset = thumbnailOffset; 312714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailLength = thumbnailLength; 312814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mFilename == null && mAssetInputStream == null) { 312914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Save the thumbnail in memory if the input doesn't support reading again. 313014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] thumbnailBytes = new byte[thumbnailLength]; 313114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.seek(thumbnailOffset); 313214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.readFully(thumbnailBytes); 313314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailBytes = thumbnailBytes; 313414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 313514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 313614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 313714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 313814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 313914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check StripOffsets & StripByteCounts tags to retrieve thumbnail offset & length values 314014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void handleThumbnailFromStrips(ByteOrderedDataInputStream in, HashMap thumbnailData) 314114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throws IOException { 314214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute stripOffsetsAttribute = 314314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) thumbnailData.get(TAG_STRIP_OFFSETS); 314414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute stripByteCountsAttribute = 314514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) thumbnailData.get(TAG_STRIP_BYTE_COUNTS); 314614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 314714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (stripOffsetsAttribute != null && stripByteCountsAttribute != null) { 314814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long[] stripOffsets = 3149f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon convertToLongArray(stripOffsetsAttribute.getValue(mExifByteOrder)); 315014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long[] stripByteCounts = 3151f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder)); 315214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 315314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (stripOffsets == null) { 315414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "stripOffsets should not be null."); 315514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 315614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 315714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (stripByteCounts == null) { 315814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "stripByteCounts should not be null."); 315914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 316014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 316114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 316214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon long totalStripByteCount = 0; 316314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (long byteCount : stripByteCounts) { 316414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon totalStripByteCount += byteCount; 316514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 316614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 316714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Set thumbnail byte array data for non-consecutive strip bytes 316814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] totalStripBytes = new byte[(int) totalStripByteCount]; 316914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 317014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int bytesRead = 0; 317114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int bytesAdded = 0; 317214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < stripOffsets.length; i++) { 317314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int stripOffset = (int) stripOffsets[i]; 317414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int stripByteCount = (int) stripByteCounts[i]; 317514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 317614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Skip to offset 317714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int skipBytes = stripOffset - bytesRead; 317814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (skipBytes < 0) { 317914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Invalid strip offset value"); 318014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 318114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.seek(skipBytes); 318214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytesRead += skipBytes; 318314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 318414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Read strip bytes 318514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] stripBytes = new byte[stripByteCount]; 318614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon in.read(stripBytes); 318714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytesRead += stripByteCount; 318814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 318914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Add bytes to array 319014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon System.arraycopy(stripBytes, 0, totalStripBytes, bytesAdded, 319114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon stripBytes.length); 319214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bytesAdded += stripBytes.length; 319314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 319414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 319514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mHasThumbnail = true; 319614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailBytes = totalStripBytes; 319714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailLength = totalStripBytes.length; 319814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 319914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 320014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 320114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check if thumbnail data type is currently supported or not 320214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private boolean isSupportedDataType(HashMap thumbnailData) throws IOException { 320314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute bitsPerSampleAttribute = 320414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) thumbnailData.get(TAG_BITS_PER_SAMPLE); 320514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (bitsPerSampleAttribute != null) { 320614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] bitsPerSampleValue = (int[]) bitsPerSampleAttribute.getValue(mExifByteOrder); 320714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 320814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (Arrays.equals(BITS_PER_SAMPLE_RGB, bitsPerSampleValue)) { 320914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return true; 321014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 321114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 321214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See DNG Specification 1.4.0.0. Section 3, Compression. 321314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mMimeType == IMAGE_TYPE_DNG) { 321414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute photometricInterpretationAttribute = 321514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) thumbnailData.get(TAG_PHOTOMETRIC_INTERPRETATION); 321614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (photometricInterpretationAttribute != null) { 321714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int photometricInterpretationValue 321814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon = photometricInterpretationAttribute.getIntValue(mExifByteOrder); 321914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if ((photometricInterpretationValue == PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO 322014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon && Arrays.equals(bitsPerSampleValue, BITS_PER_SAMPLE_GREYSCALE_2)) 322114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon || ((photometricInterpretationValue == PHOTOMETRIC_INTERPRETATION_YCBCR) 322214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon && (Arrays.equals(bitsPerSampleValue, BITS_PER_SAMPLE_RGB)))) { 322314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return true; 322414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 322514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // TODO: Add support for lossless Huffman JPEG data 322614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 322714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 322814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 322914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 323014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 323114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Unsupported data type value"); 323214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 323314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return false; 323414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 323514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 323614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Returns true if the image length and width values are <= 512. 323714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See Section 4.8 of http://standardsproposals.bsigroup.com/Home/getPDF/567 323814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private boolean isThumbnail(HashMap map) throws IOException { 323914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageLengthAttribute = (ExifAttribute) map.get(TAG_IMAGE_LENGTH); 324014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageWidthAttribute = (ExifAttribute) map.get(TAG_IMAGE_WIDTH); 324114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 324214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (imageLengthAttribute != null && imageWidthAttribute != null) { 324314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int imageLengthValue = imageLengthAttribute.getIntValue(mExifByteOrder); 324414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int imageWidthValue = imageWidthAttribute.getIntValue(mExifByteOrder); 324514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (imageLengthValue <= MAX_THUMBNAIL_SIZE && imageWidthValue <= MAX_THUMBNAIL_SIZE) { 324614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return true; 324714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 324814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 324914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return false; 325014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 325114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 325214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Validate primary, preview, thumbnail image data by comparing image size 325314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void validateImages(InputStream in) throws IOException { 325414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Swap images based on size (primary > preview > thumbnail) 325514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon swapBasedOnImageSize(IFD_TYPE_PRIMARY, IFD_TYPE_PREVIEW); 325614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon swapBasedOnImageSize(IFD_TYPE_PRIMARY, IFD_TYPE_THUMBNAIL); 325714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon swapBasedOnImageSize(IFD_TYPE_PREVIEW, IFD_TYPE_THUMBNAIL); 325814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 325914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check if image has PixelXDimension/PixelYDimension tags, which contain valid image 326014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // sizes, excluding padding at the right end or bottom end of the image to make sure that 326114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // the values are multiples of 64. See JEITA CP-3451C Table 5 and Section 4.8.1. B. 326214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute pixelXDimAttribute = 326314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_X_DIMENSION); 326414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute pixelYDimAttribute = 326514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_Y_DIMENSION); 326614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (pixelXDimAttribute != null && pixelYDimAttribute != null) { 326714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, pixelXDimAttribute); 326814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, pixelYDimAttribute); 326914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 327014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 327114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check whether thumbnail image exists and whether preview image satisfies the thumbnail 327214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // image requirements 327314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) { 327414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (isThumbnail(mAttributes[IFD_TYPE_PREVIEW])) { 327514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_THUMBNAIL] = mAttributes[IFD_TYPE_PREVIEW]; 3276abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas mAttributes[IFD_TYPE_PREVIEW] = new HashMap<>(); 327714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 327814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 327914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 328014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Check if the thumbnail image satisfies the thumbnail size requirements 328114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!isThumbnail(mAttributes[IFD_TYPE_THUMBNAIL])) { 328214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "No image meets the size requirements of a thumbnail image."); 328314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 328414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 328514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 328614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 328714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * If image is uncompressed, ImageWidth/Length tags are used to store size info. 328814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * However, uncompressed images often store extra pixels around the edges of the final image, 328914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * which results in larger values for TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH tags. 329014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This method corrects those tag values by checking first the values of TAG_DEFAULT_CROP_SIZE 329114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See DNG Specification 1.4.0.0. Section 4. (DefaultCropSize) 329214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 329314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * If image is a RW2 file, valid image sizes are stored in SensorBorder tags. 329414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See tiff_parser.cc GetFullDimension32() 329514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * */ 329614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void updateImageSizeValues(ByteOrderedDataInputStream in, int imageType) 329714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throws IOException { 329814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Uncompressed image valid image size values 329914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute defaultCropSizeAttribute = 330014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[imageType].get(TAG_DEFAULT_CROP_SIZE); 330114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // RW2 image valid image size values 330214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute topBorderAttribute = 330314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_TOP_BORDER); 330414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute leftBorderAttribute = 330514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_LEFT_BORDER); 330614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute bottomBorderAttribute = 330714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_BOTTOM_BORDER); 330814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute rightBorderAttribute = 330914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_RIGHT_BORDER); 331014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 331114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (defaultCropSizeAttribute != null) { 331214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Update for uncompressed image 331314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute defaultCropSizeXAttribute, defaultCropSizeYAttribute; 331414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (defaultCropSizeAttribute.format == IFD_FORMAT_URATIONAL) { 331514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Rational[] defaultCropSizeValue = 331614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (Rational[]) defaultCropSizeAttribute.getValue(mExifByteOrder); 331714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (defaultCropSizeValue == null || defaultCropSizeValue.length != 2) { 331814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Invalid crop size values. cropSize=" 331914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + Arrays.toString(defaultCropSizeValue)); 332014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 332114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 332214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon defaultCropSizeXAttribute = 332314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createURational(defaultCropSizeValue[0], mExifByteOrder); 332414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon defaultCropSizeYAttribute = 332514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createURational(defaultCropSizeValue[1], mExifByteOrder); 332614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 332714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] defaultCropSizeValue = 332814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (int[]) defaultCropSizeAttribute.getValue(mExifByteOrder); 332914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (defaultCropSizeValue == null || defaultCropSizeValue.length != 2) { 333014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.w(TAG, "Invalid crop size values. cropSize=" 333114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + Arrays.toString(defaultCropSizeValue)); 333214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 333314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 333414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon defaultCropSizeXAttribute = 333514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(defaultCropSizeValue[0], mExifByteOrder); 333614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon defaultCropSizeYAttribute = 333714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(defaultCropSizeValue[1], mExifByteOrder); 333814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 333914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[imageType].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute); 334014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[imageType].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute); 334114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (topBorderAttribute != null && leftBorderAttribute != null && 334214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon bottomBorderAttribute != null && rightBorderAttribute != null) { 334314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Update for RW2 image 334414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int topBorderValue = topBorderAttribute.getIntValue(mExifByteOrder); 334514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int bottomBorderValue = bottomBorderAttribute.getIntValue(mExifByteOrder); 334614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int rightBorderValue = rightBorderAttribute.getIntValue(mExifByteOrder); 334714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int leftBorderValue = leftBorderAttribute.getIntValue(mExifByteOrder); 334814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (bottomBorderValue > topBorderValue && rightBorderValue > leftBorderValue) { 334914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int length = bottomBorderValue - topBorderValue; 335014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int width = rightBorderValue - leftBorderValue; 335114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageLengthAttribute = 335214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(length, mExifByteOrder); 335314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute imageWidthAttribute = 335414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createUShort(width, mExifByteOrder); 335514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[imageType].put(TAG_IMAGE_LENGTH, imageLengthAttribute); 335614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[imageType].put(TAG_IMAGE_WIDTH, imageWidthAttribute); 335714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 335814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 335914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon retrieveJpegImageSize(in, imageType); 336014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 336114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 336214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 336314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Writes an Exif segment into the given output stream. 336414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream, 336514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int exifOffsetFromBeginning) throws IOException { 336614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // The following variables are for calculating each IFD tag group size in bytes. 336714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] ifdOffsets = new int[EXIF_TAGS.length]; 336814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int[] ifdDataSizes = new int[EXIF_TAGS.length]; 336914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 337014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Remove IFD pointer tags (we'll re-add it later.) 337114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (ExifTag tag : EXIF_POINTER_TAGS) { 337214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon removeAttribute(tag.name); 337314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 337414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Remove old thumbnail data 337514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon removeAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name); 337614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon removeAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name); 337714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 337814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Remove null value tags. 337914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) { 338014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (Object obj : mAttributes[ifdType].entrySet().toArray()) { 338114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final Map.Entry entry = (Map.Entry) obj; 338214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (entry.getValue() == null) { 338314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[ifdType].remove(entry.getKey()); 338414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 338514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 338614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 338714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 338814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD 338914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // offset when there is one or more tags in the thumbnail IFD. 339014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mAttributes[IFD_TYPE_EXIF].isEmpty()) { 339114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[1].name, 339214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(0, mExifByteOrder)); 339314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 339414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mAttributes[IFD_TYPE_GPS].isEmpty()) { 339514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[2].name, 339614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(0, mExifByteOrder)); 339714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 339814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mAttributes[IFD_TYPE_INTEROPERABILITY].isEmpty()) { 339914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_EXIF].put(EXIF_POINTER_TAGS[3].name, 340014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(0, mExifByteOrder)); 340114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 340214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mHasThumbnail) { 340314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name, 340414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(0, mExifByteOrder)); 340514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, 340614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(mThumbnailLength, mExifByteOrder)); 340714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 340814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 340914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Calculate IFD group data area sizes. IFD group data area is assigned to save the entry 341014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // value which has a bigger size than 4 bytes. 341114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < EXIF_TAGS.length; ++i) { 341214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int sum = 0; 3413abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas for (Map.Entry<String, ExifAttribute> entry : mAttributes[i].entrySet()) { 3414abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas final ExifAttribute exifAttribute = entry.getValue(); 341514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final int size = exifAttribute.size(); 341614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (size > 4) { 341714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon sum += size; 341814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 341914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 342014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ifdDataSizes[i] += sum; 342114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 342214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 342314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Calculate IFD offsets. 342414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int position = 8; 342514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) { 342614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mAttributes[ifdType].isEmpty()) { 342714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ifdOffsets[ifdType] = position; 342814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon position += 2 + mAttributes[ifdType].size() * 12 + 4 + ifdDataSizes[ifdType]; 342914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 343014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 343114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mHasThumbnail) { 343214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int thumbnailOffset = position; 343314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name, 343414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(thumbnailOffset, mExifByteOrder)); 343514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset; 343614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon position += mThumbnailLength; 343714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 343814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 343914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Calculate the total size 344014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int totalSize = position + 8; // eight bytes is for header part. 344114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 344214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "totalSize length: " + totalSize); 344314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 0; i < EXIF_TAGS.length; ++i) { 344414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d", 344514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon i, ifdOffsets[i], mAttributes[i].size(), ifdDataSizes[i])); 344614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 344714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 344814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 344914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Update IFD pointer tags with the calculated offsets. 345014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mAttributes[IFD_TYPE_EXIF].isEmpty()) { 345114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[1].name, 345214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(ifdOffsets[IFD_TYPE_EXIF], mExifByteOrder)); 345314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 345414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mAttributes[IFD_TYPE_GPS].isEmpty()) { 345514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[2].name, 345614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute.createULong(ifdOffsets[IFD_TYPE_GPS], mExifByteOrder)); 345714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 345814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mAttributes[IFD_TYPE_INTEROPERABILITY].isEmpty()) { 345914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[IFD_TYPE_EXIF].put(EXIF_POINTER_TAGS[3].name, ExifAttribute.createULong( 346014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ifdOffsets[IFD_TYPE_INTEROPERABILITY], mExifByteOrder)); 346114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 346214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 346314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Write TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1. 346414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedShort(totalSize); 346514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.write(IDENTIFIER_EXIF_APP1); 346614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeShort(mExifByteOrder == ByteOrder.BIG_ENDIAN 346714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ? BYTE_ALIGN_MM : BYTE_ALIGN_II); 346814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.setByteOrder(mExifByteOrder); 346914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedShort(START_CODE); 347014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedInt(IFD_OFFSET); 347114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 347214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Write IFD groups. See JEITA CP-3451C Section 4.5.8. Figure 9. 347314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) { 347414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (!mAttributes[ifdType].isEmpty()) { 347514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See JEITA CP-3451C Section 4.6.2: IFD structure. 347614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Write entry count 347714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedShort(mAttributes[ifdType].size()); 347814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 347914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Write entry info 348014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int dataOffset = ifdOffsets[ifdType] + 2 + mAttributes[ifdType].size() * 12 + 4; 3481abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas for (Map.Entry<String, ExifAttribute> entry : mAttributes[ifdType].entrySet()) { 348214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Convert tag name to tag number. 3483abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas final ExifTag tag = sExifTagMapsForWriting[ifdType].get(entry.getKey()); 348414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final int tagNumber = tag.number; 3485abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas final ExifAttribute attribute = entry.getValue(); 348614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final int size = attribute.size(); 348714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 348814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedShort(tagNumber); 348914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedShort(attribute.format); 349014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeInt(attribute.numberOfComponents); 349114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (size > 4) { 349214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedInt(dataOffset); 349314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOffset += size; 349414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 349514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.write(attribute.bytes); 349614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Fill zero up to 4 bytes 349714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (size < 4) { 349814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = size; i < 4; ++i) { 349914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeByte(0); 350014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 350114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 350214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 350314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 350414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 350514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Write the next offset. It writes the offset of thumbnail IFD if there is one or 350614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // more tags in the thumbnail IFD when the current IFD is the primary image TIFF 350714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // IFD; Otherwise 0. 350814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (ifdType == 0 && !mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) { 350914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedInt(ifdOffsets[IFD_TYPE_THUMBNAIL]); 351014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 351114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.writeUnsignedInt(0); 351214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 351314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 351414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Write values of data field exceeding 4 bytes after the next offset. 3515abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas for (Map.Entry<String, ExifAttribute> entry : mAttributes[ifdType].entrySet()) { 3516abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas ExifAttribute attribute = entry.getValue(); 351714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 351814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (attribute.bytes.length > 4) { 351914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.write(attribute.bytes, 0, attribute.bytes.length); 352014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 352114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 352214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 352314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 352414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 352514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Write thumbnail 352614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mHasThumbnail) { 352714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.write(getThumbnailBytes()); 352814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 352914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 353014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Reset the byte order to big endian in order to write remaining parts of the JPEG file. 353114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN); 353214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 353314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return totalSize; 353414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 353514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 353614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 353714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Determines the data format of EXIF entry value. 353814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * 353914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @param entryValue The value to be determined. 354014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * @return Returns two data formats gussed as a pair in integer. If there is no two candidate 354114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon data formats for the given entry value, returns {@code -1} in the second of the pair. 354214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 354314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static Pair<Integer, Integer> guessDataFormat(String entryValue) { 354414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // See TIFF 6.0 Section 2, "Image File Directory". 354514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Take the first component if there are more than one component. 354614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (entryValue.contains(",")) { 354714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String[] entryValues = entryValue.split(","); 354814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Pair<Integer, Integer> dataFormat = guessDataFormat(entryValues[0]); 354914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (dataFormat.first == IFD_FORMAT_STRING) { 355014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return dataFormat; 355114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 355214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon for (int i = 1; i < entryValues.length; ++i) { 355314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon final Pair<Integer, Integer> guessDataFormat = guessDataFormat(entryValues[i]); 355414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int first = -1, second = -1; 355589889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon if (guessDataFormat.first.equals(dataFormat.first) 355689889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon || guessDataFormat.second.equals(dataFormat.first)) { 355714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon first = dataFormat.first; 355814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 355989889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon if (dataFormat.second != -1 && (guessDataFormat.first.equals(dataFormat.second) 356089889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon || guessDataFormat.second.equals(dataFormat.second))) { 356114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon second = dataFormat.second; 356214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 356314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (first == -1 && second == -1) { 356414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_STRING, -1); 356514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 356614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (first == -1) { 356714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataFormat = new Pair<>(second, -1); 356814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 356914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 357014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (second == -1) { 357114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon dataFormat = new Pair<>(first, -1); 357214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon continue; 357314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 357414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 357514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return dataFormat; 357614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 357714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 357814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (entryValue.contains("/")) { 357914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon String[] rationalNumber = entryValue.split("/"); 358014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (rationalNumber.length == 2) { 358114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 358277966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon long numerator = (long) Double.parseDouble(rationalNumber[0]); 358377966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon long denominator = (long) Double.parseDouble(rationalNumber[1]); 358414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (numerator < 0L || denominator < 0L) { 358514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_SRATIONAL, -1); 358614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 358714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (numerator > Integer.MAX_VALUE || denominator > Integer.MAX_VALUE) { 358814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_URATIONAL, -1); 358914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 359014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_SRATIONAL, IFD_FORMAT_URATIONAL); 359114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException e) { 359214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Ignored 359314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 359414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 359514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_STRING, -1); 359614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 359714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 359814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Long longValue = Long.parseLong(entryValue); 359914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (longValue >= 0 && longValue <= 65535) { 360014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_USHORT, IFD_FORMAT_ULONG); 360114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 360214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (longValue < 0) { 360314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_SLONG, -1); 360414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 360514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_ULONG, -1); 360614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException e) { 360714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Ignored 360814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 360914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 361014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Double.parseDouble(entryValue); 361114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_DOUBLE, -1); 361214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (NumberFormatException e) { 361314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Ignored 361414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 361514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return new Pair<>(IFD_FORMAT_STRING, -1); 361614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 361714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 361814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // An input stream to parse EXIF data area, which can be written in either little or big endian 361914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // order. 362014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static class ByteOrderedDataInputStream extends InputStream implements DataInput { 362114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN; 362214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN; 362314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 362414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private DataInputStream mDataInputStream; 362514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN; 362614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private final int mLength; 362714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private int mPosition; 362814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 362914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public ByteOrderedDataInputStream(InputStream in) throws IOException { 363014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mDataInputStream = new DataInputStream(in); 363114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mLength = mDataInputStream.available(); 363214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition = 0; 363314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mDataInputStream.mark(mLength); 363414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 363514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 363614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public ByteOrderedDataInputStream(byte[] bytes) throws IOException { 363714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon this(new ByteArrayInputStream(bytes)); 363814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 363914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 364014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void setByteOrder(ByteOrder byteOrder) { 364114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mByteOrder = byteOrder; 364214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 364314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 364414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void seek(long byteCount) throws IOException { 364514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mPosition > byteCount) { 364614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition = 0; 364714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mDataInputStream.reset(); 364814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mDataInputStream.mark(mLength); 364914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 365014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byteCount -= mPosition; 365114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 365214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 365314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (skipBytes((int) byteCount) != (int) byteCount) { 365414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Couldn't seek up to the byteCount"); 365514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 365614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 365714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 365814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int peek() { 365914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mPosition; 366014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 366114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 366214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 366314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int available() throws IOException { 366414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mDataInputStream.available(); 366514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 366614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 366714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 366814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int read() throws IOException { 366914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++mPosition; 367014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mDataInputStream.read(); 367114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 367214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 367314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 367489889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon public int read(byte[] b, int off, int len) throws IOException { 367589889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon int bytesRead = mDataInputStream.read(b, off, len); 367689889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon mPosition += bytesRead; 367789889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon return bytesRead; 367889889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon } 367989889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon 368089889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon @Override 368114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int readUnsignedByte() throws IOException { 368214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++mPosition; 368314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mDataInputStream.readUnsignedByte(); 368414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 368514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 368614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 368714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public String readLine() throws IOException { 368814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Currently unsupported"); 368914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return null; 369014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 369114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 369214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 369314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public boolean readBoolean() throws IOException { 369414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++mPosition; 369514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mDataInputStream.readBoolean(); 369614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 369714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 369814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 369914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public char readChar() throws IOException { 370014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += 2; 370114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mDataInputStream.readChar(); 370214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 370314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 370414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 370514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public String readUTF() throws IOException { 370614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += 2; 370714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return mDataInputStream.readUTF(); 370814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 370914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 371014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 371114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void readFully(byte[] buffer, int offset, int length) throws IOException { 371214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += length; 371314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mPosition > mLength) { 371414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 371514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 371614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mDataInputStream.read(buffer, offset, length) != length) { 371714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Couldn't read up to the length of buffer"); 371814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 371914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 372014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 372114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 372214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void readFully(byte[] buffer) throws IOException { 372314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += buffer.length; 372414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mPosition > mLength) { 372514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 372614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 372714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mDataInputStream.read(buffer, 0, buffer.length) != buffer.length) { 372814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Couldn't read up to the length of buffer"); 372914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 373014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 373114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 373214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 373314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public byte readByte() throws IOException { 373414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ++mPosition; 373514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mPosition > mLength) { 373614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 373714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 373814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch = mDataInputStream.read(); 373914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (ch < 0) { 374014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 374114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 374214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (byte) ch; 374314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 374414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 374514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 374614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public short readShort() throws IOException { 374714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += 2; 374814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mPosition > mLength) { 374914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 375014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 375114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch1 = mDataInputStream.read(); 375214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch2 = mDataInputStream.read(); 375314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if ((ch1 | ch2) < 0) { 375414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 375514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 375614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mByteOrder == LITTLE_ENDIAN) { 375714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (short) ((ch2 << 8) + (ch1)); 375814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mByteOrder == BIG_ENDIAN) { 375914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (short) ((ch1 << 8) + (ch2)); 376014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 376114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid byte order: " + mByteOrder); 376214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 376314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 376414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 376514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int readInt() throws IOException { 376614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += 4; 376714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mPosition > mLength) { 376814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 376914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 377014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch1 = mDataInputStream.read(); 377114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch2 = mDataInputStream.read(); 377214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch3 = mDataInputStream.read(); 377314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch4 = mDataInputStream.read(); 377414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if ((ch1 | ch2 | ch3 | ch4) < 0) { 377514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 377614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 377714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mByteOrder == LITTLE_ENDIAN) { 377814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1); 377914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mByteOrder == BIG_ENDIAN) { 378014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); 378114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 378214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid byte order: " + mByteOrder); 378314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 378414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 378514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 378614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int skipBytes(int byteCount) throws IOException { 378714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int totalSkip = Math.min(byteCount, mLength - mPosition); 378814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int skipped = 0; 378914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon while (skipped < totalSkip) { 379014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon skipped += mDataInputStream.skipBytes(totalSkip - skipped); 379114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 379214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += skipped; 379314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return skipped; 379414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 379514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 3796e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 379714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public int readUnsignedShort() throws IOException { 379814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += 2; 379914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mPosition > mLength) { 380014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 380114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 380214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch1 = mDataInputStream.read(); 380314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch2 = mDataInputStream.read(); 380414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if ((ch1 | ch2) < 0) { 380514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 380614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 380714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mByteOrder == LITTLE_ENDIAN) { 380814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return ((ch2 << 8) + (ch1)); 380914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mByteOrder == BIG_ENDIAN) { 381014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return ((ch1 << 8) + (ch2)); 381114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 381214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid byte order: " + mByteOrder); 381314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 381414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 381514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public long readUnsignedInt() throws IOException { 381614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return readInt() & 0xffffffffL; 381714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 381814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 381914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 382014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public long readLong() throws IOException { 382114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mPosition += 8; 382214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mPosition > mLength) { 382314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 382414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 382514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch1 = mDataInputStream.read(); 382614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch2 = mDataInputStream.read(); 382714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch3 = mDataInputStream.read(); 382814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch4 = mDataInputStream.read(); 382914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch5 = mDataInputStream.read(); 383014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch6 = mDataInputStream.read(); 383114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch7 = mDataInputStream.read(); 383214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int ch8 = mDataInputStream.read(); 383314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) { 383414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new EOFException(); 383514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 383614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mByteOrder == LITTLE_ENDIAN) { 383714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (((long) ch8 << 56) + ((long) ch7 << 48) + ((long) ch6 << 40) 383814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + ((long) ch5 << 32) + ((long) ch4 << 24) + ((long) ch3 << 16) 383914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + ((long) ch2 << 8) + (long) ch1); 384014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mByteOrder == BIG_ENDIAN) { 384114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return (((long) ch1 << 56) + ((long) ch2 << 48) + ((long) ch3 << 40) 384214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + ((long) ch4 << 32) + ((long) ch5 << 24) + ((long) ch6 << 16) 384314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon + ((long) ch7 << 8) + (long) ch8); 384414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 384514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw new IOException("Invalid byte order: " + mByteOrder); 384614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 384714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 384814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 384914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public float readFloat() throws IOException { 385014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return Float.intBitsToFloat(readInt()); 385114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 385214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 385314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon @Override 385414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public double readDouble() throws IOException { 385514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return Double.longBitsToDouble(readLong()); 385614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 385714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 385814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 385914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // An output stream to write EXIF data area, which can be written in either little or big endian 386014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // order. 386114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static class ByteOrderedDataOutputStream extends FilterOutputStream { 386214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private final OutputStream mOutputStream; 386314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private ByteOrder mByteOrder; 386414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 386514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public ByteOrderedDataOutputStream(OutputStream out, ByteOrder byteOrder) { 386614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon super(out); 386714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream = out; 386814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mByteOrder = byteOrder; 386914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 387014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 387114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void setByteOrder(ByteOrder byteOrder) { 387214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mByteOrder = byteOrder; 387314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 387414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 3875e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 387614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void write(byte[] bytes) throws IOException { 387714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write(bytes); 387814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 387914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 3880e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 388114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void write(byte[] bytes, int offset, int length) throws IOException { 388214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write(bytes, offset, length); 388314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 388414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 388514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void writeByte(int val) throws IOException { 388614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write(val); 388714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 388814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 388914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void writeShort(short val) throws IOException { 389014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mByteOrder == ByteOrder.LITTLE_ENDIAN) { 389114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 0) & 0xFF); 389214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 8) & 0xFF); 389314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mByteOrder == ByteOrder.BIG_ENDIAN) { 389414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 8) & 0xFF); 389514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 0) & 0xFF); 389614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 389714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 389814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 389914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void writeInt(int val) throws IOException { 390014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mByteOrder == ByteOrder.LITTLE_ENDIAN) { 390114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 0) & 0xFF); 390214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 8) & 0xFF); 390314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 16) & 0xFF); 390414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 24) & 0xFF); 390514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (mByteOrder == ByteOrder.BIG_ENDIAN) { 390614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 24) & 0xFF); 390714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 16) & 0xFF); 390814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 8) & 0xFF); 390914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mOutputStream.write((val >>> 0) & 0xFF); 391014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 391114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 391214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 391314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void writeUnsignedShort(int val) throws IOException { 391414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon writeShort((short) val); 391514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 391614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 391714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon public void writeUnsignedInt(long val) throws IOException { 391814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon writeInt((int) val); 391914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 392014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 392114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 392214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon // Swaps image data based on image size 392314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private void swapBasedOnImageSize(@IfdType int firstIfdType, @IfdType int secondIfdType) 392414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throws IOException { 392514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (mAttributes[firstIfdType].isEmpty() || mAttributes[secondIfdType].isEmpty()) { 392614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 392714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Cannot perform swap since only one image data exists"); 392814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 392914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return; 393014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 393114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 393214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute firstImageLengthAttribute = 393314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[firstIfdType].get(TAG_IMAGE_LENGTH); 393414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute firstImageWidthAttribute = 393514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[firstIfdType].get(TAG_IMAGE_WIDTH); 393614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute secondImageLengthAttribute = 393714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[secondIfdType].get(TAG_IMAGE_LENGTH); 393814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon ExifAttribute secondImageWidthAttribute = 393914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon (ExifAttribute) mAttributes[secondIfdType].get(TAG_IMAGE_WIDTH); 394014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 394114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (firstImageLengthAttribute == null || firstImageWidthAttribute == null) { 394214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 394314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "First image does not contain valid size information"); 394414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 394514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else if (secondImageLengthAttribute == null || secondImageWidthAttribute == null) { 394614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (DEBUG) { 394714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon Log.d(TAG, "Second image does not contain valid size information"); 394814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 394914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } else { 395014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int firstImageLengthValue = firstImageLengthAttribute.getIntValue(mExifByteOrder); 395114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int firstImageWidthValue = firstImageWidthAttribute.getIntValue(mExifByteOrder); 395214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int secondImageLengthValue = secondImageLengthAttribute.getIntValue(mExifByteOrder); 395314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int secondImageWidthValue = secondImageWidthAttribute.getIntValue(mExifByteOrder); 395414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 395514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (firstImageLengthValue < secondImageLengthValue && 395614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon firstImageWidthValue < secondImageWidthValue) { 3957abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas HashMap<String, ExifAttribute> tempMap = mAttributes[firstIfdType]; 395814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[firstIfdType] = mAttributes[secondIfdType]; 395914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon mAttributes[secondIfdType] = tempMap; 396014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 396114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 396214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 396314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 396414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 396514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. 396614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 396714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static void closeQuietly(Closeable closeable) { 396814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon if (closeable != null) { 396914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon try { 397014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon closeable.close(); 397114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (RuntimeException rethrown) { 397214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon throw rethrown; 397314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } catch (Exception ignored) { 397414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 397514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 397614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 397714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon 397814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon /** 397914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed. 398014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Returns the total number of bytes transferred. 398114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */ 398214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon private static int copy(InputStream in, OutputStream out) throws IOException { 398314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int total = 0; 398414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon byte[] buffer = new byte[8192]; 398514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon int c; 398614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon while ((c = in.read(buffer)) != -1) { 398714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon total += c; 398814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon out.write(buffer, 0, c); 398914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 399014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon return total; 399114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon } 3992f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon 3993f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon /** 3994f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon * Convert given int[] to long[]. If long[] is given, just return it. 3995f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon * Return null for other types of input. 3996f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon */ 3997f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon private static long[] convertToLongArray(Object inputObj) { 3998f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon if (inputObj instanceof int[]) { 3999f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon int[] input = (int[]) inputObj; 4000f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon long[] result = new long[input.length]; 4001f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon for (int i = 0; i < input.length; i++) { 4002f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon result[i] = input[i]; 4003f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon } 4004f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon return result; 4005f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon } else if (inputObj instanceof long[]) { 4006f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon return (long[]) inputObj; 4007f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon } 4008f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon return null; 4009f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon } 401014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon} 4011