首页 > 其他分享 >View->Canvas使用RectF方式绘制Bitmap,RectF大小和Bitmap大小不同导致绘制效果不同

View->Canvas使用RectF方式绘制Bitmap,RectF大小和Bitmap大小不同导致绘制效果不同

时间:2024-06-04 14:32:26浏览次数:25  
标签:04 mRealView RectF mDestRect height width Bitmap 绘制

图片

在这里插入图片描述

XML文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.gallery20.app.MyImageView
        android:id="@+id/real_iv"
        android:layout_gravity="center"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_marginTop="30dp"
        android:layout_marginBottom="30dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:background="#00000000"/>
</LinearLayout>

Activity代码


fun getBitmap(resources : Resources, destRect : RectF, imageId: Int): Bitmap? {
    var imageWidth = -1
    var imageHeight = -1
    val preOption = BitmapFactory.Options().apply {
        // 只获取图片的宽高
        inJustDecodeBounds = true
        BitmapFactory.decodeResource(resources, imageId, this)
    }
    imageWidth = preOption.outWidth
    imageHeight = preOption.outHeight
    // 计算缩放比例
    val scaleMatrix = Matrix()
    // 确定未缩放Bitmap的RectF
    var srcRect = RectF(0f, 0f, imageWidth.toFloat(), imageHeight.toFloat())
    // 通过目标RectF, 确定缩放数值,存储在scaleMatrix中
    scaleMatrix.setRectToRect(srcRect, destRect, Matrix.ScaleToFit.CENTER)
    // 缩放数值再映射到原始Bitmap上,得到缩放后的RectF
    scaleMatrix.mapRect(srcRect)

    val finalOption = BitmapFactory.Options().apply {
        if (imageHeight > 0 && imageWidth > 0) {
            inPreferredConfig = Bitmap.Config.RGB_565
            inSampleSize = calculateInSampleSize(
                imageWidth,
                imageHeight,
                srcRect.width().toInt(),
                srcRect.height().toInt()
            )
            Log.i("yang", "inSampleSize = $inSampleSize")
        }
    }
    return BitmapFactory.decodeResource(resources, imageId, finalOption)
}

fun calculateInSampleSize(fromWidth: Int, fromHeight: Int, toWidth: Int, toHeight: Int): Int {
    var bitmapWidth = fromWidth
    var bitmapHeight = fromHeight
    if (fromWidth > toWidth|| fromHeight > toHeight) {
        var inSampleSize = 2
        // 计算最大的inSampleSize值,该值是2的幂,并保持原始宽高大于目标宽高
        while (bitmapWidth >= toWidth && bitmapHeight >= toHeight) {
            bitmapWidth /= 2
            bitmapHeight /= 2
            inSampleSize *= 2
        }
        return inSampleSize
    }
    return 1
}


const val TAG = "Yang"
class MainActivity : AppCompatActivity() {
    var mRealView: MyImageView? = null
    var tempBitmap: Bitmap? = null
    var screenWidth = 0
    var screenHeight = 0
    var mDestRect = RectF()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mRealView = findViewById(R.id.real_iv)
        // 屏幕宽高的一半作为临时RectF, 用于压缩Bitmap
        screenWidth = resources.displayMetrics.widthPixels
        screenHeight = resources.displayMetrics.heightPixels
        val tempRect = RectF(0f, 0f, screenWidth.toFloat() / 2, screenHeight.toFloat() / 2)


        CoroutineScope(Dispatchers.IO).launch {
            tempBitmap = getBitmap(resources, tempRect, R.drawable.fake)
            withContext(Dispatchers.Main) {
                mRealView?.post {
                    mDestRect.set(
                        0f,
                        0f,
                        mRealView?.width?.toFloat()!!,
                        mRealView?.height?.toFloat()!!
                    )
                    tempBitmap?.let {
                        mRealView?.setBitmap(it, mDestRect)
                    }
                }
            }
        }
    }
}

自定义View代码

class MyImageView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr){
    private val mPaint = Paint().apply {
        isAntiAlias = true
    }
    private var mBitmap : Bitmap? = null
    private var mDestRect : RectF = RectF()

    fun setBitmap(bitmap : Bitmap, destRect: RectF){
        mBitmap = bitmap
        mDestRect.set(destRect)
        invalidate()
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        Log.i("yang", "canvas.width = ${canvas?.width}, canvas.height = ${canvas?.height}")
        Log.i("yang", "mBitmap.width = ${mBitmap?.width} mBitmap.height = ${mBitmap?.height}")
        Log.i("yang", "mDestRect.width = ${mDestRect.width()} mDestRect.height = ${mDestRect.height()} mDestRect = $mDestRect")
        mBitmap?.let {
            canvas?.drawBitmap(it, null, mDestRect, mPaint)
        }
    }
}

RectF大小和Bitmap大小的绘制关系

RectF的宽高大于Bitmap的宽高

  • Bitmap会被拉伸至整个RectF区域,不会被裁剪

RectF没有加上lefttop

  • 使用完整大小的RectF区域,绘制的是整张Bitmap
CoroutineScope(Dispatchers.IO).launch {
    tempBitmap = getBitmap(resources, tempRect, R.drawable.fake)
    withContext(Dispatchers.Main) {
        mRealView?.post {
            mDestRect.set(
                0f,
                0f,
                mRealView?.width?.toFloat()!!,
                mRealView?.height?.toFloat()!!
            )
            tempBitmap?.let {
                mRealView?.setBitmap(it, mDestRect)
            }
        }
    }
}

// log reult
2024-06-04 04:48:19.010  9873-9873  yang          I  canvas.width = 900, canvas.height = 900
2024-06-04 04:48:19.010  9873-9873  yang          I  mBitmap.width = 768 mBitmap.height = 768
2024-06-04 04:48:19.010  9873-9873  yang          I  mDestRect.width = 900.0 mDestRect.height = 900.0 mDestRect = RectF(0.0, 0.0, 900.0, 900.0)

在这里插入图片描述

RectF加上lefttop

  • 在完整的RectF区域上,进行了向左和向下的偏移,绘制的是经过裁剪的Bitmap
CoroutineScope(Dispatchers.IO).launch {
     tempBitmap = getBitmap(resources, tempRect, R.drawable.fake)
     withContext(Dispatchers.Main) {
         mRealView?.post {
             mDestRect.set(
                 mRealView?.left?.toFloat()!!,
                 mRealView?.top?.toFloat()!!,
                 mRealView?.left?.toFloat()!! + mRealView?.width?.toFloat()!!,
                 mRealView?.top?.toFloat()!! + mRealView?.height?.toFloat()!!
             )
             tempBitmap?.let {
                 mRealView?.setBitmap(it, mDestRect)
             }
         }
     }
}

// log result
2024-06-04 04:50:49.826 10194-10194 yang          I  canvas.width = 900, canvas.height = 900
2024-06-04 04:50:49.826 10194-10194 yang          I  mBitmap.width = 768 mBitmap.height = 768
2024-06-04 04:50:49.826 10194-10194 yang          I  mDestRect.width = 900.0 mDestRect.height = 900.0 mDestRect = RectF(90.0, 90.0, 990.0, 990.0)

在这里插入图片描述

RectF的宽高小于Bitmap的宽高

  • Bitmap会被缩小至整个RectF区域,不会被裁剪

RectF没有加上lefttop

  • 使用完整大小的RectF区域,绘制的是整张Bitmap
CoroutineScope(Dispatchers.IO).launch {
    tempBitmap = getBitmap(resources, tempRect, R.drawable.fake)
    withContext(Dispatchers.Main) {
        mRealView?.post {
            mDestRect.set(
                0f,
                0f,
                mRealView?.width?.toFloat()!!,
                mRealView?.height?.toFloat()!!
            )
            tempBitmap?.let {
                mRealView?.setBitmap(it, mDestRect)
            }
        }
    }
}

// log result
2024-06-04 04:57:15.407 11029-11029 yang            I  canvas.width = 900, canvas.height = 900
2024-06-04 04:57:15.407 11029-11029 yang            I  mBitmap.width = 3075 mBitmap.height = 3075
2024-06-04 04:57:15.407 11029-11029 yang            I  mDestRect.width = 900.0 mDestRect.height = 900.0 mDestRect = RectF(0.0, 0.0, 900.0, 900.0)

在这里插入图片描述

RectF加上lefttop

  • 在完整的RectF区域上,进行了向左和向下的偏移,绘制的是经过裁剪的Bitmap
CoroutineScope(Dispatchers.IO).launch {
    tempBitmap = getBitmap(resources, tempRect, R.drawable.fake)
    withContext(Dispatchers.Main) {
        mRealView?.post {
            mDestRect.set(
                mRealView?.left?.toFloat()!!,
                mRealView?.top?.toFloat()!!,
                mRealView?.left?.toFloat()!! + mRealView?.width?.toFloat()!!,
                mRealView?.top?.toFloat()!! + mRealView?.height?.toFloat()!!
            )
            tempBitmap?.let {
                mRealView?.setBitmap(it, mDestRect)
            }
        }
    }
}

// log result
2024-06-04 05:04:36.477 11296-11296 yang          I  canvas.width = 900, canvas.height = 900
2024-06-04 05:04:36.477 11296-11296 yang          I  mBitmap.width = 3075 mBitmap.height = 3075
2024-06-04 05:04:36.477 11296-11296 yang          I  mDestRect.width = 900.0 mDestRect.height = 900.0 mDestRect = RectF(90.0, 90.0, 990.0, 990.0)

在这里插入图片描述

RectF的宽高等于Bitmap的宽高

  • ViewCanvas大小小于目标绘制RectF大小,只能绘制Canvas对应宽高的区域,所以只能绘制Bitmap的左上角区域
CoroutineScope(Dispatchers.IO).launch {
    tempBitmap = getBitmap(resources, tempRect, R.drawable.fake)
    withContext(Dispatchers.Main) {
        mRealView?.post {
            mDestRect.set(
                0f,
                0f,
                tempBitmap?.width?.toFloat()!!,
                tempBitmap?.height?.toFloat()!!
            )
            tempBitmap?.let {
                mRealView?.setBitmap(it, mDestRect)
            }
        }
    }
}

// log result
2024-06-04 07:12:51.487 12197-12197 yang          I  canvas.width = 900, canvas.height = 900
2024-06-04 07:12:51.487 12197-12197 yang          I  mBitmap.width = 3075 mBitmap.height = 3075
2024-06-04 07:12:51.487 12197-12197 yang          I  mDestRect.width = 3075.0 mDestRect.height = 3075.0 mDestRect = RectF(0.0, 0.0, 3075.0, 3075.0)

在这里插入图片描述

  • 创建一张缩放Bitmap使用目标RectF的大小
CoroutineScope(Dispatchers.IO).launch {
    tempBitmap = getBitmap(resources, tempRect, R.drawable.fake)
    withContext(Dispatchers.Main) {
        mRealView?.post {
            mDestRect.set(
                0f,
                0f,
                mRealView!!.width.toFloat(),
                mRealView!!.height.toFloat()
            )
            val scale = min(mDestRect.width()/ tempBitmap?.width!!, mDestRect.height()/ tempBitmap?.height!!)
            val scaleBitmap = Bitmap.createScaledBitmap(tempBitmap!!, (tempBitmap?.width!!* scale).toInt(), (tempBitmap?.height!! * scale).toInt(), false)
            scaleBitmap?.let {
                mRealView?.setBitmap(it, mDestRect)
            }
            Log.i("yang", "scale = $scale")
        }
    }
}

// log result
2024-06-04 07:36:39.921 19497-19497 yang            I  scale = 0.29268292
2024-06-04 07:36:39.924 19497-19497 yang            I  canvas.width = 900, canvas.height = 900
2024-06-04 07:36:39.924 19497-19497 yang            I  mBitmap.width = 899 mBitmap.height = 899
2024-06-04 07:36:39.924 19497-19497 yang            I  mDestRect.width = 900.0 mDestRect.height = 900.0 mDestRect = RectF(0.0, 0.0, 900.0, 900.0)

在这里插入图片描述

标签:04,mRealView,RectF,mDestRect,height,width,Bitmap,绘制
From: https://blog.csdn.net/sunshine_guo/article/details/139436679

相关文章

  • View->Bitmap缩放到自定义ViewGroup的任意区域(RectF方式绘制Bitmap)
    XML文件<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent&quo......
  • C++ Builder 2010 绘制坐标
     一、步骤:1.先确定Image的位置,大小(可以不写)          2.设置初始面板,绘制初始的x,y坐标轴          3.画x,y向的刻度线,标刻x,y轴刻度          4.获取数据(可以不写)          5.将数......
  • d3.js 构建股权架构图并绘制股权百分比
    效果:代码:StockStructureChart.jsimportReact,{useEffect,useRef}from"react"import*asd3from"d3"constStockStructureChart=({data})=>{constref=useRef()constwidth=800constheight=500constboxWidth......
  • Origin2024如何绘制3D彩色饼图?
    饼图是科研中经常用到的图表之一,当我们需要展示部分占整体的比例时,相信很多人都会想到饼图,可以非常直观地体现各部分的占比,之前给大家分享了Origin绘制2D饼图,本期给大家分享绘制3D饼图的操作方法: 操作步骤:1、打开Origin2024软件,然后在Book1中输入如下示例数据,其中新建了一列......
  • 用 python 绘制不同时间序列数据的图表
    我有两个不同的时间序列数据,如下所示。我希望将这两组不同的时间序列值放在一个图表中。代码如下,不幸的是,这并不是我想要的效果。第二张图片就是我想要的效果......
  • 绘制bubble的三方包
    文章目录1.概念介绍2.思路与方法2.1组件及属性2.2实现方法2.3功能扩展3.示例代码4.内容总结我们在上一章回中介绍了"buble包"相关的内容,本章回中将介绍chat_bubbles包.闲话休提,让我们一起TalkFlutter吧。1.概念介绍我们在本章回中介绍的chat_bubbles包......
  • WebGPU学习(11)--- 独立于 Canvas 绘制
    更多精彩内容尽在数字孪生平台,关注公众号:sky的数孪技术,技术交流、源码下载请添加VX:digital_twin123只想创建图像数据而不使用Canvas当使用WebGL时,我们始终必须从Canvas获取WebGL渲染上下文,因为渲染上下文与绘图目标紧密相关。但是WebGPU不一定需要Canvas来......
  • python 探测网络 并自动绘制ip拓扑图
    要实现网络探测并自动绘制IP拓扑图,你可以使用Python与相关库和工具来完成。一个流行的方法是使用Python的网络扫描库(例如Nmap或Scapy)来扫描网络,并使用网络图形库(例如NetworkX和Matplotlib)来绘制IP拓扑图。以下是一个粗略的步骤示例,展示了如何实现网络探测并自动绘制IP拓扑图:i......
  • python NetworkX和Matplotlib 来绘制IP拓扑图
    要使用NetworkX和Matplotlib来绘制IP拓扑图,首先需要使用NetworkX来构建图形,并在图形准备就绪后,使用Matplotlib绘制图形。以下是一个简单的示例,演示了如何使用NetworkX和Matplotlib来绘制IP拓扑图:importnetworkxasnximportmatplotlib.pyplotasplt#创建一个简单的示......
  • Vulkan矩形绘制顺序小坑
    裁剪坐标不同:1.vulkan裁剪坐标Y朝下,所以下面矩形意义:staticstd::vector<Vertex>vertices={{{-0.5f,-0.5f,0},{1.0f,0.0f,0.0f}},//左上角{{0.5f,-0.5f,0},{0.0f,1.0f,0.0f}},//右上角{{0.5f,0.5f,0},{0.0f,0.0f,1.0f}},//右下角......