圆形裁剪图像并将其保存到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编写如下代码
这段代码中有两个函数:
- getCircularBitmap(Bitmap) : 裁剪图像
- 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 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!