Draw transparent bitmap on backgound - android

I want to draw transparent bitmaps on a background in a game. However, the bitmap is not transparent, it still has white color in the background. Here is my code
inner class Canvass(context: Context) : View(context) {
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val frame_paint: Paint = Paint()
frame_paint.style = Paint.Style.FILL
frame_paint.isAntiAlias = true
val framegame = BitmapFactory.decodeResource (resources, R.drawable.frame)
canvas.drawBitmap (framegame, 0f, 0f, frame_paint)
canvas.drawPath(mPath, mPaint)
val tennis_paint: Paint = Paint()
tennis_paint.style = Paint.Style.FILL
tennis_paint.color = Color.TRANSPARENT
tennis_paint.isAntiAlias = true
val tennis = BitmapFactory.decodeResource (resources, R.drawable.tennis_ball)
canvas.drawBitmap (tennis, 50f, 200f, tennis_paint)
}
}

I found this code, it works for me.
val tennis_paint: Paint = Paint()
tennis_paint.style = Paint.Style.FILL
tennis_paint.isAntiAlias = true
val tennis = BitmapFactory.decodeResource (resources, R.drawable.tennis_ball)
var bitmap = transparent_bitmap(tennis)
canvas.drawBitmap (bitmap, 50f, 300f, tennis_paint)
fun transparent_bitmap(bmp:Bitmap):Bitmap{
var bitmap: Bitmap = Bitmap.createBitmap(
bmp.width,
bmp.height,
Bitmap.Config.ARGB_8888
)
bitmap.setHasAlpha(true)
for (x in 1..bmp.width-1){
for (y in 1..bmp.height-1){
var pixel = bmp.getPixel(x,y)
val redValue = Color.red(pixel)
val blueValue = Color.blue(pixel)
val greenValue = Color.green(pixel)
if ((redValue==255)and(blueValue==255)and(greenValue==255)){
bitmap.setPixel(x,y,Color.argb(1,0,0,0))
}else {
bitmap.setPixel(x,y,Color.rgb(redValue,greenValue,blueValue))
}
}
}
return bitmap
}

Related

Create border for custom drawable mask when image transform with Android

I have this masked transformation class, that can receive any mask:
class MaskedTransformation(private val maskDrawable: Drawable) : Transformation {
override fun key(): String = maskDrawable.hashCode().toString()
override fun transform(source: Bitmap): Bitmap? {
val result = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
val mCanvas = Canvas(result)
val o = BitmapFactory.Options()
o.inSampleSize = 2
val mask = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
val tmpCanvas = Canvas(mask)
val maskRaw9Patch = maskDrawable as? NinePatchDrawable
maskRaw9Patch?.setBounds(0, 0, tmpCanvas.width, tmpCanvas.height)
maskRaw9Patch?.draw(tmpCanvas)
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
mCanvas.drawBitmap(source, 0f, 0f, null)
mCanvas.drawBitmap(mask, 0f, 0f, paint)
paint.xfermode = null
source.recycle()
return result
}
For example, we can have this form: or any other.
How to add border (shape) around it? Please help!

How to draw border on BottomNavigation MenuItem Icon?

I am developing an android app using:
Jetpack Lifecycle (ViewModel)
Jetpack Navigation
Coil (Image Loader)
I am trying to customize the BottomNavigationMenu.
But one thing is very hard...
The last tab is the User's profile Image with Border.
If the user's profile image background color is white, then the ui is weird.
So I should show the border.
class MainActivity {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initBottomNav(binding.bottomNav)
vm.initProfileBottomIcon()
}
private fun initBottomNav(bottomNav: BottomNavigationView) {
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
bottomNav.setupWithNavController(navHostFragment.navController)
bottomNav.itemIconTintList = null
vm.profileImgUrl.observe(this) { url ->
bottomNav.menu.findItem(R.id.profileFragment).load(this, url) {
transformations(CircleCropTransformation())
}
}
}
}
This code draws the profile image on the BottomNavigationMenu.
But not draw the border.
When I googling, there is no support for CircleCrop with Border on Coil (even Glide).
So I tried the below code, But it doesn't work well..
vm.profileImg.observe(this) { imgBitmap ->
val layerBorder = ResourcesCompat.getDrawable(resources, R.drawable.oval_trans_border1_red, null)
val layerIcon = BitmapDrawable(Resources.getSystem(), imgBitmap)
val layerDrawable = LayerDrawable(arrayOf(layerIcon, layerBorder))
val bottomNavProfile = bottomNav.menu.findItem(R.id.profileFragment)
val request = ImageRequest.Builder(this)
.data(layerDrawable)
.target {
bottomNavProfile.icon = it
}
.apply {
transformations(CircleCropTransformation())
}
.build()
imageLoader.enqueue(request)
}
Somebody help me please?
You can write your own Transformation with border like this:
class BorderedCircleCropTransformation(
private val borderSize: Float = 0f,
#ColorInt private val borderColor: Int = Color.BLUE
) : Transformation {
override fun key(): String = BorderedCircleCropTransformation::class.java.name
override suspend fun transform(pool: BitmapPool, input: Bitmap, size: Size): Bitmap {
val borderOffset = (borderSize * 2).toInt()
val halfWidth = input.width / 2
val halfHeight = input.height / 2
val circleRadius = Math.min(halfWidth, halfHeight).toFloat()
val newBitmap = Bitmap.createBitmap(
input.width + borderOffset,
input.height + borderOffset,
Bitmap.Config.ARGB_8888
)
// Center coordinates of the image
val centerX = halfWidth + borderSize
val centerY = halfHeight + borderSize
val paint = Paint()
val canvas = Canvas(newBitmap).apply {
// Set transparent initial area
drawARGB(0, 0, 0, 0)
}
// Draw the transparent initial area
paint.isAntiAlias = true
paint.style = Paint.Style.FILL
canvas.drawCircle(centerX, centerY, circleRadius, paint)
// Draw the image
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(input, borderSize, borderSize, paint)
// Draw the createBitmapWithBorder
paint.xfermode = null
paint.style = Paint.Style.STROKE
paint.color = borderColor
paint.strokeWidth = borderSize
canvas.drawCircle(centerX, centerY, circleRadius, paint)
return newBitmap
}
override fun equals(other: Any?) = other is BorderedCircleCropTransformation
override fun hashCode() = javaClass.hashCode()
override fun toString() = "BorderedCircleCropTransformation()"
private companion object {
val XFERMODE = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
}
}
internal val Bitmap.safeConfig: Bitmap.Config
get() = config ?: Bitmap.Config.ARGB_8888
then pass it as a transformation to coil and it will draw what you want.
I use this code for drawing border.

Path is filled with color instead showing as contour

I faced the following problem: I need to show the contour of the human face over bitmap. I have coordinates of the face contour points. Here's my code:
private fun detectContours(
it: FirebaseVisionFace,
icon: Bitmap
) {
val faceContour = it.getContour(FirebaseVisionFaceContour.FACE)
val mutableBitmap = icon.copy(
Bitmap.Config.ARGB_8888, true
)
val canvas = Canvas(mutableBitmap)
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.color = Color.parseColor("#99ff0000")
val path = Path()
path.moveTo(faceContour.points[0].x, faceContour.points[0].y)
faceContour.points.forEach {
path.lineTo(it.x, it.y)
}
path.close()
canvas.drawPath(path, paint)
binding.ivPhoto.setImageBitmap(mutableBitmap)
}
Here I use path.moveTo(...) and I expect that mutableBitmap will look like a face with the contour. But when I run the app I see the following result:
So, why the path is filled with the colour. Thanks in advance, I will appreciate any help
Fixed by changing path.drawline to canvas.drawLine
val faceContour = it.getContour(FirebaseVisionFaceContour.FACE)
var startX = faceContour.points[0].x
var startY = faceContour.points[0].y
val initialX = faceContour.points[0].x
val initialY = faceContour.points[0].y
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.color = Color.parseColor("#ff0000")
faceContour.points.forEach {
canvas.drawLine(startX, startY, it.x, it.y, paint)
startX = it.x
startY = it.y
}
canvas.drawLine(startX, startY, initialX, initialY, paint)

Draw a path progressively with getSegment

I created a custom view to draw a line, but progressively. I tried to use PathMeasure and getSegment, but the effect doesn't work. It just keeps drawing the line already with the final size.
private val paint = Paint().apply {
isAntiAlias = true
color = Color.WHITE
style = Paint.Style.STROKE
strokeWidth = 10f
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val path = Path().apply {
moveTo(width/2.toFloat(), height/2.toFloat())
lineTo(width/2.toFloat(), height/4.toFloat())
}
val measure = PathMeasure(path, false)
val length = measure.length
val partialPath = Path()
measure.getSegment(0.0f, length, partialPath, true)
partialPath.rLineTo(0.0f, 0.0f)
canvas!!.drawPath(partialPath, paint)
}
you can do this with DashPathEffect
DashPathEffect dashPathEffect = new DashPathEffect(new float[]{1000.0f,9999999},0);
Paint.setPathEffect(dashPathEffect);
change 1000 to your length ("on" parts in Dash)
and set 99999999 to your max ("off" parts in Dash)
play with this parameters and read this article please
Here's how I made it, as #mohandes explained:
private var path = Path()
private var paint = Paint()
private val dashes = floatArrayOf(125f, 125f)
init {
paint = Paint().apply {
isAntiAlias = true
color = Color.WHITE
style = Paint.Style.STROKE
strokeWidth = 10.0f
pathEffect = CornerPathEffect(8f)
}
path = Path().apply {
moveTo(312f, 475f)
lineTo(312f, 375f)
}
val lineAnim = ValueAnimator.ofFloat(100f, 0f)
lineAnim.interpolator = LinearInterpolator()
lineAnim.addUpdateListener {
paint.pathEffect = ComposePathEffect(DashPathEffect(dashes, lineAnim.animatedValue as Float), CornerPathEffect(8f))
invalidate()
}
lineAnim.duration = 1000
lineAnim.start()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas!!.drawPath(path, paint)
}

Clear canvas area with special bitmap's form

I develop a drawing application and I need to implement eraser tool to clear special areas of pictures. Eraser must erase some circle area unevenly. It means - only center of circle should be erased completely and edges of circle should be erased partially, with alpha.
To achieve this behaviour I created the image that representes eraser's figure
Then, to erase some area of view, I draw the eraser's figure above some picture like this:
private val picture: Bitmap
private val bgPaint = Paint()
private var eraser: Bitmap
private val eraserPaint: Paint = Paint().apply {
val mode: PorterDuff.Mode = PorterDuff.Mode.SRC_OUT
xfermode = PorterDuffXfermode(mode)
color = Color.TRANSPARENT
alpha = 0
}
init {
val options = BitmapFactory.Options()
options.inMutable = true
picture = BitmapFactory.decodeResource(resources, R.drawable.petushara, options)
eraser = BitmapFactory.decodeResource(resources, R.drawable.eraser, options)
setLayerType(View.LAYER_TYPE_SOFTWARE, bgPaint)
}
override fun draw(canvas: Canvas) {
super.draw(canvas)
canvas.drawBitmap(picture, 0f, 0f, bgPaint)
canvas.drawBitmap(eraser, 100f, 300f, eraserPaint)
}
This is whole my view-class, excluding constructors. I expect that area of picture will be erased by figure of eraser, but it erases by figure of square like this:
Okay, I just found out the solution. Write code like this:
private val picture: Bitmap
private val bgPaint = Paint()
private var eraser: Bitmap
private val eraserPaint: Paint = Paint().apply {
val mode: PorterDuff.Mode = PorterDuff.Mode.XOR
xfermode = PorterDuffXfermode(mode)
}
init {
val options = BitmapFactory.Options()
options.inMutable = true
picture = BitmapFactory.decodeResource(resources, R.drawable.petushara, options)
eraser = BitmapFactory.decodeResource(resources, R.drawable.eraser, options)
setLayerType(View.LAYER_TYPE_SOFTWARE, bgPaint)
}
override fun draw(canvas: Canvas) {
super.draw(canvas)
canvas.drawBitmap(picture, 0f, 0f, bgPaint)
canvas.drawBitmap(eraser, 100f, 300f, eraserPaint)
}
Then result picture looks like my expectations:

Categories

Resources