Merge "ExifInterface: Add PEF, RW2 files parse support"
diff --git a/api/current.txt b/api/current.txt
index 6a6d8db..fbc2faa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20141,7 +20141,6 @@
field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
- field public static final java.lang.String TAG_ASPECT_FRAME = "AspectFrame";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
@@ -20223,18 +20222,26 @@
field public static final java.lang.String TAG_MODEL = "Model";
field public static final java.lang.String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
field public static final java.lang.String TAG_OECF = "OECF";
+ field public static final java.lang.String TAG_ORF_ASPECT_FRAME = "AspectFrame";
+ field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
+ field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
+ field public static final java.lang.String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
- field public static final java.lang.String TAG_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
- field public static final java.lang.String TAG_PREVIEW_IMAGE_START = "PreviewImageStart";
field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+ field public static final java.lang.String TAG_RW2_ISO = "ISO";
+ field public static final java.lang.String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
+ field public static final java.lang.String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
field public static final java.lang.String TAG_SATURATION = "Saturation";
field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
@@ -20257,7 +20264,6 @@
field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
field public static final deprecated java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
- field public static final java.lang.String TAG_THUMBNAIL_IMAGE = "ThumbnailImage";
field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
diff --git a/api/system-current.txt b/api/system-current.txt
index edba227..b2e0ee6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -21653,7 +21653,6 @@
field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
- field public static final java.lang.String TAG_ASPECT_FRAME = "AspectFrame";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
@@ -21735,18 +21734,26 @@
field public static final java.lang.String TAG_MODEL = "Model";
field public static final java.lang.String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
field public static final java.lang.String TAG_OECF = "OECF";
+ field public static final java.lang.String TAG_ORF_ASPECT_FRAME = "AspectFrame";
+ field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
+ field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
+ field public static final java.lang.String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
- field public static final java.lang.String TAG_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
- field public static final java.lang.String TAG_PREVIEW_IMAGE_START = "PreviewImageStart";
field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+ field public static final java.lang.String TAG_RW2_ISO = "ISO";
+ field public static final java.lang.String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
+ field public static final java.lang.String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
field public static final java.lang.String TAG_SATURATION = "Saturation";
field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
@@ -21769,7 +21776,6 @@
field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
field public static final deprecated java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
- field public static final java.lang.String TAG_THUMBNAIL_IMAGE = "ThumbnailImage";
field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
diff --git a/api/test-current.txt b/api/test-current.txt
index a7d5a780..5f5fd76 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -20211,7 +20211,6 @@
field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
- field public static final java.lang.String TAG_ASPECT_FRAME = "AspectFrame";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
@@ -20293,18 +20292,26 @@
field public static final java.lang.String TAG_MODEL = "Model";
field public static final java.lang.String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
field public static final java.lang.String TAG_OECF = "OECF";
+ field public static final java.lang.String TAG_ORF_ASPECT_FRAME = "AspectFrame";
+ field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
+ field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
+ field public static final java.lang.String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
- field public static final java.lang.String TAG_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
- field public static final java.lang.String TAG_PREVIEW_IMAGE_START = "PreviewImageStart";
field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+ field public static final java.lang.String TAG_RW2_ISO = "ISO";
+ field public static final java.lang.String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
+ field public static final java.lang.String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
+ field public static final java.lang.String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
field public static final java.lang.String TAG_SATURATION = "Saturation";
field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
@@ -20327,7 +20334,6 @@
field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
field public static final deprecated java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
- field public static final java.lang.String TAG_THUMBNAIL_IMAGE = "ThumbnailImage";
field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 563d9cb..dad6701 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -349,11 +349,44 @@
public static final String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
/** Type is int. DNG Specification 1.4.0.0. Section 4 */
public static final String TAG_DEFAULT_CROP_SIZE = "DefaultCropSize";
- /** Type is int. ORF Specification. http://www.exiv2.org/tags-olympus.html */
- public static final String TAG_THUMBNAIL_IMAGE = "ThumbnailImage";
- public static final String TAG_PREVIEW_IMAGE_START = "PreviewImageStart";
- public static final String TAG_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
- public static final String TAG_ASPECT_FRAME = "AspectFrame";
+ /** Type is undefined. See Olympus MakerNote tags in http://www.exiv2.org/tags-olympus.html. */
+ public static final String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
+ /** Type is int. See Olympus Camera Settings tags in http://www.exiv2.org/tags-olympus.html. */
+ public static final String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
+ /** Type is int. See Olympus Camera Settings tags in http://www.exiv2.org/tags-olympus.html. */
+ public static final String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
+ /** Type is int. See Olympus Image Processing tags in http://www.exiv2.org/tags-olympus.html. */
+ public static final String TAG_ORF_ASPECT_FRAME = "AspectFrame";
+ /**
+ * Type is int. See PanasonicRaw tags in
+ * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
+ */
+ public static final String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
+ /**
+ * Type is int. See PanasonicRaw tags in
+ * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
+ */
+ public static final String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
+ /**
+ * Type is int. See PanasonicRaw tags in
+ * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
+ */
+ public static final String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
+ /**
+ * Type is int. See PanasonicRaw tags in
+ * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
+ */
+ public static final String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
+ /**
+ * Type is int. See PanasonicRaw tags in
+ * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
+ */
+ public static final String TAG_RW2_ISO = "ISO";
+ /**
+ * Type is undefined. See PanasonicRaw tags in
+ * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
+ */
+ public static final String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
/**
* Private tags used for pointing the other IFD offsets.
@@ -365,10 +398,10 @@
private static final String TAG_GPS_INFO_IFD_POINTER = "GPSInfoIFDPointer";
private static final String TAG_INTEROPERABILITY_IFD_POINTER = "InteroperabilityIFDPointer";
private static final String TAG_SUB_IFD_POINTER = "SubIFDPointer";
- // Proprietary pointer tags used for ORF file format.
+ // Proprietary pointer tags used for ORF files.
// See http://www.exiv2.org/tags-olympus.html
- private static final String TAG_CAMERA_SETTINGS_IFD_POINTER = "CameraSettingsIFDPointer";
- private static final String TAG_IMAGE_PROCESSING_IFD_POINTER = "ImageProcessingIFDPointer";
+ private static final String TAG_ORF_CAMERA_SETTINGS_IFD_POINTER = "CameraSettingsIFDPointer";
+ private static final String TAG_ORF_IMAGE_PROCESSING_IFD_POINTER = "ImageProcessingIFDPointer";
// Private tags used for thumbnail information.
private static final String TAG_HAS_THUMBNAIL = "HasThumbnail";
@@ -417,6 +450,14 @@
private static final int ORF_MAKER_NOTE_HEADER_1_SIZE = 8;
private static final int ORF_MAKER_NOTE_HEADER_2_SIZE = 12;
+ // See http://fileformats.archiveteam.org/wiki/RW2
+ private static final short RW2_SIGNATURE = 0x0055;
+
+ // See http://fileformats.archiveteam.org/wiki/Pentax_PEF
+ private static final String PEF_SIGNATURE = "PENTAX";
+ // See http://www.exiv2.org/makernote.html#R11
+ private static final int PEF_MAKER_NOTE_SKIP_SIZE = 6;
+
private static SimpleDateFormat sFormatter;
// See Exchangeable image file format for digital still cameras: Exif version 2.2.
@@ -923,7 +964,15 @@
new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL),
new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING),
new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
- new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG)
+ new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
+ // RW2 file tags
+ // See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html)
+ new ExifTag(TAG_RW2_SENSOR_TOP_BORDER, 4, IFD_FORMAT_ULONG),
+ new ExifTag(TAG_RW2_SENSOR_LEFT_BORDER, 5, IFD_FORMAT_ULONG),
+ new ExifTag(TAG_RW2_SENSOR_BOTTOM_BORDER, 6, IFD_FORMAT_ULONG),
+ new ExifTag(TAG_RW2_SENSOR_RIGHT_BORDER, 7, IFD_FORMAT_ULONG),
+ new ExifTag(TAG_RW2_ISO, 23, IFD_FORMAT_USHORT),
+ new ExifTag(TAG_RW2_JPG_FROM_RAW, 46, IFD_FORMAT_UNDEFINED)
};
// Primary image IFD Exif Private tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels)
@@ -1073,16 +1122,20 @@
// ORF file tags (See http://www.exiv2.org/tags-olympus.html)
private static final ExifTag[] ORF_MAKER_NOTE_TAGS = new ExifTag[] {
- new ExifTag(TAG_THUMBNAIL_IMAGE, 256, IFD_FORMAT_UNDEFINED),
- new ExifTag(TAG_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_ULONG),
- new ExifTag(TAG_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_ULONG)
+ new ExifTag(TAG_ORF_THUMBNAIL_IMAGE, 256, IFD_FORMAT_UNDEFINED),
+ new ExifTag(TAG_ORF_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_ULONG),
+ new ExifTag(TAG_ORF_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_ULONG)
};
private static final ExifTag[] ORF_CAMERA_SETTINGS_TAGS = new ExifTag[] {
- new ExifTag(TAG_PREVIEW_IMAGE_START, 257, IFD_FORMAT_ULONG),
- new ExifTag(TAG_PREVIEW_IMAGE_LENGTH, 258, IFD_FORMAT_ULONG)
+ new ExifTag(TAG_ORF_PREVIEW_IMAGE_START, 257, IFD_FORMAT_ULONG),
+ new ExifTag(TAG_ORF_PREVIEW_IMAGE_LENGTH, 258, IFD_FORMAT_ULONG)
};
private static final ExifTag[] ORF_IMAGE_PROCESSING_TAGS = new ExifTag[] {
- new ExifTag(TAG_ASPECT_FRAME, 4371, IFD_FORMAT_USHORT)
+ new ExifTag(TAG_ORF_ASPECT_FRAME, 4371, IFD_FORMAT_USHORT)
+ };
+ // PEF file tag (See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Pentax.html)
+ private static final ExifTag[] PEF_TAGS = new ExifTag[] {
+ new ExifTag(TAG_COLOR_SPACE, 55, IFD_FORMAT_USHORT)
};
// See JEITA CP-3451C Section 4.6.3: Exif-specific IFD.
@@ -1098,11 +1151,12 @@
private static final int ORF_MAKER_NOTE_HINT = 6;
private static final int ORF_CAMERA_SETTINGS_HINT = 7;
private static final int ORF_IMAGE_PROCESSING_HINT = 8;
+ private static final int PEF_HINT = 9;
// List of Exif tag groups
private static final ExifTag[][] EXIF_TAGS = new ExifTag[][] {
IFD_TIFF_TAGS, IFD_EXIF_TAGS, IFD_GPS_TAGS, IFD_INTEROPERABILITY_TAGS,
IFD_THUMBNAIL_TAGS, IFD_TIFF_TAGS, ORF_MAKER_NOTE_TAGS, ORF_CAMERA_SETTINGS_TAGS,
- ORF_IMAGE_PROCESSING_TAGS
+ ORF_IMAGE_PROCESSING_TAGS, PEF_TAGS
};
// List of tags for pointing to the other image file directory offset.
private static final ExifTag[] EXIF_POINTER_TAGS = new ExifTag[] {
@@ -1110,8 +1164,8 @@
new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG),
- new ExifTag(TAG_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_BYTE),
- new ExifTag(TAG_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_BYTE)
+ new ExifTag(TAG_ORF_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_BYTE),
+ new ExifTag(TAG_ORF_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_BYTE)
};
// List of indices of the indicated tag groups according to the EXIF_POINTER_TAGS
private static final int[] EXIF_POINTER_TAG_HINTS = new int[] {
@@ -1211,6 +1265,7 @@
private int mOrfMakerNoteOffset;
private int mOrfThumbnailOffset;
private int mOrfThumbnailLength;
+ private int mRw2JpgFromRawOffset;
// Pattern to check non zero timestamp
private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
@@ -1597,13 +1652,16 @@
getOrfAttributes(in);
break;
}
+ case IMAGE_TYPE_RW2: {
+ getRw2Attributes(in);
+ break;
+ }
case IMAGE_TYPE_ARW:
case IMAGE_TYPE_CR2:
case IMAGE_TYPE_DNG:
case IMAGE_TYPE_NEF:
case IMAGE_TYPE_NRW:
case IMAGE_TYPE_PEF:
- case IMAGE_TYPE_RW2:
case IMAGE_TYPE_SRW:
case IMAGE_TYPE_UNKNOWN: {
getRawAttributes(in);
@@ -1994,7 +2052,10 @@
return IMAGE_TYPE_RAF;
} else if (isOrfFormat(signatureCheckBytes)) {
return IMAGE_TYPE_ORF;
+ } else if (isRw2Format(signatureCheckBytes)) {
+ return IMAGE_TYPE_RW2;
}
+ // Certain file formats (PEF) are identified in readImageFileDirectory()
return IMAGE_TYPE_UNKNOWN;
}
@@ -2051,6 +2112,25 @@
}
/**
+ * RW2 is TIFF-based, but stores 0x55 signature byte instead of 0x42 at the header
+ * See http://lclevy.free.fr/raw/
+ */
+ private boolean isRw2Format(byte[] signatureCheckBytes) throws IOException {
+ ByteOrderAwarenessDataInputStream signatureInputStream =
+ new ByteOrderAwarenessDataInputStream(signatureCheckBytes);
+ // Read byte order
+ mExifByteOrder = readByteOrder(signatureInputStream);
+ // Set byte order
+ signatureInputStream.setByteOrder(mExifByteOrder);
+
+ short signatureByte = signatureInputStream.readShort();
+ if (signatureByte == RW2_SIGNATURE) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Loads EXIF attributes from a JPEG input stream.
*
* @param inputStream The input stream that starts with the JPEG data.
@@ -2137,7 +2217,7 @@
if (DEBUG) {
Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")");
}
- // Save offset values for retrieveJPEGThumbnail() function
+ // Save offset values for createJpegThumbnailBitmap() function
mExifOffset = bytesRead;
byte[] bytes = new byte[length];
@@ -2247,6 +2327,32 @@
mAttributes[IFD_PREVIEW_HINT] = new HashMap();
}
}
+
+ if (mMimeType == IMAGE_TYPE_PEF) {
+ // PEF files contain a MakerNote data, which contains the data for ColorSpace tag.
+ // See http://lclevy.free.fr/raw/ and piex.cc PefGetPreviewData()
+ ExifAttribute makerNoteAttribute =
+ (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_MAKER_NOTE);
+ if (makerNoteAttribute != null) {
+ // Create an ordered DataInputStream for MakerNote
+ ByteOrderAwarenessDataInputStream makerNoteDataInputStream =
+ new ByteOrderAwarenessDataInputStream(makerNoteAttribute.bytes);
+ makerNoteDataInputStream.setByteOrder(mExifByteOrder);
+
+ // Seek to MakerNote data
+ makerNoteDataInputStream.seek(PEF_MAKER_NOTE_SKIP_SIZE);
+
+ // Read IFD data from MakerNote
+ readImageFileDirectory(makerNoteDataInputStream, PEF_HINT);
+
+ // Update ColorSpace tag
+ ExifAttribute colorSpaceAttribute =
+ (ExifAttribute) mAttributes[PEF_HINT].get(TAG_COLOR_SPACE);
+ if (colorSpaceAttribute != null) {
+ mAttributes[IFD_EXIF_HINT].put(TAG_COLOR_SPACE, colorSpaceAttribute);
+ }
+ }
+ }
}
/**
@@ -2369,12 +2475,13 @@
// Retrieve & update preview image offset & length values
ExifAttribute imageLengthAttribute = (ExifAttribute)
- mAttributes[ORF_CAMERA_SETTINGS_HINT].get(TAG_PREVIEW_IMAGE_START);
+ mAttributes[ORF_CAMERA_SETTINGS_HINT].get(TAG_ORF_PREVIEW_IMAGE_START);
ExifAttribute bitsPerSampleAttribute = (ExifAttribute)
- mAttributes[ORF_CAMERA_SETTINGS_HINT].get(TAG_PREVIEW_IMAGE_LENGTH);
+ mAttributes[ORF_CAMERA_SETTINGS_HINT].get(TAG_ORF_PREVIEW_IMAGE_LENGTH);
if (imageLengthAttribute != null && bitsPerSampleAttribute != null) {
- mAttributes[IFD_PREVIEW_HINT].put(TAG_JPEG_INTERCHANGE_FORMAT, imageLengthAttribute);
+ mAttributes[IFD_PREVIEW_HINT].put(TAG_JPEG_INTERCHANGE_FORMAT,
+ imageLengthAttribute);
mAttributes[IFD_PREVIEW_HINT].put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
bitsPerSampleAttribute);
}
@@ -2382,8 +2489,8 @@
// TODO: Check this behavior in other ORF files
// Retrieve primary image length & width values
// See piex.cc GetOlympusPreviewImage()
- ExifAttribute aspectFrameAttribute =
- (ExifAttribute) mAttributes[ORF_IMAGE_PROCESSING_HINT].get(TAG_ASPECT_FRAME);
+ ExifAttribute aspectFrameAttribute = (ExifAttribute)
+ mAttributes[ORF_IMAGE_PROCESSING_HINT].get(TAG_ORF_ASPECT_FRAME);
if (aspectFrameAttribute != null) {
int[] aspectFrameValues = new int[4];
aspectFrameValues = (int[]) aspectFrameAttribute.getValue(mExifByteOrder);
@@ -2409,6 +2516,59 @@
}
}
+ // RW2 contains the primary image data in IFD0 and the preview and/or thumbnail image data in
+ // the JpgFromRaw tag
+ // See https://libopenraw.freedesktop.org/wiki/Panasonic_RAW/ and piex.cc Rw2GetPreviewData()
+ private void getRw2Attributes(InputStream in) throws IOException {
+ // Retrieve primary image data
+ getRawAttributes(in);
+
+ // Retrieve preview and/or thumbnail image data
+ ExifAttribute jpgFromRawAttribute =
+ (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_JPG_FROM_RAW);
+ if (jpgFromRawAttribute != null) {
+ getJpegAttributes(in, mRw2JpgFromRawOffset, IFD_PREVIEW_HINT);
+ }
+
+ // Set ISO tag value if necessary
+ ExifAttribute rw2IsoAttribute =
+ (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_ISO);
+ ExifAttribute exifIsoAttribute =
+ (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_ISO_SPEED_RATINGS);
+ if (rw2IsoAttribute != null && exifIsoAttribute == null) {
+ // Place this attribute only if it doesn't exist
+ mAttributes[IFD_EXIF_HINT].put(TAG_ISO_SPEED_RATINGS, rw2IsoAttribute);
+ }
+ }
+
+ // PEF is TIFF-based and contains 3 IFDs. It also contains a MakerNote data, which contains the
+ // ColorSpace tag data.
+ // See http://lclevy.free.fr/raw/ and piex.cc PefGetPreviewData()
+ private void getPefAttributes(InputStream in) throws IOException {
+ // Retrieve ColorSpace tag
+ ExifAttribute makerNoteAttribute =
+ (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_MAKER_NOTE);
+ if (makerNoteAttribute != null) {
+ // Create an ordered DataInputStream for MakerNote
+ ByteOrderAwarenessDataInputStream makerNoteDataInputStream =
+ new ByteOrderAwarenessDataInputStream(makerNoteAttribute.bytes);
+ makerNoteDataInputStream.setByteOrder(mExifByteOrder);
+
+ // Seek to MakerNote data
+ makerNoteDataInputStream.seek(PEF_MAKER_NOTE_SKIP_SIZE);
+
+ // Read IFD data from MakerNote
+ readImageFileDirectory(makerNoteDataInputStream, PEF_HINT);
+
+ // Update ColorSpace tag
+ ExifAttribute colorSpaceAttribute =
+ (ExifAttribute) mAttributes[PEF_HINT].get(TAG_COLOR_SPACE);
+ if (colorSpaceAttribute != null) {
+ mAttributes[IFD_EXIF_HINT].put(TAG_COLOR_SPACE, colorSpaceAttribute);
+ }
+ }
+ }
+
// Stores a new JPEG image with EXIF attributes into a given output stream.
private void saveJpegAttributes(InputStream inputStream, OutputStream outputStream)
throws IOException {
@@ -2575,7 +2735,7 @@
// Check start code
int startCode = dataInputStream.readUnsignedShort();
- if (mMimeType != IMAGE_TYPE_ORF && startCode != START_CODE) {
+ if (mMimeType != IMAGE_TYPE_ORF && mMimeType != IMAGE_TYPE_RW2 && startCode != START_CODE) {
throw new IOException("Invalid start code: " + Integer.toHexString(startCode));
}
@@ -2619,7 +2779,7 @@
long nextEntryOffset = dataInputStream.peek() + 4;
// Look up a corresponding tag from tag number
- final ExifTag tag = (ExifTag) sExifTagMapsForReading[hint].get(tagNumber);
+ ExifTag tag = (ExifTag) sExifTagMapsForReading[hint].get(tagNumber);
if (DEBUG) {
Log.d(TAG, String.format("hint: %d, tagNumber: %d, tagName: %s, dataFormat: %d, " +
@@ -2651,7 +2811,7 @@
if (tag.name == TAG_MAKER_NOTE) {
// Save offset value for reading thumbnail
mOrfMakerNoteOffset = offset;
- } else if (hint == ORF_MAKER_NOTE_HINT && tag.name == TAG_THUMBNAIL_IMAGE) {
+ } else if (hint == ORF_MAKER_NOTE_HINT && tag.name == TAG_ORF_THUMBNAIL_IMAGE) {
// Retrieve & update values for thumbnail offset and length values for ORF
mOrfThumbnailOffset = offset;
mOrfThumbnailLength = numberOfComponents;
@@ -2669,6 +2829,10 @@
mAttributes[IFD_THUMBNAIL_HINT].put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
jpegInterchangeFormatLengthAttribute);
}
+ } else if (mMimeType == IMAGE_TYPE_RW2) {
+ if (tag.name == TAG_RW2_JPG_FROM_RAW) {
+ mRw2JpgFromRawOffset = offset;
+ }
}
if (offset + byteCount <= dataInputStream.mLength) {
dataInputStream.seek(offset);
@@ -2728,8 +2892,20 @@
byte[] bytes = new byte[byteCount];
dataInputStream.readFully(bytes);
- mAttributes[hint].put(
- tag.name, new ExifAttribute(dataFormat, numberOfComponents, bytes));
+ ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents, bytes);
+ mAttributes[hint].put(tag.name, attribute);
+
+ // PEF files have a Make or Model tag that begins with "PENTAX" or a compression tag
+ // that is 65535.
+ // See http://fileformats.archiveteam.org/wiki/Pentax_PEF
+ if (((tag.name == TAG_MAKE || tag.name == TAG_MODEL)
+ && attribute.getStringValue(mExifByteOrder).contains(PEF_SIGNATURE))
+ || (tag.name == TAG_COMPRESSION
+ && attribute.getIntValue(mExifByteOrder) == 65535)) {
+ mMimeType = IMAGE_TYPE_PEF;
+ }
+
+ // Seek to next tag offset
if (dataInputStream.peek() != nextEntryOffset) {
dataInputStream.seek(nextEntryOffset);
}
@@ -2744,7 +2920,10 @@
// since the first IFD offset is at least 8.
if (nextIfdOffset > 8 && nextIfdOffset < dataInputStream.mLength) {
dataInputStream.seek(nextIfdOffset);
- readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT);
+ if (mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) {
+ // Do not overwrite thumbnail IFD data if it alreay exists.
+ readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT);
+ }
}
}
}
@@ -2776,10 +2955,12 @@
}
}
- // Retrieves thumbnail based on Compression Value
+ // Sets thumbnail offset & length attributes based on JpegInterchangeFormat or StripOffsets tags
private void setThumbnailData(InputStream in) throws IOException {
HashMap thumbnailData = mAttributes[IFD_THUMBNAIL_HINT];
- ExifAttribute compressionAttribute = (ExifAttribute) thumbnailData.get(TAG_COMPRESSION);
+
+ ExifAttribute compressionAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_COMPRESSION);
if (compressionAttribute != null) {
int compressionValue = compressionAttribute.getIntValue(mExifByteOrder);
switch (compressionValue) {
@@ -2789,64 +2970,79 @@
break;
}
case DATA_JPEG: {
- ExifAttribute jpegInterchangeFormatAttribute =
- (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT);
- ExifAttribute jpegInterchangeFormatLengthAttribute =
- (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
- if (jpegInterchangeFormatAttribute != null
- && jpegInterchangeFormatLengthAttribute != null) {
- int jpegInterchangeFormat =
- jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
- int jpegInterchangeFormatLength =
- jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
- createJPEGThumbnailBitmap(in, jpegInterchangeFormat,
- jpegInterchangeFormatLength);
- }
+ handleThumbnailFromJfif(in, thumbnailData);
break;
}
case DATA_JPEG_COMPRESSED: {
- ExifAttribute stripOffsetsAttribute =
- (ExifAttribute) thumbnailData.get(TAG_STRIP_OFFSETS);
- ExifAttribute stripByteCountsAttribute =
- (ExifAttribute) thumbnailData.get(TAG_STRIP_BYTE_COUNTS);
- if (stripOffsetsAttribute != null && stripByteCountsAttribute != null) {
- long[] stripOffsetsArray =
- (long[]) stripOffsetsAttribute.getValue(mExifByteOrder);
- long[] stripByteCountsArray =
- (long[]) stripByteCountsAttribute.getValue(mExifByteOrder);
- if (stripOffsetsArray.length == 1) {
- int stripOffsetsSum = (int) Arrays.stream(stripOffsetsArray).sum();
- int stripByteCountsSum = (int) Arrays.stream(stripByteCountsArray).sum();
- createJPEGThumbnailBitmap(in, stripOffsetsSum, stripByteCountsSum);
- } else {
- // TODO: implement method to read multiple strips (b/29737797)
- Log.d(TAG, "Multiple strip thumbnail data cannot be processed");
- }
- }
+ handleThumbnailFromStrips(in, thumbnailData);
break;
}
default: {
break;
}
}
+ } else {
+ // Thumbnail data may not contain Compression tag value
+ handleThumbnailFromJfif(in, thumbnailData);
}
}
- // Retrieves thumbnail for JPEG Compression
- private void createJPEGThumbnailBitmap(InputStream in, int thumbnailOffset, int thumbnailLength)
- throws IOException {
- if (DEBUG) {
- Log.d(TAG, "Retrieving JPEG Thumbnail");
+ // Check JpegInterchangeFormat(JFIF) tags to retrieve thumbnail offset & length values and
+ // create a bitmap based on those values
+ private void handleThumbnailFromJfif(InputStream in, HashMap thumbnailData) throws IOException {
+ ExifAttribute jpegInterchangeFormatAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT);
+ ExifAttribute jpegInterchangeFormatLengthAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ if (jpegInterchangeFormatAttribute != null
+ && jpegInterchangeFormatLengthAttribute != null) {
+ int jpegInterchangeFormat =
+ jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
+ int jpegInterchangeFormatLength =
+ jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
+ createJpegThumbnailBitmap(in, jpegInterchangeFormat, jpegInterchangeFormatLength);
}
+ }
+
+ // Check StripOffsets & StripByteCounts tags to retrieve thumbnail offset & length values and
+ // create a bitmap based on those values
+ private void handleThumbnailFromStrips(InputStream in, HashMap thumbnailData)
+ throws IOException {
+ ExifAttribute stripOffsetsAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_STRIP_OFFSETS);
+ ExifAttribute stripByteCountsAttribute =
+ (ExifAttribute) thumbnailData.get(TAG_STRIP_BYTE_COUNTS);
+ if (stripOffsetsAttribute != null && stripByteCountsAttribute != null) {
+ long[] stripOffsetsArray =
+ (long[]) stripOffsetsAttribute.getValue(mExifByteOrder);
+ long[] stripByteCountsArray =
+ (long[]) stripByteCountsAttribute.getValue(mExifByteOrder);
+ if (stripOffsetsArray.length == 1) {
+ int stripOffsetsSum = (int) Arrays.stream(stripOffsetsArray).sum();
+ int stripByteCountsSum = (int) Arrays.stream(stripByteCountsArray).sum();
+ createJpegThumbnailBitmap(in, stripOffsetsSum, stripByteCountsSum);
+ } else {
+ // TODO: implement method to read multiple strips (b/29737797)
+ Log.d(TAG, "Multiple strip thumbnail data cannot be processed");
+ }
+ }
+ }
+
+ // Creates a bitmap data based on thumbnail offset and length for JPEG Compression
+ private void createJpegThumbnailBitmap(InputStream in, int thumbnailOffset, int thumbnailLength)
+ throws IOException {
// The following code limits the size of thumbnail size not to overflow EXIF data area.
thumbnailLength = Math.min(thumbnailLength, in.available() - thumbnailOffset);
- if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF) {
+ if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
+ || mMimeType == IMAGE_TYPE_RW2) {
thumbnailOffset += mExifOffset;
} else if (mMimeType == IMAGE_TYPE_ORF) {
// Update offset value since RAF files have IFD data preceding MakerNote data.
thumbnailOffset += mOrfMakerNoteOffset;
}
- Log.d(TAG, "offset: " + thumbnailOffset);
+ if (DEBUG) {
+ Log.d(TAG, "Creating JPEG Thumbnail with offset: " + thumbnailOffset);
+ }
if (thumbnailOffset > 0 && thumbnailLength > 0) {
mHasThumbnail = true;
mThumbnailOffset = thumbnailOffset;
@@ -2898,20 +3094,11 @@
* SOF(Start of Frame). In order to assure that valid image size values are stored, this method
* checks TAG_PIXEL_X_DIMENSION & TAG_PIXEL_Y_DIMENSION and updates values if necessary.
* See JEITA CP-3451C Table 5 and Section 4.8.1. B.
+ *
+ * If image is a RW2 file, valid image sizes are stored in SensorBorder tags.
+ * See tiff_parser.cc GetFullDimension32()
* */
private void updatePrimaryImageSizeValues(InputStream in) throws IOException {
- // Checks for the NewSubfileType tag and returns if the image is not original resolution,
- // which means that it is not the primary imiage
- ExifAttribute newSubfileTypeAttribute =
- (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_NEW_SUBFILE_TYPE);
- if (newSubfileTypeAttribute != null) {
- int newSubfileTypeValue = newSubfileTypeAttribute.getIntValue(mExifByteOrder);
- if (newSubfileTypeValue != ORIGINAL_RESOLUTION_IMAGE) {
- // TODO: Need to address case when NewSubFile value is REDUCED_RESOLUTION_IMAGE.
- return;
- }
- }
-
// Uncompressed image valid image size values
ExifAttribute defaultCropSizeAttribute =
(ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_DEFAULT_CROP_SIZE);
@@ -2920,6 +3107,15 @@
(ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_X_DIMENSION);
ExifAttribute pixelYDimAttribute =
(ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_Y_DIMENSION);
+ // RW2 image valid image size values
+ ExifAttribute topBorderAttribute =
+ (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_TOP_BORDER);
+ ExifAttribute leftBorderAttribute =
+ (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_LEFT_BORDER);
+ ExifAttribute bottomBorderAttribute =
+ (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_BOTTOM_BORDER);
+ ExifAttribute rightBorderAttribute =
+ (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_RIGHT_BORDER);
if (defaultCropSizeAttribute != null) {
// Update for uncompressed image
@@ -2941,6 +3137,23 @@
}
mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute);
mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute);
+ } else if (topBorderAttribute != null && leftBorderAttribute != null &&
+ bottomBorderAttribute != null && rightBorderAttribute != null) {
+ // Update for RW2 image
+ int topBorderValue = topBorderAttribute.getIntValue(mExifByteOrder);
+ int bottomBorderValue = bottomBorderAttribute.getIntValue(mExifByteOrder);
+ int rightBorderValue = rightBorderAttribute.getIntValue(mExifByteOrder);
+ int leftBorderValue = leftBorderAttribute.getIntValue(mExifByteOrder);
+ if (bottomBorderValue > topBorderValue && rightBorderValue > leftBorderValue) {
+ int length = bottomBorderValue - topBorderValue;
+ int width = rightBorderValue - leftBorderValue;
+ ExifAttribute imageLengthAttribute =
+ ExifAttribute.createUShort(length, mExifByteOrder);
+ ExifAttribute imageWidthAttribute =
+ ExifAttribute.createUShort(width, mExifByteOrder);
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, imageLengthAttribute);
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, imageWidthAttribute);
+ }
} else {
// Update for JPEG image
if (pixelXDimAttribute != null && pixelYDimAttribute != null) {
@@ -3441,6 +3654,21 @@
}
}
+ // Checks if there is a match
+ private boolean containsMatch(byte[] mainBytes, byte[] findBytes) {
+ for (int i = 0; i < mainBytes.length - findBytes.length; i++) {
+ for (int j = 0; j < findBytes.length; j++) {
+ if (mainBytes[i + j] != findBytes[j]) {
+ break;
+ }
+ if (j == findBytes.length - 1) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
// JNI methods for RAW formats.
private static native void nativeInitRaw();
private static native byte[] nativeGetThumbnailFromAsset(