Loading core/java/android/content/ContentResolver.java +26 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.content; import static android.provider.DocumentsContract.EXTRA_ORIENTATION; import android.accounts.Account; import android.annotation.IntDef; import android.annotation.NonNull; Loading @@ -40,6 +42,7 @@ import android.graphics.Bitmap; import android.graphics.ImageDecoder; import android.graphics.ImageDecoder.ImageInfo; import android.graphics.ImageDecoder.Source; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; Loading @@ -56,6 +59,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.storage.StorageManager; import android.system.Int32Ref; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; Loading Loading @@ -3563,9 +3567,14 @@ public abstract class ContentResolver implements ContentInterface { // Convert to Point, since that's what the API is defined as final Bundle opts = new Bundle(); opts.putParcelable(EXTRA_SIZE, Point.convert(size)); return ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> { return content.openTypedAssetFile(uri, "image/*", opts, signal); final Int32Ref orientation = new Int32Ref(0); Bitmap bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> { final AssetFileDescriptor afd = content.openTypedAssetFile(uri, "image/*", opts, signal); final Bundle extras = afd.getExtras(); orientation.value = (extras != null) ? extras.getInt(EXTRA_ORIENTATION, 0) : 0; return afd; }), (ImageDecoder decoder, ImageInfo info, Source source) -> { decoder.setAllocator(allocator); Loading @@ -3581,6 +3590,20 @@ public abstract class ContentResolver implements ContentInterface { decoder.setTargetSampleSize(sample); } }); // Transform the bitmap if requested. We use a side-channel to // communicate the orientation, since EXIF thumbnails don't contain // the rotation flags of the original image. if (orientation.value != 0) { final int width = bitmap.getWidth(); final int height = bitmap.getHeight(); final Matrix m = new Matrix(); m.setRotate(orientation.value, width / 2, height / 2); bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false); } return bitmap; } /** {@hide} */ Loading core/java/android/provider/DocumentsContract.java +13 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.graphics.Bitmap; import android.graphics.ImageDecoder; import android.graphics.Point; import android.media.ExifInterface; import android.media.MediaFile; import android.net.Uri; import android.os.Build; import android.os.Bundle; Loading Loading @@ -1698,6 +1699,18 @@ public final class DocumentsContract { } catch (IOException e) { } // Use ImageDecoder to do full image decode of heif format file // will have right orientation. So, we don't need to add orientation // information into extras. final String mimeType = MediaFile.getMimeTypeForFile(file.getName()); if (mimeType.equals("image/heif") || mimeType.equals("image/heif-sequence") || mimeType.equals("image/heic") || mimeType.equals("image/heic-sequence")) { return new AssetFileDescriptor(pfd, 0 /* startOffset */, AssetFileDescriptor.UNKNOWN_LENGTH, null /* extras */); } return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras); } Loading media/java/android/media/ThumbnailUtils.java +52 −5 Original line number Diff line number Diff line Loading @@ -244,30 +244,77 @@ public class ThumbnailUtils { final Resizer resizer = new Resizer(size, signal); final String mimeType = MediaFile.getMimeTypeForFile(file.getName()); Bitmap bitmap = null; ExifInterface exif = null; int orientation = 0; // get orientation if (MediaFile.isExifMimeType(mimeType)) { exif = new ExifInterface(file); switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0)) { case ExifInterface.ORIENTATION_ROTATE_90: orientation = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: orientation = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: orientation = 270; break; } } boolean isHeifFile = false; if (mimeType.equals("image/heif") || mimeType.equals("image/heif-sequence") || mimeType.equals("image/heic") || mimeType.equals("image/heic-sequence")) { isHeifFile = true; try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) { retriever.setDataSource(file.getAbsolutePath()); return retriever.getThumbnailImageAtIndex(-1, bitmap = retriever.getThumbnailImageAtIndex(-1, new MediaMetadataRetriever.BitmapParams(), size.getWidth(), size.getWidth() * size.getHeight()); } catch (RuntimeException e) { throw new IOException("Failed to create thumbnail", e); } } else if (MediaFile.isExifMimeType(mimeType)) { final ExifInterface exif = new ExifInterface(file); } if (bitmap == null && exif != null) { final byte[] raw = exif.getThumbnailBytes(); if (raw != null) { return ImageDecoder.decodeBitmap(ImageDecoder.createSource(raw), resizer); try { bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(raw), resizer); } catch (ImageDecoder.DecodeException e) { Log.w(TAG, e); } } } // Checkpoint before going deeper if (signal != null) signal.throwIfCanceled(); return ImageDecoder.decodeBitmap(ImageDecoder.createSource(file), resizer); if (bitmap == null) { bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(file), resizer); // Use ImageDecoder to do full image decode of heif format file // will have right orientation. Don't rotate the bitmap again. if (isHeifFile) { return bitmap; } } // Transform the bitmap if the orientation of the image is not 0. if (orientation != 0 && bitmap != null) { final int width = bitmap.getWidth(); final int height = bitmap.getHeight(); final Matrix m = new Matrix(); m.setRotate(orientation, width / 2, height / 2); bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false); } return bitmap; } /** Loading Loading
core/java/android/content/ContentResolver.java +26 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.content; import static android.provider.DocumentsContract.EXTRA_ORIENTATION; import android.accounts.Account; import android.annotation.IntDef; import android.annotation.NonNull; Loading @@ -40,6 +42,7 @@ import android.graphics.Bitmap; import android.graphics.ImageDecoder; import android.graphics.ImageDecoder.ImageInfo; import android.graphics.ImageDecoder.Source; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; Loading @@ -56,6 +59,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.storage.StorageManager; import android.system.Int32Ref; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; Loading Loading @@ -3563,9 +3567,14 @@ public abstract class ContentResolver implements ContentInterface { // Convert to Point, since that's what the API is defined as final Bundle opts = new Bundle(); opts.putParcelable(EXTRA_SIZE, Point.convert(size)); return ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> { return content.openTypedAssetFile(uri, "image/*", opts, signal); final Int32Ref orientation = new Int32Ref(0); Bitmap bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> { final AssetFileDescriptor afd = content.openTypedAssetFile(uri, "image/*", opts, signal); final Bundle extras = afd.getExtras(); orientation.value = (extras != null) ? extras.getInt(EXTRA_ORIENTATION, 0) : 0; return afd; }), (ImageDecoder decoder, ImageInfo info, Source source) -> { decoder.setAllocator(allocator); Loading @@ -3581,6 +3590,20 @@ public abstract class ContentResolver implements ContentInterface { decoder.setTargetSampleSize(sample); } }); // Transform the bitmap if requested. We use a side-channel to // communicate the orientation, since EXIF thumbnails don't contain // the rotation flags of the original image. if (orientation.value != 0) { final int width = bitmap.getWidth(); final int height = bitmap.getHeight(); final Matrix m = new Matrix(); m.setRotate(orientation.value, width / 2, height / 2); bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false); } return bitmap; } /** {@hide} */ Loading
core/java/android/provider/DocumentsContract.java +13 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.graphics.Bitmap; import android.graphics.ImageDecoder; import android.graphics.Point; import android.media.ExifInterface; import android.media.MediaFile; import android.net.Uri; import android.os.Build; import android.os.Bundle; Loading Loading @@ -1698,6 +1699,18 @@ public final class DocumentsContract { } catch (IOException e) { } // Use ImageDecoder to do full image decode of heif format file // will have right orientation. So, we don't need to add orientation // information into extras. final String mimeType = MediaFile.getMimeTypeForFile(file.getName()); if (mimeType.equals("image/heif") || mimeType.equals("image/heif-sequence") || mimeType.equals("image/heic") || mimeType.equals("image/heic-sequence")) { return new AssetFileDescriptor(pfd, 0 /* startOffset */, AssetFileDescriptor.UNKNOWN_LENGTH, null /* extras */); } return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras); } Loading
media/java/android/media/ThumbnailUtils.java +52 −5 Original line number Diff line number Diff line Loading @@ -244,30 +244,77 @@ public class ThumbnailUtils { final Resizer resizer = new Resizer(size, signal); final String mimeType = MediaFile.getMimeTypeForFile(file.getName()); Bitmap bitmap = null; ExifInterface exif = null; int orientation = 0; // get orientation if (MediaFile.isExifMimeType(mimeType)) { exif = new ExifInterface(file); switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0)) { case ExifInterface.ORIENTATION_ROTATE_90: orientation = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: orientation = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: orientation = 270; break; } } boolean isHeifFile = false; if (mimeType.equals("image/heif") || mimeType.equals("image/heif-sequence") || mimeType.equals("image/heic") || mimeType.equals("image/heic-sequence")) { isHeifFile = true; try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) { retriever.setDataSource(file.getAbsolutePath()); return retriever.getThumbnailImageAtIndex(-1, bitmap = retriever.getThumbnailImageAtIndex(-1, new MediaMetadataRetriever.BitmapParams(), size.getWidth(), size.getWidth() * size.getHeight()); } catch (RuntimeException e) { throw new IOException("Failed to create thumbnail", e); } } else if (MediaFile.isExifMimeType(mimeType)) { final ExifInterface exif = new ExifInterface(file); } if (bitmap == null && exif != null) { final byte[] raw = exif.getThumbnailBytes(); if (raw != null) { return ImageDecoder.decodeBitmap(ImageDecoder.createSource(raw), resizer); try { bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(raw), resizer); } catch (ImageDecoder.DecodeException e) { Log.w(TAG, e); } } } // Checkpoint before going deeper if (signal != null) signal.throwIfCanceled(); return ImageDecoder.decodeBitmap(ImageDecoder.createSource(file), resizer); if (bitmap == null) { bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(file), resizer); // Use ImageDecoder to do full image decode of heif format file // will have right orientation. Don't rotate the bitmap again. if (isHeifFile) { return bitmap; } } // Transform the bitmap if the orientation of the image is not 0. if (orientation != 0 && bitmap != null) { final int width = bitmap.getWidth(); final int height = bitmap.getHeight(); final Matrix m = new Matrix(); m.setRotate(orientation, width / 2, height / 2); bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false); } return bitmap; } /** Loading