🎨 Jetpack Compose canvas library that helps you draw paths and images on canvas with color pickers and palettes. Sketchbook also provides useful components and functions that can easily interact with canvas.
## Preview
## Contribution 💙
Sketchbook is maintained by __[Stream](https://getstream.io/)__.
If you’re interested in adding powerful In-App Messaging to your app, check out the __[Stream Chat Tutorial for Jetpack Compose](https://getstream.io/chat/compose/tutorial/?utm_source=Github&utm_campaign=Devrel_oss&utm_medium=sketchbook)__!
Also, anyone can contribute to improving code, docs, or something following our [Contributing Guideline](/CONTRIBUTING.md).
## Download
[![Maven Central](https://img.shields.io/maven-central/v/io.getstream/sketchbook.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22io.getstream%22%20AND%20a:%sketchbook%22)
### Gradle
Add the dependency below to your **module**'s `build.gradle` file:
```gradle
dependencies {
implementation "io.getstream:sketchbook:1.0.4"
}
```
## SNAPSHOT
See how to import the snapshot
### Including the SNAPSHOT
Snapshots of the current development version of Sketchbook are available, which track [the latest versions](https://oss.sonatype.org/content/repositories/snapshots/io/getstream/sketchbook/).
To import snapshot versions on your project, add the code snippet below on your gradle file.
```Gradle
repositories {
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
```
Next, add the below dependency to your **module**'s `build.gradle` file.
```gradle
dependencies {
implementation "io.getstream:sketchbook:1.0.5-SNAPSHOT"
}
```
## Usage
First, you should initialize `SketchbookController`, which allows you to control the `Sketchbook` and all components.
```kotlin
private val sketchbookController = rememberSketchbookController()
```
Next, you can implement your drawing canvas with the `Sketchbook` composable function:
```kotlin
Sketchbook(
modifier = Modifier.fillMaxSize(),
controller = sketchbookController,
backgroundColor = Color.White
)
```
### Sketchbook
**Sketchbook** implements canvas, which allows you to draw paths with custom properties. It interacts with **SketchbookController** to control other components.
You can use the `Sketchbook` as the following example:
```kotlin
Sketchbook(
modifier = Modifier.fillMaxSize(),
controller = sketchbookController,
backgroundColor = Color.White,
onEventListener = { x, y -> .. },
onRevisedListener = { canUndo, canRedo -> .. }
)
```
### SketchbookController
**SketchbookController** interacts with `Sketchbook` and it allows you to control the canvas and all of the components with it.
#### Undo and Redo
`SketchbookController` supports `undo` and `redo` to cancel or reverse drawn paths and recover the previous canvas state.
You can implement it with the following functions below:
```kotlin
sketchbookController.undo() // undo the drawn path if possible.
sketchbookController.redo() // redo the drawn path if possible.
```
#### Erase Mode
By enabling Erase Mode, you can erase the colored paths following the transparent path. You can set the mode with the function below:
```kotlin
sketchbookController.setEraseMode(true)
```
Also, you can toggle the erase mode with the following function below:
```kotlin
sketchbookController.toggleEraseMode()
```
You can get the `State` of the erase mode with the following function below:
```kotlin
val isEraseMode = sketchbookController.isEraseMode.value
```
> **Note**: If you use the erase mode, make sure you set the `backgroundColor` on the `Sketchbook` properly.
You can changes the radius size of the erase circle:
```kotlin
sketchbookController.setEraseRadius(50f)
```
#### Customize Paint
You can custom the paint to support various drawing options as the following:
```kotlin
.setPaintColor(color)
.setPaintAlpha(alpha)
.setPaintStrokeWidth(stroke)
.setPaintShader(shader)
.setLinearShader(colorList)
.setPaintingStyle(paintStyle)
.setPathEffect(pathEffect)
```
Also, you can set your own paint with the `setPaint` method:
```kotlin
sketchbookController.setPaint(paint)
```
You can set the rainbow shader to the paint with the `setRainbowShader` method:
```kotlin
sketchbookController.setRainbowShader()
```
#### ImageBitmap
Sketchbook supports to set an `ImageBitmp` on the canvas and draw paths over the bitmap. You can set an initial `ImageBitmap` on the `Sketchbook` composable as the following:
```kotlin
Sketchbook(
imageBitmap = ImageBitmap.imageResource(R.drawable.poster),
..
)
```
Also, you can set an `ImageBitmap` dynamically with the `SketchbookController` as the following:
```kotlin
sketchbookController.setImageBitmap(imageBitmap)
```
You can clear the image bitmap on canvas with the `clearImageBitmap` method:
```kotlin
sketchbookController.clearImageBitmap()
```
> **Note**: This demo project demonstrates an image picker with [ModernStorage's Photo Picker](https://google.github.io/modernstorage/photopicker/).
#### Sketchbook Bitmap
You can get the final `ImageBitmap` of the current canvas of the `Sketchbook` with the following:
```kotlin
val imageBitmap = sketchbookController.getSketchbookBitmap()
```
If you'd like to get the Android's bitmap, you can get it as the following:
```kotlin
val bitmap = sketchbookController.getSketchbookBitmap().asAndroidBitmap()
```
#### Clear
You can clear all the drawn paths and paths and the image bitmap as the following:
```kotlin
sketchbookController.clear()
```
Also, you can clear only the drawn paths and redo paths as the following:
```kotlin
sketchbookController.clearPaths()
```
### PaintColorPalette
**PaintColorPalette** provides a color palette to let users choose desired colors from a provided color list.
It provides default color palettes and shapes, which are fully customizable. You can simply implement this as the following example:
```kotlin
PaintColorPalette(
controller = sketchbookController,
borderColor = MaterialTheme.colors.onPrimary
)
```
You can customize UI themes with `PaintColorPaletteTheme` as the following example:
```kotlin
PaintColorPalette(
theme = PaintColorPaletteTheme(
shape = CircleShape,
itemSize = 48.dp,
selectedItemSize = 58.dp,
borderColor = Color.White,
borderWidth = 2.dp,
borderColor = MaterialTheme.colors.onPrimary
),
```
Also, you can set an index for selecting a color initially with the `initialSelectedIndex` parameter:
```kotlin
initialSelectedIndex = 2
```
#### onColorSelected
You can track the selected color's index and color value with the `onColorSelected` listener:
```kotlin
PaintColorPalette(
onColorSelected = { index, color -> .. },
)
```
#### Header and Footer
You can add your own composable on the very first of the palette or on the end as the following example:
```kotlin
PaintColorPalette(
header = { Text("Header") },
footer = { Text("Footer") }
)
```
#### Custom Content
You can customize the entire content with your own composable as the following example:
```kotlin
PaintColorPalette(
content = { index, color ->
Box(modifier = Modifier
.size(60.dp)
.background(color)
.clickable { .. }
)
}
)
```
> **Note**: Make sure if you use the custom content, you should implement all interactions and listeners by yourself.
### ColorPickerDialog
Sketchbook supports `ColorPickerDialog`, which lets you choose your desired color from an HSV color palette.
You can implement `ColorPickerDialog` with the following codes:
```kotlin
val expandColorPickerDialog = remember { mutableStateOf(false) }
Image(
modifier =
Modifier.clickable { expandColorPickerDialog.value = true },
bitmap = ImageBitmap.imageResource(R.drawable.palette),
contentDescription = null
)
ColorPickerDialog(
controller = sketchbookController,
expanded = expandColorPickerDialog,
initialColor = controller.currentPaintColor.value,
onColorSelected = { color ->
controller.setPaintShader(null)
controller.setSelectedColorIndex(-1)
}
)
```
### ColorPickerPaletteIcon
`ColorPickerPaletteIcon` implements the example code above internally, so you can use like an icon, which shows up a color picker dialog as the following example:
```kotlin
ColorPickerPaletteIcon(
modifier = Modifier
.size(60.dp)
.padding(6.dp),
controller = sketchbookController,
bitmap = ImageBitmap.imageResource(R.drawable.palette)
)
```
You can use the `ColorPickerPaletteIcon` with `hearder` or `footer` custom composable for the `PaintColorPalette`.
```kotlin
PaintColorPalette(
header = {
ColorPickerPaletteIcon(
..
)
}
)
```
## Find this library useful? :heart:
Support it by joining __[stargazers](https://github.com/getStream/sketchbook-compose/stargazers)__ for this repository. :star:
Also, follow **[Stream](https://twitter.com/getstream_io)** on Twitter for our next creations!
# License
```xml
Copyright 2022 Stream.IO, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```