Site icon C1CTech

Android Jetpack CameraX Example

&NewLine;<p>This post is about Android Jetpack <span style&equals;"color&colon; &num;000080&semi;"><strong>CameraX <&sol;strong><span style&equals;"color&colon; &num;000000&semi;">API and how to implement it in an android application with a simple basic example&period;<&sol;span><&sol;span><&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<div class&equals;"wp-block-buttons is-content-justification-center is-layout-flex wp-block-buttons-is-layout-flex">&NewLine;<div class&equals;"wp-block-button"><a class&equals;"wp-block-button&lowbar;&lowbar;link has-white-color has-text-color has-background" href&equals;"https&colon;&sol;&sol;github&period;com&sol;arunk7839&sol;AndroidCameraXDemo" style&equals;"background-color&colon;&num;520599" target&equals;"&lowbar;blank" rel&equals;"noreferrer noopener"><strong>DOWNLOAD CODE<&sol;strong><&sol;a><&sol;div>&NewLine;<&sol;div>&NewLine;&NewLine;&NewLine;&NewLine;<figure class&equals;"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube"><div class&equals;"wp-block-embed&lowbar;&lowbar;wrapper">&NewLine;<amp-youtube layout&equals;"responsive" width&equals;"1200" height&equals;"675" data-videoid&equals;"tYprBGzW6SY" title&equals;"Android Jetpack CameraX Example"><a placeholder href&equals;"https&colon;&sol;&sol;youtu&period;be&sol;tYprBGzW6SY"><img src&equals;"https&colon;&sol;&sol;i&period;ytimg&period;com&sol;vi&sol;tYprBGzW6SY&sol;hqdefault&period;jpg" layout&equals;"fill" object-fit&equals;"cover" alt&equals;"Android Jetpack CameraX Example"><&sol;a><&sol;amp-youtube>&NewLine;<&sol;div><&sol;figure>&NewLine;&NewLine;&NewLine;&NewLine;<h3 class&equals;"wp-block-heading"><span style&equals;"color&colon; &num;000080&semi;"><strong>CameraX<&sol;strong><&sol;span><&sol;h3>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"wp-block-list"><li class&equals;"p1">CameraX is a Jetpack support library&comma; makes it easier to add camera capabilities to your app&period;<&sol;li><li>It has backward compatibility down to Android API 21&period;<&sol;li><li>It uses a simpler&comma; <span style&equals;"color&colon; &num;000080&semi;"><strong>use case<&sol;strong><&sol;span>-based approach that is <span style&equals;"color&colon; &num;0000ff&semi;"><strong>lifecycle-aware<&sol;strong><&sol;span>&period;<&sol;li><li>It resolves device compatibility issues for you so that you don’t have to include device-specific code in your code base&period;<&sol;li><li>It also reduces the amount of code you need to write when adding camera capabilities to your app&period;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<h3 class&equals;"wp-block-heading"><span style&equals;"color&colon; &num;000080&semi;"><strong>CameraX&colon; Use Cases<&sol;strong><&sol;span><&sol;h3>&NewLine;&NewLine;&NewLine;&NewLine;<p class&equals;"p1">We use CameraX to interface with a device’s camera through an abstraction called a <span style&equals;"color&colon; &num;008000&semi;"><strong>use case<&sol;strong><&sol;span>&period; The following use cases are available&colon;<&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"ul1 wp-block-list"><li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><b>Preview<&sol;b><&sol;span>&colon; accepts a surface for displaying a preview&comma; such as a&nbsp&semi;<span style&equals;"color&colon; &num;0000ff&semi;"><strong><span class&equals;"s2">PreviewView<&sol;span><&sol;strong><&sol;span>&period;<&sol;li><li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><b>Image analysis<&sol;b><&sol;span>&colon; analyse an image&period;<&sol;li><li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><b>Image capture<&sol;b><&sol;span>&colon; captures and saves an image&period;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<h3 class&equals;"wp-block-heading"><span style&equals;"color&colon; &num;000080&semi;"><strong>Creating new project<&sol;strong><&sol;span><&sol;h3>&NewLine;&NewLine;&NewLine;&NewLine;<p>1 &period; Create a new project by going to&nbsp&semi;<span style&equals;"color&colon; &num;008000&semi;"><b>File&nbsp&semi;<&sol;b><span class&equals;"s1"><b>&Implies;<&sol;b><&sol;span><&sol;span><b><span style&equals;"color&colon; &num;008000&semi;">&nbsp&semi;New Android Project<&sol;span>&comma;<&sol;b>&nbsp&semi;select&nbsp&semi;<span style&equals;"color&colon; &num;008000&semi;"><strong>Empty Activity<&sol;strong><&sol;span>&nbsp&semi;&comma; provide&nbsp&semi;<span style&equals;"color&colon; &num;008000&semi;"><strong>app name<&sol;strong><&sol;span>&comma; select language to&nbsp&semi;<strong><span style&equals;"color&colon; &num;008000&semi;">kotlin<&sol;span>&nbsp&semi;<&sol;strong>and then finally click on&nbsp&semi;<span style&equals;"color&colon; &num;008000&semi;"><strong>finish<&sol;strong><&sol;span>&period;<&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<p>2&period; Open the&nbsp&semi;<strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">build&period;gradle&lpar;Module&colon; app&rpar;<&sol;span><&sol;strong> file and add the below <strong>CameraX<&sol;strong> dependencies inside the dependencies&nbsp&semi;section&colon;<&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong><span class&equals;"s1">build&period;gradle&lpar;Module&colon; app&rpar;<&sol;span><&sol;strong><&sol;span><&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted">dependencies &lbrace;<br> def camerax&lowbar;version &equals; "1&period;0&period;0-beta07"<br><span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; CameraX core library using camera2 implementation<&sol;strong><&sol;span><br> implementation "androidx&period;camera&colon;camera-camera2&colon;&dollar;camerax&lowbar;version"<br><strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; CameraX Lifecycle Library<&sol;span><&sol;strong><br> implementation "androidx&period;camera&colon;camera-lifecycle&colon;&dollar;camerax&lowbar;version"<br><strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; CameraX View class<&sol;span><&sol;strong><br> implementation "androidx&period;camera&colon;camera-view&colon;1&period;0&period;0-alpha14"<br>&rcub;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<p class&equals;"p1">3 &period; CameraX needs some methods that are part of Java 8&comma; so we need to set our compile options accordingly&period; At the end of the&nbsp&semi;<span class&equals;"s1">android<&sol;span>&nbsp&semi;block&comma; right after&nbsp&semi;<span class&equals;"s1">buildTypes<&sol;span>&comma; add the following&colon;<&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted">compileOptions &lbrace;<br> sourceCompatibility JavaVersion&period;VERSION&lowbar;1&lowbar;8<br> targetCompatibility JavaVersion&period;VERSION&lowbar;1&lowbar;8<br>&rcub;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<p>4 &period;Open&nbsp&semi;<strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">AndroidManifest&period;xml<&sol;span><&sol;strong> and add the below permissions before the <span class&equals;"s1">application<&sol;span>&nbsp&semi;tag&period;<&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted">&lt&semi;uses-feature android&colon;name&equals;"android&period;hardware&period;camera&period;any" &sol;&gt&semi;<br>&lt&semi;uses-permission android&colon;name&equals;"android&period;permission&period;CAMERA" &sol;&gt&semi;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"wp-block-list"><li class&equals;"p1">Adding <span style&equals;"color&colon; &num;0000ff&semi;"><strong><span class&equals;"s1">android&period;hardware&period;camera&period;any<&sol;span><&sol;strong><&sol;span>&nbsp&semi;makes sure that the device has a camera&period; Specifying&nbsp&semi;<strong><span class&equals;"s1" style&equals;"color&colon; &num;0000ff&semi;">&period;any<&sol;span><&sol;strong>&nbsp&semi;means that it can be a front camera or a back camera&period;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<p>5&period; Adding Camera View &lpar;PreviewView&rpar; and Capture Button in XML&period;<&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<p><strong><span class&equals;"has-inline-color" style&equals;"color&colon; &num;0000ff&semi;">activity&lowbar;main&period;xml<&sol;span><&sol;strong><&sol;p>&NewLine;&NewLine;&NewLine;<pre>&lt&semi;&quest;xml version&equals;"1&period;0" encoding&equals;"utf-8"&quest;&gt&semi;<br>&lt&semi;androidx&period;constraintlayout&period;widget&period;ConstraintLayout<br> xmlns&colon;android&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;apk&sol;res&sol;android"<br> xmlns&colon;tools&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;tools"<br> xmlns&colon;app&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;apk&sol;res-auto"<br> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br> android&colon;layout&lowbar;height&equals;"match&lowbar;parent"<br> tools&colon;context&equals;"&period;MainActivity"&gt&semi;<br><br> &lt&semi;Button<br> android&colon;id&equals;"&commat;&plus;id&sol;camera&lowbar;capture&lowbar;button"<br> android&colon;layout&lowbar;width&equals;"100dp"<br> android&colon;layout&lowbar;height&equals;"100dp"<br> android&colon;layout&lowbar;marginBottom&equals;"50dp"<br> android&colon;scaleType&equals;"fitCenter"<br> android&colon;text&equals;"Capture Photo"<br> app&colon;layout&lowbar;constraintLeft&lowbar;toLeftOf&equals;"parent"<br> app&colon;layout&lowbar;constraintRight&lowbar;toRightOf&equals;"parent"<br> app&colon;layout&lowbar;constraintBottom&lowbar;toBottomOf&equals;"parent"<br> android&colon;elevation&equals;"2dp" &sol;&gt&semi;<br><br> &lt&semi;androidx&period;camera&period;view&period;PreviewView<br> android&colon;id&equals;"&commat;&plus;id&sol;viewFinder"<br> android&colon;layout&lowbar;width&equals;"match&lowbar;parent"<br> android&colon;layout&lowbar;height&equals;"match&lowbar;parent" &sol;&gt&semi;<br><br>&lt&semi;&sol;androidx&period;constraintlayout&period;widget&period;ConstraintLayout&gt&semi;<&sol;pre>&NewLine;<h3 class&equals;"step-title"><span style&equals;"color&colon; &num;000080&semi;"><strong>Implement Preview use case<&sol;strong><&sol;span><&sol;h3>&NewLine;<p>6 &period; To implement the CameraX preview use case&comma; we will implement the <span style&equals;"color&colon; &num;0000ff&semi;"><strong>startCamera&lpar;&rpar;<&sol;strong><&sol;span> method&comma; which is called after allowing camera permission from user&period;<&sol;p>&NewLine;<pre><span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Request camera permissions<&sol;strong><&sol;span><br>if &lpar;allPermissionsGranted&lpar;&rpar;&rpar; &lbrace;<br> <span style&equals;"color&colon; &num;0000ff&semi;"><strong> startCamera&lpar;&rpar;<&sol;strong><&sol;span><br>&rcub; else &lbrace;<br> ActivityCompat&period;requestPermissions&lpar;<br> this&comma; REQUIRED&lowbar;PERMISSIONS&comma; REQUEST&lowbar;CODE&lowbar;PERMISSIONS<br> &rpar;<br>&rcub;<br><br>private fun startCamera&lpar;&rpar; &lbrace;<br><br> val cameraProviderFuture &equals; ProcessCameraProvider&period;getInstance&lpar;this&rpar;<br><br> cameraProviderFuture&period;addListener&lpar;Runnable &lbrace;<br><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; Used to bind the lifecycle of cameras to the lifecycle owner<&sol;span><&sol;strong><br> val cameraProvider&colon; ProcessCameraProvider &equals; cameraProviderFuture&period;get&lpar;&rpar;<br><br> <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Preview <&sol;span><&sol;strong><br> val preview &equals; Preview&period;Builder&lpar;&rpar;<br> &period;build&lpar;&rpar;<br> &period;also &lbrace;<br> it&period;setSurfaceProvider&lpar;viewFinder&period;createSurfaceProvider&lpar;&rpar;&rpar;<br> &rcub;<br><br> <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Select back camera as a default<&sol;span><&sol;strong><br> val cameraSelector &equals; CameraSelector&period;DEFAULT&lowbar;BACK&lowbar;CAMERA<br><br> try &lbrace;<br> <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Unbind use cases before rebinding<&sol;span><&sol;strong><br> cameraProvider&period;unbindAll&lpar;&rpar;<br><br> <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Bind preview use case to camera<&sol;span><&sol;strong><br> cameraProvider&period;bindToLifecycle&lpar;<br> this&comma; cameraSelector&comma; preview<br> &rpar;<br><br> &rcub; catch &lpar;exc&colon; Exception&rpar; &lbrace;<br> Log&period;e&lpar;TAG&comma; "Use case binding failed"&comma; exc&rpar;<br> &rcub;<br><br> &rcub;&comma; ContextCompat&period;getMainExecutor&lpar;this&rpar;&rpar;<br>&rcub;<&sol;pre>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1">Create an instance of the&nbsp&semi;<span style&equals;"color&colon; &num;0000ff&semi;"><strong><a style&equals;"color&colon; &num;0000ff&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;androidx&sol;camera&sol;lifecycle&sol;ProcessCameraProvider"><span class&equals;"s2">ProcessCameraProvider<&sol;span><&sol;a><&sol;strong><&sol;span>&period; This is used to bind the lifecycle of cameras to the lifecycle owner&period; This eliminates the task of opening and closing the camera since CameraX is lifecycle-aware&period;<&sol;li>&NewLine;<&sol;ul>&NewLine;<pre>val cameraProviderFuture &equals; ProcessCameraProvider&period;getInstance&lpar;this&rpar;<&sol;pre>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1">Add a listener to the&nbsp&semi;<span class&equals;"s2">cameraProviderFuture<&sol;span>&period; Add a&nbsp&semi;<span style&equals;"color&colon; &num;008000&semi;"><strong><span class&equals;"s2">Runnable<&sol;span><&sol;strong><&sol;span> as one argument and <strong><span style&equals;"color&colon; &num;008000&semi;"><a style&equals;"color&colon; &num;008000&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;kotlin&sol;androidx&sol;core&sol;content&sol;ContextCompat"><span class&equals;"s3">ContextCompat<&sol;span><&sol;a><span class&equals;"s3">&period;getMainExecutor&lpar;&rpar;<&sol;span><&sol;span><&sol;strong> as the second argument &lpar; returns an <span style&equals;"color&colon; &num;008000&semi;"><strong><a style&equals;"color&colon; &num;008000&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;java&sol;util&sol;concurrent&sol;Executor"><span class&equals;"s3">Executor<&sol;span><&sol;a><&sol;strong><&sol;span> that runs on the main thread&rpar;&period;<&sol;li>&NewLine;<&sol;ul>&NewLine;<pre>cameraProviderFuture&period;addListener&lpar;Runnable &lbrace;&rcub;&comma; ContextCompat&period;getMainExecutor&lpar;this&rpar;&rpar;<&sol;pre>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1">In the&nbsp&semi;<span class&equals;"s2">Runnable<&sol;span>&comma; add a&nbsp&semi;<span style&equals;"color&colon; &num;008000&semi;"><strong><a style&equals;"color&colon; &num;008000&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;androidx&sol;camera&sol;lifecycle&sol;ProcessCameraProvider"><span class&equals;"s3">ProcessCameraProvider<&sol;span><&sol;a><&sol;strong><&sol;span>&period; This is used to bind the lifecycle of your camera to the&nbsp&semi;<span class&equals;"s2">LifecycleOwner<&sol;span> within the application&&num;8217&semi;s process&period;<&sol;li>&NewLine;<&sol;ul>&NewLine;<pre>val cameraProvider&colon; ProcessCameraProvider &equals; cameraProviderFuture&period;get&lpar;&rpar;<&sol;pre>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1">Initialize the <span style&equals;"color&colon; &num;008000&semi;"><strong><a style&equals;"color&colon; &num;008000&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;kotlin&sol;androidx&sol;camera&sol;core&sol;Preview"><span class&equals;"s2">Preview<&sol;span><&sol;a><&sol;strong><&sol;span> object&comma; get a surface provider from viewfinder&comma; and then set it on the preview&period;<&sol;li>&NewLine;<&sol;ul>&NewLine;<pre><strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Preview<&sol;span><&sol;strong><br>val preview &equals; Preview&period;Builder&lpar;&rpar;<br> &period;build&lpar;&rpar;<br> &period;also &lbrace;<br> it&period;setSurfaceProvider&lpar;viewFinder&period;createSurfaceProvider&lpar;&rpar;&rpar;<br> &rcub;<&sol;pre>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1">Create a&nbsp&semi;<span style&equals;"color&colon; &num;008000&semi;"><strong><a style&equals;"color&colon; &num;008000&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;androidx&sol;camera&sol;core&sol;CameraSelector"><span class&equals;"s2">CameraSelector<&sol;span><&sol;a><&sol;strong><&sol;span>&nbsp&semi;object and select&nbsp&semi;<span style&equals;"color&colon; &num;0000ff&semi;"><strong><span class&equals;"s3">DEFAULT&lowbar;BACK&lowbar;CAMERA<&sol;span><&sol;strong><&sol;span>&period;<&sol;li>&NewLine;<&sol;ul>&NewLine;<pre><span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Select back camera as a default<&sol;strong><&sol;span><br>val cameraSelector &equals; CameraSelector&period;DEFAULT&lowbar;BACK&lowbar;CAMERA<&sol;pre>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1">Inside <span class&equals;"s2">try<&sol;span> block&comma; make sure nothing is bound to your&nbsp&semi;<span class&equals;"s2">cameraProvider<&sol;span>&comma; and then bind your&nbsp&semi;<span class&equals;"s2">cameraSelector<&sol;span>&nbsp&semi;and preview object to the&nbsp&semi;<span class&equals;"s2">cameraProvider<&sol;span>&period; Add catch block to log if there&&num;8217&semi;s a failure&period;<&sol;li>&NewLine;<&sol;ul>&NewLine;<pre>try &lbrace;<br> <strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; Unbind use cases from app lifecycle<&sol;span><&sol;strong><br> cameraProvider&period;unbindAll&lpar;&rpar;<br><br> <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Bind use cases to camera<&sol;strong><&sol;span><br> cameraProvider&period;bindToLifecycle&lpar;<br> this&comma; cameraSelector&comma; preview<br> &rpar;<br><br>&rcub; catch &lpar;exc&colon; Exception&rpar; &lbrace;<br> Log&period;e&lpar;TAG&comma; "Use case binding failed"&comma; exc&rpar;<br>&rcub;<&sol;pre>&NewLine;<ul>&NewLine;<li>Run the app&period; You should see a camera preview&excl;<&sol;li>&NewLine;<&sol;ul>&NewLine;&NewLine;&NewLine;<div class&equals;"wp-block-image"><figure class&equals;"aligncenter size-large is-resized"><img src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2021&sol;03&sol;Screenshot&lowbar;1615977610-1-576x1024&period;png" alt&equals;"" class&equals;"wp-image-2427" width&equals;"392" height&equals;"697"&sol;><&sol;figure><&sol;div>&NewLine;&NewLine;&NewLine;&NewLine;<h3 class&equals;"step-title wp-block-heading"><span style&equals;"color&colon; &num;000080&semi;"><strong>Implement ImageCapture use case<&sol;strong><&sol;span><&sol;h3>&NewLine;&NewLine;&NewLine;&NewLine;<p>7 &period; To capture and save photos&comma; we will implement the<span style&equals;"color&colon; &num;008000&semi;"><strong> takePhoto&lpar;&rpar;<&sol;strong><&sol;span> method&comma; which is called when the <span style&equals;"color&colon; &num;0000ff&semi;"><strong>CAPTURE PHOTO<&sol;strong><&sol;span>&nbsp&semi;button is pressed &period;<&sol;p>&NewLine;<&excl;-- WP QUADS Content Ad Plugin v&period; 2&period;0&period;98&period;1 -->&NewLine;<div class&equals;"quads-location quads-ad2" id&equals;"quads-ad2" style&equals;"float&colon;none&semi;margin&colon;0px&semi;">&NewLine;&NewLine;<&sol;div>&NewLine;&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted"><strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Set up the listener for capture photo button<&sol;span><&sol;strong><br>camera&lowbar;capture&lowbar;button&period;setOnClickListener &lbrace; takePhoto&lpar;&rpar; &rcub;<br><br>private fun takePhoto&lpar;&rpar; &lbrace;<br><br> val imageCapture &equals; imageCapture &quest;&colon; return<br><br><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Create time-stamped output file to hold the image<&sol;strong><&sol;span><br> val photoFile &equals; File&lpar;<br> outputDirectory&comma;<br> SimpleDateFormat&lpar;<br> FILENAME&lowbar;FORMAT&comma; Locale&period;US<br> &rpar;&period;format&lpar;System&period;currentTimeMillis&lpar;&rpar;&rpar; &plus; "&period;jpg"<br> &rpar;<br><br><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Create output options object which contains file &plus; metadata<&sol;strong><&sol;span><br> val outputOptions &equals; ImageCapture&period;OutputFileOptions&period;Builder&lpar;photoFile&rpar;&period;build&lpar;&rpar;<br><br> <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Set up image capture listener&comma; which is triggered after photo has<&sol;strong><&sol;span><br><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; been taken<&sol;strong><&sol;span><br> imageCapture&period;takePicture&lpar;<br> outputOptions&comma;<br> ContextCompat&period;getMainExecutor&lpar;this&rpar;&comma;<br> object &colon; ImageCapture&period;OnImageSavedCallback &lbrace;<br> override fun onError&lpar;exc&colon; ImageCaptureException&rpar; &lbrace;<br> Log&period;e&lpar;TAG&comma; "Photo capture failed&colon; &dollar;&lbrace;exc&period;message&rcub;"&comma; exc&rpar;<br> &rcub;<br><br> override fun onImageSaved&lpar;output&colon; ImageCapture&period;OutputFileResults&rpar; &lbrace;<br> val savedUri &equals; Uri&period;fromFile&lpar;photoFile&rpar;<br> val msg &equals; "Photo capture succeeded&colon; &dollar;savedUri"<br> Toast&period;makeText&lpar;baseContext&comma; msg&comma; Toast&period;LENGTH&lowbar;SHORT&rpar;&period;show&lpar;&rpar;<br> Log&period;d&lpar;TAG&comma; msg&rpar;<br> &rcub;<br> &rcub;&rpar;<br>&rcub;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"ul1 wp-block-list"><li class&equals;"li1">First&comma; get a reference to the&nbsp&semi;<span style&equals;"color&colon; &num;0000ff&semi;"><strong><a style&equals;"color&colon; &num;0000ff&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;kotlin&sol;androidx&sol;camera&sol;core&sol;ImageCapture"><span class&equals;"s2">ImageCapture<&sol;span><&sol;a><&sol;strong><&sol;span> use case&period; If the use case is null&comma; exit out of the function&period;&nbsp&semi;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted">val imageCapture &equals; imageCapture &quest;&colon; return<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"ul1 wp-block-list"><li class&equals;"li1">Create a file to hold the image&period; Add a time stamp so the file name will be unique&period;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted">val photoFile &equals; File&lpar;<br> outputDirectory&comma;<br> SimpleDateFormat&lpar;<br> FILENAME&lowbar;FORMAT&comma; Locale&period;US<br> &rpar;&period;format&lpar;System&period;currentTimeMillis&lpar;&rpar;&rpar; &plus; "&period;jpg"<br>&rpar;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"ul1 wp-block-list"><li class&equals;"li1">Create an&nbsp&semi;<span style&equals;"color&colon; &num;0000ff&semi;"><strong><a style&equals;"color&colon; &num;0000ff&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;kotlin&sol;androidx&sol;camera&sol;core&sol;ImageCapture&period;OutputFileOptions"><span class&equals;"s2">OutputFileOptions<&sol;span><&sol;a><&sol;strong><&sol;span> object&comma; where you can specify things about how you want your output to be&period; You want the output saved in the file we just created&comma; so add your <span style&equals;"color&colon; &num;008000&semi;"><strong><span class&equals;"s3">photoFile<&sol;span><&sol;strong><&sol;span>&period;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted"><span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Create output options object which contains file &plus; metadata<&sol;strong><&sol;span><br>val outputOptions &equals; ImageCapture&period;OutputFileOptions&period;Builder&lpar;photoFile&rpar;&period;build&lpar;&rpar;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"ul1 wp-block-list"><li class&equals;"li1">Call&nbsp&semi;<span style&equals;"color&colon; &num;0000ff&semi;"><strong><span class&equals;"s2">takePicture&lpar;&rpar;<&sol;span><&sol;strong><&sol;span>&nbsp&semi;on the&nbsp&semi;<span class&equals;"s2">imageCapture<&sol;span>&nbsp&semi;object&period; Pass in&nbsp&semi;<span class&equals;"s2">outputOptions<&sol;span>&comma; the executor&comma; and a callback for when the image is saved&period;&nbsp&semi;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted">imageCapture&period;takePicture&lpar;<br> outputOptions&comma;<br> ContextCompat&period;getMainExecutor&lpar;this&rpar;&comma;<br> object &colon; ImageCapture&period;OnImageSavedCallback &lbrace;<br> override fun onError&lpar;exc&colon; ImageCaptureException&rpar; &lbrace;<br> Log&period;e&lpar;TAG&comma; "Photo capture failed&colon; &dollar;&lbrace;exc&period;message&rcub;"&comma; exc&rpar;<br> &rcub;<br><br> override fun onImageSaved&lpar;output&colon; ImageCapture&period;OutputFileResults&rpar; &lbrace;<br> val savedUri &equals; Uri&period;fromFile&lpar;photoFile&rpar;<br> val msg &equals; "Photo capture succeeded&colon; &dollar;savedUri"<br> Toast&period;makeText&lpar;baseContext&comma; msg&comma; Toast&period;LENGTH&lowbar;SHORT&rpar;&period;show&lpar;&rpar;<br> Log&period;d&lpar;TAG&comma; msg&rpar;<br> &rcub;<br> &rcub;&rpar;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"ul1 wp-block-list"><li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><strong>onError&lpar;&rpar;<&sol;strong><&sol;span> &colon; call when image capture fails or saving the image capture fails&period;<&sol;li><li class&equals;"li1"><strong><span style&equals;"color&colon; &num;0000ff&semi;">onImageSaved&lpar;&rpar;<&sol;span><&sol;strong> &colon; call when the photo was taken successfully&period; Saves the photo to the file you created earlier&comma; present a toast to let the user know it was successful&comma; and print a log statement&period;<&sol;li><li class&equals;"li1">Go to the&nbsp&semi;<strong><span style&equals;"color&colon; &num;008000&semi;"><span class&equals;"s1">startCamera&lpar;&rpar;<&sol;span>&nbsp&semi;<&sol;span><&sol;strong>method and copy this code under the code for preview&period;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted">imageCapture &equals; ImageCapture&period;Builder&lpar;&rpar;<br> &period;build&lpar;&rpar;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"ol1 wp-block-list"><li class&equals;"li1">Finally&comma; update the call to&nbsp&semi;<span style&equals;"color&colon; &num;0000ff&semi;"><strong><span class&equals;"s1">bindToLifecycle&lpar;&rpar;<&sol;span><&sol;strong><&sol;span>&nbsp&semi;in the&nbsp&semi;<span class&equals;"s1">try<&sol;span>&nbsp&semi;block to include the new use case&colon;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted"><span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Add imageCapture use case to camera<&sol;strong><&sol;span><br>cameraProvider&period;bindToLifecycle&lpar;<br> this&comma; cameraSelector&comma; preview&comma; <span style&equals;"color&colon; &num;0000ff&semi;"><strong>imageCapture<&sol;strong><&sol;span><br>&rpar;<&sol;pre>&NewLine;&NewLine;&NewLine;&NewLine;<ul class&equals;"wp-block-list"><li>Rerun the app and press&nbsp&semi;<span style&equals;"color&colon; &num;008000&semi;"><strong>Capture Photo<&sol;strong><&sol;span>&period; You will see a toast presented on the screen and a message in the logs&period;<&sol;li><&sol;ul>&NewLine;&NewLine;&NewLine;&NewLine;<div class&equals;"wp-block-image"><figure class&equals;"aligncenter size-large is-resized"><img src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2021&sol;03&sol;Screenshot&lowbar;1615977619-1-576x1024&period;png" alt&equals;"" class&equals;"wp-image-2426" width&equals;"303" height&equals;"539"&sol;><&sol;figure><&sol;div>&NewLine;&NewLine;&NewLine;&NewLine;<p><span style&equals;"font-size&colon; inherit&semi; font-family&colon; -apple-system&comma; BlinkMacSystemFont&comma; 'Segoe UI'&comma; Roboto&comma; Oxygen-Sans&comma; Ubuntu&comma; Cantarell&comma; 'Helvetica Neue'&comma; sans-serif&semi;">8 &period; Open <&sol;span><strong style&equals;"font-size&colon; inherit&semi; font-family&colon; -apple-system&comma; BlinkMacSystemFont&comma; 'Segoe UI'&comma; Roboto&comma; Oxygen-Sans&comma; Ubuntu&comma; Cantarell&comma; 'Helvetica Neue'&comma; sans-serif&semi;"><span style&equals;"color&colon; &num;008000&semi;">MainActivity&period;kt<&sol;span><&sol;strong><span style&equals;"font-size&colon; inherit&semi; font-family&colon; -apple-system&comma; BlinkMacSystemFont&comma; 'Segoe UI'&comma; Roboto&comma; Oxygen-Sans&comma; Ubuntu&comma; Cantarell&comma; 'Helvetica Neue'&comma; sans-serif&semi;"> and add the below code&period;<&sol;span><&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<p><strong><span style&equals;"color&colon; &num;0000ff&semi;">MainActivity&period;kt<&sol;span><&sol;strong><&sol;p>&NewLine;&NewLine;&NewLine;&NewLine;<pre class&equals;"wp-block-preformatted">package com&period;c1ctech&period;androidcameraxdemo<br><br>import androidx&period;appcompat&period;app&period;AppCompatActivity<br>import android&period;os&period;Bundle<br>import android&period;Manifest<br>import android&period;content&period;pm&period;PackageManager<br>import android&period;net&period;Uri<br>import android&period;util&period;Log<br>import android&period;widget&period;Toast<br>import androidx&period;core&period;app&period;ActivityCompat<br>import androidx&period;core&period;content&period;ContextCompat<br>import java&period;util&period;concurrent&period;Executors<br>import androidx&period;camera&period;core&period;&ast;<br>import androidx&period;camera&period;lifecycle&period;ProcessCameraProvider<br>import kotlinx&period;android&period;synthetic&period;main&period;activity&lowbar;main&period;&ast;<br>import java&period;io&period;File<br>import java&period;text&period;SimpleDateFormat<br>import java&period;util&period;&ast;<br>import java&period;util&period;concurrent&period;ExecutorService<br><br>class MainActivity &colon; AppCompatActivity&lpar;&rpar; &lbrace;<br> private var imageCapture&colon; ImageCapture&quest; &equals; null<br><br> private lateinit var outputDirectory&colon; File<br> private lateinit var cameraExecutor&colon; ExecutorService<br><br> override fun onCreate&lpar;savedInstanceState&colon; Bundle&quest;&rpar; &lbrace;<br> super&period;onCreate&lpar;savedInstanceState&rpar;<br> setContentView&lpar;R&period;layout&period;activity&lowbar;main&rpar;<br><br> <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Request camera permissions<&sol;strong><&sol;span><br> if &lpar;allPermissionsGranted&lpar;&rpar;&rpar; &lbrace;<br> startCamera&lpar;&rpar;<br> &rcub; else &lbrace;<br> ActivityCompat&period;requestPermissions&lpar;<br> this&comma; REQUIRED&lowbar;PERMISSIONS&comma; REQUEST&lowbar;CODE&lowbar;PERMISSIONS<br> &rpar;<br> &rcub;<br><br> <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Set up the listener for take photo button<&sol;strong><&sol;span><br> camera&lowbar;capture&lowbar;button&period;setOnClickListener &lbrace; takePhoto&lpar;&rpar; &rcub;<br><br> outputDirectory &equals; getOutputDirectory&lpar;&rpar;<br><br> cameraExecutor &equals; Executors&period;newSingleThreadExecutor&lpar;&rpar;<br> &rcub;<br><br> private fun takePhoto&lpar;&rpar; &lbrace;<br><br><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Get a stable reference of the modifiable image capture use case<&sol;strong><&sol;span><br> val imageCapture &equals; imageCapture &quest;&colon; return<br><br><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Create time-stamped output file to hold the image<&sol;strong><&sol;span><br> val photoFile &equals; File&lpar;<br> outputDirectory&comma;<br> SimpleDateFormat&lpar;<br> FILENAME&lowbar;FORMAT&comma; Locale&period;US<br> &rpar;&period;format&lpar;System&period;currentTimeMillis&lpar;&rpar;&rpar; &plus; "&period;jpg"<br> &rpar;<br><br><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Create output options object which contains file &plus; metadata<&sol;strong><&sol;span><br> val outputOptions &equals; ImageCapture&period;OutputFileOptions&period;Builder&lpar;photoFile&rpar;&period;build&lpar;&rpar;<br><br> <strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; Set up image capture listener&comma; which is triggered after photo has<&sol;span><&sol;strong><br><strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; been taken<&sol;span><&sol;strong><br> imageCapture&period;takePicture&lpar;<br> outputOptions&comma;<br> ContextCompat&period;getMainExecutor&lpar;this&rpar;&comma;<br> object &colon; ImageCapture&period;OnImageSavedCallback &lbrace;<br> override fun onError&lpar;exc&colon; ImageCaptureException&rpar; &lbrace;<br> Log&period;e&lpar;TAG&comma; "Photo capture failed&colon; &dollar;&lbrace;exc&period;message&rcub;"&comma; exc&rpar;<br> &rcub;<br><br> override fun onImageSaved&lpar;output&colon; ImageCapture&period;OutputFileResults&rpar; &lbrace;<br> val savedUri &equals; Uri&period;fromFile&lpar;photoFile&rpar;<br> val msg &equals; "Photo capture succeeded&colon; &dollar;savedUri"<br> Toast&period;makeText&lpar;baseContext&comma; msg&comma; Toast&period;LENGTH&lowbar;SHORT&rpar;&period;show&lpar;&rpar;<br> Log&period;d&lpar;TAG&comma; msg&rpar;<br> &rcub;<br> &rcub;&rpar;<br> &rcub;<br><br> private fun startCamera&lpar;&rpar; &lbrace;<br><br> val cameraProviderFuture &equals; ProcessCameraProvider&period;getInstance&lpar;this&rpar;<br><br> cameraProviderFuture&period;addListener&lpar;Runnable &lbrace;<br><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Used to bind the lifecycle of cameras to the lifecycle owner<&sol;strong><&sol;span><br> val cameraProvider&colon; ProcessCameraProvider &equals; cameraProviderFuture&period;get&lpar;&rpar;<br><br> <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; creating Preview instance<&sol;strong><&sol;span><br> val preview &equals; Preview&period;Builder&lpar;&rpar;<br> &period;build&lpar;&rpar;<br> &period;also &lbrace;<br> it&period;setSurfaceProvider&lpar;viewFinder&period;createSurfaceProvider&lpar;&rpar;&rpar;<br> &rcub;<br><br><span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; creating ImageCapture instance<&sol;strong><&sol;span><br> imageCapture &equals; ImageCapture&period;Builder&lpar;&rpar;<br> &period;build&lpar;&rpar;<br><br> <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Select back camera as a default<&sol;strong><&sol;span><br> val cameraSelector &equals; CameraSelector&period;DEFAULT&lowbar;BACK&lowbar;CAMERA<br><br> try &lbrace;<br> <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Unbind use cases before rebinding<&sol;strong><&sol;span><br> cameraProvider&period;unbindAll&lpar;&rpar;<br><br> <span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Bind use cases to camera<&sol;strong><&sol;span><br> cameraProvider&period;bindToLifecycle&lpar;<br> this&comma; cameraSelector&comma; preview&comma; imageCapture<br> &rpar;<br><br> &rcub; catch &lpar;exc&colon; Exception&rpar; &lbrace;<br> Log&period;e&lpar;TAG&comma; "Use case binding failed"&comma; exc&rpar;<br> &rcub;<br><br> &rcub;&comma; ContextCompat&period;getMainExecutor&lpar;this&rpar;&rpar;<br> &rcub;<br><br> private fun allPermissionsGranted&lpar;&rpar; &equals; REQUIRED&lowbar;PERMISSIONS&period;all &lbrace;<br> ContextCompat&period;checkSelfPermission&lpar;<br> baseContext&comma; it<br> &rpar; &equals;&equals; PackageManager&period;PERMISSION&lowbar;GRANTED<br> &rcub;<br><br> private fun getOutputDirectory&lpar;&rpar;&colon; File &lbrace;<br> val mediaDir &equals; externalMediaDirs&period;firstOrNull&lpar;&rpar;&quest;&period;let &lbrace;<br> File&lpar;it&comma; resources&period;getString&lpar;R&period;string&period;app&lowbar;name&rpar;&rpar;&period;apply &lbrace; mkdirs&lpar;&rpar; &rcub;<br> &rcub;<br> return if &lpar;mediaDir &excl;&equals; null &amp&semi;&amp&semi; mediaDir&period;exists&lpar;&rpar;&rpar;<br> mediaDir else filesDir<br> &rcub;<br><br> override fun onDestroy&lpar;&rpar; &lbrace;<br> super&period;onDestroy&lpar;&rpar;<br> cameraExecutor&period;shutdown&lpar;&rpar;<br> &rcub;<br><br> companion object &lbrace;<br> private const val TAG &equals; "CameraXBasic"<br> private const val FILENAME&lowbar;FORMAT &equals; "yyyy-MM-dd-HH-mm-ss-SSS"<br> private const val REQUEST&lowbar;CODE&lowbar;PERMISSIONS &equals; 10<br> private val REQUIRED&lowbar;PERMISSIONS &equals; arrayOf&lpar;Manifest&period;permission&period;CAMERA&rpar;<br> &rcub;<br><br> override fun onRequestPermissionsResult&lpar;<br> requestCode&colon; Int&comma; permissions&colon; Array&lt&semi;String&gt&semi;&comma; grantResults&colon;<br> IntArray<br> &rpar; &lbrace;<br> if &lpar;requestCode &equals;&equals; REQUEST&lowbar;CODE&lowbar;PERMISSIONS&rpar; &lbrace;<br> if &lpar;allPermissionsGranted&lpar;&rpar;&rpar; &lbrace;<br> startCamera&lpar;&rpar;<br> &rcub; else &lbrace;<br> Toast&period;makeText&lpar;<br> this&comma;<br> "Permissions not granted by the user&period;"&comma;<br> Toast&period;LENGTH&lowbar;SHORT<br> &rpar;&period;show&lpar;&rpar;<br> finish&lpar;&rpar;<br> &rcub;<br> &rcub;<br> &rcub;<br>&rcub;<&sol;pre>&NewLine;&NewLine;

Exit mobile version