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

05 Aug, 2021
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 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:android="http://schemas.android.com/apk/res/android"    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:
getCircularBitmap(Bitmap) : To crop the imagesaveMediaToStorage(Bitmap) : To save the image. Refer How to Capture Screenshot of a View and Save it to Gallery in Android?
getCircularBitmap(Bitmap) : To crop the image
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.ContentValuesimport android.graphics.*import android.net.Uriimport android.os.Buildimport androidx.appcompat.app.AppCompatActivityimport android.os.Bundleimport android.os.Environmentimport android.provider.MediaStoreimport android.widget.Buttonimport android.widget.ImageViewimport android.widget.Toastimport androidx.annotation.RequiresApiimport java.io.Fileimport java.io.FileOutputStreamimport java.io.OutputStreamimport 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:
Android
Kotlin
Android
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Flutter - Custom Bottom Navigation Bar
How to Read Data from SQLite Database in Android?
Retrofit with Kotlin Coroutine in Android
Android Listview in Java with Example
How to Change the Background Color After Clicking the Button in Android?
Android UI Layouts
Kotlin Array
Retrofit with Kotlin Coroutine in Android
Kotlin Setters and Getters
MVP (Model View Presenter) Architecture Pattern in Android with Example