
Interactive canvas component enabling freehand and shape drawing with customizable background, stroke size, color/opacity, eraser, fill, eyedropper, spray, undo/redo, bitmap import/export.
Building on the work of Mark Yavorskyi's DrawBox, DrawBox Enhanced is a Compose Multiplatform library to quickly and easily provide a canvas for your users to draw on.
Planned features:
Using Gradle Kotlin DSL:
implementation("uk.codecymru.drawbox:DrawBox-Enhanced:2.1.2")val controller = remember { DrawController() }
DrawBox(drawController = controller, modifier = Modifier.fillMaxSize())Configuring settings
// The following optional parameters can be set to
val controller = remember {
DrawController(
startingTool = CanvasTool.BRUSH,
startingOpacity = 1f,
startingStrokeWidth = 10f,
startingColor = Color.Red,
startingBackground = DrawBoxBackground.NoBackground,
startingCanvasOpacity = 1f
)
}Enabling undo/redo
val enableUndo by controller.canUndo.collectAsState(false)
val enableRedo by controller.canRedo.collectAsState(false)
// Then create a button for each:
IconButton(onClick = controller::undo, enabled = enableUndo) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "undo")
}
IconButton(onClick = controller::redo, enabled = enableRedo) {
Icon(imageVector = Icons.Default.ArrowForward, contentDescription = "redo")
}Switching tools
// To see the current tool
val tool by controller.canvasTool.collectAsState()
// To set the current tool, as an example:
TextButton(onClick = { controller.canvasTool.value = CanvasTool.BRUSH }) {
Text("Brush")
}
TextButton(onClick = { controller.canvasTool.value = CanvasTool.ERASER }) {
Text("Eraser")
}
// etc...Importing a bitmap
val bitmap: ImageBitmap = /* (...) */
drawController.open(bitmap)Exporting a bitmap
// This provides the up-to-date drawn bitmap
controller.internalBitmap
// As an example, on the JVM target we could save this via:
TextButton(onClick = { saveImage(controller.internalBitmap) }) {
Text("Save")
}
fun saveImage(bitmap: ImageBitmap) {
val dialog = FileDialog(null as Frame?, "Save Image", FileDialog.SAVE)
dialog.file = "image.png"
dialog.isVisible = true
val directory = dialog.directory
val fileName = dialog.file
if (directory != null && fileName != null) {
val file = File(directory, fileName)
ImageIO.write(
bitmap.toAwtImage(),
"png",
file
)
}
}Creating another viewer
// FinishDrawingUpdate means that this viewer won't show the user any in-progress strokes as they draw
DrawBoxViewer(
controller = controller,
subscription = DrawBoxSubscription.FinishDrawingUpdate,
modifier = Modifier.size(200.dp).border(width = 1.dp, color = Color.Red)
)Two useful samples of this library's basic usage can be found, written by Mark, in the sample package:
For example projects, see the following:
The original project was created by Mark Yavorskyi, with the Enhanced edition being created by Cyrus Castle
I love my work. The idea of creating this open-source project appeared because I needed a multiplatform (Android + desktop) library for drawing. I found several popular libs for Android but there was ZERO for using in KMM/KMP. I still have some aspects to improve and I will be happy if you share your feedback or propose an idea!
Hope you enjoy it!
Mark
Licensed under the Apache License, Version 2.0, click here for the full license.
Building on the work of Mark Yavorskyi's DrawBox, DrawBox Enhanced is a Compose Multiplatform library to quickly and easily provide a canvas for your users to draw on.
Planned features:
Using Gradle Kotlin DSL:
implementation("uk.codecymru.drawbox:DrawBox-Enhanced:2.1.2")val controller = remember { DrawController() }
DrawBox(drawController = controller, modifier = Modifier.fillMaxSize())Configuring settings
// The following optional parameters can be set to
val controller = remember {
DrawController(
startingTool = CanvasTool.BRUSH,
startingOpacity = 1f,
startingStrokeWidth = 10f,
startingColor = Color.Red,
startingBackground = DrawBoxBackground.NoBackground,
startingCanvasOpacity = 1f
)
}Enabling undo/redo
val enableUndo by controller.canUndo.collectAsState(false)
val enableRedo by controller.canRedo.collectAsState(false)
// Then create a button for each:
IconButton(onClick = controller::undo, enabled = enableUndo) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "undo")
}
IconButton(onClick = controller::redo, enabled = enableRedo) {
Icon(imageVector = Icons.Default.ArrowForward, contentDescription = "redo")
}Switching tools
// To see the current tool
val tool by controller.canvasTool.collectAsState()
// To set the current tool, as an example:
TextButton(onClick = { controller.canvasTool.value = CanvasTool.BRUSH }) {
Text("Brush")
}
TextButton(onClick = { controller.canvasTool.value = CanvasTool.ERASER }) {
Text("Eraser")
}
// etc...Importing a bitmap
val bitmap: ImageBitmap = /* (...) */
drawController.open(bitmap)Exporting a bitmap
// This provides the up-to-date drawn bitmap
controller.internalBitmap
// As an example, on the JVM target we could save this via:
TextButton(onClick = { saveImage(controller.internalBitmap) }) {
Text("Save")
}
fun saveImage(bitmap: ImageBitmap) {
val dialog = FileDialog(null as Frame?, "Save Image", FileDialog.SAVE)
dialog.file = "image.png"
dialog.isVisible = true
val directory = dialog.directory
val fileName = dialog.file
if (directory != null && fileName != null) {
val file = File(directory, fileName)
ImageIO.write(
bitmap.toAwtImage(),
"png",
file
)
}
}Creating another viewer
// FinishDrawingUpdate means that this viewer won't show the user any in-progress strokes as they draw
DrawBoxViewer(
controller = controller,
subscription = DrawBoxSubscription.FinishDrawingUpdate,
modifier = Modifier.size(200.dp).border(width = 1.dp, color = Color.Red)
)Two useful samples of this library's basic usage can be found, written by Mark, in the sample package:
For example projects, see the following:
The original project was created by Mark Yavorskyi, with the Enhanced edition being created by Cyrus Castle
I love my work. The idea of creating this open-source project appeared because I needed a multiplatform (Android + desktop) library for drawing. I found several popular libs for Android but there was ZERO for using in KMM/KMP. I still have some aspects to improve and I will be happy if you share your feedback or propose an idea!
Hope you enjoy it!
Mark
Licensed under the Apache License, Version 2.0, click here for the full license.