-
-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possible to capture Composables not visible on screen #33
Comments
From what I've seen is not possible, would be nice to have that option though :) @PatilShreyas wdyt? |
Maybe using something like a canvas or a graphics context, I don't know if it's really possible. But has great advantages in doing so, sometimes the app has the need to generate another version of a shown component. |
I had the same problem, I had to create another screen for the desired image capturing |
If something which is not yet rendered on screen then it's not possible to capture. This is not case only limited to compose but it's also not possible in View as well. |
hey @PatilShreyas, in fact, it is possible to render even if the view (regular Android view not compose) hasn't been laid out yet, but for compose I think it's not possible so far. |
Can you describe how this solution using View could work? Maybe we can abstract away from Jetpack Compose and use AndroidView or something like that. Do you think it's possible? |
sure, I'll write a snippet over the weekend and will share it here |
Creating a As for Compose, there would be a way to capture a |
could you check this library https://github.com/guhungry/android-photo-manipulator I can overlay images or text on each other without showing on screen.
|
I see someone has done it on StackOverflow https://stackoverflow.com/a/74814850/6745085 |
Maybe something to follow along with https://issuetracker.google.com/issues/288494724 |
Let's keep an eye on it 👁️ |
I tried it with a hack for a quick workaround and explained it here: https://stackoverflow.com/a/78170757/11326621 There's a way for it to capture the composable content by rendering composable content into an Invisible window and capturing it secretly from there. Create a invisible composable@Composable
fun InvisibleContent(content: @Composable () -> Unit) {
val context = LocalContext.current
val windowManager = context.getSystemService<WindowManager>()!!
DisposableEffect(key1 = content) {
val composeView = ComposeView(context).apply {
setParentCompositionContext(null)
setContent {
content()
}
setOwners(context.findActivity())
}
windowManager.addView(
/* view = */ composeView,
/* params = */ WindowManager.LayoutParams(
/* w = */ WindowManager.LayoutParams.WRAP_CONTENT,
/* h = */ WindowManager.LayoutParams.WRAP_CONTENT,
/* _type = */ WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
/* _flags = */ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
/* _format = */ PixelFormat.TRANSLUCENT
)
)
onDispose { windowManager.removeView(composeView) }
}
}
private fun View.setOwners(fromActivity: ComponentActivity) {
if (findViewTreeLifecycleOwner() == null) {
setViewTreeLifecycleOwner(fromActivity)
}
if (findViewTreeViewModelStoreOwner() == null) {
setViewTreeViewModelStoreOwner(fromActivity)
}
if (findViewTreeSavedStateRegistryOwner() == null) {
setViewTreeSavedStateRegistryOwner(fromActivity)
}
}
/**
* Traverses through this [Context] and finds [Activity] wrapped inside it.
*/
private fun Context.findActivity(): ComponentActivity {
var context = this
while (context is ContextWrapper) {
if (context is ComponentActivity) return context
context = context.baseContext
}
throw IllegalStateException("Unable to retrieve Activity from the current context")
} Usage@Composable
fun CaptureDemo() {
val captureController = rememberCaptureController()
val uiScope = rememberCoroutineScope()
InvisibleContent {
Ticket(modifier = Modifier.capturable(captureController))
}
Button(
onClick = {
uiScope.launch {
ticketBitmap = captureController.captureAsync().await()
}
}
) {
Text("Preview Ticket Image")
}
} Here, the content of the I've tried this and it works. Let me know your thoughts and if it works for you. |
I think this API allows this without all your window manager code You can create a new graphics layer, the draw into it as well as or instead of the content
But I'd have to try to confirm. |
But I think this will occupy a space in UI. We don't want that. |
Let me see if that can be avoided. I suspect it can. |
Yeah, I couldn't get it working. I was trying to create a new graphics layer, and a modifier to avoid drawing to the screen, and then either capture a bitmap with beginRecording, or just draw to the new layer and write that to a canvas/ImageBitmap. But it's still treating the Composables as part of the main composition, so I can't actually change the size to something greater. I suspect I need non landed CLs to get this working. https://android-review.googlesource.com/c/platform/frameworks/support/+/2969199/4 |
The content in InvisibleContent is displayed at the front of the screen |
Is it possible to capture another version of a Composable just to the Capturable and capture a bitmap?
The text was updated successfully, but these errors were encountered: