这里 Android挖取原图中心区域RectF(并框线标记)放大到ImageView宽高,Kotlin-CSDN博客 实现的是把原图中心区域的一片小图挖取出来放大放到下面的ImageView里面,现在不再固定中心位置,而是以手指在上图的触点位置为中心位置,挖取一片区域图放大,然后放到下面的ImageView里面。
- "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:clickable="true"
- android:scaleType="fitCenter"
- android:src="@mipmap/image" />
-
- <ImageView
- android:id="@+id/result"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- LinearLayout>
- 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.view.MotionEvent
- 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
(R.id.iv) - val iv = findViewById
(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
-
- private var mTouchX = 0f
- private var mTouchY = 0f
- private var mCanDraw = false
- private var mCircleRadius = 30f
-
- 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
- }
-
- override fun onTouchEvent(event: MotionEvent?): Boolean {
- if (event == null) {
- return false
- }
-
- mTouchX = event.x
- mTouchY = event.y
-
- when (event.action) {
- MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
- mCanDraw = true
-
- myInvalidate()
- }
- }
-
- return super.onTouchEvent(event)
- }
-
- private fun myInvalidate() {
- this.invalidate()
- }
-
- 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())
-
- //需要特别注意,要把手指在屏幕上触点坐标,经过比例映射到原始图Bitmap的对应位置。
- val mapToOriginBmpX = mOriginBmp!!.width * (mTouchX / W)
- val mapToOriginBmpY = mOriginBmp!!.height * (mTouchY / H)
-
- val centerRectF =
- RectF(
- mapToOriginBmpX - mSizeF.width / 2f,
- mapToOriginBmpY - mSizeF.height / 2f,
- mapToOriginBmpX + mSizeF.width / 2f,
- mapToOriginBmpY + mSizeF.height / 2f
- )
-
- c.drawBitmap(mOriginBmp!!, centerRectF.toRect(), dstRectF, null)
-
- val mx = Matrix()
- mx.setScale(dstRectF.width() / centerRectF.width(), dstRectF.width() / centerRectF.width())
-
- //下面图中的中心圆圈。
- mPaint.color = Color.YELLOW
- c.drawCircle(
- W / 2f, H / 2f,
- mx.mapRadius(mCircleRadius), //注意同步放大小图的圆圈半径。
- mPaint
- )
-
- return bmp
- }
-
- override fun onDraw(canvas: Canvas) {
- super.onDraw(canvas)
-
- if (mCanDraw) {
- //绘制中心圆圈。
- mPaint.color = Color.YELLOW
- canvas.drawCircle(mTouchX, mTouchY, mCircleRadius, mPaint)
-
- drawRoundRectLine(canvas)
-
- result?.setImageBitmap(getCenterBmp())
-
-
- mCanDraw = false
- }
- }
-
- 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)
-
- lineRectF.offset(mTouchX - lineRectF.width() / 2f, mTouchY - 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)
- }
- }
运行后,点击上图不同位置点: