Guy Bieber
06/24/2020, 11:33 PMfun getScreenShotFromView(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 {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PixelCopy.request(
window,
Rect(
locationOfViewInWindow[0],
locationOfViewInWindow[1],
locationOfViewInWindow[0] + view.width,
locationOfViewInWindow[1] + view.height
), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
callback(bitmap) }
else {
}
// possible to handle other result codes ...
},
Handler()
)
}
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
e.printStackTrace()
}
}
}
Leland Richardson [G]
06/24/2020, 11:37 PMromainguy
06/24/2020, 11:58 PMPixelCopy
does not need a View
View
just to get the coordinates of part of the window?Filip Pavlis
06/25/2020, 9:58 AMfindRoot().captureToBitmap()
which would capture your whole compose view for you. You can also capture individual composables if needed.Mark Murphy
06/25/2020, 3:43 PMI am trying to use pixelcopy to capture the screen in a compose applicationCan you just render the composable to a bitmap-backed
Canvas
and bypass all the "capture the screen" stuff?Guy Bieber
06/25/2020, 4:32 PMMantas Varnagiris
07/05/2020, 6:11 PMMark Murphy
07/05/2020, 7:38 PMCanvas
, after all. Looking at AndroidComposeView
, though, it appears as though "render to a `Canvas`" is intertwined with lots of other stuff. ☹️
That being said, calling draw()
on a View
is fairly simple. Given a layout like this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="<http://schemas.android.com/apk/res/android>"
xmlns:app="<http://schemas.android.com/apk/res-auto>"
xmlns:tools="<http://schemas.android.com/tools>"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/composeTarget"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/capturedImage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/capturedImage"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/composeTarget" />
</androidx.constraintlayout.widget.ConstraintLayout>
...then this code renders a composable into the FrameLayout
and displays a captured Bitmap
of that output into the ImageView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.composeTarget.setContent(Recomposer.current()) {
MaterialTheme {
Text("hello, world!", modifier = Modifier.padding(8.dp))
}
}
binding.composeTarget.doOnLayout {
val bitmap = Bitmap.createBitmap(
binding.composeTarget.width,
binding.composeTarget.height,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
binding.root.draw(canvas)
binding.capturedImage.setImageBitmap(bitmap)
}
}
}
Mantas Varnagiris
07/06/2020, 11:07 AMModifier.drawLayer(...)
Seems like all modifications inside drawLayer
are ignoredMark Murphy
07/20/2020, 9:42 PMMantas Varnagiris
07/21/2020, 7:27 AMView.drawToBitmap
which effectively does the same thing as code above, it says:
/**
* Return a [Bitmap] representation of this [View].
*
* The resulting bitmap will be the same width and height as this view's current layout
* dimensions. This does not take into account any transformations such as scale or translation.
*
* Note, this will use the software rendering pipeline to draw the view to the bitmap. This may
* result with different drawing to what is rendered on a hardware accelerated canvas (such as
* the device screen).
*
* If this view has not been laid out this method will throw a [IllegalStateException].
*
* @param config Bitmap config of the desired bitmap. Defaults to [Bitmap.Config.ARGB_8888].
*/
Seems like the issue is that drawLayer
users hardware accelerated canvas that's why all transformations seem to be ignored for me.
Now need to investigate if it's possible to capture pixels from hardware accelerated canvas.Filip Pavlis
07/27/2020, 5:03 PMfindRoot
or now called onRoot
is a testing API. if you don't need it for testing then my advise above does not apply (sorry for delay).Mantas Varnagiris
07/27/2020, 5:09 PMPiotr Prus
03/05/2021, 12:38 PMMantas Varnagiris
03/08/2021, 8:28 AM