You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:使用Android Camera API保存原始尺寸图片失败,代码排查

解决Fragment中相机拍照仅保存低分辨率图片的问题

嘿,这个问题我之前也踩过坑!核心原因是你大概率用了默认的相机Intent启动方式,没有指定输出文件路径——Android的ACTION_IMAGE_CAPTURE默认只会返回一张缩略图,而不是原始尺寸的照片。要保存原图,必须让相机直接把照片写入你指定的文件里,而不是通过Intent的data返回。

下面是具体的解决步骤和代码示例:

1. 先创建用于保存原图的文件(适配Android版本)

首先要处理不同Android版本的存储规则:Android 10及以上推荐用FileProvider来规避权限问题,Android 9及以下可以直接创建文件。这里给出兼容性更好的FileProvider适配示例:

// 在Fragment中创建保存照片的方法
private fun createImageFile(): File? {
    // 获取应用私有存储目录,无需额外读写权限
    val storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
    return try {
        // 用时间戳生成唯一文件名,避免重复
        File.createTempFile(
            "JPEG_${System.currentTimeMillis()}_",
            ".jpg",
            storageDir
        )
    } catch (ex: IOException) {
        ex.printStackTrace()
        null
    }
}

2. 配置FileProvider(必须步骤)

在AndroidManifest.xml里添加FileProvider的声明:

<application>
    ...
    <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>
</application>

然后在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>

3. 启动相机并指定输出Uri

启动相机时,必须添加EXTRA_OUTPUT参数,把刚才创建的文件Uri传进去,让相机直接把原图写入这个文件:

private val REQUEST_CAMERA_PERMISSION = 1001
private val REQUEST_IMAGE_CAPTURE = 1002
private var mCurrentPhotoPath: String? = null

// 启动相机的方法
private fun launchCamera() {
    // 先检查相机权限(Android 6+需要动态申请)
    if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
        != PackageManager.PERMISSION_GRANTED
    ) {
        ActivityCompat.requestPermissions(
            requireActivity(),
            arrayOf(Manifest.permission.CAMERA),
            REQUEST_CAMERA_PERMISSION
        )
        return
    }

    val imageFile = createImageFile() ?: return
    mCurrentPhotoPath = imageFile.absolutePath

    // 通过FileProvider获取文件Uri
    val imageUri = FileProvider.getUriForFile(
        requireContext(),
        "${requireContext().packageName}.fileprovider",
        imageFile
    )

    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    // 关键:指定输出Uri,让相机直接写入原图
    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
    // 授予相机临时读写权限
    requireContext().grantUriPermission(
        "com.android.camera",
        imageUri,
        Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
    )

    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}

4. 在onActivityResult中处理原图

注意:因为已经指定了输出文件,data参数会是null,直接读取之前保存的mCurrentPhotoPath对应的文件即可,这就是原始尺寸的照片:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
        mCurrentPhotoPath?.let { path ->
            val imageFile = File(path)
            if (imageFile.exists()) {
                // 添加到RecyclerView的ArrayList
                yourPhotoList.add(imageFile)
                yourAdapter.notifyDataSetChanged()

                // 存入Photos表
                savePhotoToDatabase(imageFile)
            }
        }
    }
}

额外推荐:用新的Activity Result API(更简洁)

如果你的项目基于AndroidX,建议弃用startActivityForResult,改用ActivityResultContracts.TakePicture,代码更简洁且兼容性更好:

// 初始化ActivityResultLauncher
private val takePictureLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
    if (success) {
        mCurrentPhotoPath?.let { path ->
            val imageFile = File(path)
            // 后续处理和上面一致
            yourPhotoList.add(imageFile)
            yourAdapter.notifyDataSetChanged()
            savePhotoToDatabase(imageFile)
        }
    }
}

// 启动相机的方法改成这样
private fun launchCameraWithNewAPI() {
    // 权限检查同上...
    val imageFile = createImageFile() ?: return
    mCurrentPhotoPath = imageFile.absolutePath
    val imageUri = FileProvider.getUriForFile(
        requireContext(),
        "${requireContext().packageName}.fileprovider",
        imageFile
    )
    takePictureLauncher.launch(imageUri)
}

这样处理后,你就能拿到原始分辨率的照片了,再也不会只有缩略图啦。

内容的提问来源于stack exchange,提问作者mmmmm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:01:12