Android摄影App中Bitmap无法获取最大分辨率,ImageView显示画质骤降求助
解决Android上传Fragment中图片显示画质损失的问题
嘿,我太懂这种糟心的感觉了——辛辛苦苦拍的高清图,放到ImageView里就糊成马赛克,大概率是你拿到的是系统返回的压缩缩略图,而非真正的原图!下面给你拆解具体的解决办法,分相机和相册两种场景来处理:
一、相机Intent:别依赖返回的data,直接指定原图保存路径
很多人习惯用Intent(MediaStore.ACTION_IMAGE_CAPTURE)后,从返回的data里拿Bitmap,但这个Bitmap是系统压缩后的缩略图,尺寸通常只有几百像素,画质自然差。正确的做法是让相机直接把原图保存到你指定的文件里:
1. 配置FileProvider(Android 7.0+必备)
首先在AndroidManifest.xml里注册FileProvider:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
然后在res/xml下创建file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="my_images" path="Pictures" /> </paths>
2. 启动相机并指定原图保存路径
private lateinit var photoFile: File private fun takePhoto() { // 创建保存原图的文件 photoFile = createImageFile() val photoUri = FileProvider.getUriForFile( requireContext(), "${requireContext().packageName}.fileprovider", photoFile ) // 启动相机Intent,指定输出路径 val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri) startActivityForResult(takePictureIntent, REQUEST_CODE_CAMERA) } // 生成唯一的图片文件 private fun createImageFile(): File { val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) val storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES) return File.createTempFile( "JPEG_${timeStamp}_", /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ).apply { // 保存文件路径,后续可以用来读取 absolutePath } }
二、相册Intent:通过ContentResolver获取原图
从相册选图时,data.getData()返回的Uri可能指向缩略图,也可能是原图的Uri,但直接解码的话要注意避免OOM,最好配合合理的缩放:
1. 处理相册返回的结果
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK) { when (requestCode) { REQUEST_CODE_GALLERY -> { data?.data?.let { uri -> // 获取ImageView的目标尺寸,避免加载过大的Bitmap导致OOM val targetWidth = imageView.width val targetHeight = imageView.height // 通过ContentResolver读取原图并缩放 val originalBitmap = decodeSampledBitmapFromUri(uri, targetWidth, targetHeight) imageView.setImageBitmap(originalBitmap) // 或者用Glide等图片库更省心: // Glide.with(this).load(uri).centerCrop().into(imageView) } } REQUEST_CODE_CAMERA -> { // 读取相机保存的原图文件并缩放 val targetWidth = imageView.width val targetHeight = imageView.height val originalBitmap = decodeSampledBitmapFromFile(photoFile.absolutePath, targetWidth, targetHeight) imageView.setImageBitmap(originalBitmap) } } } }
2. 实现Bitmap的高效缩放(避免OOM)
// 从Uri解码并缩放Bitmap private fun decodeSampledBitmapFromUri(uri: Uri, reqWidth: Int, reqHeight: Int): Bitmap { val inputStream = requireContext().contentResolver.openInputStream(uri) // 先获取Bitmap的尺寸,不加载到内存 val options = BitmapFactory.Options().apply { inJustDecodeBounds = true BitmapFactory.decodeStream(inputStream, null, this) inputStream?.close() } // 计算缩放比例 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight) // 加载缩放后的Bitmap options.inJustDecodeBounds = false val newInputStream = requireContext().contentResolver.openInputStream(uri) return BitmapFactory.decodeStream(newInputStream, null, options)!!.apply { newInputStream?.close() } } // 从文件解码并缩放Bitmap private fun decodeSampledBitmapFromFile(path: String, reqWidth: Int, reqHeight: Int): Bitmap { val options = BitmapFactory.Options().apply { inJustDecodeBounds = true BitmapFactory.decodeFile(path, this) } options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight) options.inJustDecodeBounds = false return BitmapFactory.decodeFile(path, options)!! } // 计算合适的缩放比例 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 // 找到最大的inSampleSize,使得缩放后的尺寸不小于目标尺寸 while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) { inSampleSize *= 2 } } return inSampleSize }
三、ImageView的额外配置
别忘了给ImageView设置合适的属性,让图片显示更清晰:
<ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="200dp" android:adjustViewBounds="true" android:scaleType="centerCrop" android:antiAlias="true" />
android:antiAlias="true"可以开启抗锯齿,让边缘更平滑;scaleType根据你的需求选centerCrop或fitCenter。
内容的提问来源于stack exchange,提问作者alfonso claros
相关产品推荐
相关产品推荐

