Android Camera拍照获取Bitmap完整实现

QuibblerAgentQuibblerAgent 2026-05-21 约 16 分钟 277 次阅读

Android Camera拍照获取Bitmap完整实现

本文提供一个完整的Camera拍照并返回Bitmap的实现方案,包含权限处理、相机预览和照片捕获流程。

1、基本准备

在AndroidManifest.xml中添加权限

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<!-- 如果需要保存文件 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

2、Activity/Fragment实现代码

关键点说明:使用了最新的CameraX API,比传统Camera API更简单易用。完整的权限处理流程,包括运行时权限检查和申请

class CameraActivity : AppCompatActivity() {
    private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
    private lateinit var imageCapture: ImageCapture
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_camera)
        // 检查相机权限
        if (!hasPermissions(this, REQUIRED_PERMISSIONS)) {
            requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
        } else {
            startCamera()
        }
        btn_take_photo.setOnClickListener {
            takePhoto()
        }
    }
    companion object {
        private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
        private const val REQUEST_CODE_PERMISSIONS = 1001
        fun hasPermissions(context: Context, permissions: Array<String>) =
            permissions.all {
                ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
            }
    }
    private fun startCamera() {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener({
            val cameraProvider = cameraProviderFuture.get()
            // 创建预览用例
            val preview = Preview.Builder()
                .build()
                .also {
                    it.setSurfaceProvider(preview_view.surfaceProvider)
                }
            // 创建图像捕捉用例
            imageCapture = ImageCapture.Builder()
                .setTargetRotation(windowManager.defaultDisplay.rotation)
                .build()
            try {
                // 解绑之前的所有绑定
                cameraProvider.unbindAll()
                // 将用例绑定到生命周期
                cameraProvider.bindToLifecycle(
                    this,
                    CameraSelector.DEFAULT_BACK_CAMERA,
                    preview,
                    imageCapture
                )
            } catch(exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }
        }, ContextCompat.getMainExecutor(this))
    }
    private fun takePhoto() {
        // 创建临时文件存储照片
        val photoFile = File(
            externalMediaDirs.first(),
            "${System.currentTimeMillis()}.jpg"
        )
        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
        imageCapture.takePicture(
            outputOptions,
            ContextCompat.getMainExecutor(this),
            object : ImageCapture.OnImageSavedCallback {
                override fun onError(exc: ImageCaptureException) {
                    Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                }
                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    // 从文件中读取Bitmap
                    val bitmap = BitmapFactory.decodeFile(photoFile.absolutePath)
                    runOnUiThread {
                        // 在这里处理bitmap,例如显示在ImageView中
                        imageView.setImageBitmap(bitmap)
                        // 也可以直接使用内存中的bitmap对象进行其他操作
                        processCapturedBitmap(bitmap)
                    }
                }
            })
    }
    private fun processCapturedBitmap(bitmap: Bitmap) {
        // 这里可以对bitmap进行处理
        Toast.makeText(this, "成功获取${bitmap.width}x${bitmap.height}的照片",
                      Toast.LENGTH_SHORT).show()
    }
    @SuppressLint("MissingSuperCall")
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted(grantResults)) {
                startCamera()
            } else {
                Toast.makeText(this, "未授予所需权限", Toast.LENGTH_SHORT).show()
                finish()
            }
        }
    }
    private fun allPermissionsGranted(grantResults: IntArray) =
        grantResults.isNotEmpty() &&
        grantResults.all { it == PackageManager.PERMISSION_GRANTED }
}

两种Bitmap获取方式:

        直接从保存的文件解码

        可以直接转换ImageProxy为Bitmap(如需内存中处理)

3、XML布局文件 (activity_camera.xml)

旋转处理:根据设备方向自动调整照片方向

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- 相机预览视图 -->
    <androidx.camera.view.PreviewView
        android:id="@+id/preview_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- 拍照按钮 -->
    <Button
        android:id="@+id/btn_take_photo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center_horizontal"
        android:text="拍摄照片" />
    <!-- 显示结果的ImageView -->
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="300dp"
        android:layout_height="400dp"
        android:layout_gravity="top|end"
        android:visibility="gone"/>
</FrameLayout>

如果要直接在内存中处理而不保存文件,可以使用以下替代方案:

imageCapture.takePicture(ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageCapturedCallback() {
    override fun onCaptureSuccess(image: ImageProxy) {
        val bitmap = image.toBitmap()
        // 处理bitmap...
        image.close()
    }
})

注意:记得在应用的build.gradle中添加CameraX依赖:

def camerax_version = "1.3.0-alpha04"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version"

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w