simple fun
fun getCircleBitmap(bitmap: Bitmap, recycle: Boolean): Bitmap {
val paint = Paint()
paint.isAntiAlias = true
paint.color = Color.WHITE
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
val rect = Rect(0, 0, bitmap.width, bitmap.height)
val rectF = RectF(rect)
val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
canvas.drawARGB(0, 0, 0, 0)
canvas.drawOval(rectF, paint)
canvas.drawBitmap(bitmap, rect, rect, paint)
if (recycle) {
bitmap.recycle()
}
return output
}
Taget API 29. Emulator API 28. Kotlin 1.3.40.
About month ago this fun worked. But now on "canvas.drawBitmap" error "Software rendering doesn't support hardware bitmaps". Try android:hardwareAccelerated="false" - same error. Why?
so, my solution:
fun getCircleBitmapDrawable(bitmap: Bitmap): RoundedBitmapDrawable {
val round = RoundedBitmapDrawableFactory.create(context.resources, bitmap)
round.isCircular = true
round.setAntiAlias(true)
return round
}
Related
I can't seem to figure out how can I make an image (such as ImageView) a circle image, inside an app widget. I mean crop it in the form of a circle, like .clipShape(Circle()) in SwiftUI.
I tried some solutions but they won't work in widgets:
ShapeableImageView breaks the widget
Androidx library is not allowed in widget
Any other solutions?
Updated
I have tried doing it programatically from Kotlin, converting the solution from here:
class AppWidgetProvider : HomeWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
appWidgetIds.forEach { widgetId ->
val view = RemoteViews(context.packageName, R.layout.widget_layout)
val pendingIntent = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("https://example.com"))
view.setOnClickPendingIntent(R.id.widgetRoot, pendingIntent)
val logoBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.app_icon)
view.setImageViewBitmap(R.id.smarthutsLogo, getCroppedBitmap(logoBitmap))
appWidgetManager.updateAppWidget(widgetId, view)
}
}
#Throws(Exception::class)
fun getCroppedBitmap(bitmap: Bitmap): Bitmap {
val output: Bitmap =
Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val color = -0xbdbdbe
val paint = Paint()
val rect = Rect(0, 0, bitmap.width, bitmap.height)
paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
paint.color = color
canvas.drawCircle(
(bitmap.width / 2).toFloat(),
(bitmap.height / 2).toFloat(),
(bitmap.width / 2).toFloat(),
paint
)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(bitmap, rect, rect, paint)
return output
}
}
HomeWidgetProvider is from a Flutter plugin, you can find the code for it here.
What happens is that the the image despite being being cropped as a circle it's shown with a white square background.
From this issue, using Android Studio's code converter, I managed to make a solution in Kotlin:
#Throws(Exception::class)
fun getCroppedBitmap(bitmap: Bitmap): Bitmap {
val output: Bitmap =
Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val paint = Paint()
val rect = Rect(0, 0, bitmap.width, bitmap.height)
paint.isAntiAlias = true
canvas.drawCircle(
(bitmap.width / 2).toFloat(),
(bitmap.height / 2).toFloat(),
(bitmap.width / 2).toFloat(),
paint
)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(bitmap, rect, rect, paint)
return output
}
The newly created function can be used inside the widget's onUpdate method as follows:
val view = RemoteViews(context.packageName, R.layout.widget_layout)
val logoBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.app_icon)
view.setImageViewBitmap(R.id.imageView, getCroppedBitmap(logoBitmap))
Be careful not have android:background="#android:color/white" added to your ImageView. If you need to add a background color, add it when creating the bitmap.
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!
Am using DantSu library to print receipts but Arabic text is never printed
here is my code
val printer = EscPosPrinter(
deviceConnection,
printerData.printerDpi,
printerData.printerWidthMM,
printerData.printerNbrCharactersPerLine,
EscPosCharsetEncoding("windows-1252", 16)
)
According to this comment on the issue on the library .. we found a solution but not totally correct
private fun getBitmap(text: String): Bitmap? {
val paint = Paint()
paint.setTextSize(28f)
val bounds = Rect()
paint.getTextBounds(text, 0, text.length, bounds)
val width: Int = bounds.width()
val height: Int = bounds.height()
val bitmap = Bitmap.createBitmap(width * 2, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
canvas.drawColor(Color.WHITE)
canvas.drawText(text, 20f, 20f, paint)
return bitmap
}
Currently there are so many ways to create a Circle Bitmap in Android. But none of them are working for rectangle bitmap image. Even the Android API RoundedBitmapDrawable doesn't help much.
Basically this kotlin extension function will solve the issue.
fun Bitmap.cropToCircle(): Bitmap {
val circleBitmap = if (this.width > this.height) {
Bitmap.createBitmap(this.height, this.height, Bitmap.Config.ARGB_8888)
} else {
Bitmap.createBitmap(this.width, this.width, Bitmap.Config.ARGB_8888)
}
val bitmapShader = BitmapShader(this, TileMode.CLAMP, TileMode.CLAMP)
val paint = Paint().apply {
isAntiAlias = true
shader = bitmapShader
}
val radius = if (this.width > this.height) {
this.height / 2f
} else {
this.width / 2f
}
Canvas(circleBitmap).apply {
drawCircle(radius, radius, radius, paint)
}
this.recycle()
return circleBitmap
}
Hope this helps someone!
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
}