📜  圆形裁剪图像并将其保存到Android中的文件

📅  最后修改于: 2022-05-13 01:55:46.057000             🧑  作者: Mango

圆形裁剪图像并将其保存到Android中的文件

市场上有多种应用程序可帮助处理图像处理,但其中大多数无法生成非常基本的操作。裁剪是一种简单的应用程序,可以通过裁剪来调整图像的大小。当涉及徒手或形状裁剪时,此任务变得复杂,这意味着将图像裁剪为所需的形状。

在本文中,我们将向您展示如何创建应用程序以循环方式裁剪图像并将其存储在本地设备中。不使用外部库或服务来生成此应用程序。

分步实施

第 1 步:在 Android Studio 中创建一个新项目

要在 Android Studio 中创建新项目,请参阅如何在 Android Studio 中创建/启动新项目。我们在 Kotlin 中演示了该应用程序,因此请确保在创建新项目时选择 Kotlin 作为主要语言。



第二步:在activity_main.xml或者布局文件中添加一个ImageView和两个Button

XML


  
      
    
  
      
    


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()
        }
    }
}


XML

  
    
  
    
    


第三步:在 res > drawable 文件夹中添加想要的图片

添加时,为其指定所需的名称。供我们参考,这张图片是“image.png”,它是从网上下载并直接复制到drawable文件夹中的。

第四步:为MainActivity.kt编写如下代码

这段代码中有两个函数:

  1. getCircularBitmap(Bitmap) : 裁剪图像
  2. saveMediaToStorage(Bitmap) : 保存图像。请参阅如何在 Android 中捕获视图的屏幕截图并将其保存到图库?

请参阅注释以获得更好的理解。

科特林

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()
        }
    }
}

第 4 步:在 AndroidManifest.xml 文件中添加 Storage 权限

需要此权限才能将图像存储在设备中。

XML


  
    
  
    
    

输出:

想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!