draw_your_image 0.4.2 copy "draw_your_image: ^0.4.2" to clipboard
draw_your_image: ^0.4.2 copied to clipboard

A Flutter package which enables users to draw with fingers in your designed UI.

draw_your_image #

draw_your_image is a Flutter package for drawing pictures/letters with fingers with Draw widget.

Draw is just a tiny widget which just feedbacks generated strokes by user's gestures and draws the given strokes on their screen.

Although this means all the state management for stroke data, such as undo/redo, clear, or preserving stroke values, is your business, this approach enables you to seemlessly collaborate with the functionalities of your apps, such as persistence of the strokes data, integrated undo/redo with other editings, etc.

Also, all the configuration about colors and stroke width, smoothing logics, strokes data can be customized.

Demos #

Demo

Features #

  • Fully declarative
  • Smoothing strokes
  • All the data can be customized on your side
  • Configuration of any stroke colors and background color
  • Configuration of stroke width
  • Erasor mode

Note #

Though this package is available with a couple of features, it's still under development. Any feedbacks or bug reports, and off course Pull Requests, are welcome. Feel free to visit the GitHub repository below.

https://github.com/chooyan-eng/draw_your_image

Usage #

Draw #

The very first step for draw_your_image is to place Draw widget at anywhere you want in the widget tree.

The Draw requires a parent widget, typically StatefulWidget, that manages the stroke state as Draw only handles the drawing interaction and draws the given strokes.

class MyDrawingPage extends StatefulWidget {
  @override
  _MyDrawingPageState createState() => _MyDrawingPageState();
}

class _MyDrawingPageState extends State<MyDrawingPage> {
  List<Stroke> _strokes = []; 

  @override
  Widget build(BuildContext context) {
    return Draw(
      // give back stroke data to Draw
      strokes: _strokes, 
      onStrokeDrawn: (stroke) {
        // Add a drawn stroke to _strokes
        setState(() {
          _strokes = [..._strokes, stroke];
        });
      },
      backgroundColor: Colors.blue.shade50,
      strokeColor: Colors.red,
      strokeWidth: 8,
      isErasing: false,
    );
  }
}

Required properties:

  • strokes: List of Stroke objects to display on the canvas
  • onStrokeDrawn: Callback invoked when a stroke is completed

**Optional properties: **

  • strokeColor, strokeWidth: Draw widget displays a canvas where users can draw with the given configurations.
  • isErasing: A flag for erasing drawn strokes. If true, new strokes will erase previously drawn strokes. Note that erasing strokes are also represented by Stroke and passed via onStrokeDrawn callback as well.

If you wish to change colors or width, simply call setState() in your StatefulWidget and change the properties passed to Draw. Other state management systems are also available.

Input Device Control #

The onStrokeStarted callback allows you to control drawing behavior based on input situations, typically input device type (stylus, finger, mouse, etc.). This callback is invoked when a new stroke is about to start, giving you the opportunity to:

  • Accept or reject the stroke based on the situation (e.g. accept only stylus)
  • Modify stroke properties (color, width, erasing mode) based on input device
  • Handle multi-touch scenarios by choosing which stroke to continue

Callback signature:

Stroke? Function(Stroke newStroke, Stroke? currentStroke)? onStrokeStarted

Parameters:

  • newStroke: The new stroke being started with initial configuration
  • currentStroke: The currently ongoing stroke (if any)

Return value: Draw continues the returned Stroke, thus:

  • return newStroke to start the new stroke
  • return currentStroke to continue the existing stroke (rejecting the new one)
  • return null to cancel both strokes
  • return a modified stroke with newStroke.copyWith(...) to customize properties

You can use the pre-defined utility functions, stylusOnlyHandler or stylusPriorHandler, if they fit your needs. Or you can also make your own function.

Example: Accept only stylus input #

import 'package:draw_your_image/draw_your_image.dart';

Draw(
  strokes: _strokes,
  onStrokeDrawn: (stroke) => setState(() => _strokes.add(stroke)),
  onStrokeStarted: stylusOnlyHandler,
)

The stylusOnlyHandler utility function only accepts stylus input and automatically sets inverted stylus to erasing mode.

Example: Prioritize stylus over other inputs #

Draw(
  strokes: _strokes,
  onStrokeDrawn: (stroke) => setState(() => _strokes.add(stroke)),
  onStrokeStarted: stylusPriorHandler,
)

The stylusPriorHandler utility function gives priority to stylus input. If a stylus is already drawing, other input types are ignored.

Example: Custom handler - Stylus draws black, finger erases #

Stroke? customHandler(Stroke newStroke, Stroke? currentStroke) {
  // If stylus is already drawing, continue with it
  if (currentStroke?.deviceKind == PointerDeviceKind.stylus) {
    return currentStroke;
  }
  
  // New stroke: stylus draws black, finger erases
  if (newStroke.deviceKind == PointerDeviceKind.stylus) {
    return newStroke.copyWith(color: Colors.black, isErasing: false);
  } else if (newStroke.deviceKind == PointerDeviceKind.touch) {
    return newStroke.copyWith(isErasing: true);
  }
  
  // Reject other input types
  return currentStroke;
}

Draw(
  strokes: _strokes,
  onStrokeDrawn: (stroke) => setState(() => _strokes.add(stroke)),
  onStrokeStarted: customHandler,
)

Path Smoothing #

By default, strokes are smoothed using Catmull-Rom spline interpolation. You can customize this behavior using the smoothingFunc parameter.

Using built-in smoothing modes: #

You can use SmoothingMode enum for pre-defined smoothing logics. As SmoothingMode has a field of function named converter, you can simply pass the function to smoothingFunc.

// Smooth curves (default)
Draw(
  strokes: _strokes,
  onStrokeDrawn: (stroke) => setState(() => _strokes.add(stroke)),
  smoothingFunc: SmoothingMode.catmullRom.converter,
)

// No smoothing (straight lines)
Draw(
  strokes: _strokes,
  onStrokeDrawn: (stroke) => setState(() => _strokes.add(stroke)),
  smoothingFunc: SmoothingMode.none.converter,
)

Using custom smoothing function: #

Because smoothingFunc can receive any functions as long as they apply the type Path Function(Stroke), you can implement your own logic and pass the function here for customizing smoothing logics.

Draw(
  strokes: _strokes,
  onStrokeDrawn: (stroke) => setState(() => _strokes.add(stroke)),
  smoothingFunc: (stroke) {
    // Custom path generation logic
    final path = Path();
    final points = stroke.points;
    
    if (points.isNotEmpty) {
      path.moveTo(points[0].dx, points[0].dy);
      for (int i = 1; i < points.length; i++) {
        path.lineTo(points[i].dx, points[i].dy);
      }
    }
    
    return path;
  },
)

Stroke Data Structure #

Strokes are stored as a list of point and its metadata containing:

  • points: List of Offset representing the stroke path
  • color: Stroke color
  • width: Stroke width
  • isErasing: Whether the stroke is in eraser mode

This structure allows you to:

  • Access and process stroke data independently from UI
  • Apply post-processing like resampling
  • Implement custom rendering logic

Resampling Utility #

The resamplePoints function allows you to resample stroke points for uniform density:

import 'package:draw_your_image/draw_your_image.dart';

// Resample points with 5.0 pixel spacing
final originalPoints = [
  Offset(0, 0),
  Offset(10, 10),
  Offset(20, 15),
  // ... more points
];

final resampledPoints = resamplePoints(originalPoints, 5.0);

// Use resampled points to create a new stroke
final newStroke = stroke.copyWith(points: resampledPoints);

This is useful for:

  • Reducing the number of points while maintaining shape
  • Normalizing point density across different drawing speeds
  • Pre-processing data for machine learning or gesture recognition
45
likes
0
points
430
downloads

Publisher

verified publishertsuyoshichujo.com

Weekly Downloads

A Flutter package which enables users to draw with fingers in your designed UI.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on draw_your_image