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

Android中如何为CameraX设置宽高比以支持1:1/4:3/16:9拍摄

CameraX实现1:1、4:3、16:9比例拍照

核心思路

CameraX的ImageCapture和Preview用例都支持通过setTargetAspectRatio()指定宽高比,切换比例时只需更新对应参数并重新绑定相机用例即可。若需要严格保证输出图片比例,可在拍照后对原始图片进行裁剪。

实现步骤

1. 初始化相机用例

先定义全局变量保存当前比例和ImageCapture实例,然后初始化相机绑定预览和拍照用例:

private lateinit var imageCapture: ImageCapture
private var currentAspectRatio = AspectRatio.RATIO_4_3 // 默认4:3比例

private fun startCamera() {
    val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())

    cameraProviderFuture.addListener({
        val cameraProvider = cameraProviderFuture.get()

        // 配置预览用例,匹配当前比例
        val preview = Preview.Builder()
            .setTargetAspectRatio(currentAspectRatio)
            .build()
            .also {
                it.setSurfaceProvider(binding.viewFinder.surfaceProvider)
            }

        // 配置拍照用例,设置目标比例和低延迟模式
        imageCapture = ImageCapture.Builder()
            .setTargetAspectRatio(currentAspectRatio)
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
            .build()

        // 选择后置摄像头
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

        try {
            // 先解绑所有用例,再重新绑定
            cameraProvider.unbindAll()
            cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
        } catch(exc: Exception) {
            Log.e("CameraX", "绑定相机用例失败", exc)
        }
    }, ContextCompat.getMainExecutor(requireContext()))
}

2. 切换宽高比

提供切换方法,更新当前比例后重新初始化相机即可:

fun switchAspectRatio(ratio: Int) {
    when(ratio) {
        AspectRatio.RATIO_1_1, AspectRatio.RATIO_4_3, AspectRatio.RATIO_16_9 -> {
            currentAspectRatio = ratio
            startCamera()
        }
    }
}

// 调用示例:
// switchAspectRatio(AspectRatio.RATIO_1_1) // 切换为1:1
// switchAspectRatio(AspectRatio.RATIO_16_9) // 切换为16:9

3. 拍照后裁剪(可选)

若相机输出的原始图片比例与目标比例有偏差(比如部分设备传感器比例限制),可在拍照完成后裁剪图片到指定比例:

private fun takePhoto() {
    val outputFile = createImageFile()
    val outputOptions = ImageCapture.OutputFileOptions.Builder(outputFile).build()

    imageCapture.takePicture(
        outputOptions, ContextCompat.getMainExecutor(requireContext()),
        object : ImageCapture.OnImageSavedCallback {
            override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                // 裁剪图片到当前目标比例
                cropToTargetRatio(Uri.fromFile(outputFile), currentAspectRatio)
            }

            override fun onError(exc: ImageCaptureException) {
                Log.e("CameraX", "拍照失败", exc)
            }
        }
    )
}

private fun cropToTargetRatio(imageUri: Uri, aspectRatio: Int) {
    val bitmap = MediaStore.Images.Media.getBitmap(requireContext().contentResolver, imageUri)
    val targetWidth: Int
    val targetHeight: Int

    // 根据目标比例计算裁剪尺寸
    when(aspectRatio) {
        AspectRatio.RATIO_1_1 -> {
            val size = min(bitmap.width, bitmap.height)
            targetWidth = size
            targetHeight = size
        }
        AspectRatio.RATIO_4_3 -> {
            targetHeight = if(bitmap.width * 3 > bitmap.height *4) bitmap.height else bitmap.width *3 /4
            targetWidth = targetHeight *4 /3
        }
        AspectRatio.RATIO_16_9 -> {
            targetHeight = if(bitmap.width *9 > bitmap.height *16) bitmap.height else bitmap.width *9 /16
            targetWidth = targetHeight *16 /9
        }
        else -> {
            targetWidth = bitmap.width
            targetHeight = bitmap.height
        }
    }

    // 计算裁剪偏移量,保证居中裁剪
    val xOffset = (bitmap.width - targetWidth) / 2
    val yOffset = (bitmap.height - targetHeight) / 2

    val croppedBitmap = Bitmap.createBitmap(bitmap, xOffset, yOffset, targetWidth, targetHeight)
    // 保存裁剪后的图片(需处理权限和文件存储逻辑)
    saveCroppedBitmap(croppedBitmap)
}

// 辅助方法:创建临时图片文件
private fun createImageFile(): File {
    val storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
    return File.createTempFile(
        "JPEG_${System.currentTimeMillis()}_",
        ".jpg",
        storageDir
    )
}

注意事项

  • 预览布局需适配比例:建议使用CameraX PreviewView,并设置scaleType为ScaleType.FIT_CENTER或ScaleType.CENTER_CROP,避免画面拉伸。
  • 权限处理:确保已申请CAMERA和WRITE_EXTERNAL_STORAGE(或使用MediaStore)权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 16:45:40