Loading media/java/android/media/ExifInterface.java +97 −49 Original line number Diff line number Diff line Loading @@ -1169,7 +1169,7 @@ public class ExifInterface { }; // List of indices of the indicated tag groups according to the EXIF_POINTER_TAGS private static final int[] EXIF_POINTER_TAG_HINTS = new int[] { IFD_TIFF_HINT, IFD_EXIF_HINT, IFD_GPS_HINT, IFD_INTEROPERABILITY_HINT, IFD_PREVIEW_HINT, IFD_EXIF_HINT, IFD_GPS_HINT, IFD_INTEROPERABILITY_HINT, ORF_CAMERA_SETTINGS_HINT, ORF_IMAGE_PROCESSING_HINT }; // Tags for indicating the thumbnail offset and length Loading Loading @@ -2298,35 +2298,15 @@ public class ExifInterface { parseTiffHeaders(dataInputStream, exifBytes.length); // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6. readImageFileDirectory(dataInputStream, IFD_PREVIEW_HINT); // Check if the preview image data should be a primary image data. // The 0th IFD (first to be parsed) is presumed to be a preview image data, with a SubIFD // that is a primary image data. // But if the 0th IFD does not have a SubIFD, then it must be a primary image data since // a primary image data must exist, but a preview image data does not have to. if (mAttributes[IFD_TIFF_HINT].isEmpty() && !mAttributes[IFD_PREVIEW_HINT].isEmpty()) { mAttributes[IFD_TIFF_HINT] = mAttributes[IFD_PREVIEW_HINT]; mAttributes[IFD_PREVIEW_HINT] = new HashMap(); } readImageFileDirectory(dataInputStream, IFD_TIFF_HINT); // Update TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH for primary image. updatePrimaryImageSizeValues(in); // Update ImageLength/Width tags for all image data. updateImageSizeValues(in, IFD_TIFF_HINT); updateImageSizeValues(in, IFD_PREVIEW_HINT); updateImageSizeValues(in, IFD_THUMBNAIL_HINT); // Check if the preview image data should be a thumbnail image data. // In a RAW file, there may be a preview image, which is smaller than a primary image but // larger than a thumbnail image. Normally, the preview image can be considered a thumbnail // image if its size meets the requirements. Therefore, when a thumbnail image has not yet // been found, we should check if the preview image can be one. if (!mAttributes[IFD_PREVIEW_HINT].isEmpty() && mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) { // Update preview image size if necessary retrieveJpegImageSize(in, IFD_PREVIEW_HINT); if (isThumbnail(mAttributes[IFD_PREVIEW_HINT])) { mAttributes[IFD_THUMBNAIL_HINT] = mAttributes[IFD_PREVIEW_HINT]; mAttributes[IFD_PREVIEW_HINT] = new HashMap(); } } // Check if each image data is in valid position. validateImages(in); if (mMimeType == IMAGE_TYPE_PEF) { // PEF files contain a MakerNote data, which contains the data for ColorSpace tag. Loading Loading @@ -2923,6 +2903,8 @@ public class ExifInterface { if (mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) { // Do not overwrite thumbnail IFD data if it alreay exists. readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT); } else if (mAttributes[IFD_PREVIEW_HINT].isEmpty()) { readImageFileDirectory(dataInputStream, IFD_PREVIEW_HINT); } } } Loading Loading @@ -3081,6 +3063,28 @@ public class ExifInterface { return false; } // Validate primary, preview, thumbnail image data by comparing image size private void validateImages(InputStream in) throws IOException { // Swap images based on size (primary > preview > thumbnail) swapBasedOnImageSize(IFD_TIFF_HINT, IFD_PREVIEW_HINT); swapBasedOnImageSize(IFD_TIFF_HINT, IFD_THUMBNAIL_HINT); swapBasedOnImageSize(IFD_PREVIEW_HINT, IFD_THUMBNAIL_HINT); // Check whether thumbnail image exists and whether preview image satisfies the thumbnail // image requirements if (mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) { if (isThumbnail(mAttributes[IFD_PREVIEW_HINT])) { mAttributes[IFD_THUMBNAIL_HINT] = mAttributes[IFD_PREVIEW_HINT]; mAttributes[IFD_PREVIEW_HINT] = new HashMap(); } } // Check if the thumbnail image satisfies the thumbnail size requirements if (!isThumbnail(mAttributes[IFD_THUMBNAIL_HINT])) { Log.d(TAG, "No image meets the size requirements of a thumbnail image."); } } /** * If image is uncompressed, ImageWidth/Length tags are used to store size info. * However, uncompressed images often store extra pixels around the edges of the final image, Loading @@ -3098,24 +3102,19 @@ public class ExifInterface { * 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 { private void updateImageSizeValues(InputStream in, int imageType) throws IOException { // Uncompressed image valid image size values ExifAttribute defaultCropSizeAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_DEFAULT_CROP_SIZE); // Compressed image valid image size values ExifAttribute pixelXDimAttribute = (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_X_DIMENSION); ExifAttribute pixelYDimAttribute = (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_Y_DIMENSION); (ExifAttribute) mAttributes[imageType].get(TAG_DEFAULT_CROP_SIZE); // RW2 image valid image size values ExifAttribute topBorderAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_TOP_BORDER); (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_TOP_BORDER); ExifAttribute leftBorderAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_LEFT_BORDER); (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_LEFT_BORDER); ExifAttribute bottomBorderAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_BOTTOM_BORDER); (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_BOTTOM_BORDER); ExifAttribute rightBorderAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_RIGHT_BORDER); (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_RIGHT_BORDER); if (defaultCropSizeAttribute != null) { // Update for uncompressed image Loading @@ -3135,8 +3134,8 @@ public class ExifInterface { defaultCropSizeYAttribute = ExifAttribute.createUShort(defaultCropSizeValue[1], mExifByteOrder); } mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute); mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute); mAttributes[imageType].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute); mAttributes[imageType].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute); } else if (topBorderAttribute != null && leftBorderAttribute != null && bottomBorderAttribute != null && rightBorderAttribute != null) { // Update for RW2 image Loading @@ -3151,17 +3150,24 @@ public class ExifInterface { 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); mAttributes[imageType].put(TAG_IMAGE_LENGTH, imageLengthAttribute); mAttributes[imageType].put(TAG_IMAGE_WIDTH, imageWidthAttribute); } } else { // Update for JPEG image if (imageType == IFD_TIFF_HINT) { ExifAttribute pixelXDimAttribute = (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_X_DIMENSION); ExifAttribute pixelYDimAttribute = (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_Y_DIMENSION); if (pixelXDimAttribute != null && pixelYDimAttribute != null) { mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, pixelXDimAttribute); mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, pixelYDimAttribute); mAttributes[imageType].put(TAG_IMAGE_WIDTH, pixelXDimAttribute); mAttributes[imageType].put(TAG_IMAGE_LENGTH, pixelYDimAttribute); } else { // Update image size values from SOF marker if necessary retrieveJpegImageSize(in, IFD_TIFF_HINT); retrieveJpegImageSize(in, imageType); } } else { retrieveJpegImageSize(in, imageType); } } } Loading Loading @@ -3654,6 +3660,48 @@ public class ExifInterface { } } // Swaps image data based on image size private void swapBasedOnImageSize(int firstImageHint, int secondImageHint) throws IOException { if (mAttributes[firstImageHint].isEmpty() || mAttributes[secondImageHint].isEmpty()) { if (DEBUG) { Log.d(TAG, "Cannot perform swap since only one image data exists"); } return; } ExifAttribute firstImageLengthAttribute = (ExifAttribute) mAttributes[firstImageHint].get(TAG_IMAGE_LENGTH); ExifAttribute firstImageWidthAttribute = (ExifAttribute) mAttributes[firstImageHint].get(TAG_IMAGE_WIDTH); ExifAttribute secondImageLengthAttribute = (ExifAttribute) mAttributes[secondImageHint].get(TAG_IMAGE_LENGTH); ExifAttribute secondImageWidthAttribute = (ExifAttribute) mAttributes[secondImageHint].get(TAG_IMAGE_WIDTH); if (firstImageLengthAttribute == null || firstImageWidthAttribute == null) { if (DEBUG) { Log.d(TAG, "First image does not contain valid size information"); } } else if (secondImageLengthAttribute == null || secondImageWidthAttribute == null) { if (DEBUG) { Log.d(TAG, "Second image does not contain valid size information"); } } else { int firstImageLengthValue = firstImageLengthAttribute.getIntValue(mExifByteOrder); int firstImageWidthValue = firstImageWidthAttribute.getIntValue(mExifByteOrder); int secondImageLengthValue = secondImageLengthAttribute.getIntValue(mExifByteOrder); int secondImageWidthValue = secondImageWidthAttribute.getIntValue(mExifByteOrder); if (firstImageLengthValue < secondImageLengthValue && firstImageWidthValue < secondImageWidthValue) { HashMap tempMap = mAttributes[firstImageHint]; mAttributes[firstImageHint] = mAttributes[secondImageHint]; mAttributes[secondImageHint] = tempMap; } } } // Checks if there is a match private boolean containsMatch(byte[] mainBytes, byte[] findBytes) { for (int i = 0; i < mainBytes.length - findBytes.length; i++) { Loading Loading
media/java/android/media/ExifInterface.java +97 −49 Original line number Diff line number Diff line Loading @@ -1169,7 +1169,7 @@ public class ExifInterface { }; // List of indices of the indicated tag groups according to the EXIF_POINTER_TAGS private static final int[] EXIF_POINTER_TAG_HINTS = new int[] { IFD_TIFF_HINT, IFD_EXIF_HINT, IFD_GPS_HINT, IFD_INTEROPERABILITY_HINT, IFD_PREVIEW_HINT, IFD_EXIF_HINT, IFD_GPS_HINT, IFD_INTEROPERABILITY_HINT, ORF_CAMERA_SETTINGS_HINT, ORF_IMAGE_PROCESSING_HINT }; // Tags for indicating the thumbnail offset and length Loading Loading @@ -2298,35 +2298,15 @@ public class ExifInterface { parseTiffHeaders(dataInputStream, exifBytes.length); // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6. readImageFileDirectory(dataInputStream, IFD_PREVIEW_HINT); // Check if the preview image data should be a primary image data. // The 0th IFD (first to be parsed) is presumed to be a preview image data, with a SubIFD // that is a primary image data. // But if the 0th IFD does not have a SubIFD, then it must be a primary image data since // a primary image data must exist, but a preview image data does not have to. if (mAttributes[IFD_TIFF_HINT].isEmpty() && !mAttributes[IFD_PREVIEW_HINT].isEmpty()) { mAttributes[IFD_TIFF_HINT] = mAttributes[IFD_PREVIEW_HINT]; mAttributes[IFD_PREVIEW_HINT] = new HashMap(); } readImageFileDirectory(dataInputStream, IFD_TIFF_HINT); // Update TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH for primary image. updatePrimaryImageSizeValues(in); // Update ImageLength/Width tags for all image data. updateImageSizeValues(in, IFD_TIFF_HINT); updateImageSizeValues(in, IFD_PREVIEW_HINT); updateImageSizeValues(in, IFD_THUMBNAIL_HINT); // Check if the preview image data should be a thumbnail image data. // In a RAW file, there may be a preview image, which is smaller than a primary image but // larger than a thumbnail image. Normally, the preview image can be considered a thumbnail // image if its size meets the requirements. Therefore, when a thumbnail image has not yet // been found, we should check if the preview image can be one. if (!mAttributes[IFD_PREVIEW_HINT].isEmpty() && mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) { // Update preview image size if necessary retrieveJpegImageSize(in, IFD_PREVIEW_HINT); if (isThumbnail(mAttributes[IFD_PREVIEW_HINT])) { mAttributes[IFD_THUMBNAIL_HINT] = mAttributes[IFD_PREVIEW_HINT]; mAttributes[IFD_PREVIEW_HINT] = new HashMap(); } } // Check if each image data is in valid position. validateImages(in); if (mMimeType == IMAGE_TYPE_PEF) { // PEF files contain a MakerNote data, which contains the data for ColorSpace tag. Loading Loading @@ -2923,6 +2903,8 @@ public class ExifInterface { if (mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) { // Do not overwrite thumbnail IFD data if it alreay exists. readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT); } else if (mAttributes[IFD_PREVIEW_HINT].isEmpty()) { readImageFileDirectory(dataInputStream, IFD_PREVIEW_HINT); } } } Loading Loading @@ -3081,6 +3063,28 @@ public class ExifInterface { return false; } // Validate primary, preview, thumbnail image data by comparing image size private void validateImages(InputStream in) throws IOException { // Swap images based on size (primary > preview > thumbnail) swapBasedOnImageSize(IFD_TIFF_HINT, IFD_PREVIEW_HINT); swapBasedOnImageSize(IFD_TIFF_HINT, IFD_THUMBNAIL_HINT); swapBasedOnImageSize(IFD_PREVIEW_HINT, IFD_THUMBNAIL_HINT); // Check whether thumbnail image exists and whether preview image satisfies the thumbnail // image requirements if (mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) { if (isThumbnail(mAttributes[IFD_PREVIEW_HINT])) { mAttributes[IFD_THUMBNAIL_HINT] = mAttributes[IFD_PREVIEW_HINT]; mAttributes[IFD_PREVIEW_HINT] = new HashMap(); } } // Check if the thumbnail image satisfies the thumbnail size requirements if (!isThumbnail(mAttributes[IFD_THUMBNAIL_HINT])) { Log.d(TAG, "No image meets the size requirements of a thumbnail image."); } } /** * If image is uncompressed, ImageWidth/Length tags are used to store size info. * However, uncompressed images often store extra pixels around the edges of the final image, Loading @@ -3098,24 +3102,19 @@ public class ExifInterface { * 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 { private void updateImageSizeValues(InputStream in, int imageType) throws IOException { // Uncompressed image valid image size values ExifAttribute defaultCropSizeAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_DEFAULT_CROP_SIZE); // Compressed image valid image size values ExifAttribute pixelXDimAttribute = (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_X_DIMENSION); ExifAttribute pixelYDimAttribute = (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_Y_DIMENSION); (ExifAttribute) mAttributes[imageType].get(TAG_DEFAULT_CROP_SIZE); // RW2 image valid image size values ExifAttribute topBorderAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_TOP_BORDER); (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_TOP_BORDER); ExifAttribute leftBorderAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_LEFT_BORDER); (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_LEFT_BORDER); ExifAttribute bottomBorderAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_BOTTOM_BORDER); (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_BOTTOM_BORDER); ExifAttribute rightBorderAttribute = (ExifAttribute) mAttributes[IFD_TIFF_HINT].get(TAG_RW2_SENSOR_RIGHT_BORDER); (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_RIGHT_BORDER); if (defaultCropSizeAttribute != null) { // Update for uncompressed image Loading @@ -3135,8 +3134,8 @@ public class ExifInterface { defaultCropSizeYAttribute = ExifAttribute.createUShort(defaultCropSizeValue[1], mExifByteOrder); } mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute); mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute); mAttributes[imageType].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute); mAttributes[imageType].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute); } else if (topBorderAttribute != null && leftBorderAttribute != null && bottomBorderAttribute != null && rightBorderAttribute != null) { // Update for RW2 image Loading @@ -3151,17 +3150,24 @@ public class ExifInterface { 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); mAttributes[imageType].put(TAG_IMAGE_LENGTH, imageLengthAttribute); mAttributes[imageType].put(TAG_IMAGE_WIDTH, imageWidthAttribute); } } else { // Update for JPEG image if (imageType == IFD_TIFF_HINT) { ExifAttribute pixelXDimAttribute = (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_X_DIMENSION); ExifAttribute pixelYDimAttribute = (ExifAttribute) mAttributes[IFD_EXIF_HINT].get(TAG_PIXEL_Y_DIMENSION); if (pixelXDimAttribute != null && pixelYDimAttribute != null) { mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, pixelXDimAttribute); mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, pixelYDimAttribute); mAttributes[imageType].put(TAG_IMAGE_WIDTH, pixelXDimAttribute); mAttributes[imageType].put(TAG_IMAGE_LENGTH, pixelYDimAttribute); } else { // Update image size values from SOF marker if necessary retrieveJpegImageSize(in, IFD_TIFF_HINT); retrieveJpegImageSize(in, imageType); } } else { retrieveJpegImageSize(in, imageType); } } } Loading Loading @@ -3654,6 +3660,48 @@ public class ExifInterface { } } // Swaps image data based on image size private void swapBasedOnImageSize(int firstImageHint, int secondImageHint) throws IOException { if (mAttributes[firstImageHint].isEmpty() || mAttributes[secondImageHint].isEmpty()) { if (DEBUG) { Log.d(TAG, "Cannot perform swap since only one image data exists"); } return; } ExifAttribute firstImageLengthAttribute = (ExifAttribute) mAttributes[firstImageHint].get(TAG_IMAGE_LENGTH); ExifAttribute firstImageWidthAttribute = (ExifAttribute) mAttributes[firstImageHint].get(TAG_IMAGE_WIDTH); ExifAttribute secondImageLengthAttribute = (ExifAttribute) mAttributes[secondImageHint].get(TAG_IMAGE_LENGTH); ExifAttribute secondImageWidthAttribute = (ExifAttribute) mAttributes[secondImageHint].get(TAG_IMAGE_WIDTH); if (firstImageLengthAttribute == null || firstImageWidthAttribute == null) { if (DEBUG) { Log.d(TAG, "First image does not contain valid size information"); } } else if (secondImageLengthAttribute == null || secondImageWidthAttribute == null) { if (DEBUG) { Log.d(TAG, "Second image does not contain valid size information"); } } else { int firstImageLengthValue = firstImageLengthAttribute.getIntValue(mExifByteOrder); int firstImageWidthValue = firstImageWidthAttribute.getIntValue(mExifByteOrder); int secondImageLengthValue = secondImageLengthAttribute.getIntValue(mExifByteOrder); int secondImageWidthValue = secondImageWidthAttribute.getIntValue(mExifByteOrder); if (firstImageLengthValue < secondImageLengthValue && firstImageWidthValue < secondImageWidthValue) { HashMap tempMap = mAttributes[firstImageHint]; mAttributes[firstImageHint] = mAttributes[secondImageHint]; mAttributes[secondImageHint] = tempMap; } } } // Checks if there is a match private boolean containsMatch(byte[] mainBytes, byte[] findBytes) { for (int i = 0; i < mainBytes.length - findBytes.length; i++) { Loading