Android 使用 ACTION_IMAGE_CAPTURE 拍照时,若仅从 Intent.getExtras().get("data") 获取 Bitmap,实际得到的是低分辨率缩略图;必须通过 EXTRA_OUTPUT 指定文件路径,才能保存并读取原始高清照片。
android 使用 `action_image_capture` 拍照时,若仅从 `intent.getextras().get("data")` 获取 bitmap,实际得到的是低分辨率缩略图;必须通过 `extra_output` 指定文件路径,才能保存并读取原始高清照片。
问题根源在于:MediaStore.ACTION_IMAGE_CAPTURE 的默认行为——当未指定输出路径时,系统仅在 Intent 的 "data" extra 中返回一个压缩后的缩略图(通常仅 500–800px 宽),而非相机拍摄的原始高分辨率图像。这正是你调用 imageBitmap.compress(...) 时质量“看似降低”的根本原因:起点已是降质缩略图,后续压缩与裁剪只会进一步劣化。
✅ 正确做法是显式指定 EXTRA_OUTPUT,让相机将全尺寸照片直接写入本地文件(如应用私有目录或 MediaStore),再从该 URI 加载图像进行后续处理。
✅ 修复步骤(关键修改)
1. 创建安全、可持久化的临时文件 URI
private Uri createImageUri() {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
String imageFileName = "IMG_" + timeStamp + "_";
File storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
try {
File imageFile = File.createTempFile(imageFileName, ".jpg", storageDir);
return FileProvider.getUriForFile(
requireContext(),
"com.yourpackage.fileprovider", // 替换为你的 file_provider_paths authority
imageFile
);
} catch (IOException e) {
throw new RuntimeException("Failed to create temp image file", e);
}
}
⚠️ 注意:务必在 AndroidManifest.xml 中声明 FileProvider,并配置 res/xml/file_paths.xml(支持 external-files-path),否则 FileProvider 会抛出异常。
2. 修改拍照 Intent,添加 EXTRA_OUTPUT
case R.id.layoutcam:
dialog.dismiss();
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(requireActivity().getPackageManager()) != null) {
Uri photoUri = createImageUri(); // 关键:生成目标 URI
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
takePictureLauncher.launch(takePictureIntent);
}
break;
3. 更新 takePictureLauncher:直接使用 photoUri,不再依赖 "data" extra
private final ActivityResultLauncher<intent> takePictureLauncher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// ✅ 直接使用之前传入的 photoUri —— 这里就是全尺寸原图!
Uri fullSizeImageUri = /* 你需要在 launch 前保存该 URI */;
// 推荐:将 photoUri 存为 Fragment 成员变量,或通过 launch 参数传递
// 示例(假设已定义成员变量 `pendingPhotoUri`):
// CropImage.activity(pendingPhotoUri)
// 启动裁剪(传入真实高清 URI)
CropImage.activity(fullSizeImageUri)
.setGuidelines(CropImageView.Guidelines.ON)
.setRequestedSize(1080, 1080, CropImageView.RequestSizeOptions.RESIZE_INSIDE)
.setOutputCompressQuality(95) // 保留较高质量(JPEG 推荐 90–95)
.setMaxCropResultSize(1080, 1080)
.start(requireContext(), ScanFragment.this);
}
});</intent>
? 关键点:pendingPhotoUri 必须在 launch() 前保存(例如在 onClick 中创建后立即赋值),因为 ActivityResultLauncher 回调中无法访问原始 Intent 的 EXTRA_OUTPUT。
4. 裁剪完成后加载高质量 Bitmap(可选优化)
在 onActivityResult 中,从裁剪结果 URI 加载 Bitmap 时,建议使用 BitmapFactory.Options 控制采样率,避免 OOM:
if (resultCode == Activity.RESULT_OK) {
Uri croppedImageUri = result.getUri();
// 高效加载:先获取尺寸,再按需缩放
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(croppedImageUri.getPath(), options);
options.inSampleSize = calculateInSampleSize(options, 1080, 1080);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(croppedImageUri.getPath(), options);
imageView.setImageBitmap(bitmap);
recognizeText(bitmap);
}
? 补充注意事项
- 不要用 PNG 存储拍照原图:Bitmap.CompressFormat.PNG 不压缩但体积巨大(尤其 12MP+ 图像),且相机输出本质是 JPEG。改用 JPEG 并设 quality=95 更合理。
- setOutputCompressQuality(90) 是裁剪库的压缩参数,它作用于裁剪后的输出,不影响原始输入质量——前提是输入 URI 指向的是全尺寸图。
- 权限无需额外申请:getExternalFilesDir() 属于应用私有目录,无需 READ_EXTERNAL_STORAGE(Android 10+ Scoped Storage 下更安全)。
- 测试验证:可用 ContentResolver.openInputStream(uri) 读取文件并打印 BitmapFactory.decodeStream(...).getWidth(),确认是否达到预期分辨率(如 4000×3000)。
遵循以上方案,即可彻底规避“拍照变糊”问题,确保从捕获、裁剪到识别全流程使用原始画质图像。











