Lume

High-performance image manipulation for Flutter, powered by Rust.

Lume provides a fluent, chainable API for image processing through Rust's image and imageproc libraries via Flutter Rust Bridge.

Overview

Two main interfaces:

  • LumeImage — Basic operations: resize, crop, rotate, color adjustments, format conversion.
  • LumeCanvas — Advanced processing: edge detection, filters, morphology, computer vision, drawing.
import 'package:lume/lume.dart';

// Basic: load, resize, convert to grayscale
final img = LumeImage.fromFile(file)
  .resize(width: 800, height: 600)
  .grayscale()
  .toPng();

// Advanced: Canny edge detection + drawing
final processed = LumeCanvas(img)
  .canny(low: 50, high: 150)
  .drawFilledCircle(cx: 100, cy: 100, radius: 30, color: Colors.red)
  .toLumeImage();

// Use in Flutter widgets
LumeImageWidget(image: processed, fit: BoxFit.cover);

Installation

Add to pubspec.yaml:

dependencies:
  lume:
    path: ./lume # or from pub.dev when published

Run:

flutter pub get

LumeImage — Basic Operations

Factories

Method Description
LumeImage.fromBytes(Uint8List bytes) From raw encoded bytes (PNG, JPEG, WebP, etc.)
LumeImage.fromFile(File file) From file (sync)
LumeImage.fromFileAsync(File file) From file (async)
LumeImage.fromPath(String path) From path string (sync)
LumeImage.fromPathAsync(String path) From path string (async)
LumeImage.fromAsset(String assetPath) From Flutter asset
LumeImage.blank({width, height, r, g, b, a}) Create blank image
LumeImage.from(LumeImage other) Copy constructor

Accessors

Uint8List bytes = img.bytes;    // Raw encoded bytes
int width = img.width;          // Image width
int height = img.height;        // Image height
String format = img.format;     // Format (png, jpeg, etc.)
int size = img.sizeBytes;       // Size in bytes
LumeImageInfo info = img.info;  // Full metadata

Transform Operations

// Resize
img.resize(width: 800, height: 600, keepAspectRatio: true);
img.resizeWithFilter(width: 800, height: 600, filter: 'lanczos3');
img.thumbnail(maxWidth: 300, maxHeight: 300);
img.thumbnailExact(width: 200, height: 200);

// Crop
img.crop(x: 100, y: 100, width: 400, height: 400);

// Rotate & Flip
img.rotate(degrees: 90);   // 90, 180, 270
img.flipHorizontal();
img.flipVertical();

// Compose
img.overlay(otherImage, x: 50, y: 50);
img.tile(cols: 3, rows: 2);

Color Operations

img.grayscale();
img.adjustBrightness(30);      // Positive = brighter
img.adjustContrast(0.5);       // >0 = more contrast
img.blur(sigma: 2.0);
img.sharpen(sigma: 1.0, threshold: 10);
img.invertColors();
img.hueRotate(degrees: 45);

Format Conversion

img.convertFormat('png');
img.toPng();
img.toJpeg();
img.toWebp();

Persistence

// Async
await img.writeToFile(file);
await img.saveTo('/path/to/output.png');

// Sync
img.writeToFileSync(file);
img.saveToSync('/path/to/output.png');

LumeCanvas — Advanced Processing

Filters

LumeCanvas(img)
  .gaussianBlur(sigma: 2.0)
  .medianFilter(xRadius: 2, yRadius: 2)
  .bilateralFilter(windowSize: 5, sigmaColor: 10.0, sigmaSpatial: 10.0)
  .boxFilter(xRadius: 3, yRadius: 3)
  .sharpen3x3()
  .sharpenGaussian(sigma: 1.0, amount: 2.0)
  .laplacianFilter()
  .toLumeImage();

Edge Detection

LumeCanvas(img)
  .canny(low: 50, high: 150)      // Canny edge detector
  .sobelGradients()                // Sobel gradients
  .toLumeImage();

Contrast & Threshold

LumeCanvas(img)
  .adaptiveThreshold(blockRadius: 5)
  .otsuThreshold()
  .threshold(value: 128, invert: false)
  .equalizeHistogram()
  .stretchContrast(
    inputLower: 50,
    inputUpper: 200,
    outputLower: 0,
    outputUpper: 255,
  )
  .toLumeImage();

Morphology

LumeCanvas(img)
  .dilate(radius: 2)               // Expand white regions
  .erode(radius: 2)                // Shrink white regions
  .morphologicalOpen(radius: 3)    // Erode then dilate
  .morphologicalClose(radius: 3)   // Dilate then erode
  .toLumeImage();

Geometric Transformations

LumeCanvas(img)
  .rotateAboutCenter(theta: 0.5, backgroundColor: Colors.black)
  .translate(tx: 50, ty: -30)
  .toLumeImage();

Noise

LumeCanvas(img)
  .gaussianNoise(mean: 0.0, stddev: 20.0, seed: BigInt.from(42))
  .saltAndPepperNoise(rate: 0.05, seed: BigInt.from(123))
  .toLumeImage();

Seam Carving

// Content-aware width reduction
LumeCanvas(img).seamCarveWidth(newWidth: 400).toLumeImage();

Drawing

LumeCanvas(img)
  // Lines
  .drawLine(x1: 0, y1: 0, x2: 100, y2: 100, color: Colors.red)
  .drawAntialiasedLine(x1: 0, y1: 0, x2: 100, y2: 100, color: Colors.blue)

  // Rectangles
  .drawHollowRect(x: 10, y: 10, width: 100, height: 50, color: Colors.green)
  .drawFilledRect(x: 10, y: 10, width: 100, height: 50, color: Colors.yellow)

  // Circles
  .drawHollowCircle(cx: 100, cy: 100, radius: 50, color: Colors.purple)
  .drawFilledCircle(cx: 100, cy: 100, radius: 50, color: Colors.orange)

  // Ellipses
  .drawHollowEllipse(cx: 100, cy: 100, widthRadius: 80, heightRadius: 40, color: Colors.cyan)
  .drawFilledEllipse(cx: 100, cy: 100, widthRadius: 80, heightRadius: 40, color: Colors.pink)

  // Polygons
  .drawFilledPolygon(points: [(0, 0), (100, 0), (50, 100)], color: Colors.teal)
  .drawHollowPolygon(points: [(0, 0), (100, 0), (50, 100)], color: Colors.indigo)

  // Curves
  .drawCubicBezier(
    startX: 0, startY: 0,
    endX: 200, endY: 200,
    ctrl1X: 50, ctrl1Y: 100,
    ctrl2X: 150, ctrl2Y: 50,
    color: Colors.brown,
  )

  // Markers
  .drawCross(cx: 100, cy: 100, color: Colors.white)

  .toLumeImage();

Computer Vision / Analysis

// Find contours
List<LumeContour> contours = LumeCanvas(binaryImg).findContours();

// Distance transform
LumeImage distance = LumeCanvas(img).distanceTransform().toLumeImage();

Flutter Integration

LumeImageProvider

Use LumeImage with any Flutter widget that accepts an ImageProvider:

Image(image: LumeImageProvider(myLumeImage));
DecorationImage(image: LumeImageProvider(myLumeImage), fit: BoxFit.cover);
CircleAvatar(backgroundImage: LumeImageProvider(myLumeImage));

LumeImageWidget

Convenience widget with common Image parameters:

LumeImageWidget(
  image: myLumeImage,
  fit: BoxFit.cover,
  width: 300,
  height: 200,
);

Chainable API

Both LumeImage and LumeCanvas are immutable — each operation returns a new instance:

// Branch pipelines freely
final original = LumeImage.fromFile(file);

final small = original.thumbnail(maxWidth: 100, maxHeight: 100);
final grayscale = original.grayscale();
final edges = LumeCanvas(original).canny(low: 50, high: 150).toLumeImage();

// Original is unchanged

Example Showcase

The example app demonstrates all operations with visual before/after comparisons:

Gallery Basic Transforms Color Operations

Main menu with all demos

Resize, crop, rotate, flip

Grayscale, brightness, contrast
Filters (imageproc) Edge Detection Morphology

Gaussian blur, sharpen, laplacian

Canny, sobel, threshold

Dilate, erode, open, close
Drawing Primitives Compose & Tile Format Conversion

Lines, circles, rects, bézier

Overlay and tile operations

PNG, JPEG, BMP sizes

To run the example:

cd example
flutter pub get
flutter run

Technical Details

  • Rust libraries: image 0.25, imageproc 0.25
  • Bridge: Flutter Rust Bridge 2.11.1
  • Data transfer: Uint8List / Vec<u8> — zero-copy where possible
  • Sync operations: Most operations are synchronous for better performance
  • Formats supported: PNG, JPEG, GIF, WebP, BMP, TIFF, ICO

License

MIT

Libraries

lume
Lume — high-performance image manipulation powered by Rust.