Skip to content

Images and drawing

depthbomb edited this page Sep 22, 2026 · 1 revision

The image tools turn PNG, JPEG, or the first frame of a GIF into skribbl drawing commands. Install the images extra for the Python API, or cli for both the API and command-line tools.

Convert and preview

from asyncio import run
from skribblpy.images import generate_image, render_preview


async def main() -> None:
    image = await generate_image('photo.png', preset='optimized')
    await image.save('drawing.json')
    preview = await render_preview(image)
    await preview.save('preview.png')


if __name__ == '__main__':
    run(main())

The JSON stores commands and image metadata. The PNG is a local preview. Rendering uses an integer approximation, so browser antialiasing may look a little different.

Pick a preset

Preset What it does
cluster-dot The default. Converts colors and compresses them into brush runs.
yliluoma-1 Uses ordered dithering for intermediate tones, often with more commands.
optimized Compares rendered region, stripe, and dither plans under an optional budget.

The optimizer compares visual error, then drawing event bytes and command count to break ties. PNG or source file size doesn't drive that choice. It's the JSON sent to the server that matters.

Set a drawing budget

Both limits default to None, meaning unlimited within the 100,000-command ceiling. To set them explicitly:

image = await generate_image(
    'photo.png',
    preset='optimized',
    max_commands=4000,
    max_duration=15.0,
)

Use either limit or both. When you supply both, both apply. Budgets require preset='optimized'; the other presets reject them. A duration budget measures pacing delays, not network or server latency. It doesn't guarantee the server will finish displaying the drawing within that time.

To inspect the alternatives, call await optimize_image(...) from skribblpy.images. Its result includes the selected image, the selected plan name, and candidate quality scores, event payload sizes, command counts, and budget eligibility. await drawing_payload_bytes(image) measures paced DRAW event JSON, excluding the clear event and WebSocket/TLS framing.

Send it during your turn

Inside your application, once the client is the active drawer:

await client.send_image(image)

This clears the canvas and sends paced batches. send_drawing(commands) plays commands without clearing. Playback uses up to eight commands per batch with 33 ms between batches, and stops with ActionError if the drawing turn changes. Keep one playback active per client.

For manual commands, use DrawCommand.brush and DrawCommand.fill. PALETTE, CANVAS_WIDTH, and CANVAS_HEIGHT are exported from skribblpy. undo_drawing(retained) keeps the first retained commands; the argument is the count to keep.

Image buffers and file operations

await render_preview(image) returns an immutable RasterImage. Common operations are:

Operation Result
await RasterImage.load(path) Decode a source image.
await ImageData.load(path) Load and validate saved drawing JSON.
await raster.to_rgb() Composite transparency over white and return RGB pixels.
await raster.to_png() Encode PNG bytes.
await raster.save(path) Write a PNG preview.

Conversion, rendering, encoding, metrics, and file operations run off the event loop. Reading pixels, size, tobytes(), or getpixel() stays synchronous. getpixel() expects an RGB buffer, so call to_rgb() first for other modes.

Cancelling an image operation stops waiting for it. A worker or file write that's already running may still finish.

Command-line tools

Run these in your environment on Windows:

.venv\Scripts\python.exe -m skribblpy.cli generate --input photo.png --output drawing.json --preset optimized
.venv\Scripts\python.exe -m skribblpy.cli generate --input photo.png --output drawing.json --preset optimized --max-commands 4000
.venv\Scripts\python.exe -m skribblpy.cli preview --input drawing.json --output preview.png
.venv\Scripts\python.exe -m skribblpy.cli generate --help

On Linux and macOS, use .venv/bin/python. The installed skribbl-image command exposes the same options when your environment is active.

preview accepts a source image or saved drawing JSON. Budget options apply to source images; they don't rewrite a saved drawing.

Clone this wiki locally