Take screenshot from io.flutter.embedding.android.flutterview - android

I want to programmatically take screenshots from my FlutterView in Android.
When it was io.flutter.view.FlutterView I just use getBitmap()
But how can I make screenshot from io.flutter.embedding.android.FlutterView ?
I tried following code but this does not work:
private fun getBitmapFromNewEmbeddedFlutterView(flutterView: io.flutter.embedding.android.FlutterView): Bitmap {
val bitmap = Bitmap.createBitmap(
flutterView.width,
flutterView.height,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
flutterView.layout(
0,
0,
flutterView.measuredWidth,
flutterView.measuredHeight
)
flutterView.draw(canvas)
return bitmap
}

Related

How to fill with color only the icon on canvas,without the background android studio

I want to change the color of my png,i want to fill it with color,so i thought about creating a bitmap from the png,placing it on a canvas and drawing the canvas,but it is drawing the whole canvas,like this,so my icons are covered completely
This is my code:
private fun testResizeImg(imgRes: Int): BitmapDescriptor {
var bm = BitmapFactory.decodeResource(resources, imgRes)
bm = Bitmap.createScaledBitmap(bm, (bm.width * 0.1).toInt(), (bm.height * 0.1).toInt(), true)
val canvas = Canvas(bm)
val paint = Paint()
paint.color = Color.BLUE
canvas.drawPaint(paint)
return BitmapDescriptorFactory.fromBitmap(bm)
}
What is the best approach to do this,i have a png and i want to paint it.
You can try something like that ? (not tested)
You can use theColor Filter to change the icon's color at runtime.
Then you transform the drawable into Bitmap.
private fun testResizeImg(#DrawableRes imgRes: Int): BitmapDescriptor {
val mIcon = ContextCompat.getDrawable(getActivity(), imgRes)
mIcon?.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.BLUE, BlendModeCompat.SRC_ATOP)
var bm : Bitmap = (mIcon as BitmapDrawable).bitmap
bm = Bitmap.createScaledBitmap(bm, (bm.width * 0.1).toInt(), (bm.height * 0.1).toInt(), true)
return BitmapDescriptorFactory.fromBitmap(bm)
}
Note that the #DrawableRes is here to help for the code inspection
private fun testResizeImg(imgRes: Int): BitmapDescriptor {
var bm = BitmapFactory.decodeResource(resources, imgRes)
bm = Bitmap.createScaledBitmap(bm, (bm.width * 0.1).toInt(), (bm.height * 0.1).toInt(), true)
val canvas = Canvas(bm)
canvas.drawBitmap(bm,0F,0F,null)
return BitmapDescriptorFactory.fromBitmap(bm)
}

Android: Blur background of LinearLayout using Kotlin

I have seen a lot of posts on this topic with all solutions being based on Java and not Kotlin. Is there a solution similiar to the one using Java but in Kotlin?
first get a screenshot of the layout:
getViewScreenshot(view: View): Bitmap {
view.setDrawingCacheEnabled(true)
val bitmap = Bitmap.createBitmap(view.getDrawingCache())
view.setDrawingCacheEnabled(false)
return bitmap
}
then blur it with this function:
fun blurBitmap(bitmap: Bitmap, applicationContext: Context): Bitmap {
lateinit var rsContext: RenderScript
try {
// Create the output bitmap
val output = Bitmap.createBitmap(
bitmap.width, bitmap.height, bitmap.config)
// Blur the image
rsContext = RenderScript.create(applicationContext, RenderScript.ContextType.DEBUG)
val inAlloc = Allocation.createFromBitmap(rsContext, bitmap)
val outAlloc = Allocation.createTyped(rsContext, inAlloc.type)
val theIntrinsic = ScriptIntrinsicBlur.create(rsContext, Element.U8_4(rsContext))
theIntrinsic.apply {
setRadius(10f)
theIntrinsic.setInput(inAlloc)
theIntrinsic.forEach(outAlloc)
}
outAlloc.copyTo(output)
return output
} finally {
rsContext.finish()
}
}

Jetpack Compose Immutable ImageBitmap to pass to Canvas

Loading an immutable image to canvas crashes with
java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor
both in classic Android Canvas and Compose Canvas.
Using the snippet below is the cause for crash in Jetpack Compose.
val deferredResource: DeferredResource<ImageBitmap> =
loadImageResource(id = R.drawable.landscape2)
deferredResource.resource.resource?.let { imageBitmap ->
val paint = Paint().apply {
style = PaintingStyle.Stroke
strokeWidth = 1f
color = Color(0xffFFEE58)
}
Canvas(image = imageBitmap).drawRect(0f, 0f, 100f, 100f, paint)
}
Which is solved with Bitmap as can be seen here with
Bitmap workingBitmap = Bitmap.createBitmap(chosenFrame);
Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutableBitmap);
I can convert ImageBitmap to Android Bitmap using
val bitmap = imageBitmap.asAndroidBitmap().copy(Bitmap.Config.ARGB_8888, true)
Found that it's also possible to convert Bitmap back to ImageBitmap using
val newImageBitmap = bitmap.asImageBitmap()
And as result i get after drawing on that Bitmap with snippet below
val canvas = Canvas(newImageBitmap)
canvas.drawRect(0f, 0f, 200f, 200f, paint = paint)
canvas.drawCircle(
Offset(
newImageBitmap.width / 2 - 75f,
newImageBitmap.height / 2 + 75f
), 150.0f, paint
)
Image(bitmap = newImageBitmap)
Is there a less convoluted way to draw on ImageBitmap with Canvas without converting back and forth between Bitmap and ImageBitmap?
loadImageResource() is using AndroidImageBitmap implementation with Bitmap.decodeResource(resources, drawableId) which requests calling it without options.
This is probably limitation of the compose. You'll probably need to write your own loadingImageResource() that will call your own ImageBitmap implementation with mutable Bitmap.
fun imageFromResource(res: Resources, resId: Int): ImageBitmap {
return MutableAndroidImageBitmap(BitmapFactory.decodeResource(res, resId, BitmapFactory.Options().apply { inMutable = true }))
}
class MutableAndroidImageBitmap(internal val bitmap: Bitmap) : ImageBitmap
Note that drawaing of this will fail since, conversion asAndroidBitmap() checks for implementation of ImageBitmap when drawing the ImageBitmap to the foundation Canvas.
I guess you should stick with the steps you have stated in the question. asImageBitmap() does not convert ImageBitmap to Bitmap it just return the wrapped internal property. Converting Bitmap to ImageBitmap does reading the of the pixel data and creates copy of it.
suspend fun ImageBitmap.mutate(context: CoroutineContext = EmptyCoroutineContext, config: Bitmap.Config) = withContext(context) {
val workingBitmap = asAndroidBitmap() //this is just access to `bitmap` property
val mutableBitmap = workingBitmap.copy(config, true)
workingBitmap.recycle()
mutableBitmap.asImageBitmap()
}
Opened bug on issue tracker https://issuetracker.google.com/issues/177129056

Native Crash in getting bitmap from resource

I have a native crash:
A/libc: invalid address or address of corrupt block 0x55766f1b00 passed to try_realloc_chunk
A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdeadbaad in tid 32219 (onPool-worker-1)
when executing the drawable.draw(canvas) line in the following method:
fun getBitmapFromResource(context: Context, imageRes: Int, iconSize: Float = CATEGORY_ICON_SIZE): Bitmap? {
val drawable = ContextCompat.getDrawable(context, imageRes)
if (drawable is BitmapDrawable) {
return drawable.bitmap
}
val size = GraphicsUtils.toPx(context, iconSize)
val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable!!.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas) // crash!!
return bitmap
}
The drawable is VectorDrawable implementation. I am executing this code on a background thread in a coroutine.
I added vectorDrawables.useSupportLibrary = true to build.gradle file, but it did not help.
I need bitmap object because from its width and height I draw a custom chart and I need to perform size calculations there.
I had the suspicion that multi-threading might break the process, so I added this code in the runBlocking section (still on a background thread) - no effect.
Any ideas how to fix this?
After several hours of investigation, I fixed the issue.
The problem seems to be that more than one coroutine was entering the method at the same time. I used Mutex to make sure only one coroutine can be inside the method.
object UIUtilsSingleton {
private val mutex = Mutex()
suspend fun getBitmapFromResource(context: Context, imageRes: Int): Bitmap? {
var bitmap: Bitmap? = null
mutex.withLock {
val iconSize = 42f
val drawable = ContextCompat.getDrawable(context, imageRes)
if (drawable is BitmapDrawable) {
return drawable.bitmap
}
val size = GraphicsUtils.toPx(context, iconSize)
bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable!!.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
}
return bitmap
}
}

view.getDrawingCache() is deprecated in Android API 28

In android API 28 view.getDrawingCache() has been deprecated. Is there any newer solution to generate a Bitmap of a particular view in android.
Two ways to get bitmap of view
Using Canvas
Using Pixel Api
Canvas Java
Bitmap getBitmapFromView(View view) {
Bitmap bitmap = Bitmap.createBitmap(
view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888
);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
Bitmap getBitmapFromView(View view,int defaultColor) {
Bitmap bitmap = Bitmap.createBitmap(
view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888
);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(defaultColor);
view.draw(canvas);
return bitmap;
}
Canvas Kotlin
fun getBitmapFromView(view: View): Bitmap {
val bitmap = Bitmap.createBitmap(
view.width, view.height, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
view.draw(canvas)
return bitmap
}
fun getBitmapFromView(view: View, defaultColor: Int): Bitmap {
val bitmap = Bitmap.createBitmap(
view.width, view.height, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
canvas.drawColor(defaultColor)
view.draw(canvas)
return bitmap
}
Example
//#param rootView is View object which you want to get bitmap
Bitmap bitmap = getBitmapFromView(rootView);
Bitmap bitmapColored = getBitmapFromView(rootView,Color.WHITE);
PixelCopy Api
https://stackoverflow.com/a/52985554/9909365
fun getBitmapFromView(view: View, activity: Activity, callback: (Bitmap) -> Unit) {
activity.window?.let { window ->
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
callback(bitmap)
}
// possible to handle other result codes ...
}, Handler())
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
e.printStackTrace()
}
}
}
For More See About
Bitmaps
Canvas
I have found a way to use PixelCopy API for retrieving the view as a Bitmap. Used Kotlin
fun getBitmapFromView(view: View, activity: Activity, callback: (Bitmap) -> Unit) {
activity.window?.let { window ->
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
callback(bitmap)
}
// possible to handle other result codes ...
}, Handler())
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
e.printStackTrace()
}
}
}
Try this:
private fun convertViewToDrawable(view: View): Bitmap {
val spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
view.measure(spec, spec)
view.layout(0, 0, view.measuredWidth, view.measuredHeight)
val b = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight,
Bitmap.Config.ARGB_8888)
val c = Canvas(b)
c.translate((-view.scrollX).toFloat(), (-view.scrollY).toFloat())
view.draw(c)
return b
}
As of the official documentation getDrawingCache() you should use the PixelCopy api.
much precise code..
private fun convertViewToDrawable(view: View): Bitmap {
val b = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight,
Bitmap.Config.ARGB_8888)
val c = Canvas(b)
c.translate((-view.scrollX).toFloat(), (-view.scrollY).toFloat())
view.draw(c)
return b
}
Some other kotlin code (ScrollView case)
val ScrollView.bitmap: Bitmap
get() {
val bitmap = Bitmap.createBitmap(width, getChildAt(0).height, Bitmap.Config.RGB_565)
with(Canvas(bitmap)) {
val background = background
if (background != null) {
background.draw(this)
} else {
drawColor(Color.WHITE)
}
draw(this)
}
return bitmap
}
bitmap = view.drawToBitmap()
val pixel = bitmap.getpixel(x,y)
Kotlin code with view inflation:
fun getBitmapFromView(layoutInflater: LayoutInflater): Bitmap =
layoutInflater.inflate(R.layout.layoutID, null).run {
//Bind data If you needed Example - [findViewById<TextView>(R.id.viewId).text = data]
measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
layout(0, 0, measuredWidth, measuredHeight)
val bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
draw(canvas)
bitmap
}
layoutInflater can be retrieved like,
Inside activity or fragment -
this.layoutInflater
Outside activity or fragment -
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater

Categories

Resources