Android Capturing Images from Camera or Gallery as Bitmaps using ActivityResultLauncher in Kotlin

Hamza Asif
8 min readMar 1, 2023

--

Photo by Eaters Collective on Unsplash

Learn the use of machine learning and computer vision in Android, Flutter & React Native with our Mobile Machine Learning courses. You can avail 92% discount on following Android Machine learning courses

  1. Android & Google Gemini — Build Smart Android Kotlin Apps
  2. Face Recognition and Detection in Android- The 2024 Guide
  3. Train Object Detection Models for Android — The 2024 Guide
  4. Android ML — Train Tensorflow Lite Models for Android Apps
  5. ChatGPT & Android — Build Chatbots & Smart Apps for Android
  6. Machine Learning use in Android — The 2024 Guide

Capturing images using a camera and using it in your Android applications can be tricky at times but the process is quite simple.

So in this story, I will teach you to get images from the gallery or capture images using a camera and then get those images as bitmaps in our applications.

So firstly create a new Android Studio project and select Java as the programming language. For Kotlin click here.

Layout

Now in the activity_main.xml file place an ImageView and two buttons. So replace activity_main.xml code with blow code..

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
    <ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="40dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="40dp"
android:layout_marginBottom="40dp"
app:layout_constraintBottom_toTopOf="@+id/button2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="Gallery"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="Camera"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button" />
</androidx.constraintlayout.widget.ConstraintLayout>

So we have placed an imageView to display the image that the user will choose or capture. And we added two buttons, one is for choosing images from the gallery and the second one is for capturing images using the camera. Now inside MainActivity create and initialize this imageview and buttons.

    lateinit var imageView: ImageView;
lateinit var galleryBtn: Button;
lateinit var cameraBtn:Button;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
imageView = findViewById(R.id.imageView);
galleryBtn = findViewById(R.id.button);
cameraBtn = findViewById(R.id.button2);
}

Choosing Images from the gallery

Let’s say we want to choose an image from the gallery when the user will click on the gallery button that we placed earlier inside our application layout.

So for that purpose, we need to set an OnClickListener on our button and launch an intent to open the gallery.

So inside the onCreate method set OnClick listener for the galleryBtn.

//TODO chose image from gallery
galleryBtn.setOnClickListener {
val galleryIntent =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
galleryActivityResultLauncher.launch(galleryIntent)
}

Now you can see the error for this galleryActivityResultLauncher. So starting from AndroidX to launch an intent we need to create an object of the type ActivityResultLauncher and then by using it we are going to launch the intent. So above onCreate method declare and initialize ActivityResultLauncher by pasting this code.

//TODO get the image from gallery and display it
var galleryActivityResultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(), ActivityResultCallback {

}
)

Now there you can see when the user will click on the galleryBtn we are launching an intent to open the gallery. And once the user will select an image onActivityResult method of ActivityResultLauncher will be called and we can get the URI of the selected image inside that method and display it inside our imageView. So add this code inside the onActivityResult method

 if (it.getResultCode() === RESULT_OK) {
val image_uri: Uri? = it.data?.data
imageView.setImageURI(image_uri)
}

So inside this method, we are getting chosen image Uri and displaying that image inside our image view.

Now when you will run this application you will be able to choose an image from the gallery. So let’s test the application.

Capturing images using Camera

Now let’s add the code to capture the image using the camera and display it inside our application.

Permissions

As we want to capture images from the camera so we need the camera permission and then to save those images we need storage permission so in the manifest file add these lines

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>

Ask for these permissions dynamically inside MainActivity. So add these lines inside the onCreate method of MainActivity.

//TODO ask for permission of camera upon first launch of application
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_DENIED ||
checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_DENIED) {
val permission = arrayOf<String>(
android.Manifest.permission.CAMERA,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
requestPermissions(permission, 112)
}
}

So now we want to open the camera and capture the image when the user will click on cameraBtn. Then we want to display that captured image inside our Android application inside the imageView.

So to achieve that set OnClickListener on the cameraBtn. So inside onCreate method paste the below code.

//TODO captue image using camera
cameraBtn.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_DENIED ||
checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_DENIED
) {
val permission = arrayOf<String>(
android.Manifest.permission.CAMERA,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
requestPermissions(permission, 112)
} else {
openCamera()
}
} else {
openCamera()
}
}

So inside this method, we are again checking if the camera and storage permission is granted or not. If the permission is not granted then we are asking for permission again otherwise we are calling a method name openCamera. So Inside this method, we have the code to launch the camera. So place this code below onCreate method.

var image_uri: Uri? = null
//TODO opens camera so that user can capture image
private fun openCamera() {
val values = ContentValues()
values.put(MediaStore.Images.Media.TITLE, "New Picture")
values.put(MediaStore.Images.Media.DESCRIPTION, "From the Camera")
image_uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri)
cameraActivityResultLauncher.launch(cameraIntent)
}
//TODO capture the image using camera and display it
private var cameraActivityResultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(), ActivityResultCallback {
if (it.resultCode === RESULT_OK) {
imageView.setImageURI(image_uri);
}
}
)

Now we have added the openCamera method along with cameraActivityResultLauncher. So inside this openCamera method, we are launching an intent using this cameraActivityResultLauncher to open the camera and capture an image.

And once the user will capture the image then the URI of that image will be stored inside the image_uri variable and onActivityResult method of cameraActivityResultLauncher will be called. So inside this method, we can simply display the captured image inside our imageView. So add these lines inside the onActivityResult method.

if (it.resultCode === RESULT_OK) {
imageView.setImageURI(image_uri);
}

Now you can run the application and capture the image by clicking on the camera button.

Converting Image into bitmap

Now we are choosing or capturing images inside our android application but to get the image in a bitmap format place these uriToBitmap & rotateBitmap methods inside MainActivity.

    //TODO takes URI of the image and returns bitmap
private fun uriToBitmap(selectedFileUri: Uri): Bitmap? {
try {
val parcelFileDescriptor = contentResolver.openFileDescriptor(selectedFileUri, "r")
val fileDescriptor: FileDescriptor = parcelFileDescriptor!!.fileDescriptor
val image = BitmapFactory.decodeFileDescriptor(fileDescriptor)
parcelFileDescriptor.close()
return image
} catch (e: IOException) {
e.printStackTrace()
}
return null
}
//TODO rotate image if image captured on samsung devices
//TODO Most phone cameras are landscape, meaning if you take the photo in portrait, the resulting photos will be rotated 90 degrees.
@SuppressLint("Range")
fun rotateBitmap(input: Bitmap): Bitmap? {
val orientationColumn =
arrayOf(MediaStore.Images.Media.ORIENTATION)
val cur: Cursor? = contentResolver.query(image_uri!!, orientationColumn, null, null, null)
var orientation = -1
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]))
}
Log.d("tryOrientation", orientation.toString() + "")
val rotationMatrix = Matrix()
rotationMatrix.setRotate(orientation.toFloat())
return Bitmap.createBitmap(input, 0, 0, input.width, input.height, rotationMatrix, true)
}

Here uriToBitmap is used to convert an image into a bitmap format and then we will pass that bitmap to rotateBitmap method so that we can get that bitmap in portrait orientation. In most cases when we capture an image using the camera the captured image is in landscape orientation. So we are using this rotateBitmap method to ensure that we get that image is in portrait mode in a bitmap format.

Now call these methods inside onActivityResult method of both cameraActivityResultLauncher and galleryActivityResultLauncher. So the code inside onActivityResult of cameraActivityResultLauncher will look like this

//TODO capture the image using camera and display it
private var cameraActivityResultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(), ActivityResultCallback {
if (it.resultCode === RESULT_OK) {
val inputImage = uriToBitmap(image_uri!!)
val rotated = rotateBitmap(inputImage!!)
imageView.setImageBitmap(rotated)
}
}
)

And the code inside onActivityResult of galleryActivityResultLauncher will look like this

private var galleryActivityResultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(), ActivityResultCallback {
if (it.getResultCode() === RESULT_OK) {
image_uri = it.data?.data
val inputImage = uriToBitmap(image_uri!!)
val rotated = rotateBitmap(inputImage!!)
imageView.setImageBitmap(rotated)
}
}
)

And that’s it. Now when you will run this application you will be able to capture an image from the camera and then that image will be displayed inside imageView. As we also converted that image into a bitmap so you can use it for a variety of different purposes like for Performing different Machine Learning related operations.

So the complete code of our MainActivity will look like this

package com.example.imk

import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Intent
import android.content.pm.PackageManager
import android.database.Cursor
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.widget.Button
import android.widget.ImageView
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import java.io.FileDescriptor
import java.io.IOException


class MainActivity : AppCompatActivity() {

private var galleryActivityResultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(), ActivityResultCallback {
if (it.getResultCode() === RESULT_OK) {
image_uri = it.data?.data
val inputImage = uriToBitmap(image_uri!!)
val rotated = rotateBitmap(inputImage!!)
imageView.setImageBitmap(rotated)
}
}
)

//TODO capture the image using camera and display it
private var cameraActivityResultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(), ActivityResultCallback {
if (it.resultCode === RESULT_OK) {
val inputImage = uriToBitmap(image_uri!!)
val rotated = rotateBitmap(inputImage!!)
imageView.setImageBitmap(rotated)
}
}
)



lateinit var imageView: ImageView;
lateinit var galleryBtn: Button;
lateinit var cameraBtn:Button;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
imageView = findViewById(R.id.imageView);
galleryBtn = findViewById(R.id.button);
cameraBtn = findViewById(R.id.button2);

galleryBtn.setOnClickListener {
val galleryIntent =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
galleryActivityResultLauncher.launch(galleryIntent)
}

//TODO ask for permission of camera upon first launch of application
//TODO ask for permission of camera upon first launch of application
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_DENIED ||
checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_DENIED) {
val permission = arrayOf<String>(
android.Manifest.permission.CAMERA,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
requestPermissions(permission, 112)
}
}

cameraBtn.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_DENIED ||
checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_DENIED
) {
val permission = arrayOf<String>(
android.Manifest.permission.CAMERA,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
requestPermissions(permission, 112)
} else {
openCamera()
}
} else {
openCamera()
}
}
}

var image_uri: Uri? = null
//TODO opens camera so that user can capture image
private fun openCamera() {
val values = ContentValues()
values.put(MediaStore.Images.Media.TITLE, "New Picture")
values.put(MediaStore.Images.Media.DESCRIPTION, "From the Camera")
image_uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri)
cameraActivityResultLauncher.launch(cameraIntent)
}

//TODO takes URI of the image and returns bitmap
private fun uriToBitmap(selectedFileUri: Uri): Bitmap? {
try {
val parcelFileDescriptor = contentResolver.openFileDescriptor(selectedFileUri, "r")
val fileDescriptor: FileDescriptor = parcelFileDescriptor!!.fileDescriptor
val image = BitmapFactory.decodeFileDescriptor(fileDescriptor)
parcelFileDescriptor.close()
return image
} catch (e: IOException) {
e.printStackTrace()
}
return null
}

//TODO rotate image if image captured on samsung devices
//TODO Most phone cameras are landscape, meaning if you take the photo in portrait, the resulting photos will be rotated 90 degrees.
@SuppressLint("Range")
fun rotateBitmap(input: Bitmap): Bitmap? {
val orientationColumn =
arrayOf(MediaStore.Images.Media.ORIENTATION)
val cur: Cursor? = contentResolver.query(image_uri!!, orientationColumn, null, null, null)
var orientation = -1
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]))
}
Log.d("tryOrientation", orientation.toString() + "")
val rotationMatrix = Matrix()
rotationMatrix.setRotate(orientation.toFloat())
return Bitmap.createBitmap(input, 0, 0, input.width, input.height, rotationMatrix, true)
}
}

Mobile Machine Learning

Learn the use of machine learning and computer vision in Android, Flutter & React Native with our Mobile Machine Learning courses. You can avail discount on the following Mobile Machine learning courses

Android Machine Learning Courses

Face Recognition in Android — Build Attendance Systems

Train Object Detection Models & build Android Applications

ChatGPT & Android — Build Chatbots & Smart Apps for Android

Android Machine Learning with TensorFlow lite in Java/Kotlin

Android & Regression: Train Prediction ML models for Android

Flutter Machine Learning Courses

Machine Learning for Flutter The Complete 2023 Guide

Face Recognition and Detection in Flutter — The 2024 Guide

Flutter and Linear Regression: Build Prediction Apps Flutter

ChatGPT & Flutter: Build Chatbots & Assistants in Flutter

Train Object Detection and classification models for Flutter

React Native Courses

ChatGPT & React Native — Build Chatbots for Android & IOS

Connect With Me

My Courses: https://www.udemy.com/user/e1c14fb5-1c9b-45ef-a479-bbc543e33254/

My Facebook: https://www.facebook.com/MobileMachineLearning

Youtube Channel: https://www.youtube.com/channel/UCuM6FHbMdYXQCR8syEtnM9Q

--

--

Hamza Asif
Hamza Asif

Written by Hamza Asif

Udemy Instructor, Flutter Dev helping people Integrate ML & AI in Mobile Apps . Visit my courses https://www.udemy.com/user/e1c14fb5-1c9b-45ef-a479-bbc543e33254

No responses yet