Размытость пикселей выбора изображения - PullRequest
0 голосов
/ 26 июня 2019

Я пишу приложение во Флаттере.У меня есть случай, когда пользователь должен выбрать изображение камеры / галереи, после этого я использую CustomPainter для рисования изображения на холсте.Я расширил функциональность, позволив пользователю рисовать поверх изображения, и все это идет хорошо.Однако моя проблема заключается в том, что пользователь также должен иметь возможность размыть свой выбор.Для его выбора я использую начальную точку + смещение, чтобы нарисовать прямоугольник.Однако этот подход не кажется мне очень элегантным, поскольку мы просто рисуем прямоугольники поверх изображения, а не модифицируем / размываем пиксели изображения, отображаемые в результате выбора пользователя.

Ниже приведен CustomPainter, используемый для рисования на холсте.Любая помощь будет принята с благодарностью.

 class DrawingPainter extends ChangeNotifier implements CustomPainter {
  static int blurColor = 0xFFB3E5FC;
  UI.Image paintedImage;
  ItemCountListener countListener;
  List<DrawingPoints> _pointsList = new List();
  List<DrawingPoints> _blurPoints = new List();
  Size _canvasSize;
  Offset blurIndicatorOffset;
  Offset blurStartOffset;
  bool shouldColorWhiteBackground = false;

  /// To blur an image we need a [MaskFilter]
  Paint blurIndicatorPaint = new Paint()
     ..blendMode = BlendMode.dstOut
     ..color = Colors.white.withOpacity(0.8)
     ..maskFilter = MaskFilter.blur(BlurStyle.normal, 3.0);

  DrawingPainter(
     {this.countListener,
     this.paintedImage,
     this.blurIndicatorOffset,
     this.blurStartOffset});

  @override
  void paint(Canvas canvas, Size size) {
     _canvasSize = size;
     _paintBackgroundImage(canvas);
     _drawPoints(canvas);
     _drawBlurIndicator(canvas);
     _drawBlurPoints(canvas);
      // canvas.restore();
   }

   /// Paints the image onto the canvas
   void _paintBackgroundImage(Canvas canvas) {
       if (paintedImage == null) {
           return;
        }
       //Draw image:
       canvas.drawImage(paintedImage, Offset.zero, Paint());
   }

   /// Paints the lines onto the canvas
   void _drawPoints(Canvas canvas) {
        for (int i = 0; i < _pointsList.length - 1; i++) {
          if (_pointsList[i] != null && _pointsList[i + 1] != null)      {
            canvas.drawLine(_pointsList[i].points, _pointsList[i +   1].points,
            _pointsList[i].paint);
        }
      }
    }

    /// Paints the blur indicator onto the canvas
    void _drawBlurIndicator(Canvas canvas) {
        if (blurStartOffset != null && blurIndicatorOffset != null) {
         canvas.drawRect(Rect.fromPoints(blurStartOffset, blurIndicatorOffset),
      blurIndicatorPaint);
           }
     }

     void _drawBlurPoints(Canvas canvas) {
       for (int j = 0; j < _blurPoints.length - 1; j++) {
           if (_blurPoints[j] != null && _blurPoints[j + 1] != null) {
           if (blurStartOffset == null) blurStartOffset = _blurPoints[j].points;
           if (_blurPoints.length >= j + 3 && _blurPoints[j + 2] == null) {
    canvas.drawRect(
          Rect.fromPoints(blurStartOffset, _blurPoints[j + 1].points),
              blurIndicatorPaint);
             blurStartOffset = null;
              }
           }
       }
   }

      void startStroke(DrawingPoints drawingPoint) {
        print("startStroke");
        _pointsList.add(drawingPoint);
        notifyListeners();
        countListener(_pointsList.length);
      }

      void appendStroke(DrawingPoints drawingPoint) {
        print("appendStroke");
        if (paintedImage != null) {
        if ((drawingPoint.points.dx <= paintedImage.width) &&
            (drawingPoint.points.dy <= paintedImage.height)) {
            _pointsList.add(drawingPoint);
            notifyListeners();
            countListener(_pointsList.length);
       }
     } else {
       _pointsList.add(drawingPoint);
        notifyListeners();
        countListener(_pointsList.length);
     }
  }

   void endStroke() {
    _pointsList.add(null);
    notifyListeners();
    countListener(_pointsList.length);
   }

  void setBlurIndicator(Offset localOffset) {
     blurIndicatorOffset = localOffset;
    notifyListeners();
  }

  void setStartBlurIndicatorOffset(Offset localOffset) {
    blurStartOffset = localOffset;
  }

  void resetBlurIndicator() {
    blurStartOffset = null;
    blurIndicatorOffset = null;
    notifyListeners();
  }

  void clear() {
    _pointsList.clear();
    _blurPoints.clear();
    resetBlurIndicator();
    countListener(_pointsList.length);
  }

  void setImage(UI.Image paintedImage) {
    this.paintedImage = paintedImage;
  }

  void undo() {
    bool isLast = false;
    if (_pointsList.length != 0) {
       _pointsList.removeLast();
      int _resizeIndex = _pointsList.lastIndexOf(null);

    if (_resizeIndex <= 0) {
         isLast = true;
        _pointsList.clear();
       } else {
        isLast = false;
       _pointsList.removeRange(_resizeIndex, _pointsList.length);
       _pointsList.add(null);
      }
    }
    if (isLast) {
      countListener(0);
     }
     notifyListeners();
   }

  Future<List<int>> save() async {
    //Create canvas
    // Set PictureRecorder on the canvas and start recording
    UI.PictureRecorder recorder = UI.PictureRecorder();
    Canvas canvas = Canvas(recorder);

    //Draw image on new canvas
    if (paintedImage != null) {
      canvas.drawImage(paintedImage, Offset.zero, Paint());
    }

    //Draw points on new canvas
    for (int i = 0; i < _pointsList.length - 1; i++) {
      if (_pointsList[i] != null && _pointsList[i + 1] != null) {
        canvas.drawLine(
          _pointsList[i].points,
          _pointsList[i + 1].points,
          _pointsList[i].paint,
        );
     }
    }

    //End recording
    final resultImage = await recorder.endRecording().toImage(
          _canvasSize.width.floor(),
          _canvasSize.height.floor(),
        );

    final imageBytes =
        await resultImage.toByteData(format: UI.ImageByteFormat.png);

    var image =  imageBytes.buffer.asUint8List();
    var pngImage = img.decodeImage(image);
    return img.encodeJpg(pngImage);
  }

  @override
  bool hitTest(Offset position) {
     if (paintedImage != null) {
     if ((position.dx <= paintedImage.width) &&
          (position.dy <= paintedImage.height)) {
        return true;
      } else {
        return false;
      }
    } else {
      return true;
    }
  }

  @override
  bool shouldRepaint(DrawingPainter oldDelegate) {
    return (oldDelegate._pointsList.length != _pointsList.length)   || (oldDelegate.paintedImage != paintedImage);
   }

  @override
  get semanticsBuilder => null;

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

  void setBlurPoints(DrawingPoints drawingPoints) {
      _blurPoints.add(drawingPoints);
      notifyListeners();
  }
}

 class DrawingPoints {
  Paint paint;
  Offset points;

  DrawingPoints({this.points, this.paint});
}

enum SelectedMode { StrokeWidth, Opacity, Color, Blur }
...