[![official project](http://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![version](https://img.shields.io/badge/dynamic/json.svg?color=orange&label=latest%20version&query=%24.tag_name&url=https%3A%2F%2Fgithub.com%2FJetBrains%2Fskiko%2Freleases%2Flatest)](https://github.com/JetBrains/skiko/releases/latest)
# Kotlin Multiplatform library for Skia and window management #

Skiko (short for Skia for Kotlin) is the graphical library exposing significant part
of [Skia library](https://skia.org) APIs to Kotlin, along with the gluing code for rendering context.

Supported platforms:
   * Kotlin/JVM on Linux(x86_64 and arm64)
   * Kotlin/JVM on Windows(x86_64)
   * Kotlin/JVM on macOS(x86_64 and arm64)
   * Kotlin/JVM on Android(x86_64 and arm64), starting with API version 24
   * Kotlin/JS + WebAssembly in browsers
   * Kotlin/Native on iOS(arm64 and x64)
   * Kotlin/Native on macOS (arm64 and x64)

## API documentation

 See autogenerated API docs at [https://jetbrains.github.io/skiko/](https://jetbrains.github.io/skiko/)

## Using as dependency

To use in build scripts one has to compute appropriate target platform and version,
i.e. something like this

```kotlin
    repositories {
        mavenCentral()
        maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
    }

    val osName = System.getProperty("os.name")
    val targetOs = when {
        osName == "Mac OS X" -> "macos"
        osName.startsWith("Win") -> "windows"
        osName.startsWith("Linux") -> "linux"
        else -> error("Unsupported OS: $osName")
    }

    val osArch = System.getProperty("os.arch")
    var targetArch = when (osArch) {
        "x86_64", "amd64" -> "x64"
        "aarch64" -> "arm64"
        else -> error("Unsupported arch: $osArch")
    }

    val version = "0.7.9" // or any more recent version
    val target = "${targetOs}-${targetArch}"
    dependencies {
        implementation("org.jetbrains.skiko:skiko-awt-runtime-$target:$version")
    }
```

Simple example for Kotlin/JVM
```kotlin
fun main() {
    val skiaLayer = SkiaLayer()
    skiaLayer.skikoView = GenericSkikoView(skiaLayer, object : SkikoView {
        val paint = Paint().apply {
            color = Color.RED
        }
        override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
            canvas.clear(Color.CYAN)
            val ts = nanoTime / 5_000_000
            canvas.drawCircle( (ts % width).toFloat(), (ts % height).toFloat(), 20f, paint )
        }
    })
    SwingUtilities.invokeLater {
        val window = JFrame("Skiko example").apply {
            defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
            preferredSize = Dimension(800, 600)
        }
        skiaLayer.attachTo(window.contentPane)
        skiaLayer.needRedraw()
        window.pack()
        window.isVisible = true
    }
}
```

Simple example for iOS
```kotlin
fun main() {
    val args = emptyArray<String>()
    memScoped {
        val argc = args.size + 1
        val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues()
        autoreleasepool {
            UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate))
        }
    }
}

class SkikoAppDelegate : UIResponder, UIApplicationDelegateProtocol {
    companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta

    @ObjCObjectBase.OverrideInit
    constructor() : super()

    private var _window: UIWindow? = null
    override fun window() = _window
    override fun setWindow(window: UIWindow?) {
        _window = window
    }

    override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map<Any?, *>?): Boolean {
        window = UIWindow(frame = UIScreen.mainScreen.bounds)
        window!!.rootViewController = SkikoViewController(
            SkikoUIView(
                SkiaLayer().apply {
                    gesturesToListen = SkikoGestureEventKind.values()
                    skikoView = GenericSkikoView(skiaLayer, object : SkikoView {
                      val paint = Paint().apply { color = Color.RED }
                      override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
                        canvas.clear(Color.CYAN)
                        val ts = nanoTime / 5_000_000
                        canvas.drawCircle( (ts % width).toFloat(), (ts % height).toFloat(), 20f, paint )
                      }
                    })
                }
            )
        )
        window!!.makeKeyAndVisible()
        return true
    }
}
```
See this [sample](/samples/SkiaMultiplatformSample) for complete example.

To use latest development snapshot use version `0.0.0-SNAPSHOT`.

