Skip to content

Instantly share code, notes, and snippets.

@cmelchior
Created December 23, 2023 19:03
Show Gist options
  • Save cmelchior/5ebf2ed8c29b96b956d532ea2dd64eb5 to your computer and use it in GitHub Desktop.
Save cmelchior/5ebf2ed8c29b96b956d532ea2dd64eb5 to your computer and use it in GitHub Desktop.
Show how to capture a snapshot from a screen built using Compose inside Kotlin Notebooks
// JVM dependencies in build.gradle
val jvmMain by getting {
dependencies {
implementation(compose.desktop.currentOs)
implementation("org.jetbrains.skiko:skiko-awt-runtime-macos-arm64:+")
api(compose.preview)
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.desktop.uiTestJUnit4)
}
}
package dk.ilios.jervis.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asSkiaBitmap
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.runDesktopComposeUiTest
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import org.jetbrains.skia.Bitmap
import org.jetbrains.skia.Data
import org.jetbrains.skia.EncodedImageFormat
import org.jetbrains.skiko.toBufferedImage
import org.jetbrains.skiko.toImage
import java.awt.image.BufferedImage
import java.io.File
@Composable
fun Test(message: String) {
Box(
modifier = Modifier.background(color = Color.Gray).fillMaxSize().padding(16.dp),
contentAlignment = Alignment.Center
) {
Text(text = message, fontWeight = FontWeight.Thin, color = Color.White)
}
}
/**
* Easy entry point for taking snapshots that can be used by Kotlin Notebooks.
* This code must live inside a normal Gradle module, and can not be written
* directly inside the Notebook.
*/
object Imager {
/**
* Take a screenshot of a specific screen.
*/
fun testScreenshot(message: String, width: Int, height: Int): BufferedImage {
return renderScreenshot(width, height) {
Test(message)
}
}
/**
* Generic render function. Unfortunately it does not look it is possible to use
* Composables directly from Kotlin Notebook, so instead we need to add a helper
* method for each use case.
*/
@OptIn(ExperimentalTestApi::class)
fun renderScreenshot(width: Int, height: Int, renderView: @Composable () -> Unit): BufferedImage {
lateinit var image: BufferedImage
runDesktopComposeUiTest(width, height) {
setContent {
renderView()
}
val screenshot: Bitmap = this.captureToImage().asSkiaBitmap()
image = screenshot.toBufferedImage()
}
return image
}
/**
* Optionally save the screenshot to a file
*/
fun saveScreenshot(image: BufferedImage, name: String): File {
val file = File.createTempFile(name, ".png")
val img: Data? = image.toImage().encodeToData(EncodedImageFormat.PNG)
file.outputStream().use { stream ->
stream.write(img!!.bytes)
}
return file
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment