@@ -36,6 +36,7 @@ import androidx.compose.ui.unit.IntSize
3636import androidx.compose.ui.unit.LayoutDirection
3737import androidx.compose.ui.util.fastAll
3838import androidx.compose.ui.awt.UNSPECIFIED_DIMENSION_VALUE
39+ import androidx.compose.ui.unit.union
3940import androidx.compose.ui.util.fastForEach
4041import androidx.compose.ui.util.fastForEachReversed
4142import androidx.compose.ui.util.fastRoundToInt
@@ -58,14 +59,14 @@ import java.awt.event.MouseEvent as AwtMouseEvent
5859import java.awt.event.WindowEvent
5960import java.awt.event.WindowFocusListener
6061import java.awt.event.WindowListener
62+ import java.awt.image.BufferedImage
6163import javax.swing.JLayeredPane
6264import javax.swing.SwingUtilities
6365import kotlin.coroutines.AbstractCoroutineContextElement
6466import kotlin.coroutines.CoroutineContext
6567import kotlin.coroutines.EmptyCoroutineContext
6668import kotlin.math.ceil
6769import kotlinx.coroutines.CoroutineExceptionHandler
68- import kotlinx.coroutines.Job
6970import org.jetbrains.annotations.VisibleForTesting
7071import org.jetbrains.skia.Canvas
7172import org.jetbrains.skiko.MainUIDispatcher
@@ -621,6 +622,42 @@ internal class ComposeContainer(
621622 override fun shouldSendMouseEvent (event : AwtMouseEvent ): Boolean = noBlockingInputLayers
622623 override fun shouldSendKeyEvent (event : AwtKeyEvent ): Boolean = noBlockingInputLayers
623624 }
625+
626+ /* *
627+ * Captures the content of this container into an image.
628+ *
629+ * Returns `null` if the window has not been made visible yet.
630+ *
631+ * This may be called only on the event dispatch thread.
632+ */
633+ fun captureContentToImage (): BufferedImage ? {
634+ val mainLayerBounds = mediator.boundsOnScreenPx() ? : return null
635+ val layersAndBounds = layers.map {
636+ it to it.boundsOnScreenPx()
637+ }
638+
639+ var resultBounds = mainLayerBounds
640+ for ((_, bounds) in layersAndBounds) {
641+ if (bounds != null ) {
642+ resultBounds = resultBounds.union(bounds)
643+ }
644+ }
645+
646+ val x = resultBounds.left
647+ val y = resultBounds.top
648+ val width = resultBounds.width
649+ val height = resultBounds.height
650+
651+ val image = BufferedImage (width, height, BufferedImage .TYPE_INT_ARGB )
652+ mediator.drawContentInto(image, mainLayerBounds.left - x, mainLayerBounds.top - y)
653+ for ((layer, bounds) in layersAndBounds) {
654+ if (bounds == null ) continue
655+ // The offset is from mainLayerBounds because layers draw themselves relative to it
656+ layer.drawContentInto(image, mainLayerBounds.left - x, mainLayerBounds.top - y)
657+ }
658+
659+ return image
660+ }
624661}
625662
626663/* *
0 commit comments