Android矩阵setRectToRect裁剪Bitmap原图Matrix放大,mapRect标记中心区域,Kotlin

Android矩阵setRectToRect裁剪Bitmap原图Matrix放大,mapRect标记中心区域,Kotlin

Kotlin 复制代码
import android.content.Context
import android.graphics.Bitmap
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.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.util.AttributeSet
import android.util.SizeF
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView


class MainActivity : AppCompatActivity() {
    private var iv: MyImageView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        iv = findViewById(R.id.iv)

        val result = findViewById<ImageView>(R.id.result)
        iv?.setTestImageView(result)
    }
}

class MyImageView : AppCompatImageView {
    private var mSrcBmp: Bitmap? = null
    private var testIV: ImageView? = null

    //这个SizeF是针对原图的没有缩放的宽高。
    //目的是在没有缩放的原图上规划出相当于原图的120f,80f的区域。
    private val mSizeF = SizeF(120f, 80f)

    private var mPathPaint: Paint? = null

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
        //mSrcBmp是原始图大小,没有缩放和拉伸的。
        mSrcBmp = (drawable as BitmapDrawable).bitmap

        mPathPaint = Paint()
        mPathPaint?.style = Paint.Style.STROKE
        mPathPaint?.strokeWidth = 3f
        mPathPaint?.isAntiAlias = true
        mPathPaint?.color = Color.RED
    }

    fun setTestImageView(imageView: ImageView) {
        testIV = imageView
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        //因为所以的原始图片几乎都会被Android缩放后最终展示在手机屏幕上,这里需要计算出原始图片被Android系统缩放了多少比例。
        //本例是一个宽400高300左右的小图,必定会被Android系统拉伸放到ImageView里面。
        val originBmpScaleFactor: Float = (this.width.toFloat()) / (mSrcBmp!!.width.toFloat())

        //这个RectF是相对于原始图框出来的RectF。
        val lineRectF = RectF(
            0f,
            0f,
            mSizeF.width,
            mSizeF.height
        )

        //因为原始图被Android系统拉伸放到屏幕上,所以这个RectF也需要进行相同的拉伸。
        val originBmpSizeMapMatrix = Matrix()
        originBmpSizeMapMatrix.setScale(originBmpScaleFactor, originBmpScaleFactor)
        originBmpSizeMapMatrix.mapRect(lineRectF)

        //注意移动到中心位置,此时是ImageView的中心位置。
        lineRectF.offset(this.width / 2f - lineRectF.width() / 2f, this.height / 2f - lineRectF.height() / 2f)

        //绘制红色的lineRectF线框。
        val path = Path()
        path.addRoundRect(lineRectF, 20f, 20f, Path.Direction.CW)
        canvas.drawPath(path, mPathPaint!!)

        //绘制黄颜色的中心圆圈。
        mPathPaint!!.color = Color.YELLOW
        mPathPaint!!.strokeWidth = 10f
        canvas.drawCircle(this.width / 2f, this.height / 2f, 50f, mPathPaint!!)


        //选取源bitmap的一块中心区域。SizeF宽高。
        val bmpCenterX = mSrcBmp!!.width / 2f
        val bmpCenterY = mSrcBmp!!.height / 2f

        //规划一片mSrcBmp原图中心区域的RectF
        val bmpRectF = RectF(
            bmpCenterX - mSizeF.width / 2f,
            bmpCenterY - mSizeF.height / 2f,
            bmpCenterX + mSizeF.width / 2f,
            bmpCenterY + mSizeF.height / 2f
        )

        //缩放比例。
        val scaleFactor = 8.5f

        val dst = RectF(0f, 0f, bmpRectF.width() * scaleFactor, bmpRectF.height() * scaleFactor)

        val mx = Matrix()
        mx.setRectToRect(bmpRectF, dst, Matrix.ScaleToFit.CENTER)

        val bmp = Bitmap.createBitmap((mSizeF.width * scaleFactor).toInt(), (mSizeF.height * scaleFactor).toInt(), Bitmap.Config.ARGB_8888)
        val c = Canvas(bmp)
        c.drawColor(Color.BLUE)
        c.drawBitmap(mSrcBmp!!, mx, null)

        testIV?.setImageBitmap(bmp)
    }
}

红色框选框住的区域即为要放大的区域:

https://zhangphil.blog.csdn.net/article/details/135158644https://zhangphil.blog.csdn.net/article/details/135158644

https://zhangphil.blog.csdn.net/article/details/135601993https://zhangphil.blog.csdn.net/article/details/135601993

相关推荐
用户2018792831677 分钟前
Java 泛型:快递站老板的 "类型魔法" 故事
android
Knight_AL21 分钟前
浅拷贝与深拷贝详解:概念、代码示例与后端应用场景
android·java·开发语言
夜晚中的人海1 小时前
【C++】智能指针介绍
android·java·c++
用户2018792831672 小时前
后台Activity输入分发超时ANR分析(无焦点窗口)
android
用户2018792831672 小时前
Activity配置变化后ViewModel 的 “不死之谜”
android
游戏开发爱好者82 小时前
BShare HTTPS 集成与排查实战,从 SDK 接入到 iOS 真机调试(bshare https、签名、回调、抓包)
android·ios·小程序·https·uni-app·iphone·webview
2501_916008893 小时前
iOS 26 系统流畅度实战指南|流畅体验检测|滑动顺畅对比
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_915106325 小时前
苹果软件加固与 iOS App 混淆完整指南,IPA 文件加密、无源码混淆与代码保护实战
android·ios·小程序·https·uni-app·iphone·webview
2501_915921435 小时前
iOS 26 崩溃日志解析,新版系统下崩溃获取与诊断策略
android·ios·小程序·uni-app·cocoa·iphone·策略模式
齊家治國平天下7 小时前
Android 14 Input 事件派发机制深度剖析
android·input·hal