1
1
import 'dart:async' ;
2
- import 'dart:math' ;
3
2
import 'dart:ui' as ui;
4
3
5
4
import 'package:flutter/material.dart' ;
@@ -10,6 +9,8 @@ import 'package:custom_image_crop/src/controllers/controller.dart';
10
9
import 'package:custom_image_crop/src/painters/dotted_path_painter.dart' ;
11
10
import 'package:custom_image_crop/src/clippers/inverted_clipper.dart' ;
12
11
import 'package:custom_image_crop/src/models/model.dart' ;
12
+ import 'package:custom_image_crop/src/calculators/calculate_crop_params.dart' ;
13
+ import 'package:custom_image_crop/src/calculators/calculate_on_crop_params.dart' ;
13
14
14
15
/// An image cropper that is customizable.
15
16
/// You can rotate, scale and translate either
@@ -31,6 +32,9 @@ class CustomImageCrop extends StatefulWidget {
31
32
/// The shape of the cropping area
32
33
final CustomCropShape shape;
33
34
35
+ /// How to fit image inside visible space
36
+ final CustomImageFit imageFit;
37
+
34
38
/// The percentage of the available area that is
35
39
/// reserved for the cropping area
36
40
final double cropPercentage;
@@ -83,6 +87,7 @@ class CustomImageCrop extends StatefulWidget {
83
87
this .overlayColor = const Color .fromRGBO (0 , 0 , 0 , 0.5 ),
84
88
this .backgroundColor = Colors .white,
85
89
this .shape = CustomCropShape .Circle ,
90
+ this .imageFit = CustomImageFit .fitCropSpace,
86
91
this .cropPercentage = 0.8 ,
87
92
this .drawPath = DottedCropPathPainter .drawPath,
88
93
this .canRotate = true ,
@@ -159,10 +164,16 @@ class _CustomImageCropState extends State<CustomImageCrop>
159
164
builder: (context, constraints) {
160
165
_width = constraints.maxWidth;
161
166
_height = constraints.maxHeight;
162
- final cropWidth = min (_width, _height) * widget.cropPercentage;
163
- final defaultScale = cropWidth / max (image.width, image.height);
164
- final scale = data.scale * defaultScale;
165
- _path = _getPath (cropWidth, _width, _height);
167
+ final cropParams = calculateCropParams (
168
+ cropPercentage: widget.cropPercentage,
169
+ imageFit: widget.imageFit,
170
+ imageHeight: image.height,
171
+ imageWidth: image.width,
172
+ screenHeight: _height,
173
+ screenWidth: _width,
174
+ );
175
+ final scale = data.scale * cropParams.additionalScale;
176
+ _path = _getPath (cropParams.cropSizeToPaint, _width, _height);
166
177
return XGestureDetector (
167
178
onMoveStart: onMoveStart,
168
179
onMoveUpdate: onMoveUpdate,
@@ -270,20 +281,29 @@ class _CustomImageCropState extends State<CustomImageCrop>
270
281
final imageHeight = _imageAsUIImage! .height;
271
282
final pictureRecorder = ui.PictureRecorder ();
272
283
final canvas = Canvas (pictureRecorder);
273
- final uiWidth = min (_width, _height) * widget.cropPercentage;
274
- final cropWidth = max (imageWidth, imageHeight).toDouble ();
275
- final translateScale = cropWidth / uiWidth;
276
- final scale = data.scale;
277
- final clipPath = Path .from (_getPath (cropWidth, cropWidth, cropWidth));
284
+ final onCropParams = caclulateOnCropParams (
285
+ cropPercentage: widget.cropPercentage,
286
+ imageFit: widget.imageFit,
287
+ imageHeight: imageHeight,
288
+ imageWidth: imageWidth,
289
+ screenHeight: _height,
290
+ screenWidth: _width,
291
+ dataScale: data.scale,
292
+ );
293
+ final clipPath = Path .from (_getPath (
294
+ onCropParams.cropSize, onCropParams.cropSize, onCropParams.cropSize));
278
295
final matrix4Image = Matrix4 .diagonal3 (vector_math.Vector3 .all (1 ))
279
- ..translate (translateScale * data.x + cropWidth / 2 ,
280
- translateScale * data.y + cropWidth / 2 )
281
- ..scale (scale)
296
+ ..translate (
297
+ onCropParams.translateScale * data.x + onCropParams.cropSize / 2 ,
298
+ onCropParams.translateScale * data.y + onCropParams.cropSize / 2 )
299
+ ..scale (onCropParams.scale)
282
300
..rotateZ (data.angle);
283
301
final bgPaint = Paint ()
284
302
..color = widget.backgroundColor
285
303
..style = PaintingStyle .fill;
286
- canvas.drawRect (Rect .fromLTWH (0 , 0 , cropWidth, cropWidth), bgPaint);
304
+ canvas.drawRect (
305
+ Rect .fromLTWH (0 , 0 , onCropParams.cropSize, onCropParams.cropSize),
306
+ bgPaint);
287
307
canvas.save ();
288
308
canvas.clipPath (clipPath);
289
309
canvas.transform (matrix4Image.storage);
@@ -297,8 +317,8 @@ class _CustomImageCropState extends State<CustomImageCrop>
297
317
// final bytes = await compute(computeToByteData, <String, dynamic>{'pictureRecorder': pictureRecorder, 'cropWidth': cropWidth});
298
318
299
319
ui.Picture picture = pictureRecorder.endRecording ();
300
- ui.Image image =
301
- await picture. toImage (cropWidth .floor (), cropWidth .floor ());
320
+ ui.Image image = await picture. toImage (
321
+ onCropParams.cropSize .floor (), onCropParams.cropSize .floor ());
302
322
303
323
// Adding compute would be preferrable. Unfortunately we cannot pass an ui image to this.
304
324
// A workaround would be to save the image and load it inside of the isolate
@@ -333,3 +353,13 @@ enum CustomCropShape {
333
353
Circle ,
334
354
Square ,
335
355
}
356
+
357
+ enum CustomImageFit {
358
+ fitCropSpace,
359
+ fillCropWidth,
360
+ fillCropHeight,
361
+ fitVisibleSpace,
362
+ fillVisibleSpace,
363
+ fillVisibleHeight,
364
+ fillVisiblelWidth,
365
+ }
0 commit comments