diff --git a/lib/src/crop_controller.dart b/lib/src/crop_controller.dart index ee628ff..e28f0fc 100644 --- a/lib/src/crop_controller.dart +++ b/lib/src/crop_controller.dart @@ -186,11 +186,14 @@ class CropController extends ValueNotifier { /// Returns the bitmap cropped with the current crop rectangle. /// /// [maxSize] is the maximum width or height you want. + /// [overlayPainter] is an optional painter on top of the cropped image; + /// could be used for special effects on the cropped area. /// You can provide the [quality] used in the resizing operation. /// Returns an [ui.Image] asynchronously. Future croppedBitmap({ final double? maxSize, final ui.FilterQuality quality = FilterQuality.high, + final CustomPainter? overlayPainter, }) async => getCroppedBitmap( maxSize: maxSize, @@ -198,11 +201,14 @@ class CropController extends ValueNotifier { crop: crop, rotation: value.rotation, image: _bitmap!, + overlayPainter: overlayPainter, ); /// Returns the bitmap cropped with parameters. /// /// [maxSize] is the maximum width or height you want. + /// [overlayPainter] is an optional painter on top of the cropped image; + /// could be used for special effects on the cropped area. /// The [crop] `Rect` is normalized to (0, 0) x (1, 1). /// You can provide the [quality] used in the resizing operation. static Future getCroppedBitmap({ @@ -211,6 +217,7 @@ class CropController extends ValueNotifier { required final Rect crop, required final CropRotation rotation, required final ui.Image image, + final CustomPainter? overlayPainter, }) async { final ui.PictureRecorder pictureRecorder = ui.PictureRecorder(); final Canvas canvas = Canvas(pictureRecorder); @@ -286,20 +293,34 @@ class CropController extends ValueNotifier { canvas.restore(); } + final double outputWidth = cropWidth * factor; + final double outputHeight = cropHeight * factor; + overlayPainter?.paint(canvas, ui.Size(outputWidth, outputHeight)); + //FIXME Picture.toImage() crashes on Flutter Web with the HTML renderer. Use CanvasKit or avoid this operation for now. https://github.com/flutter/engine/pull/20750 - return await pictureRecorder - .endRecording() - .toImage((cropWidth * factor).round(), (cropHeight * factor).round()); + return await pictureRecorder.endRecording().toImage( + outputWidth.round(), + outputHeight.round(), + ); } /// Returns the image cropped with the current crop rectangle. /// /// You can provide the [quality] used in the resizing operation. + /// [overlayPainter] is an optional painter on top of the cropped image; + /// could be used for special effects on the cropped area. /// Returns an [Image] asynchronously. - Future croppedImage( - {ui.FilterQuality quality = FilterQuality.high}) async { + Future croppedImage({ + ui.FilterQuality quality = FilterQuality.high, + final CustomPainter? overlayPainter, + }) async { return Image( - image: UiImageProvider(await croppedBitmap(quality: quality)), + image: UiImageProvider( + await croppedBitmap( + quality: quality, + overlayPainter: overlayPainter, + ), + ), fit: BoxFit.contain, ); } diff --git a/lib/src/crop_image.dart b/lib/src/crop_image.dart index a117732..4531701 100644 --- a/lib/src/crop_image.dart +++ b/lib/src/crop_image.dart @@ -107,6 +107,11 @@ class CropImage extends StatefulWidget { /// When `false`, moves when panning beyond corners but inside the crop rect. final bool alwaysMove; + /// An optional painter between the image and the crop grid. + /// + /// Could be used for special effects on the cropped area. + final CustomPainter? overlayPainter; + const CropImage({ Key? key, this.controller, @@ -126,6 +131,7 @@ class CropImage extends StatefulWidget { this.minimumImageSize = 100, this.maximumImageSize = double.infinity, this.alwaysMove = false, + this.overlayPainter, }) : gridInnerColor = gridInnerColor ?? gridColor, gridCornerColor = gridCornerColor ?? gridColor, assert(gridCornerSize > 0, 'gridCornerSize cannot be zero'), @@ -293,6 +299,12 @@ class _CropImageState extends State { ), ), ), + if (widget.overlayPainter != null) + SizedBox( + width: width, + height: height, + child: CustomPaint(painter: widget.overlayPainter), + ), SizedBox( width: width + 2 * widget.paddingSize, height: height + 2 * widget.paddingSize,