Merge "[DO NOT MERGE] Return correct offsets for getAttributeRange()" into qt-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
acd260e11f
@@ -1345,7 +1345,9 @@ public class ExifInterface {
|
|||||||
private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
|
private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
|
||||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||||
private boolean mHasThumbnail;
|
private boolean mHasThumbnail;
|
||||||
// The following values used for indicating a thumbnail position.
|
private boolean mHasThumbnailStrips;
|
||||||
|
private boolean mAreThumbnailStripsConsecutive;
|
||||||
|
// Used to indicate the position of the thumbnail (includes offset to EXIF data segment).
|
||||||
private int mThumbnailOffset;
|
private int mThumbnailOffset;
|
||||||
private int mThumbnailLength;
|
private int mThumbnailLength;
|
||||||
private byte[] mThumbnailBytes;
|
private byte[] mThumbnailBytes;
|
||||||
@@ -2043,10 +2045,12 @@ public class ExifInterface {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset and length of thumbnail inside the image file, or
|
* Returns the offset and length of thumbnail inside the image file, or
|
||||||
* {@code null} if there is no thumbnail.
|
* {@code null} if either there is no thumbnail or the thumbnail bytes are stored
|
||||||
|
* non-consecutively.
|
||||||
*
|
*
|
||||||
* @return two-element array, the offset in the first value, and length in
|
* @return two-element array, the offset in the first value, and length in
|
||||||
* the second, or {@code null} if no thumbnail was found.
|
* the second, or {@code null} if no thumbnail was found or the thumbnail strips are
|
||||||
|
* not placed consecutively.
|
||||||
* @throws IllegalStateException if {@link #saveAttributes()} has been
|
* @throws IllegalStateException if {@link #saveAttributes()} has been
|
||||||
* called since the underlying file was initially parsed, since
|
* called since the underlying file was initially parsed, since
|
||||||
* that means offsets may have changed.
|
* that means offsets may have changed.
|
||||||
@@ -2058,10 +2062,12 @@ public class ExifInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mHasThumbnail) {
|
if (mHasThumbnail) {
|
||||||
|
if (mHasThumbnailStrips && !mAreThumbnailStripsConsecutive) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return new long[] { mThumbnailOffset, mThumbnailLength };
|
return new long[] { mThumbnailOffset, mThumbnailLength };
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2536,10 +2542,9 @@ public class ExifInterface {
|
|||||||
final byte[] value = Arrays.copyOfRange(bytes,
|
final byte[] value = Arrays.copyOfRange(bytes,
|
||||||
IDENTIFIER_EXIF_APP1.length, bytes.length);
|
IDENTIFIER_EXIF_APP1.length, bytes.length);
|
||||||
|
|
||||||
readExifSegment(value, imageType);
|
|
||||||
|
|
||||||
// Save offset values for createJpegThumbnailBitmap() function
|
// Save offset values for createJpegThumbnailBitmap() function
|
||||||
mExifOffset = (int) offset;
|
mExifOffset = (int) offset;
|
||||||
|
readExifSegment(value, imageType);
|
||||||
} else if (ArrayUtils.startsWith(bytes, IDENTIFIER_XMP_APP1)) {
|
} else if (ArrayUtils.startsWith(bytes, IDENTIFIER_XMP_APP1)) {
|
||||||
// See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6
|
// See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6
|
||||||
final long offset = start + IDENTIFIER_XMP_APP1.length;
|
final long offset = start + IDENTIFIER_XMP_APP1.length;
|
||||||
@@ -2843,6 +2848,8 @@ public class ExifInterface {
|
|||||||
if (in.read(bytes) != length) {
|
if (in.read(bytes) != length) {
|
||||||
throw new IOException("Can't read exif");
|
throw new IOException("Can't read exif");
|
||||||
}
|
}
|
||||||
|
// Save offset values for handling thumbnail and attribute offsets.
|
||||||
|
mExifOffset = offset;
|
||||||
readExifSegment(bytes, IFD_TYPE_PRIMARY);
|
readExifSegment(bytes, IFD_TYPE_PRIMARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2988,7 +2995,7 @@ public class ExifInterface {
|
|||||||
// Write EXIF APP1 segment
|
// Write EXIF APP1 segment
|
||||||
dataOutputStream.writeByte(MARKER);
|
dataOutputStream.writeByte(MARKER);
|
||||||
dataOutputStream.writeByte(MARKER_APP1);
|
dataOutputStream.writeByte(MARKER_APP1);
|
||||||
writeExifSegment(dataOutputStream, 6);
|
writeExifSegment(dataOutputStream);
|
||||||
|
|
||||||
byte[] bytes = new byte[4096];
|
byte[] bytes = new byte[4096];
|
||||||
|
|
||||||
@@ -3319,7 +3326,7 @@ public class ExifInterface {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int bytesOffset = dataInputStream.peek();
|
final int bytesOffset = dataInputStream.peek() + mExifOffset;
|
||||||
final byte[] bytes = new byte[(int) byteCount];
|
final byte[] bytes = new byte[(int) byteCount];
|
||||||
dataInputStream.readFully(bytes);
|
dataInputStream.readFully(bytes);
|
||||||
ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents,
|
ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents,
|
||||||
@@ -3451,31 +3458,28 @@ public class ExifInterface {
|
|||||||
|
|
||||||
// The following code limits the size of thumbnail size not to overflow EXIF data area.
|
// The following code limits the size of thumbnail size not to overflow EXIF data area.
|
||||||
thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
|
thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
|
||||||
if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
|
if (mMimeType == IMAGE_TYPE_ORF) {
|
||||||
|| mMimeType == IMAGE_TYPE_RW2) {
|
|
||||||
thumbnailOffset += mExifOffset;
|
|
||||||
} else if (mMimeType == IMAGE_TYPE_ORF) {
|
|
||||||
// Update offset value since RAF files have IFD data preceding MakerNote data.
|
// Update offset value since RAF files have IFD data preceding MakerNote data.
|
||||||
thumbnailOffset += mOrfMakerNoteOffset;
|
thumbnailOffset += mOrfMakerNoteOffset;
|
||||||
}
|
}
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
|
|
||||||
+ ", length: " + thumbnailLength);
|
|
||||||
}
|
|
||||||
if (thumbnailOffset > 0 && thumbnailLength > 0) {
|
if (thumbnailOffset > 0 && thumbnailLength > 0) {
|
||||||
mHasThumbnail = true;
|
mHasThumbnail = true;
|
||||||
mThumbnailOffset = thumbnailOffset;
|
mThumbnailOffset = thumbnailOffset + mExifOffset;
|
||||||
mThumbnailLength = thumbnailLength;
|
mThumbnailLength = thumbnailLength;
|
||||||
mThumbnailCompression = DATA_JPEG;
|
mThumbnailCompression = DATA_JPEG;
|
||||||
|
|
||||||
if (mFilename == null && mAssetInputStream == null
|
if (mFilename == null && mAssetInputStream == null
|
||||||
&& mSeekableFileDescriptor == null) {
|
&& mSeekableFileDescriptor == null) {
|
||||||
// Save the thumbnail in memory if the input doesn't support reading again.
|
// Save the thumbnail in memory if the input doesn't support reading again.
|
||||||
byte[] thumbnailBytes = new byte[thumbnailLength];
|
byte[] thumbnailBytes = new byte[mThumbnailLength];
|
||||||
in.seek(thumbnailOffset);
|
in.seek(mThumbnailOffset);
|
||||||
in.readFully(thumbnailBytes);
|
in.readFully(thumbnailBytes);
|
||||||
mThumbnailBytes = thumbnailBytes;
|
mThumbnailBytes = thumbnailBytes;
|
||||||
}
|
}
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
|
||||||
|
+ ", length: " + thumbnailLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3494,12 +3498,16 @@ public class ExifInterface {
|
|||||||
long[] stripByteCounts =
|
long[] stripByteCounts =
|
||||||
convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder));
|
convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder));
|
||||||
|
|
||||||
if (stripOffsets == null) {
|
if (stripOffsets == null || stripOffsets.length == 0) {
|
||||||
Log.w(TAG, "stripOffsets should not be null.");
|
Log.w(TAG, "stripOffsets should not be null or have zero length.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stripByteCounts == null) {
|
if (stripByteCounts == null || stripByteCounts.length == 0) {
|
||||||
Log.w(TAG, "stripByteCounts should not be null.");
|
Log.w(TAG, "stripByteCounts should not be null or have zero length.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stripOffsets.length != stripByteCounts.length) {
|
||||||
|
Log.w(TAG, "stripOffsets and stripByteCounts should have same length.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3509,10 +3517,18 @@ public class ExifInterface {
|
|||||||
|
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
int bytesAdded = 0;
|
int bytesAdded = 0;
|
||||||
|
mHasThumbnail = mHasThumbnailStrips = mAreThumbnailStripsConsecutive = true;
|
||||||
for (int i = 0; i < stripOffsets.length; i++) {
|
for (int i = 0; i < stripOffsets.length; i++) {
|
||||||
int stripOffset = (int) stripOffsets[i];
|
int stripOffset = (int) stripOffsets[i];
|
||||||
int stripByteCount = (int) stripByteCounts[i];
|
int stripByteCount = (int) stripByteCounts[i];
|
||||||
|
|
||||||
|
// Check if strips are consecutive
|
||||||
|
// TODO: Add test for non-consecutive thumbnail image
|
||||||
|
if (i < stripOffsets.length - 1
|
||||||
|
&& stripOffset + stripByteCount != stripOffsets[i + 1]) {
|
||||||
|
mAreThumbnailStripsConsecutive = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip to offset
|
// Skip to offset
|
||||||
int skipBytes = stripOffset - bytesRead;
|
int skipBytes = stripOffset - bytesRead;
|
||||||
if (skipBytes < 0) {
|
if (skipBytes < 0) {
|
||||||
@@ -3531,10 +3547,13 @@ public class ExifInterface {
|
|||||||
stripBytes.length);
|
stripBytes.length);
|
||||||
bytesAdded += stripBytes.length;
|
bytesAdded += stripBytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
mHasThumbnail = true;
|
|
||||||
mThumbnailBytes = totalStripBytes;
|
mThumbnailBytes = totalStripBytes;
|
||||||
mThumbnailLength = totalStripBytes.length;
|
|
||||||
|
if (mAreThumbnailStripsConsecutive) {
|
||||||
|
// Need to add mExifOffset, which is the offset to the EXIF data segment
|
||||||
|
mThumbnailOffset = (int) stripOffsets[0] + mExifOffset;
|
||||||
|
mThumbnailLength = totalStripBytes.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3691,8 +3710,7 @@ public class ExifInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Writes an Exif segment into the given output stream.
|
// Writes an Exif segment into the given output stream.
|
||||||
private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream,
|
private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream) throws IOException {
|
||||||
int exifOffsetFromBeginning) throws IOException {
|
|
||||||
// The following variables are for calculating each IFD tag group size in bytes.
|
// The following variables are for calculating each IFD tag group size in bytes.
|
||||||
int[] ifdOffsets = new int[EXIF_TAGS.length];
|
int[] ifdOffsets = new int[EXIF_TAGS.length];
|
||||||
int[] ifdDataSizes = new int[EXIF_TAGS.length];
|
int[] ifdDataSizes = new int[EXIF_TAGS.length];
|
||||||
@@ -3751,6 +3769,8 @@ public class ExifInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate IFD offsets.
|
// Calculate IFD offsets.
|
||||||
|
// 8 bytes are for TIFF headers: 2 bytes (byte order) + 2 bytes (identifier) + 4 bytes
|
||||||
|
// (offset of IFDs)
|
||||||
int position = 8;
|
int position = 8;
|
||||||
for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
|
for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
|
||||||
if (!mAttributes[ifdType].isEmpty()) {
|
if (!mAttributes[ifdType].isEmpty()) {
|
||||||
@@ -3762,7 +3782,8 @@ public class ExifInterface {
|
|||||||
int thumbnailOffset = position;
|
int thumbnailOffset = position;
|
||||||
mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
|
mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
|
||||||
ExifAttribute.createULong(thumbnailOffset, mExifByteOrder));
|
ExifAttribute.createULong(thumbnailOffset, mExifByteOrder));
|
||||||
mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
|
// Need to add mExifOffset, which is the offset to the EXIF data segment
|
||||||
|
mThumbnailOffset = thumbnailOffset + mExifOffset;
|
||||||
position += mThumbnailLength;
|
position += mThumbnailLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user