scribe_canvas 0.5.0 copy "scribe_canvas: ^0.5.0" to clipboard
scribe_canvas: ^0.5.0 copied to clipboard

A high-performance Flutter multi-page canvas library for handwriting, drawing, and annotation with customizable tools and PDF export.

scribe_canvas #

A high-performance Flutter multi-page canvas library for handwriting, drawing, and annotation. Scribe handles multiple A4-sized pages with smooth variable-width strokes, customizable tools, PDF export, and a clean Controller-based API.

Features #

  • 📄 Multi-page Canvas — Multiple A4-sized pages in a single scrollable view, with dynamic add/insert/delete support.
  • đŸ–‹ī¸ Variable-Width Drawing — Authentic ink-like strokes with dynamic width sampling, central-difference tangents, Catmull-Rom splines, and multi-pass smoothing filters.
  • đŸ› ī¸ Customizable Tools — Cycling pen/eraser sizes, multi-color palette, and an integrated PageHeader tool bar.
  • 📑 Backgrounds & Templates — Load local or network images, or render a full PDF as per-page background templates.
  • đŸ–ŧī¸ Headers & Footers — Persistent banner images applied to every page on export.
  • 🔄 Navigation — Pinch-to-zoom and pan with dynamic constraints. No infinite zoom-out.
  • â†Šī¸ Undo / Redo — Global and per-page undo/redo stacks.
  • 💾 Serialization — Save and restore canvas state as a compact JSON string (variable-width preserved).
  • 📤 PDF Export — Export the full multi-page drawing with backgrounds, headers, and footers.

Installation #

dependencies:
  scribe_canvas: ^0.5.0

Quick Start #

All interactions with the canvas are done through a ScribeCanvasController. This follows Flutter's standard controller pattern (like TextEditingController or ScrollController).

import 'package:flutter/material.dart';
import 'package:scribe_canvas/scribe_canvas.dart';

class DrawingPage extends StatefulWidget {
  const DrawingPage({super.key});
  @override
  State<DrawingPage> createState() => _DrawingPageState();
}

class _DrawingPageState extends State<DrawingPage> {
  final _controller = ScribeCanvasController();
  bool _isEraser = false;

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(icon: const Icon(Icons.undo), onPressed: _controller.undo),
          IconButton(icon: const Icon(Icons.redo), onPressed: _controller.redo),
          IconButton(
            icon: Icon(_isEraser ? Icons.edit : Icons.auto_fix_normal),
            onPressed: () => setState(() => _isEraser = !_isEraser),
          ),
          IconButton(
            icon: const Icon(Icons.picture_as_pdf),
            onPressed: _controller.exportToPdf,
          ),
        ],
      ),
      body: ScribeCanvas(
        controller: _controller,  // attach the controller
        isEraser: _isEraser,
        onToggleEraser: (val) => setState(() => _isEraser = val),
        onStrokeEnd: () => setState(() {}),
        onUndo: () => setState(() {}),
        onRedo: () => setState(() {}),
      ),
    );
  }
}

ScribeCanvas Properties #

Property Type Default Description
controller ScribeCanvasController? — Required to call any imperative API.
color Color Colors.black Initial pen color.
strokeWidth double 4.0 Initial pen stroke width.
strokeSizes List<double> [2,4,8,16,32] Sizes to cycle through in the header.
isEraser bool false Whether eraser mode is active.
eraserWidth double 30.0 Initial eraser width.
eraserSizes List<double> [10,20,30,60,100] Eraser sizes to cycle through.
isPanMode bool false When true, disables drawing and enables panning only.
multiPage bool true Enables multi-page mode. When false, the canvas is a single fixed page.
initialColor Color Colors.black Initial color selected in the palette.
colors List<Color> (6 colors) Colors shown in the palette.
onStrokeStart VoidCallback? — Called when a stroke begins.
onStrokeEnd VoidCallback? — Called when a stroke is finalized. Good place to call setState to refresh undo/redo button states.
onUndo VoidCallback? — Called after an undo operation.
onRedo VoidCallback? — Called after a redo operation.
onStrokeWidthChanged ValueChanged<double>? — Called when the user cycles the pen size.
onEraserWidthChanged ValueChanged<double>? — Called when the user cycles the eraser size.
onToggleEraser ValueChanged<bool>? — Called when pen/eraser is toggled from the header.
onColorChanged ValueChanged<Color>? — Called when the user picks a color.

ScribeCanvasController API #

Undo & Redo #

_controller.undo();             // Undo last global stroke
_controller.redo();             // Redo last global stroke
_controller.undoPage(0);        // Undo last stroke on page 0
_controller.redoPage(0);        // Redo last stroke on page 0

bool canUndo = _controller.canUndo;   // Check before enabling undo button
bool canRedo = _controller.canRedo;

Canvas Operations #

_controller.clear();            // Clear all strokes
_controller.resetView();        // Reset zoom/pan to initial state

Page Management #

_controller.addPage();          // Append a new page at the end
_controller.insertPage(1);      // Insert a blank page at index 1
_controller.deletePage(1);      // Delete the page at index 1

Backgrounds & Templates #

// Local image bytes as a background for page 0
final bytes = await rootBundle.load('assets/template.png');
await _controller.setBackgroundImage(0, bytes.buffer.asUint8List(), clearOthers: true);

// Network image as background for page 0
await _controller.setNetworkBackgroundImage(0, 'https://example.com/bg.png');

// PDF rendered as per-page background templates
await _controller.loadPdfBackground(pdfBytes);

Headers & Footers #

Headers and footers are rendered on every page during PDF export.

// From local file
await _controller.setHeaderImage(headerBytes);
await _controller.setFooterImage(footerBytes);

// From network URL
await _controller.setNetworkHeaderImage('https://example.com/logo.png');
await _controller.setNetworkFooterImage('https://example.com/footer.png');

Serialization (Save & Load) #

// Save the current drawing state
final String data = _controller.getEncodedData();
await prefs.setString('canvas', data);

// Restore a previously saved drawing
final String? saved = prefs.getString('canvas');
if (saved != null) _controller.loadEncodedData(saved);

// Legacy format (no variable-width data)
final String legacy = _controller.getLegacyEncodedData();
_controller.loadLegacyEncodedData(legacy);

PDF Export #

// Renders all pages with backgrounds, headers, and footers
// and opens the system share / print dialog.
await _controller.exportToPdf();

Additional Information #

Scribe uses InteractiveViewer for navigation and CustomPainter for rendering. It leverages the pdf and printing packages for cross-platform PDF generation, and pdfx for rendering PDF background templates.

3
likes
0
points
281
downloads

Publisher

unverified uploader

Weekly Downloads

A high-performance Flutter multi-page canvas library for handwriting, drawing, and annotation with customizable tools and PDF export.

Homepage

License

unknown (license)

Dependencies

file_picker, flutter, meta, pdf, pdfx, printing

More

Packages that depend on scribe_canvas