4
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'dart:ui' as ui;

class EditImage extends StatefulWidget {
  final String filePath;
  EditImage({this.filePath});

  @override
  _EditImageState createState() => _EditImageState();
}

class _EditImageState extends State<EditImage> {
  ui.Image decodedImage;
  String newFilePath;
  GlobalKey myCanvasKey = GlobalKey();
  ImageEditor editor;
  Color color = Colors.blue;

  @override
  void initState() {
    loadImage(File(widget.filePath));
    super.initState();
  }

  void loadImage(File image) async {
    final data = await image.readAsBytes();
    decodedImage = await decodeImageFromList(data);
    editor = ImageEditor(image: decodedImage, strokeColor: color);
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: InkWell(
          onTap: () {
            Navigator.pop(context, newFilePath ?? widget.filePath);
          },
          child: Icon(Icons.close),
        ),
        //centerTitle: true,
        title: Text('Edit'),
        actions: [
          InkWell(
            onTap: () {
              editor.undo();
              myCanvasKey.currentContext.findRenderObject().markNeedsPaint();
            },
            child: Icon(Icons.undo),
          ),
          SizedBox(
            width: 10.0,
          ),
          InkWell(
            onTap: () async {
              Color pickedColor;
              bool isSelected = false;
              await showDialog(
                context: context,
                child: AlertDialog(
                  contentPadding: const EdgeInsets.all(8.0),
                  title: const Text('Stroke Color'),
                  content: SingleChildScrollView(
                    child: ColorPicker(
                      pickerColor: color,
                      onColorChanged: (color) {
                        pickedColor = color;
                      },
                      enableAlpha: false,
                      showLabel: false,
                      pickerAreaHeightPercent: 0.6,
                    ),
                  ),
                  actions: <Widget>[
                    FlatButton(
                      child: const Text('Cancel'),
                      onPressed: () => Navigator.pop(context),
                    ),
                    FlatButton(
                      child: const Text('Select'),
                      onPressed: () {
                        isSelected = true;
                        Navigator.of(context).pop();
                      },
                    ),
                  ],
                ),
              );
              if (isSelected) {
                editor.updateStrokeColor(pickedColor);
                setState(() {
                  color = pickedColor;
                });
              }
            },
            child: Container(
              decoration: BoxDecoration(
                //borderRadius: BorderRadius.circular(15.0),
                border: Border.all(color: Colors.grey),
                shape: BoxShape.circle,
                color: color,
              ),
              child: Padding(
                padding: const EdgeInsets.all(5.0),
                child: Container(
                  decoration: BoxDecoration(
                      color: Colors.black26, shape: BoxShape.circle),
                  child: Padding(
                    padding: const EdgeInsets.all(3.0),
                    child: Icon(
                      Icons.edit_outlined,
                      color: Colors.white,
                      semanticLabel: 'Stroke',
                    ),
                  ),
                ),
              ),
            ),
          ),
          SizedBox(
            width: 10.0,
          ),
          InkWell(
            onTap: () {
              Navigator.pop(context, newFilePath ?? widget.filePath);
            },
            child: Icon(Icons.done),
          ),
          SizedBox(
            width: 10.0,
          ),
        ],
      ),
      body: decodedImage == null
          ? Center(child: CircularProgressIndicator())
          : Center(
              child: FittedBox(
                child: SizedBox(
                  height: decodedImage.height.toDouble(),
                  width: decodedImage.width.toDouble(),
                  child: GestureDetector(
                    onPanDown: (detailData) {
                      editor.update(detailData.localPosition);
                      myCanvasKey.currentContext
                          .findRenderObject()
                          .markNeedsPaint();
                    },
                    onPanUpdate: (detailData) {
                      editor.update(detailData.localPosition);
                      myCanvasKey.currentContext
                          .findRenderObject()
                          .markNeedsPaint();
                    },
                    onPanEnd: (detailData) {
                      editor.addNewPointsList();
                    },
                    child: CustomPaint(
                      key: myCanvasKey,
                      painter: editor,
                    ),
                  ),
                ),
              ),
            ),
    );
  }
}

class ImageEditor extends CustomPainter {
  ImageEditor({
    this.image,
    this.strokeColor = Colors.black,
  }) {
    _strokes.add(_StrokeData());
  }

  final ui.Image image;
  Color strokeColor;

  List<_StrokeData> _strokes = [];

  void updateStrokeColor(Color color) {
    strokeColor = color;
  }

  void update(Offset offset) {
    if (_strokes.last.color == null) _strokes.last.color = strokeColor;
    _strokes.last.points.add(offset);
  }

  void addNewPointsList() {
    print('pan end');
    _strokes.add(_StrokeData());
  }

  void undo() {
    if (_strokes.length > 1) _strokes.removeAt(_strokes.length - 2);
  }

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawImage(image, Offset.zero, Paint());

    for (int i = 0; i < _strokes.length; i++) {
      Paint _painter = Paint();
      _painter.color = _strokes[i].color ?? Colors.transparent;
      _painter.style = PaintingStyle.stroke;
      _painter.strokeWidth = 15;
      _painter.isAntiAlias = true;

      for (int j = 0; j < _strokes[i].points.length; j++) {
        if (j > 0)
          canvas.drawLine(
              _strokes[i].points[j - 1], _strokes[i].points[j], _painter);
      }
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

class _StrokeData {
  Color color;
  List<Offset> points;
  _StrokeData() {
    points = List<Offset>();
  }
}

在此处输入图像描述

如何限制在图像区域内绘图?

4

1 回答 1

1

使用 ClipRRect() 作为 FittedBox 的父级。这解决了问题

ClipRRect(child: FittedBox(child: SizedBox(...Painter widget goes here...) ))
于 2022-02-23T03:37:23.400 回答