finger_painter 1.1.0 copy "finger_painter: ^1.1.0" to clipboard
finger_painter: ^1.1.0 copied to clipboard

Painting package that let you finger paint with different brushes and different blend modes. The result can be read as a bitmap or list of Points to be used ie on a Map.

example/lib/main.dart

import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:finger_painter/finger_painter.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Image? image;
  late PainterController painterController;

  @override
  void initState() {
    super.initState();
    painterController = PainterController()
      ..setStrokeColor(Colors.black)
      ..setMinStrokeWidth(3)
      ..setMaxStrokeWidth(15)
      ..setBlurSigma(0.0)
      ..setPenType(PenType.paintbrush2)
      ..setBlendMode(ui.BlendMode.srcOver);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Column(
          children: [
            const SizedBox(height: 30),
            Painter(
              controller: painterController,
              backgroundColor: const Color(0xFFF0F0F0),
              onDrawingEnded: (bytes) async {
                print('${painterController.getPoints()?.length} drawn points');
                setState(() {});
              },
              size: const Size(double.infinity, 250),
              // child: Image.asset('assets/map.png', fit: BoxFit.cover),
            ),
            const SizedBox(height: 30),
            Expanded(
              child: SingleChildScrollView(
                  child: Controls(
                pc: painterController,
                imgBytesList: painterController.getImageBytes(),
              )),
            ),
          ],
        ),
      ),
    );
  }
}

class Controls extends StatefulWidget {
  final PainterController? pc;
  final Uint8List? imgBytesList;

  const Controls({
    Key? key,
    this.pc,
    this.imgBytesList,
  }) : super(key: key);

  @override
  State<Controls> createState() => _ControlsState();
}

class _ControlsState extends State<Controls> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // display current drawing
            if (widget.imgBytesList != null)
              Container(
                decoration: BoxDecoration(
                  color: const Color(0x00FFFFFF),
                  border: Border.all(
                    color: const Color(0xFF000000),
                    style: BorderStyle.solid,
                    width: 4.0,
                  ),
                  borderRadius: BorderRadius.zero,
                  shape: BoxShape.rectangle,
                  boxShadow: const <BoxShadow>[
                    BoxShadow(
                      color: Color(0x66000000),
                      blurRadius: 10.0,
                      spreadRadius: 4.0,
                    )
                  ],
                ),
                child: Image.memory(
                  widget.imgBytesList!,
                  gaplessPlayback: true,
                  fit: BoxFit.scaleDown,
                  height: 140,
                ),
              ),

            const SizedBox(width: 30),

            // Pen types
            Column(
              children: [
                for (int i = 0; i < PenType.values.length; i++)
                  OutlinedButton(
                      child: Text(PenType.values[i].name),
                      style: ButtonStyle(
                          backgroundColor: widget.pc
                                      ?.getState()
                                      ?.penType
                                      .index ==
                                  i
                              ? MaterialStateProperty.all(
                                  Colors.greenAccent.withOpacity(0.5))
                              : MaterialStateProperty.all(Colors.transparent)),
                      onPressed: () {
                        if (widget.pc != null) {
                          widget.pc!.setPenType(PenType.values[i]);
                          setState(() {});
                        }
                      }),
              ],
            ),
          ],
        ),

        const SizedBox(height: 30),

        // Colors, background & delete
        Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            FloatingActionButton(
                backgroundColor: Colors.red,
                onPressed: () => widget.pc?.setStrokeColor(Colors.red)),
            FloatingActionButton(
                backgroundColor: Colors.yellowAccent,
                onPressed: () =>
                    widget.pc?.setStrokeColor(Colors.yellowAccent)),
            FloatingActionButton(
                backgroundColor: Colors.black,
                onPressed: () => widget.pc?.setStrokeColor(Colors.black)),
            FloatingActionButton(
                backgroundColor: Colors.green,
                onPressed: () => widget.pc?.setStrokeColor(Colors.green)),
            FloatingActionButton(
                backgroundColor: Colors.blue,
                child: const Icon(Icons.image),
                onPressed: () async {
                  Uint8List image = (await rootBundle.load('assets/dash.png'))
                      .buffer
                      .asUint8List();
                  widget.pc?.setBackgroundImage(image);
                  setState(() {});
                }),
            FloatingActionButton(
                backgroundColor: Colors.red,
                child: const Icon(Icons.delete_outline),
                onPressed: () => widget.pc
                    ?.clearContent(clearColor: const Color(0xfff0f0ff))),
          ],
        ),

        const SizedBox(height: 30),

        /// min stroke width
        Row(
          children: [
            Text('  min stroke '
                '${widget.pc?.getState()!.strokeMinWidth.toStringAsFixed(1)}'),
            Expanded(
              child: Slider.adaptive(
                  value: widget.pc?.getState()?.strokeMinWidth ?? 0,
                  min: 1,
                  max: 20,
                  onChanged: (value) {
                    if (widget.pc != null) {
                      widget.pc?.setMinStrokeWidth(value);
                      if (widget.pc!.getState()!.strokeMinWidth >
                          widget.pc!.getState()!.strokeMaxWidth) {
                        widget.pc?.setMinStrokeWidth(
                            widget.pc!.getState()!.strokeMaxWidth);
                      }
                      setState(() {});
                    }
                  }),
            ),
          ],
        ),

        /// max stroke width
        Row(
          children: [
            Text('  max stroke '
                '${widget.pc?.getState()!.strokeMaxWidth.toStringAsFixed(1)}'),
            Expanded(
              child: Slider.adaptive(
                  value: widget.pc?.getState()?.strokeMaxWidth ?? 0,
                  min: 1,
                  max: 40,
                  onChanged: (value) {
                    if (widget.pc != null) {
                      widget.pc!.setMaxStrokeWidth(value);
                      if (widget.pc!.getState()!.strokeMaxWidth <
                          widget.pc!.getState()!.strokeMinWidth) {
                        widget.pc!.setMaxStrokeWidth(
                            widget.pc!.getState()!.strokeMinWidth);
                      }
                      setState(() {});
                    }
                  }),
            ),
          ],
        ),

        /// blur
        Row(
          children: [
            Text('  blur '
                '${widget.pc?.getState()!.blurSigma.toStringAsFixed(1)}'),
            Expanded(
              child: Slider.adaptive(
                  value: widget.pc?.getState()?.blurSigma ?? 0,
                  min: 0.0,
                  max: 10.0,
                  onChanged: (value) {
                    if (widget.pc != null) {
                      widget.pc!.setBlurSigma(value);
                      setState(() {});
                    }
                  }),
            ),
          ],
        ),

        const SizedBox(height: 30),

        // blends modes
        Wrap(
          spacing: 4,
          alignment: WrapAlignment.center,
          crossAxisAlignment: WrapCrossAlignment.center,
          children: [
            const Text(' blend modes: '),
            for (int i = 0; i < ui.BlendMode.values.length; i++)
              OutlinedButton(
                  child: Text(ui.BlendMode.values[i].name),
                  style: ButtonStyle(
                      backgroundColor:
                          widget.pc?.getState()?.blendMode.index == i
                              ? MaterialStateProperty.all(
                                  Colors.greenAccent.withOpacity(0.5))
                              : MaterialStateProperty.all(Colors.transparent)),
                  onPressed: () {
                    widget.pc?.setBlendMode(ui.BlendMode.values[i]);
                    setState(() {});
                  }),
          ],
        ),
        const SizedBox(height: 30),
      ],
    );
  }
}
44
likes
130
points
87
downloads

Documentation

API reference

Publisher

verified publishermarcobavagnoli.com

Weekly Downloads

Painting package that let you finger paint with different brushes and different blend modes. The result can be read as a bitmap or list of Points to be used ie on a Map.

Repository (GitHub)
View/report issues

License

BSD-2-Clause (license)

Dependencies

flutter

More

Packages that depend on finger_painter