Mehdi Haghgoo
Mehdi Haghgoo

Reputation: 3474

How to capture and display a picture with camera in Jetpack Compose

This seems to be so easy that I feel embarrassed to ask. However, I have been fighting it for hours and scratching my head. The goal is to simply launch camera, if the button is pressed and camera permission has been granted, and then take a picture and display it in an Image composable with Coil. Each time I try this, the ActivityResultContract fails to save the image. I think something with the given URI is messy, but it's beyond my magical powers to solve it. Long story short, here's my code. Hope someone has an idea of how to remedy this issue!

@Composable
fun MyPicker() {
    val context = LocalContext.current
    val permissionLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission().apply{
    }){
    }

    val imgUri by remember{mutableStateOf("${context.filesDir}/temp.jpg".toUri())}

    val captureLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.TakePicture()){
            Toast.makeText(context, "Image capture: ${if(it) "Successful" else "Failed"}", Toast.LENGTH_SHORT)
                .show()
    }

    Column {
        Button(onClick = {
            if(ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) != PERMISSION_GRANTED)
                permissionLauncher.launch(android.Manifest.permission.CAMERA)
            else captureLauncher.launch(imgUri)
        }) {
            Text("Load")
        }
        Image(painter = rememberAsyncImagePainter(imgUri), null)
    }
}

The error says different things for each Uri I provide. For example, for the above uri, it says the following:

  E  exception while saving result to URI: Optional.of(/data/user/0/com.mycompany.activityops/files/temp.jpg)
                                                                                                    java.io.FileNotFoundException: No content provider: /data/user/0/com.mycompany.activityops/files/temp.jpg

And then I tried to, also, provide a Uri.fromFile("${context.filesDir}/temp.jpg"), which was also frowned upon by Android throwing a huge FileUriExposedException, and then I'm clueless, with my head wandering around storage, content resolvers, Uris, etc.

Upvotes: 1

Views: 3453

Answers (1)

sarthak gupta
sarthak gupta

Reputation: 876

In a util file create a function which returns a temporary file

fun createImageFile(context: Context): File {
    // Create an image file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
    val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
    return File.createTempFile(
        "JPEG_${timeStamp}_", //prefix
        ".jpg", //suffix
        storageDir //directory
    )
}

Further get uri for the file

val file = Utils.createImageFile(context = context)
val imageUri = FileProvider.getUriForFile(
        context,
        "application_authority",
        file
    )

NOTE: The path of the image will be

val path = file.absolutePath

When starting a result contract you need to send uri

val cameraLauncher = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.TakePicture(),
    onResult = {isSuccess: Boolean ->
      // Handle Result
    }
cameraLauncher.launch(uri)

On getting a success call back, you can get the image inside file by

File(path) // Where **path** is defined above.

Upvotes: 1

Related Questions