diff --git a/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java b/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java index 970f8cbf53..3bc2b56d96 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java @@ -1,5 +1,7 @@ package com.bumptech.glide.load.engine; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; import android.os.Build; import android.os.Process; import android.util.Log; @@ -642,8 +644,10 @@ Resource onResourceDecoded(DataSource dataSource, @NonNull Resource de Transformation appliedTransformation = null; Resource transformed = decoded; if (dataSource != DataSource.RESOURCE_DISK_CACHE) { - appliedTransformation = decodeHelper.getTransformation(resourceSubClass); - transformed = appliedTransformation.transform(glideContext, decoded, width, height); + if (!shouldBypassSoftwareTransformation(decoded)) { + appliedTransformation = decodeHelper.getTransformation(resourceSubClass); + transformed = appliedTransformation.transform(glideContext, decoded, width, height); + } } // TODO: Make this the responsibility of the Transformation. if (!decoded.equals(transformed)) { @@ -695,6 +699,40 @@ Resource onResourceDecoded(DataSource dataSource, @NonNull Resource de return result; } + /** + * Returns {@code true} if we should bypass applying software transformations to the decoded + * resource. + * + *

This is only true if the resource is a hardware bitmap, and both ALLOW_HARDWARE_CONFIG and + * BYPASS_TRANSFORMATIONS_FOR_HARDWARE_BITMAPS options are enabled. + */ + private boolean shouldBypassSoftwareTransformation(Resource decoded) { + Boolean bypassOption = options.get(Downsampler.BYPASS_TRANSFORMATIONS_FOR_HARDWARE_BITMAPS); + if (bypassOption == null || !bypassOption) { + return false; + } + + Boolean allowHardware = options.get(Downsampler.ALLOW_HARDWARE_CONFIG); + if (allowHardware == null || !allowHardware) { + return false; + } + + Object resource = decoded.get(); + Bitmap bitmap = null; + if (resource instanceof Bitmap) { + bitmap = (Bitmap) resource; + } else if (resource instanceof BitmapDrawable) { + bitmap = ((BitmapDrawable) resource).getBitmap(); + } + + if (bitmap == null) { + return false; + } + + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O + && bitmap.getConfig() == Bitmap.Config.HARDWARE; + } + private final class DecodeCallback implements DecodePath.DecodeCallback { private final DataSource dataSource; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java index 5c24a15d82..f2c40ba84a 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java @@ -113,6 +113,26 @@ public final class Downsampler { Option.memory( "com.bumptech.glide.load.resource.bitmap.Downsampler.AllowHardwareDecode", false); + /** + * Indicates that we should bypass applying transformations when the decoded bitmap config is + * {@link Bitmap.Config#HARDWARE}. + * + *

Enabling this option avoids copying hardware bitmaps to software canvases for + * transformations (like center-cropping or rounding), which reduces memory usage and avoids + * crashes caused by software rendering of hardware bitmaps. + * + *

Tradeoffs: Enabled transformations will NOT be applied to the resulting bitmap. This is only + * safe for display-only layouts (like grids) where the target {@link android.widget.ImageView} + * can handle the scaling/cropping using its {@link android.widget.ImageView.ScaleType} (e.g., + * {@link android.widget.ImageView.ScaleType#CENTER_CROP}). + * + *

This option is ignored unless {@link #ALLOW_HARDWARE_CONFIG} is also enabled. + */ + public static final Option BYPASS_TRANSFORMATIONS_FOR_HARDWARE_BITMAPS = + Option.memory( + "com.bumptech.glide.load.resource.bitmap.Downsampler.BypassTransformationsForHardwareBitmaps", + false); + private static final String WBMP_MIME_TYPE = "image/vnd.wap.wbmp"; private static final String ICO_MIME_TYPE = "image/x-ico"; private static final Set NO_DOWNSAMPLE_PRE_N_MIME_TYPES =