A Flutter plugin providing signature pad for drawing smooth signatures.

Overview

A Flutter plugin providing Signature Pad for drawing smooth signatures. Library is written in pure Dart/Flutter environment to provide support for all platforms..
Easy to use library with variety of draw and export settings. Also supports SVG files.

Structure

Signature pad drawing is based on Cubic Bézier curves.


Usage

    import 'package:hand_signature/signature.dart';

With HandSignatureControl and HandSignaturePainterView is possible to tweak some drawing aspects like stroke width, smoothing ratio or velocity weight.

    final control = HandSignatureControl(
      threshold: 3.0,
      smoothRatio: 0.65,
      velocityRange: 2.0,
    );

    final widget = HandSignaturePainterView(
      control: control,
      color: Colors.blueGrey,
      width: 1.0,
      maxWidth: 10.0,
      type: SignatureDrawType.shape,
    );

HandSignatureControl sets up 'math' to control input touches and handles control points of signature curve.

  • threshold: (LP) controls minimal distance between two points - higher distance creates smoother curve, but less precise. Higher distance also creates bigger input draw lag.
  • smoothRatio: (0 - 1) controls how smooth curve will be - higher ratio creates smoother curve, but less precise. In most of cases are best results with values between 0.5 - 0.75.
  • velocityRange: (LP per millisecond) controls curve size based on distance and duration between two points. Thin line - fast move, thick line - slow move. With higher velocityRange user must swing faster to draw thinner line.
  • reverseVelocity: swaps stroke width. Thin line - slow move, thick line - fast move. Simply swaps min/max size based on velocity.

HandSignaturePainterView sets up visual style of signature curve.

  • control: processes input, handles math and stores raw data.
  • color: just color of line.
  • width: minimal width of line. Width at maximum swing speed (clamped by velocityRange).
  • maxWidth: maximum width of line. Width at slowest swing speed.
  • type: draw type of curve. Default and main draw type is shape - not so nice as arc, but has better performance. And line is simple path with uniform stroke width.

Export
Properties, like canvas size, stroke min/max width and color can be modified during export.
There are more ways and more formats how to export signature, most used ones are svg and png formats.

    final control = HandSignatureControl();

    final svg = control.toSvg();
    final png = control.toImage();

Of course draw type is also supported during export. SignatureDrawType shape generates reasonably small file and is read well by all programs. On the other side arc generates really big file and some programs can have hard times handling so much objects.
Export to image supports ImageByteFormat and provides png or raw rgba data.\

Parsing
Exported svg is possible to display in classic flutter_svg widget.
Or use build in HandSignatureView for greater control.

    final widget = HandSignatureView.svg(
      data: svgString,
      strokeWidth: (width) => width * 0.35,
      padding: EdgeInsets.all(16.0),
      placeholder: Container(
        color: Colors.red,
        child: Center(
          child: Text('not signed yet'),
        ),
      ),
    );

Signature is automatically centered and fills given area.
Currently stroke width can be controlled only for line and arc exports.
HandSignatureView handles most of svg files, but is optimized for drawing signatures created with this library and don't provide all features like flutter_svg.


Contribution
Any contribution is highly welcomed.
Library is in good condition, but still in early development.
Mainly to improve smoothing and line weight to better match real signature.
Remove dependency to flutter_svg and make library dependent only on path_drawing or path_parsing.
Performance can be always better..
Also currently there are no tests or documentation.

Comments
  • Cannot drawing signatures inside SingleChildScrollView

    Cannot drawing signatures inside SingleChildScrollView

    I have a code:

    child: SingleChildScrollView(
                child: Column(
                  mainAxisSize: MainAxisSize.max,
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    HtmlWidget(_formatHTMLRender(html)),
                    Container(
                      height: 300,
                      width: double.infinity,
                      color: Colors.white,
                      child: HandSignaturePainterView(
                        control: control,
                        type: SignatureDrawType.shape,
                        color: Colors.cyan,
                      ),
                    ),
                  ],
                )
              )
    

    But I can't draw when scroll page. Please help me. Thanks

    opened by leewonghao 7
  •  Offset argument contained a NaN value

    Offset argument contained a NaN value

    Not sure exactly how to reproduce, but I will occasionally get this error when attempting to convert to an image. As I am signing my line disappears and then I will encounter this error when saving as an image a.k.a await control.toImage().

    This issue goes away if you undo the change where your line disappeared. I believe something is getting set to null along the way.

    [VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: 'dart:ui/painting.dart': Failed assertion: line 43: '<optimized out>': Offset argument contained a NaN value.
    #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39)
    #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:36:5)
    #2      _offsetIsValid (dart:ui/painting.dart:43:10)
    #3      Path.arcToPoint (dart:ui/painting.dart:2051:12)
    #4      CubicArc.path
    package:hand_signature/src/signature_control.dart:381
    #5      PathSignaturePainter.paint.<anonymous closure>.<anonymous closure>
    package:hand_signature/src/signature_painter.dart:89
    #6      List.forEach (dart:core-patch/growable_array.dart:313:8)
    #7      PathSignaturePainter.paint.<anonymous closure>
    package:hand_signature/src/signature_painter.dart:87
    #8      List.forEach (dart:core-patch/growable_array.dart:313:8)
    #9      PathSignaturePainter.paint
    package:hand_signature/src/signature_painter.dart:86
    #10     HandSignatureControl.toPicture <…>
    

    Here is the controller setup and body of my scaffold:

    HandSignatureControl

    final control = HandSignatureControl(
        threshold: 0,
        smoothRatio: 0.65,
        velocityRange: 2,
      );
    

    Body

    SafeArea(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Stack(
                  fit: StackFit.expand,
                  children: [
                    HandSignaturePainterView(
                      control: control,
                      color: Colors.blue,
                      maxWidth: 7,
                      type: SignatureDrawType.shape,
                    ),
                    Stack(
                      alignment: Alignment.bottomLeft,
                      children: [
                        Text(
                          'X',
                          style: TextStyle(
                            fontSize: 50,
                            color: Colors.blue.withOpacity(0.7),
                            fontWeight: FontWeight.w100,
                          ),
                        ).paddingOnly(bottom: 10),
                        Divider(
                          height: 2,
                          thickness: 2,
                          color: Colors.blue.withOpacity(0.7),
                        ),
                      ],
                    ).paddingOnly(bottom: 50)
                  ],
                ).expanded(),
              ],
            ),
          ),
    

    found this while looking through the lines in my controller: Screen Shot 2021-02-19 at 2 12 50 PM

    Lmk if there is anything I missed. Happened on an iPhone 12 Pro running iOS 14.4. I'm on Flutter channel stable 1.22.6

    opened by Manguelo 5
  • Added import export functionality

    Added import export functionality

    • Saving only OffsetPoints as they're sufficient for reinitialization

    Data Size

    I have tested multiple times to check the JSON string's size. On average the SVG export is around 30 kilobytes and the JSON string is about 9 kilobytes.

    Usage Example

    final control = HandSignatureControl()
    [Draw the signature using the UI]
    final jsonMap = control.toMap
    [Save the jsonMap as you want]
    

    On the next launch:

    final jsonMap  = [load the saved map]
    final control = HandSignatureControl.fromMap(jsonMap)
    
    opened by alifurkanbudak 4
  • Implementation of toMap / fromMap methods for saving the state

    Implementation of toMap / fromMap methods for saving the state

    Currently, there are only image / SVG exports but it would be nice to save and reinitialize the current state of the signature so we can edit later. I implemented this and opened a PR.

    opened by alifurkanbudak 4
  • Added scaleToFill bool in HandSignatureControl.toPicture

    Added scaleToFill bool in HandSignatureControl.toPicture

    Hello,

    I'm using your package and I think it's really nice. However I'm facing this little issue, where the image produced by the controller is not the same picture drawn.

    Example below:

    | HandSignaturePainterView | controller.toImage() | | ------------ | ------------ | | IMG_0159 | IMG_0158| | IMG_0157 | IMG_0156|

    I inspected the toImage code and found that the path is being scaled by a PathUtil.fill() method.

    While I understand the optimization of trimming whitespace, this scales the path points but not its width, resulting in a different image.

    So I forked your repository and added a bool scaleToFill to disable this behavior and obtain the same image as the one shown by HandSignaturePainterView.

    The bool is also set to true by default, so when omitted it keeps the old behavior, and won't result in a breaking change.

    I would be awesome if you could accept this pull request and publish the updated package on pub.dev.

    opened by TheManuz 3
  • Save and modify

    Save and modify

    Hi. I know I can export the signature to svg and png, but is there a way to save the draw, then reopen and modify it?? Like for example the Samsung notes app

    Thank you

    opened by bobosette 3
  • lines.length > 0

    lines.length > 0

    Hello, I'm using this package but I have this problem below while writing a signature.

    'package:hand_signature/src/utils.dart': Failed assertion: line 369 pos 12: 'lines.length > 0': is not true.
    The relevant error-causing widget was HandSignaturePainterView
    

    This is my code to show widget

    Container(
      width: double.infinity,
      height: 250,
      child: HandSignaturePainterView(
        control: control,
        decoration: ... ,
        type: SignatureDrawType.line,
        width: 3,
      ),
    )
    

    And this is style of HandSignatureControl

    final HandSignatureControl control = new HandSignatureControl(
        threshold: 0.01,
        smoothRatio: 0.65,
        velocityRange: 2.0,
      );
    

    Do you have any solution?

    opened by c0c4i 3
  • PointerEvent and drawing bug

    PointerEvent and drawing bug

    Hello. Let me congrat with you for this work, It's a really useful package. Thank you. But I noticed two issue: 1 Is there a way to get from the control some other infos like tilt, pressure, distance (these can be retreived with PointerEvent)? 2 When you first touch the display with the pen/hand, draw a very small path, then you get off the pen/hand from the display, and keep going like this, it seems difficult for the painter to draw these minipaths with precision. I don't know how to explain, I hope you have understood. Maybe I can fix this issue be increasing the velocity property??

    opened by bobosette 3
  • Some Future Requests

    Some Future Requests

    Hello, I am planning to add these;

    • Be able to change controller properties while drawing. (width, color)
    • Basic undo functionality.

    Any toughts? Thanks.

    opened by furkansarihan 3
  • Feature/scale to fill

    Feature/scale to fill

    Hello RomanBase,

    I updated my brach as you suggested.

    When the scaleToFill boolean is true (default behavior) it will behave like before. When the scaleToFill boolean is false, it will use the canvas bounds instead of the path bounds, so the transparent pixels outside the path will not be trimmed.

    I've also updated the method CubicArc.scale() and CubicLine.scale() to scale the size of the stroke. This will prevent the path from becoming thinner when upscaling or thicker when downscaling.

    I've also updated the example to show the feature, as you can see in the screenshots below.

    IMG_0163

    IMG_0162

    I hope everything is ok for the merge request, let me know if anything else is needed!

    opened by TheManuz 2
  • Null Check for .toImage()

    Null Check for .toImage()

    Turns out null check is missing in controller.toImage(...) resulting in [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0

    Adding if (!isFilled) { return null; } In signature_control.dart [Line 1104] , should do the job

    It actually is done in .toSvg() function in same file - signature_control.dart [Line 872-874]

    If Interested in replicated this issue

    Step 1: Fork the official example from https://github.com/RomanBase/hand_signature/tree/master/example Step 2: Build and Run it Step 3: Without drawing anything on canvas press 'export' button OR, - Draw something, press 'export', press 'clear', and then press 'export' again Step 4: Observer the debug console

    opened by MorosophDude 2
  • There is a problem uploading json data to firestore.

    There is a problem uploading json data to firestore.

    My code is as follows. After drawing, I'm going to convert the data I drew into Json and upload it to Firestore. (And I'm going to get it back later.)

    Container(
                          width: _screenWidth ?? 525, 
                          height: _screenHeight ?? 736,
                          color: Colors.transparent,
                          child: HandSignature(
                            control: signControl,
                            type: SignatureDrawType.shape,
    
                            onPointerUp: () async {
                              final drawJson = signControl.toMap();
    
                              // TODO firebase upload
                              await FirebaseFirestore.instance
                                  .collection(COL_ROOMS)
                                  .doc(widget.roomKey)
                                  .collection(COL_DRAW)
                                  .doc()
                                  .set(drawJson);
                            },
                          ),
    

    However, the following error is printed when uploading.

    Nested arrays are not supported

    There seems to be a problem with the json data. Is there a way to do this?

    wontfix 
    opened by schosdas 1
Owner
Roman Hornak
Flutter is way to go.
Roman Hornak
Open-source And Fully Functional Digital Signature App Built With Flutter

Open-source and fully functional digital signature app "E-Gol" ?? Don't forget to star ⭐ the repo if you like what I have created ?? . ?? ScreenShots

Ruslan Hasanov 14 Oct 19, 2022
A control pad with a virtual joystick and buttons.

control_pad A virtual pad with joystick controller and configurable buttons. Features Joystick controller Pad's buttons Configurable events interval C

Artur Rymarz 39 Dec 7, 2022
Sample Flutter Drawing App which allows the user to draw onto the canvas along with color picker and brush thickness slider.

DrawApp Sample Flutter Drawing App which allows the user to draw onto the canvas along with color picker and brush thickness slider. All code free to

Jake Gough 226 Nov 3, 2022
Doddle - A Flutter app where you can draw symmetrical drawing

doddle - (still under development) Amazing magical doodle game provide a creativ

Naser 53 Dec 28, 2022
A Flutter plugin for IOS and Android providing a simple way to display PDFs.

Pdf Viewer Plugin A Flutter plugin for IOS and Android providing a simple way to display PDFs. Features: Display PDF. Installation First, add pdf_view

Lucas Britto 56 Sep 26, 2022
Wraps Flutter shared_preferences plugin, providing a iOS Suite Name support, it's helpful for sharing data from App to Widget.

shared_preferences_ios_sn Wraps Flutter shared_preferences plugin and provides an iOS Suite Name support, it's helpful for sharing data from App to iO

null 3 Sep 14, 2022
Flutter package. A wrapper for scrollable widgets that enables smooth scrolling with a mouse on all platforms.

Dynamic Mouse Scroll A wrapper for scrollable widgets that enables smooth scrolling with a mouse on all platforms. First gif: Scrolling slowly. Second

null 3 Dec 15, 2022
A Smooth rating bar

A Star rating with touch and swipe rate enabled Supports replacing default star icons with desired IconData Supports half rate and full rate (1.0 or 0

Thangmam 146 Sep 15, 2022
Clock loader - Highly versatile Widget display the smooth and creative loader named as clock loader

Clock Loader Highly versatile Widget display the smooth and creative loader name

MindInventory 20 Dec 30, 2022
User onboarding library with smooth animation of objects and background colors

SlidingTutorial Cleveroad introduces Sliding Tutorial Library for Flutter Hey guys, hope you haven’t started developing a tutorial for your Flutter ap

Cleveroad 127 Dec 31, 2022
Simple and beautiful smooth animated charts.

Charts Flutter Simple and beautiful smooth animated charts. Supported charts Bar Group bar Candle Line Pie Example Check /example folder for more deta

Merixstudio 55 Jan 3, 2023
Flutter package to create list of radio button, by providing a list of objects it can be a String list or list of Map.

Custom Radio Group List Flutter package to create list of radio button, by providing a list of objects it can be a String list or list of Map. Feature

Ashok Kumar Verma 0 Nov 30, 2021
A Flutter package providing an easy way to add floating ribbon to images.

Floating Ribbon A new Flutter package for creating floating ribbons on images. Dependency dependencies: floating_ribbon: any How To Use In order to

101Loop 12 Sep 26, 2022
A wrapper around our Cocoa and Java client library SDKs, providing iOS and Android support for those using Flutter and Dart.

Ably Flutter Plugin A Flutter plugin wrapping the ably-cocoa (iOS) and ably-java (Android) client library SDKs for Ably, the platform that powers sync

Ably Realtime - our client library SDKs and libraries 46 Dec 13, 2022
A flutter package that helps you create an on-boarding screen for your project within minutes just by providing a few parameters.

A flutter package that helps you create an on-boarding screen for your project within minutes just by providing a few parameters.

Sachin Kr. Shukla 40 Sep 27, 2022
Nebula makes your Flutter development journey easier by providing helper widgets, utilities and abstractions.

Nebula makes your Flutter development journey easier by providing helper widgets, utilities and abstractions.

Aldrin's Art Factory 1 Apr 21, 2022
CoVAC is an all-in-one Covid info toolkit app, providing users the facility to check for available slots along with receiving the latest updates related to the pandemic and the virus.

CoVAC - Covid 19 Vaccine Availability Checker Introduction ?? CoVAC is an android application developed to provide users the facility to check the ava

Aryan Kenchappagol 6 Dec 29, 2021
Created application for team to help each other with providing food they want

Food wishes app When you login or create your account, you can write what do you wish right now as a separate card, using "Edit" button. If you no lon

Pavlo Osadchuk 0 Nov 29, 2021
A simple library providing programmatic access to the iTunes search API for podcasts.

A library for searching for podcasts, parsing podcast RSS feeds and obtaining episodes details. Supports searching via iTunes and PodcastIndex (previe

Ben Hills 23 Dec 28, 2022