mypaint_ffi

A Flutter FFI plugin that wraps libmypaint to paint MyPaint brush strokes onto a pixel surface.

Android only. This plugin builds libmypaint from source with the Android NDK and exposes it through dart:ffi. No iOS, macOS, Windows, Linux, or web support is provided.

Features

  • Paint brush strokes with pressure and tilt onto a fixed-size RGBA surface.
  • Load MyPaint .myb brushes from JSON strings.
  • Set brush base values (radius, hardness, opacity, eraser, …) and color.
  • Render the surface to a ui.Image, converting only the dirty region each frame for performance.

Project structure

  • src: The native glue (mypaint_ffi.c / mypaint_ffi.h), built into libmypaint_ffi.so by src/CMakeLists.txt.
  • src/third_party: libmypaint, json-c and mypaint-brushes as git submodules, pinned to known-good commits.
  • src/libmypaint_shim: libmypaint's config.h and pre-generated *-gen.h headers, kept here (not in the submodule) because libmypaint's own .gitignore excludes them.
  • lib: The Dart API (mypaint_ffi.dart) and the hand-written dart:ffi bindings (mypaint_ffi_bindings_generated.dart).
  • android: The Gradle/NDK build that compiles the native library and bundles it into the app's APK.
  • example: A small painting app demonstrating the plugin.

Bindings

The native API surface is small, so the dart:ffi bindings in lib/mypaint_ffi_bindings_generated.dart are maintained by hand rather than generated with package:ffigen (which would require a host LLVM/libclang install). When you change src/mypaint_ffi.h, update those bindings to match.

Usage

final engine = BrushEngine(
  surface: MyPaintSurface(width, height),
  brush: Brush()..loadFromString(mybJson)..setColor(0, 0, 0),
);

engine.surface.beginAtomic();
engine.strokeTo(x, y, pressure: 0.8);
engine.surface.endAtomic();

final ui.Image image = await engine.surface.toImage();

See example/lib/main.dart for a full painting screen, including a brush picker over the bundled MyPaint brush sets.

Building

Clone with submodules

The libmypaint, json-c and mypaint-brushes sources live in src/third_party as git submodules, so clone recursively:

git clone --recursive https://github.com/dima-xd/mypaint_ffi.git

If you already cloned without --recursive, pull the submodules in:

git submodule update --init --recursive

To update the vendored sources to their latest upstream commits later:

git submodule update --remote

Build

The native library is built automatically by the Android Gradle plugin when you run the app; no manual step is required. The build is driven by android/build.gradle, which invokes CMake (src/CMakeLists.txt) with the Android NDK for each target ABI. To build the example app:

cd example
flutter run            # or: flutter build apk

Libraries

mypaint_ffi
Dart wrapper around libmypaint for Flutter.
mypaint_ffi_bindings_generated