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

如何让CameraController捕获的图片填充CameraPreview整个视口?

return cameraView

}

#### startCamera方法(在onCreate中调用)
```kotlin
private fun startCamera() {
    cameraController = LifecycleCameraController(requireContext())
    cameraController.bindToLifecycle(this)
}

拍照回调实现

cameraController.takePicture(ContextCompat.getMainExecutor(requireContext()),
    object : ImageCapture.OnImageCapturedCallback() {
        override fun onCaptureSuccess(image: ImageProxy) {
            Log.d("ImageCapture", "Success")
            val buffer = image.planes[0].buffer
            val bytes = ByteArray(buffer.capacity())
            buffer[bytes]
            val bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)

            imagePreview.rotation = image.imageInfo.rotationDegrees.toFloat()
            imagePreview.setImageBitmap(bitmapImage)
            imagePreview.isVisible = true
        }

        override fun onError(exception: ImageCaptureException) {
            Log.e("ImageCapture", "Failed to capture image: $exception")
            super.onError(exception)
        }
    })

补充说明

尝试过以下裁剪方式也无效:

val croppedBitmap = Bitmap.createBitmap(
    bitmapImage, 
    image.cropRect.left, 
    image.cropRect.top, 
    image.cropRect.width(), 
    image.cropRect.height()
)

怀疑问题出在ImageView的布局适配,而非相机逻辑本身。


解决方案

1. 修改ImageView的缩放模式

当前adjustViewBounds="true"会保持图片比例但不填满容器,改成以下配置:

<ImageView
    android:id="@+id/image_preview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"
    android:adjustViewBounds="false" />

centerCrop会让图片按比例缩放至填满整个ImageView,超出部分自动裁剪,完全符合“填满屏幕”的需求。

2. 匹配PreviewView的宽高比裁剪图片

直接用ImageProxy的cropRect裁剪不生效,是因为它基于传感器原始分辨率,未考虑显示方向和Preview的缩放比例。需要手动计算裁剪区域:

override fun onCaptureSuccess(image: ImageProxy) {
    Log.d("ImageCapture", "Success")
    // 获取适配显示方向的Bitmap
    val originalBitmap = image.toBitmap()
    
    // 计算PreviewView和图片的宽高比
    val previewRatio = viewFinder.width.toFloat() / viewFinder.height.toFloat()
    val imageRatio = originalBitmap.width.toFloat() / originalBitmap.height.toFloat()
    
    val scaledBitmap: Bitmap = if (previewRatio > imageRatio) {
        // Preview更宽,裁剪图片左右两侧
        val targetWidth = (originalBitmap.height * previewRatio).toInt()
        val cropX = (originalBitmap.width - targetWidth) / 2
        Bitmap.createBitmap(originalBitmap, cropX, 0, targetWidth, originalBitmap.height)
    } else {
        // Preview更高,裁剪图片上下两侧
        val targetHeight = (originalBitmap.width / previewRatio).toInt()
        val cropY = (originalBitmap.height - targetHeight) / 2
        Bitmap.createBitmap(originalBitmap, 0, cropY, originalBitmap.width, targetHeight)
    }
    
    // 设置旋转并显示图片
    imagePreview.rotation = image.imageInfo.rotationDegrees.toFloat()
    imagePreview.setImageBitmap(scaledBitmap)
    imagePreview.isVisible = true
    
    // 务必关闭ImageProxy释放资源
    image.close()
}

3. 提前配置CameraController的ImageCapture参数

在startCamera中设置ImageCapture的宽高比与PreviewView一致,确保拍摄的图片比例更贴近预览:

private fun startCamera() {
    cameraController = LifecycleCameraController(requireContext())
    // 等待View布局完成后获取正确宽高比,避免onCreate中宽高为0
    viewFinder.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            viewFinder.viewTreeObserver.removeOnGlobalLayoutListener(this)
            val previewRatio = Rational(viewFinder.width, viewFinder.height)
            cameraController.setImageCaptureCropAspectRatio(previewRatio)
        }
    })
    cameraController.bindToLifecycle(this)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 07:45:29