You want to implement an in-app camera
in your Jetpack Compose Android app, which allows you to take a photo
and store it in your app gallery? In this video, you will learn how. Hi guys. My name is Yanneck Reiß, I hope you're doing well
and I welcome you to a new video. When in one of my latest videos
I showed you how you can implement an in-app
camera preview in Jetpack Compose, with the help of CameraX,
one part in this video was missing. Therefore, in this video
we will build up on the code base and you will learn
how to extend the camera in app preview with the functionality
to capture a photo and store it correctly so it gets visible in your device’s
photo gallery. So now we're back in the GitHub repository
I used for my last video about Jetpack Compose and CameraX
and now I will show you how I extended the repository so we can actually take a photo
and store it in the app gallery. So if you haven't watched the video yet,
make sure to check it out. And from this point on, you should feel
a little bit familiar with this code here. We still have our camera screen and in the camera screen
there is still the camera content. And if we scroll down,
we come back to the in-app camera preview, which we implemented
using an Android View. And now there's an additional composable
here, that is the last photo preview. So this preview takes the last picture
we actually captured. And this captured photo is a regular
Bitmap which you may already know. So but how do we actually capture a photo
now using the camera library in the last video,
I already teasered a little bit. Now we can just jump into the actual code
for that. So we have here
our extended floating action button and this action
button has an onClick function, which on the other hand
calls the capture photo. So we have three input parameters here. One is the context. The second is the camera controller,
which is actually coming from the CameraX library. And then we also have a callback
which passes a Bitmap, which is, of course,
the captured photo at the end. So let's take a look at the capture
photo function here. Inside the capturePhoto function, you can see that
we started using here a main executor. And we also are still using
the same build up for capturing a photo. But what we now do is that we access the image proxy
and convert it to a bitmap. And afterward we need to rotate the bitmap
and we can do that because we have the image info here
from the image proxy, which on the other hand
contains the rotation degrees. And this will rotate bitmap
here is just a little helper function. So let's quickly step through that. We use here a matrix
that uses a post rotate function, and this function here counterclockwise rotates the bitmap at the end. And then we also use a post scale,
which flips the bitmap
horizontally and also vertically. Then afterward we create with this information
a new bitmap from the original bitmap and have the bitmap corrected
from our capturing process. Afterward,
we just pass the corrected the bitmap to our on photo captured callback here. And then at last step
we will clear up the resources. So we just call image dot close and now with this callback function here,
we can quickly scroll up. We see it gets passed to the camera
content here and then finally here in the camera
screen, it gets passed to the view model. And here we have the store
photo and gallery function. So let's go in here. And as you can see,
we have here a use case that is called Save Photo To Gallery
use case. So what we finally want to achieve
is that the photo gets visible in the regular gallery app of your choice, and that is handled by this use case. So we have this function here
that says you want to scope launch. So we launched a new coroutine and then we call this use case here
with the captured bitmap. So let's jump into that. So here you can see that
we switch here to the IO dispatcher because we are using here
input and output operations. So we write to our media store at the end and then we use a content resolver because
we want to write to the media store. And whether you are above or equal to API version
29, which is the same version code as Q, then you use here
the volume external primary. And if you're below
that you use the external content URI, then we have here content values. And these content values actually describe the image
you will want to save in the media store. So you have various options you can use. Like some examples here date taken, date modified, author and so on. So you don't have to use all of those. Of course, the path here is relevant and also the actual state
of the media store. So you should use if you are once again
above or equal to Android version Q is pending. So you say I'm currently editing this file and if you are done later in the process
you would say image content videos put
media columns is pending to zero. But let's quickly
come back to the next line here, because here we say
insert the image content values we defined here
and use the image collection we defined here
above in the earlier process. And with this reference via this URI here, we can actually write to the media store
using the resolver once again. So we can just say open output stream, use
the URI as a reference and then we can use a little helper
function that is called ‘use’. So it will automatically clean up
the resources after the usage of this output stream here. And then we just need to say
capturePhotoBitmap compress. And because it's a photo we use here,
a JPEG you could also use for example. Yeah, PNG. You want to have the full quality
and want to write to the output stream. And just to mention if you have never used
that before, the check not is just a little helper,
so you don't have to say if output stream is not null
then do this or that. You can just use here this checkNotNull
and put in the output stream so the compiler knows, ‘okay,
after this line, this output stream
will definitely be not null’ because if it's null,
an exception will be thrown here. But that's not a problem
because we wrapped this whole block here inside and run catching
block and evaluate this result at the end. So the next line is
then the mentioned clean up. So we say here for the version greater than or equal to Android version Q once again set this is pending to zero and update the URI here
once again with this value. And then at the end
we return a Kotlin result. So if you want to handle some error cases
which might occur, then you could do that
by evaluating the Kotlin result here. But now enough of the talk. Here is the actual running app
and now I can just click here, take photo. So thumbs up. And as you can see down here is the mentioned preview. But let's see if this photo
actually got saved in the gallery. So let's quickly jump here to Google
photos in this case on the emulator. And as you can see,
here is the yeah, great photo of me. And by that we achieved our final goal. We have a fully functional camera app
with an in-app preview function to capture photo
and all of that in jetpack compose. Of course, the last part can also be used
in the regular Android app, but in this case
we focused on Jetpack Compose. But as you saw, it's
not that complicated to implement a camera functionality
in your Android app. Did you already have some use cases where you implemented a in-app preview
and also some camera functionality? Let me know in the comments. And as always, I hope you had some
takeaways like the video. Subscribe to my YouTube channel activate the notification
bell and I hope to see you soon.