Open In App

Circular Crop an Image and Save it to the File in Android

Improve
Improve
Like Article
Like
Save
Share
Report

There are multiple applications available in the market that help in dealing with image processing, while most of them fail to produce very basic operations. Cropping is a simple application when one could resize an image by cutting it down. This task becomes complex when it comes to free-hand or shape cropping, meaning cropping the image in the desired shape.

In this article, we will show you how you create an application to crop an image in a circular manner and store it in the local device. No external library or service is used to generate this application.

Step by Step Implementation

Step 1: Create a New Project in Android Studio

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. We demonstrated the application in Kotlin, so make sure you select Kotlin as the primary language while creating a New Project.

Step 2: Add an ImageView and two Buttons in the activity_main.xml or the layout file

XML




<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  
      <!-- Image will be loaded here -->
    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        android:layout_centerInParent="true" />
  
      <!-- Button to perform Cropping -->
    <Button
        android:id="@+id/btnCrop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="Crop" />
  
      <!-- Button to save the image in ImageView -->
    <Button
        android:id="@+id/btnSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:text="Save" />
  
</RelativeLayout>


Step 3: Add the desired image in the res > drawable folder

While adding, give it the desired name. For our reference, this image is “image.png” which is downloaded from the Internet and copied directly into the drawable folder.

Step 4: Write the following code for MainActivity.kt

There are two functions inside this code:

  1. getCircularBitmap(Bitmap) : To crop the image
  2. saveMediaToStorage(Bitmap) : To save the image. Refer How to Capture Screenshot of a View and Save it to Gallery in Android?

Refer to the comments for better understanding.

Kotlin




import android.content.ContentValues
import android.graphics.*
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.widget.Button
import android.widget.ImageView
import android.widget.Toast
import androidx.annotation.RequiresApi
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream
import java.lang.Integer.min
  
class MainActivity : AppCompatActivity() {
  
    // Declaring the UI elements from the layout file
    private lateinit var buttonCrop: Button
    private lateinit var buttonSave: Button
    private lateinit var imageView: ImageView
    
    // Declaring the Bitmap
    private lateinit var bitmap: Bitmap
  
    @RequiresApi(Build.VERSION_CODES.N)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Initializing the UI elements
        imageView = findViewById(R.id.iv)
        buttonCrop = findViewById(R.id.btnCrop)
        buttonSave = findViewById(R.id.btnSave)
  
        // Declaring resource address ( type integer)
        val bitmapResourceID: Int = R.drawable.image
        
        // Setting the ImageView with the Image
        imageView.setImageBitmap(BitmapFactory.decodeResource(resources, bitmapResourceID))
        bitmap = BitmapFactory.decodeResource(resources, bitmapResourceID)
  
        // When Crop button is clicked
        buttonCrop.setOnClickListener {
              // runs a custom function on the original image
            bitmap = getCircularBitmap(bitmap)
              
            // Sets the ImageView with the editted/cropped Image
            imageView.setImageBitmap(bitmap)
        }
  
        // When Save button is clicked
        buttonSave.setOnClickListener {
             // Save whatever the bitmap is (edited/uneditted) into the device.
            saveMediaToStorage(bitmap)
        }
    }
  
    // Function to crop the image in a circle
    @RequiresApi(Build.VERSION_CODES.N)
    private fun getCircularBitmap(srcBitmap: Bitmap?): Bitmap {
        
        // Select whichever of width or height is minimum
        val squareBitmapWidth = min(srcBitmap!!.width, srcBitmap.height)
          
        // Generate a bitmap with the above value as dimensions
        val dstBitmap = Bitmap.createBitmap(
            squareBitmapWidth,
            squareBitmapWidth,
            Bitmap.Config.ARGB_8888
        )
          
        // Initializing a Canvas with the above generated bitmap
        val canvas = Canvas(dstBitmap)
          
        // initializing Paint
        val paint = Paint()
        paint.isAntiAlias = true
        
        // Generate a square (rectangle with all sides same)
        val rect = Rect(0, 0, squareBitmapWidth, squareBitmapWidth)
        val rectF = RectF(rect)
          
        // Operations to draw a circle
        canvas.drawOval(rectF, paint)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        val left = ((squareBitmapWidth - srcBitmap.width) / 2).toFloat()
        val top = ((squareBitmapWidth - srcBitmap.height) / 2).toFloat()
        canvas.drawBitmap(srcBitmap, left, top, paint)
        srcBitmap.recycle()
          
        // Return the bitmap
        return dstBitmap
    }
  
    // Function to save an Image
    private fun saveMediaToStorage(bitmap: Bitmap) {
        val filename = "${System.currentTimeMillis()}.jpg"
  
        var fos: OutputStream? = null
  
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            this.contentResolver?.also { resolver ->
                val contentValues = ContentValues().apply {
                    put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
                    put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
                    put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
                }
                val imageUri: Uri? = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
                fos = imageUri?.let { resolver.openOutputStream(it) }
            }
        } else {
            val imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
            val image = File(imagesDir, filename)
            fos = FileOutputStream(image)
        }
  
        fos?.use {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
            Toast.makeText(this , "Captured View and saved to Gallery" , Toast.LENGTH_SHORT).show()
        }
    }
}


Step 4: Add Storage permission in the AndroidManifest.xml file

This permission is needed to store the image in the device.

XML




<manifest....">
  
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  
    <application....>
    </application>
</manifest>


Output:



Last Updated : 05 Aug, 2021
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads