如何将ImageUri转换为Bitmap以实现图片压缩适配ImageView加载要求
ImageUri转Bitmap实现方案
需求背景:需要对图片做压缩处理,ImageView不支持直接加载高分辨率图片,该转换是图片压缩操作的前置步骤。
前置权限要求
- 访问外部存储图片时,Android 12及以下系统需申请
READ_EXTERNAL_STORAGE权限,Android 13及以上系统需申请READ_MEDIA_IMAGES权限 - 读取应用内Uri、系统媒体库返回的安全Uri无需额外申请权限
核心实现代码
实现逻辑采用先读取图片边界、计算采样率再解码的方式,避免直接加载高分辨率图片导致内存溢出:
Kotlin 实现
fun uriToBitmap(context: Context, uri: Uri): Bitmap? { return try { // 仅读取图片分辨率,不加载完整图片到内存 val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } context.contentResolver.openInputStream(uri)?.use { inputStream -> BitmapFactory.decodeStream(inputStream, null, options) } // 可根据实际业务需求调整目标宽高,示例为1080p规格 val targetWidth = 1080 val targetHeight = 1920 options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight) options.inJustDecodeBounds = false // 按采样率解码得到适配后的Bitmap context.contentResolver.openInputStream(uri)?.use { inputStream -> BitmapFactory.decodeStream(inputStream, null, options) } } catch (e: Exception) { e.printStackTrace() null } } /** * 计算Bitmap采样率,数值为2的n次方,采样率越高输出的Bitmap分辨率越低 */ private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int { val height = options.outHeight val width = options.outWidth var inSampleSize = 1 if (height > reqHeight || width > reqWidth) { val halfHeight = height / 2 val halfWidth = width / 2 while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) { inSampleSize *= 2 } } return inSampleSize }
Java 实现
public Bitmap uriToBitmap(Context context, Uri uri) { try { // 仅读取图片分辨率,不加载完整图片到内存 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; InputStream inputStream = context.getContentResolver().openInputStream(uri); BitmapFactory.decodeStream(inputStream, null, options); inputStream.close(); // 可根据实际业务需求调整目标宽高,示例为1080p规格 int targetWidth = 1080; int targetHeight = 1920; options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight); options.inJustDecodeBounds = false; // 按采样率解码得到适配后的Bitmap InputStream inputStream2 = context.getContentResolver().openInputStream(uri); Bitmap bitmap = BitmapFactory.decodeStream(inputStream2, null, options); inputStream2.close(); return bitmap; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 计算Bitmap采样率,数值为2的n次方,采样率越高输出的Bitmap分辨率越低 */ private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int height = options.outHeight; int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { int halfHeight = height / 2; int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
注意事项
- 上述实现已经在解码阶段完成了初步的分辨率压缩,无需再单独对原始高分辨率图片做全量加载
- 得到转换后的Bitmap后,可继续通过质量压缩、格式转换等操作完成后续的图片压缩需求,再加载到ImageView中即可
内容的提问来源于stack exchange,提问作者Shahzad Khan
相关产品推荐
相关产品推荐

