我正在Flutter中编写一个应用程序。我有一个用例,用户需要选择一个摄像头/画廊,然后使用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 }