Android挖取原图中心区域RectF(并框线标记)放大到ImageView宽高,Kotlin
红色线框区域即为选中的原图中心区域,放大后放到等宽高的ImageView里面。
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.os.Bundle
import android.util.AttributeSet
import android.util.Log
import android.util.SizeF
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.core.graphics.toRect
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val miv = findViewById<MyImageView>(R.id.iv)
val iv = findViewById<ImageView>(R.id.result)
miv.setResultImage(iv)
}
}
class MyImageView : AppCompatImageView {
private var W = 0
private var H = 0
private val mSizeF = SizeF(400f, 200f)
private var mOriginBmp: Bitmap? = null
private var mPaint = Paint()
private var result: ImageView? = null
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
mPaint.style = Paint.Style.STROKE
mPaint.strokeWidth = 5f
mPaint.isAntiAlias = true
mPaint.color = Color.RED
mOriginBmp = getOriginalBitmap(ctx, R.mipmap.image)
Log.d("fly", "origin bmp w=${mOriginBmp!!.width} h=${mOriginBmp!!.height}")
}
private fun getOriginalBitmap(ctx: Context, resId: Int): Bitmap {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true //只解析原始图片的宽高,不decode原始文件装载到内存的Bitmap。
BitmapFactory.decodeResource(resources, resId, options)
//这一阶段,最关键的是获取原始图的真实宽高。
val srcBmpWidth = options.outWidth
val srcBmpHeight = options.outHeight
val d = ContextCompat.getDrawable(ctx, resId)
//根据原始图片的宽高创建一个空的Bitmap
val bitmap = Bitmap.createBitmap(srcBmpWidth, srcBmpHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
d?.setBounds(0, 0, srcBmpWidth, srcBmpHeight)
d?.draw(canvas) //至此,bitmap即为原始图片。
return bitmap
}
fun setResultImage(iv: ImageView) {
result = iv
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
W = w
H = h
Log.d("fly", "W=$W H=$H")
}
//从原始的Bitmap图中抠出一块SizeF大小的图。
private fun getCenterBmp(): Bitmap {
val bmp = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888)
val c = Canvas(bmp)
val dstRectF = RectF(0f, 0f, bmp.width.toFloat(), bmp.height.toFloat())
val cx = mOriginBmp!!.width / 2f
val cy = mOriginBmp!!.height / 2f
val centerRectF = RectF(cx - mSizeF.width / 2f, cy - mSizeF.height / 2f, cx + mSizeF.width / 2f, cy + mSizeF.height / 2f)
c.drawBitmap(mOriginBmp!!, centerRectF.toRect(), dstRectF, null)
return bmp
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//绘制中心圆圈。
mPaint.color = Color.YELLOW
canvas.drawCircle(W / 2f, H / 2f, 40f, mPaint)
drawRoundRectLine(canvas)
result?.setImageBitmap(getCenterBmp())
}
private fun drawRoundRectLine(canvas: Canvas) {
val lineRectF = RectF(
0f,
0f,
mSizeF.width,
mSizeF.height
)
//原始图被Android系统拉伸放到屏幕上,所以lineRectF也需要进行相同的拉伸。
val originBmpSizeMapMatrix = Matrix()
originBmpSizeMapMatrix.setScale(getOriginBmpScaleToImageViewFactor(), getOriginBmpScaleToImageViewFactor())
originBmpSizeMapMatrix.mapRect(lineRectF)
//注意移动到中心位置,ImageView的中心位置。
lineRectF.offset(W / 2f - lineRectF.width() / 2f, H / 2f - lineRectF.height() / 2f)
//绘制红色的lineRectF线框。
val path = Path()
path.addRoundRect(lineRectF, 20f, 20f, Path.Direction.CW)
mPaint.color = Color.RED
canvas.drawPath(path, mPaint)
}
private fun getOriginBmpScaleToImageViewFactor(): Float {
return (W.toFloat()) / (mOriginBmp!!.width.toFloat())
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:background="@android:color/darker_gray"
android:orientation="vertical"
tools:context=".MainActivity">
<com.pkg.MyImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@mipmap/image" />
<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>