Android capture image from camera programmatically

Camera is a very common feature that lots of apps provide. Most of the required image capture feature in own application. eg. profile image, creating a post with an image, every food or social media app required camera feature in own application. Basically, Image capturing is very simple task, even if you are using custom. In this article, we are going to see how to capture image from camera using FileProvider in your Android app.

Google introduces FileProvider in version 22.1.0. FileProvider class is a derived class from ContentProvider. In other words you can say, FileProvider provide facilitates to secure file sharing in android viacontent://Uri instead of a file:///Uri

So, Let’s start how can we achieve capturing an image from the camera and getting the file path and load an image in an ImageView.

Step to capture image from camera programmatically

  1. Defining a FileProvider
  2. Granting Permissions to a URI, Storage & Camera
  3. Image Capture using Camera
  4. Manage Result and show image over the ImageView

1. Defining a FileProvider

Define list of file paths for FileProvider in xml file and save it in res/xml folder. Since we want to save only in public picture directory, we’ll just add path of it to xml.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Android/data/com.example.captureimage/files/Pictures" />
</paths>

In AndroidMenifest.xml you have to specify FileProvider component by adding an element<provider>like below

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.captureimage.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"></meta-data>
        </provider>

Note – Replace com.example.captureimage with your package name

2. Granting Permissions to a URI, Storage & Camera

you need to add the permission in the manifest file as

<uses-feature android:name="android.hardware.camera"
    android:required="true" />

In the permission, the android:required=”true” is to tell the Google’s play to filter all the Android devices which have camera function. If we use android:required=”false”, we need to check for the camera via programmatically.

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

In Android 6, it contain a permission system for certain tasks. Each application can request the required permission on runtime. So let’s open Activity class add below code for requesting runtime permission

if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.CAMERA
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE),
                0
            )
        } else {
            // Your code 
                    }
                } catch (ex: Exception) {
                    // Error occurred while creating the File
                    displayMessage(baseContext, ex.message.toString())
                }

            } else {
                displayMessage(baseContext, "Null")
            }
        }

3. Image Capture using Camera

Now let’s create a function to generate a random file name with .jpg extension in the external files directory.

  • We need to create an Image file
@Throws(IOException::class)
    private fun createImageFile(): File {
        // Create an image file name
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val imageFileName = "JPEG_" + timeStamp + "_"
        val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        val image = File.createTempFile(
            imageFileName, /* prefix */
            ".jpg", /* suffix */
            storageDir      /* directory */
        )

        // Save a file: path for use with ACTION_VIEW intents
        mCurrentPhotoPath = image.absolutePath
        return image
    }
  • Create a new Intent with FileProvider URI
try {
                    photoFile = createImageFile()
                    // Continue only if the File was successfully created
                    if (photoFile != null) {
                        val photoURI = FileProvider.getUriForFile(
                            this,
                            "com.example.captureimage.fileprovider",
                            photoFile!!
                        )
                        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                        startActivityForResult(takePictureIntent, CAPTURE_IMAGE_REQUEST)
                    }
                } catch (ex: Exception) {
                    // Error occurred while creating the File
                    displayMessage(baseContext, ex.message.toString())
                }

4. Manage Result and show image over the ImageView

After action performing, we will manage the result on onActivityResult by using ResultCode and RequestCode.  In onActivityResult we have to manage three things.

  • Get actual file path or file from result intent
  • Compress file using FileCompressor utility
  • Finally set final output over the ImageView in Android
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (requestCode == CAPTURE_IMAGE_REQUEST &amp;&amp; resultCode == Activity.RESULT_OK) {
            val myBitmap = BitmapFactory.decodeFile(photoFile!!.absolutePath)
            imageView.setImageBitmap(myBitmap)
        } else {
            displayMessage(baseContext, "Request cancelled or something went wrong.")
        }
    }

Final MainActivity.kt

class MainActivity : AppCompatActivity() {
    var photoFile: File? = null
    val CAPTURE_IMAGE_REQUEST = 1
    var mCurrentPhotoPath: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_capture.setOnClickListener {
            captureImage()
        }

    }

    private fun captureImage() {

        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.CAMERA
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE),
                0
            )
        } else {
            val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            if (takePictureIntent.resolveActivity(packageManager) != null) {
                // Create the File where the photo should go
                try {
                    photoFile = createImageFile()
                    // Continue only if the File was successfully created
                    if (photoFile != null) {
                        val photoURI = FileProvider.getUriForFile(
                            this,
                            "com.example.captureimage.fileprovider",
                            photoFile!!
                        )
                        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                        startActivityForResult(takePictureIntent, CAPTURE_IMAGE_REQUEST)
                    }
                } catch (ex: Exception) {
                    // Error occurred while creating the File
                    displayMessage(baseContext, ex.message.toString())
                }

            } else {
                displayMessage(baseContext, "Null")
            }
        }

    }

    @Throws(IOException::class)
    private fun createImageFile(): File {
        // Create an image file name
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val imageFileName = "JPEG_" + timeStamp + "_"
        val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        val image = File.createTempFile(
            imageFileName, /* prefix */
            ".jpg", /* suffix */
            storageDir      /* directory */
        )

        // Save a file: path for use with ACTION_VIEW intents
        mCurrentPhotoPath = image.absolutePath
        return image
    }

    private fun displayMessage(context: Context, message: String) {
        Toast.makeText(context, message, Toast.LENGTH_LONG).show()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (requestCode == CAPTURE_IMAGE_REQUEST &amp;&amp; resultCode == Activity.RESULT_OK) {
            val myBitmap = BitmapFactory.decodeFile(photoFile!!.absolutePath)
            imageView.setImageBitmap(myBitmap)
        } else {
            displayMessage(baseContext, "Request cancelled or something went wrong.")
        }
    }
    
}

Screenshots

capture image from camera
capture image from camera
github_link

In Conclusion

I believe, It will help you to manage your android project resource better. Thanks for the reading.

Leave a Reply

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

Back to Top