Canvas.drawBitmap
常用重载方法的详解
/**
* 如果绘制的Bitmap不需要拉伸,缩放,使用这个方法,比如绘制马赛克底图
*
* @param bitmap 要绘制的位图
* @param left 被绘制的位图左侧的位置
* @param top 被绘制的位图顶部的位置
* @param paint 用于绘制位图的 Paint(可以为 null)
*/
public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
super.drawBitmap(bitmap, left, top, paint);
}
/**
* 从Bitmap中拿出一块Rect区域,绘制到另外一块Rect区域上,比如绘制到一个指定的View区域上
*
* @param bitmap 要绘制的位图
* @param src 源矩形,定义位图中要绘制的区域。可以为 null,表示绘制整个位图。
* @param dst 目标矩形,定义位图在画布上绘制的位置和大小。
* @param paint 用于绘制位图的 Paint(可以为 null)
*/
public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint) {
super.drawBitmap(bitmap, src, dst, paint);
}
/**
* 通过矩阵变换Bitmap,适合需要复杂变换的场景,比如绘制一张平移、旋转、缩放的Bitmap
*
* @param bitmap 要绘制的位图
* @param matrix 用于变换位图的 Matrix,包括平移、旋转、缩放等操作
* @param paint 用于绘制位图的 Paint(可以为 null)
*/
public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
super.drawBitmap(bitmap, matrix, paint);
}
如何把Bitmap
从原始区域Rect
绘制到目标区域Rect
上?
- 一张
Bitmap
的宽高往往是比手机屏幕宽高大得多,原始Bitmap
自身携带一个原始区域Rect
,也就是Rect(0, 0, bitmap.width, bitmap.height)
,如果要绘制到手机屏幕区域某个View
的区域,也就是目标Rect
,需要使用到Canvas
和变换矩阵Matrix
的组合使用
方法一
override fun onDraw(canvas: Canvas) {
// 如果需要在一块指定Rect上绘制平移、旋转、缩放的Bitmap
bitmap?.let { bitmap ->
// 计算平移
val translateX = targetRect.left + (targetRect.width() - bitmap.width) / 2
val translateY = targetRect.top + (targetRect.height() - bitmap.height) / 2
// 计算缩放
val scaleX = targetRect.width() / bitmap.width
val scaleY = targetRect.height() / bitmap.height
val scale = min(scaleX, scaleY)
// 计算旋转
val degree = 15f
// 图片原始区域到目标区域的变换矩阵,存储平移、缩放、旋转数值
val targetMatrix = Matrix().apply {
postTranslate(translateX, translateY)
postScale(scale, scale, targetRect.centerX(), targetRect.centerY())
postRotate(degree, targetRect.centerX(), targetRect.centerY())
postConcat(手势矩阵)
}
canvas.concat(targetMatrix) // canvas拼接变换矩阵
canvas.drawBitmap(bitmap, null, targetRect, Paint())
}
}
方法二
override fun onDraw(canvas: Canvas) {
// 如果需要在一块指定Rect上绘制平移、旋转、缩放的Bitmap
bitmap?.let { bitmap ->
// 计算平移
val translateX = targetRect.left + (targetRect.width() - bitmap.width) / 2
val translateY = targetRect.top + (targetRect.height() - bitmap.height) / 2
// 计算缩放
val scaleX = targetRect.width() / bitmap.width
val scaleY = targetRect.height() / bitmap.height
val scale = min(scaleX, scaleY)
// 计算旋转
val degree = 15f
// 图片原始区域到目标区域的变换矩阵,存储平移、缩放、旋转数值
val targetMatrix = Matrix().apply {
postTranslate(translateX, translateY)
postScale(scale, scale, targetRect.centerX(), targetRect.centerY())
postRotate(degree, targetRect.centerX(), targetRect.centerY())
postConcat(手势矩阵)
}
canvas.drawBitmap(bitmap, targetMatrix, Paint())
}
}
方法三
override fun onDraw(canvas: Canvas) {
// 如果需要在一块指定Rect上绘制平移、旋转、缩放的Bitmap
bitmap?.let { bitmap ->
// 定义源矩形和目标矩形
val srcRect = RectF(0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat())
val targetRectF = RectF(targetRect)
// 创建一个矩阵来描述从源矩形到目标矩形的变换
val targetMatrix = Matrix().apply {
// 设置矩形到矩形的变换,保持纵横比居中缩放
setRectToRect(srcRect, targetRectF, Matrix.ScaleToFit.CENTER)
// 额外的旋转变换
postRotate(15f, targetRectF.centerX(), targetRectF.centerY())
postConcat(手势矩阵)
}
// 使用变换矩阵绘制位图
canvas.drawBitmap(bitmap, targetMatrix, Paint())
}
}
Canvas绘制现场保护
override fun onDraw(canvas: Canvas) {
canvas.save() // 隔离绘制现场,以下修改画布的操作不会记录
canvas.concat(变换矩阵) // 画布绘制的所有东西,应用这个变换
canvas.clipRect(目标区域) // 将画布裁剪到目标区域中
canvas.clipOutRecet(目标区域) // 将画布裁剪到目标区域之外
canvas.restore() // 恢复绘制现场,恢复修改画布之前的画布状态
canvas.withSave{
canvas.concat(变换矩阵) // 画布绘制的所有东西,应用这个变换
canvas.clipRect(目标区域) // 将画布裁剪到目标区域中
canvas.clipOutRecet(目标区域) // 将画布裁剪到目标区域之外
}
}
public inline fun Canvas.withSave(block: Canvas.() -> Unit) {
val checkpoint = save() // 返回一个Int值
try {
block() // 执行lambda表达式
} finally {
restoreToCount(checkpoint) // 从绘制栈中恢复指定Int值时的画布状态
}
}
标签:Canvas,targetRect,val,canvas,bitmap,Bitmap,绘制
From: https://blog.csdn.net/sunshine_guo/article/details/145033413