Android从一个view创建Bitmap 作为高斯模糊贴到浮
2023-07-11 本文已影响0人
为自己代颜_
直接上代码:
object QMUIDrawableHelper {
private val TAG = QMUIDrawableHelper::class.java.simpleName
//节省每次创建时产生的开销,但要注意多线程操作synchronized
private val sCanvas = Canvas()
/**
* 从一个view创建Bitmap。
* 注意点:绘制之前要清掉 View 的焦点,因为焦点可能会改变一个 View 的 UI 状态。
* 来源:https://github.com/tyrantgit/ExplosionField
*
* @param view 传入一个 View,会获取这个 View 的内容创建 Bitmap。
* @param scale 缩放比例,对创建的 Bitmap 进行缩放,数值支持从 0 到 1。
*/
@JvmOverloads
fun createBitmapFromView(view: View, scale: Float = 1f): Bitmap? {
if (view is ImageView) {
val drawable = view.drawable
if (drawable != null && drawable is BitmapDrawable) {
return (drawable as BitmapDrawable).getBitmap()
}
}
view.clearFocus()
val bitmap: Bitmap? = createBitmapSafely((view.width * scale).toInt(), (view.height * scale).toInt(), Bitmap.Config.ARGB_8888, 1)
if (bitmap != null) {
synchronized(sCanvas) {
val canvas = sCanvas
canvas.setBitmap(bitmap)
canvas.save()
canvas.drawColor(Color.TRANSPARENT) // 防止 View 上面有些区域空白导致最终 Bitmap 上有些区域变黑
canvas.scale(scale, scale)
view.draw(canvas)
canvas.restore()
canvas.setBitmap(null)
}
}
return bitmap
}
/**
* 从一个view创建Bitmap。把view的区域截掉leftCrop/topCrop/rightCrop/bottomCrop
*/
fun createBitmapFromView(view: View, leftCrop: Int, topCrop: Int, rightCrop: Int, bottomCrop: Int): Bitmap? {
val originBitmap: Bitmap = createBitmapFromView(view) ?: return null
val cutBitmap: Bitmap = createBitmapSafely(view.width - rightCrop - leftCrop, view.height - topCrop - bottomCrop, Bitmap.Config.ARGB_8888, 1) ?: return null
val canvas = Canvas(cutBitmap)
val src = Rect(leftCrop, topCrop, view.width - rightCrop, view.height - bottomCrop)
val dest = Rect(0, 0, view.width - rightCrop - leftCrop, view.height - topCrop - bottomCrop)
canvas.drawColor(Color.WHITE) // 防止 View 上面有些区域空白导致最终 Bitmap 上有些区域变黑
canvas.drawBitmap(originBitmap, src, dest, null)
originBitmap.recycle()
return cutBitmap
}
/**
* 安全的创建bitmap。
* 如果新建 Bitmap 时产生了 OOM,可以主动进行一次 GC - System.gc(),然后再次尝试创建。
*
* @param width Bitmap 宽度。
* @param height Bitmap 高度。
* @param config 传入一个 Bitmap.Config。
* @param retryCount 创建 Bitmap 时产生 OOM 后,主动重试的次数。
* @return 返回创建的 Bitmap。
*/
fun createBitmapSafely(width: Int, height: Int, config: Bitmap.Config, retryCount: Int): Bitmap? {
return try {
Bitmap.createBitmap(width, height, config)
} catch (e: OutOfMemoryError) {
e.printStackTrace()
if (retryCount > 0) {
System.gc()
return createBitmapSafely(width, height, config, retryCount - 1)
}
null
}
}
/**
* 创建一张指定大小的纯色图片,支持圆角
*
* @param resources Resources对象,用于创建BitmapDrawable
* @param width 图片的宽度
* @param height 图片的高度
* @param cornerRadius 图片的圆角,不需要则传0
* @param filledColor 图片的填充色
* @return 指定大小的纯色图片
*/
fun createDrawableWithSize(resources: Resources?, width: Int, height: Int, cornerRadius: Int, @ColorInt filledColor: Int): BitmapDrawable {
var filledColor = filledColor
val output: Bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
if (filledColor == 0) {
filledColor = Color.TRANSPARENT
}
if (cornerRadius > 0) {
val paint = Paint()
paint.isAntiAlias = true
paint.style = Paint.Style.FILL
paint.color = filledColor
canvas.drawRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat()), cornerRadius.toFloat(), cornerRadius.toFloat(), paint)
} else {
canvas.drawColor(filledColor)
}
return BitmapDrawable(resources, output)
}
/**
* 设置Drawable的颜色
* **这里不对Drawable进行mutate(),会影响到所有用到这个Drawable的地方,如果要避免,请先自行mutate()**
*
* please use [DrawableCompat.setTint] replace this.
*/
@Deprecated("")
fun setDrawableTintColor(drawable: Drawable?, @ColorInt tintColor: Int): ColorFilter {
val colorFilter = LightingColorFilter(Color.argb(255, 0, 0, 0), tintColor)
if (drawable != null) {
drawable.colorFilter = colorFilter
}
return colorFilter
}
/**
* 由一个drawable生成bitmap
*/
fun drawableToBitmap(drawable: Drawable?): Bitmap? {
if (drawable == null) return null else if (drawable is BitmapDrawable) {
return (drawable as BitmapDrawable).getBitmap()
}
val intrinsicWidth = drawable.intrinsicWidth
val intrinsicHeight = drawable.intrinsicHeight
return if (!(intrinsicWidth > 0 && intrinsicHeight > 0)) null else try {
val config: Bitmap.Config = if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
val bitmap: Bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, config)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
bitmap
} catch (e: OutOfMemoryError) {
e.printStackTrace()
null
}
}
/**
* 创建一张渐变图片,支持韵脚。
*
* @param startColor 渐变开始色
* @param endColor 渐变结束色
* @param radius 圆角大小
* @param centerX 渐变中心点 X 轴坐标
* @param centerY 渐变中心点 Y 轴坐标
* @return 返回所创建的渐变图片。
*/
@TargetApi(16)
fun createCircleGradientDrawable(
@ColorInt startColor: Int,
@ColorInt endColor: Int, radius: Int,
@FloatRange(from = 0.0, to = 1.0) centerX: Float,
@FloatRange(from = 0.0, to = 1.0) centerY: Float
): GradientDrawable {
val gradientDrawable = GradientDrawable()
gradientDrawable.setColors(
intArrayOf(
startColor,
endColor
)
)
gradientDrawable.setGradientType(GradientDrawable.RADIAL_GRADIENT)
gradientDrawable.setGradientRadius(radius.toFloat())
gradientDrawable.setGradientCenter(centerX, centerY)
return gradientDrawable
}
/**
* 动态创建带上分隔线或下分隔线的Drawable。
*
* @param separatorColor 分割线颜色。
* @param bgColor Drawable 的背景色。
* @param top true 则分割线为上分割线,false 则为下分割线。
* @return 返回所创建的 Drawable。
*/
fun createItemSeparatorBg(@ColorInt separatorColor: Int, @ColorInt bgColor: Int, separatorHeight: Int, top: Boolean): LayerDrawable {
val separator = ShapeDrawable()
separator.getPaint().setStyle(Paint.Style.FILL)
separator.getPaint().setColor(separatorColor)
val bg = ShapeDrawable()
bg.getPaint().setStyle(Paint.Style.FILL)
bg.getPaint().setColor(bgColor)
val layers = arrayOf<Drawable>(separator, bg)
val layerDrawable = LayerDrawable(layers)
layerDrawable.setLayerInset(1, 0, if (top) separatorHeight else 0, 0, if (top) 0 else separatorHeight)
return layerDrawable
}
/////////////// VectorDrawable /////////////////////
fun getVectorDrawable(context: Context, @DrawableRes resVector: Int): Drawable? {
return try {
AppCompatResources.getDrawable(context, resVector)
} catch (e: Exception) {
LogUtil.d(TAG, "Error in getVectorDrawable. resVector=" + resVector + ", resName=" + context.resources.getResourceName(resVector) + e.message)
null
}
}
fun vectorDrawableToBitmap(context: Context, @DrawableRes resVector: Int): Bitmap? {
val drawable = getVectorDrawable(context, resVector)
if (drawable != null) {
val b: Bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val c = Canvas(b)
drawable.setBounds(0, 0, c.width, c.height)
drawable.draw(c)
return b
}
return null
} /////////////// VectorDrawable /////////////////////
}
view的扩展函数:
fun View?.getBitmap(): Bitmap? {
this ?: return null
var scale = 1f
if (this.height > 8000f) {
scale = 8000f / this.height
}
return QMUIDrawableHelper.createBitmapFromView(this, scale)
}
调用的地方:
var sBgBitmap = activity.window.decorView.getBitmap()
GlideUtils.imgNormal(this, sBgBitmap, iv_bg)