How to capture images using the camera in jetpack compose

In this tutorial, I am going to explain how to capture images in a jetpack compose using a device camera. Also, I have added code to asking runtime permissions for the camera.

To get started with taking photos using the camera, First need to add camera permission on the manifest.xml file.

<uses-permission android:name="android.permission.CAMERA"/>
    <uses-feature android:name="android.hardware.camera.any"/>

Get File URI From Pathprovider

In the next step, need to get the file URI to store the captured image. So, we need to use the file Provider to get the file URI.

need to create a path_provider.xml file and define the cache directory.

<?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-cache-path name="my_images" path="/"/>
    </paths>

After creating the path provider XML file need to declare that in the manifest.xml file.

<provider
                android:name="androidx.core.content.FileProvider"
                android:authorities="${applicationId}.provider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/path_provider" />
            </provider>

Now, we have access to the external cache directory. Then create the file and get the URL from the file provider.

val context = LocalContext.current
        val file = context.createImageFile()
        val uri = FileProvider.getUriForFile(
            Objects.requireNonNull(context),
            BuildConfig.APPLICATION_ID + ".provider", file
        )

    fun Context.createImageFile(): File {
        // Create an image file name
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val imageFileName = "JPEG_" + timeStamp + "_"
        val image = File.createTempFile(
            imageFileName, /* prefix */
            ".jpg", /* suffix */
            externalCacheDir      /* directory */
        )
        return image
    }

Now the file is ready to store the captured image. But to launch the camera we need camera permission for the application. let’s create the permission launcher to get the camera permission.

check my another tutorial to learn runtime permissions on jetpack compose.

https://www.howtodoandroid.com/runtime-permission-on-jetpack-compose/
val permissionLauncher = rememberLauncherForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) {
            if (it) {
                Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
                cameraLauncher.launch(uri)
            } else {
                Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
            }
        }
requsting capture runtime permisson

Also, create the camera launcher to capture the image. Also, create mutableStateOf() a variable to store the captured image URL. by default it will be empty. After capture, the image updates the captured image URI.

var capturedImageUri by remember {
            mutableStateOf<Uri>(Uri.EMPTY)
        }

        val cameraLauncher =
            rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {
                capturedImageUri = uri
            }

Check the camera permission, if permission is granted call the camera launcher or launch the camera launcher.

val permissionCheckResult =
                    ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
                if (permissionCheckResult == PackageManager.PERMISSION_GRANTED) {
                    cameraLauncher.launch(uri)
                } else {
                    // Request a permission
                    permissionLauncher.launch(Manifest.permission.CAMERA)
                }

In the above code in the camera launcher, we are updating the captured image URI, So that the image will be displayed using the URL.

if (capturedImageUri.path?.isNotEmpty() == true) {
            Image(
                modifier = Modifier
                    .padding(16.dp, 8.dp),
                painter = rememberImagePainter(capturedImageUri),
                contentDescription = null
            )
        }

final code for this example,

class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContent {
                CaptureImageFromCameraJetpackComposeTheme {
                    // A surface container using the 'background' color from the theme
                    Surface(
                        modifier = Modifier.fillMaxSize(),
                        color = MaterialTheme.colors.background
                    ) {
                        AppContent()
                        //check permission
                    }
                }
            }
        }
    }

    @OptIn(ExperimentalCoilApi::class)
    @Composable
    fun AppContent() {

        val context = LocalContext.current
        val file = context.createImageFile()
        val uri = FileProvider.getUriForFile(
            Objects.requireNonNull(context),
            BuildConfig.APPLICATION_ID + ".provider", file
        )

        var capturedImageUri by remember {
            mutableStateOf<Uri>(Uri.EMPTY)
        }

        val cameraLauncher =
            rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {
                capturedImageUri = uri
            }

        val permissionLauncher = rememberLauncherForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) {
            if (it) {
                Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
                cameraLauncher.launch(uri)
            } else {
                Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
            }
        }

        Column(
            Modifier
                .fillMaxSize()
                .padding(10.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Button(onClick = {
                val permissionCheckResult =
                    ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
                if (permissionCheckResult == PackageManager.PERMISSION_GRANTED) {
                    cameraLauncher.launch(uri)
                } else {
                    // Request a permission
                    permissionLauncher.launch(Manifest.permission.CAMERA)
                }
            }) {
                Text(text = "Capture Image From Camera")
            }
        }

        if (capturedImageUri.path?.isNotEmpty() == true) {
            Image(
                modifier = Modifier
                    .padding(16.dp, 8.dp),
                painter = rememberImagePainter(capturedImageUri),
                contentDescription = null
            )
        }

    }

output

display captured image

Thanks for reading. let me know your feedback in the comments. Also, you can download is sample source code on Github.


Comments

One response to “How to capture images using the camera in jetpack compose”

  1. […] How to capture images using the camera in jetpack compose (howtodoandroid.com) […]

Leave a Reply

Your email address will not be published. Required fields are marked *


Latest Posts