Skip to content

Commit 75def6b

Browse files
Merge pull request #44 from icapps/feature/keep-ratio-while-cropping
Feature/keep ratio while cropping
2 parents 08486fd + 7c83219 commit 75def6b

11 files changed

+398
-223
lines changed

CHANGELOG.md

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,55 @@
1+
## [0.0.12] - 2023-09-08
2+
3+
- Fixed issues with Ratio and CustomImageCrop
4+
- Added fillCropSpace as CustomImageFit
5+
16
## [0.0.11] - 2023-09-01
27

3-
* Added clipShapeOnCrop to prevent clipping the image to the crop shape
8+
- Added clipShapeOnCrop to prevent clipping the image to the crop shape
49

510
## [0.0.10] - 2023-08-17
611

7-
* Added didupdateWidget check to fix issues with updated images
12+
- Added didupdateWidget check to fix issues with updated images
813

914
## [0.0.9] - 2023-08-10
1015

11-
* Added borderRadius
16+
- Added borderRadius
1217

1318
## [0.0.8] - 2023-08-10
1419

15-
* Added pathPaint to customize the crop border style
20+
- Added pathPaint to customize the crop border style
1621

1722
## [0.0.7] - 2023-08-09
1823

19-
* Added Ratio as new shape and arguments
24+
- Added Ratio as new shape and arguments
2025

2126
## [0.0.6]
2227

23-
* Added new param to CustomImageCrop for new image fit types
28+
- Added new param to CustomImageCrop for new image fit types
2429

2530
## [0.0.5]
2631

27-
* Added canRotate
28-
* Added customProgressIndicator
29-
* Added canScale
30-
* Added canMove
32+
- Added canRotate
33+
- Added customProgressIndicator
34+
- Added canScale
35+
- Added canMove
3136

3237
## [0.0.4]
3338

34-
* Added documentation
39+
- Added documentation
3540

3641
## [0.0.3]
3742

38-
* Fixed issue where cropped image's size depends on screen size used
39-
* Fixed issue where cropped image's quality is worse than original image
40-
* Updated to flutter 2.8.0
43+
- Fixed issue where cropped image's size depends on screen size used
44+
- Fixed issue where cropped image's quality is worse than original image
45+
- Updated to flutter 2.8.0
4146

4247
## [0.0.2]
4348

44-
* Updated docs
49+
- Updated docs
4550

4651
## [0.0.1]
4752

48-
* Added custom crop
49-
* Added Cicrle and Square crop shapes
50-
* Added Solid and Dotted painters for crop border
53+
- Added custom crop
54+
- Added Cicrle and Square crop shapes
55+
- Added Solid and Dotted painters for crop border

example/assets/test2.png

81 KB
Loading

example/lib/main.dart

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class MyHomePage extends StatefulWidget {
4141
class _MyHomePageState extends State<MyHomePage> {
4242
late CustomImageCropController controller;
4343
CustomCropShape _currentShape = CustomCropShape.Circle;
44+
CustomImageFit _imageFit = CustomImageFit.fillCropSpace;
4445
final TextEditingController _widthController = TextEditingController();
4546
final TextEditingController _heightController = TextEditingController();
4647
final TextEditingController _radiusController = TextEditingController();
@@ -67,6 +68,12 @@ class _MyHomePageState extends State<MyHomePage> {
6768
});
6869
}
6970

71+
void _changeImageFit(CustomImageFit imageFit) {
72+
setState(() {
73+
_imageFit = imageFit;
74+
});
75+
}
76+
7077
void _updateRatio() {
7178
setState(() {
7279
if (_widthController.text.isNotEmpty) {
@@ -102,17 +109,17 @@ class _MyHomePageState extends State<MyHomePage> {
102109
? Ratio(width: _width, height: _height)
103110
: null,
104111
canRotate: true,
105-
canMove: false,
106-
canScale: false,
112+
canMove: true,
113+
canScale: true,
107114
borderRadius:
108115
_currentShape == CustomCropShape.Ratio ? _radius : 0,
109116
customProgressIndicator: const CupertinoActivityIndicator(),
110-
// use custom paint if needed
111-
// pathPaint: Paint()
112-
// ..color = Colors.red
113-
// ..strokeWidth = 4.0
114-
// ..style = PaintingStyle.stroke
115-
// ..strokeJoin = StrokeJoin.round,
117+
imageFit: _imageFit,
118+
pathPaint: Paint()
119+
..color = Colors.red
120+
..strokeWidth = 4.0
121+
..style = PaintingStyle.stroke
122+
..strokeJoin = StrokeJoin.round,
116123
),
117124
),
118125
Row(
@@ -136,34 +143,51 @@ class _MyHomePageState extends State<MyHomePage> {
136143
icon: const Icon(Icons.rotate_right),
137144
onPressed: () =>
138145
controller.addTransition(CropImageData(angle: pi / 4))),
139-
IconButton(
140-
icon: const Icon(Icons.crop),
141-
onPressed: () async {
142-
final image = await controller.onCropImage();
143-
if (image != null) {
144-
Navigator.of(context).push(MaterialPageRoute(
145-
builder: (BuildContext context) =>
146-
ResultScreen(image: image)));
147-
}
148-
},
149-
),
150-
PopupMenuButton<CustomCropShape>(
146+
PopupMenuButton(
151147
icon: const Icon(Icons.crop_original),
152148
onSelected: _changeCropShape,
153149
itemBuilder: (BuildContext context) {
154150
return CustomCropShape.values.map(
155151
(shape) {
156-
return PopupMenuItem<CustomCropShape>(
152+
return PopupMenuItem(
157153
value: shape,
158154
child: getShapeIcon(shape),
159155
);
160156
},
161157
).toList();
162158
},
163159
),
160+
PopupMenuButton(
161+
icon: const Icon(Icons.fit_screen),
162+
onSelected: _changeImageFit,
163+
itemBuilder: (BuildContext context) {
164+
return CustomImageFit.values.map(
165+
(imageFit) {
166+
return PopupMenuItem(
167+
value: imageFit,
168+
child: Text(imageFit.label),
169+
);
170+
},
171+
).toList();
172+
},
173+
),
174+
IconButton(
175+
icon: const Icon(
176+
Icons.crop,
177+
color: Colors.green,
178+
),
179+
onPressed: () async {
180+
final image = await controller.onCropImage();
181+
if (image != null) {
182+
Navigator.of(context).push(MaterialPageRoute(
183+
builder: (BuildContext context) =>
184+
ResultScreen(image: image)));
185+
}
186+
},
187+
),
164188
],
165189
),
166-
if (_currentShape == CustomCropShape.Ratio)
190+
if (_currentShape == CustomCropShape.Ratio) ...[
167191
SizedBox(
168192
child: Row(
169193
children: [
@@ -198,6 +222,7 @@ class _MyHomePageState extends State<MyHomePage> {
198222
],
199223
),
200224
),
225+
],
201226
SizedBox(height: MediaQuery.of(context).padding.bottom),
202227
],
203228
),
@@ -215,3 +240,26 @@ class _MyHomePageState extends State<MyHomePage> {
215240
}
216241
}
217242
}
243+
244+
extension CustomImageFitExtension on CustomImageFit {
245+
String get label {
246+
switch (this) {
247+
case CustomImageFit.fillCropSpace:
248+
return 'Fill crop space';
249+
case CustomImageFit.fitCropSpace:
250+
return 'Fit crop space';
251+
case CustomImageFit.fillCropHeight:
252+
return 'Fill crop height';
253+
case CustomImageFit.fillCropWidth:
254+
return 'Fill crop width';
255+
case CustomImageFit.fillVisibleSpace:
256+
return 'Fill visible space';
257+
case CustomImageFit.fitVisibleSpace:
258+
return 'Fit visible space';
259+
case CustomImageFit.fillVisibleHeight:
260+
return 'Fill visible height';
261+
case CustomImageFit.fillVisibleWidth:
262+
return 'Fill visible width';
263+
}
264+
}
265+
}

example/lib/result_screen.dart

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,36 @@ class ResultScreen extends StatelessWidget {
1616
title: const Text('Result'),
1717
systemOverlayStyle: SystemUiOverlayStyle.dark,
1818
),
19-
body: Center(
20-
child: Column(
21-
children: [
22-
const Spacer(),
23-
Image(
19+
body: Stack(
20+
children: [
21+
Positioned.fill(
22+
child: Container(
23+
decoration: BoxDecoration(
24+
gradient: LinearGradient(
25+
colors: [
26+
Colors.blueGrey.shade400,
27+
Colors.blueGrey.shade600,
28+
],
29+
begin: Alignment.topCenter,
30+
end: Alignment.bottomCenter,
31+
),
32+
)),
33+
),
34+
Center(
35+
child: Image(
2436
image: image,
2537
),
26-
ElevatedButton(
38+
),
39+
Positioned(
40+
bottom: 16,
41+
left: 16,
42+
right: 16,
43+
child: ElevatedButton(
2744
child: const Text('Back'),
2845
onPressed: () => Navigator.of(context).pop(),
2946
),
30-
const Spacer(),
31-
],
32-
),
47+
),
48+
],
3349
),
3450
);
3551
}

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ packages:
4949
path: ".."
5050
relative: true
5151
source: path
52-
version: "0.0.9"
52+
version: "0.0.12"
5353
fake_async:
5454
dependency: transitive
5555
description:
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import 'package:custom_image_crop/src/models/params_model.dart';
2+
import 'package:custom_image_crop/src/widgets/custom_image_crop_widget.dart';
3+
4+
/// Returns params to use for displaying crop screen.
5+
CropFitParams calculateCropFitParams({
6+
required double screenWidth,
7+
required double screenHeight,
8+
required double cropPercentage,
9+
required int imageWidth,
10+
required int imageHeight,
11+
required CustomImageFit imageFit,
12+
required double aspectRatio,
13+
}) {
14+
/// the width of the area to crop
15+
final double cropSizeWidth;
16+
17+
/// the height of the area to crop
18+
final double cropSizeHeight;
19+
20+
/// used to adjust image scale
21+
final double defaultScale;
22+
23+
switch (imageFit) {
24+
case CustomImageFit.fillCropSpace:
25+
if (screenWidth <= screenHeight * aspectRatio) {
26+
cropSizeWidth = screenWidth * cropPercentage;
27+
cropSizeHeight = cropSizeWidth / aspectRatio;
28+
defaultScale = cropSizeWidth / imageWidth;
29+
} else {
30+
cropSizeHeight = screenHeight * cropPercentage;
31+
cropSizeWidth = cropSizeHeight * aspectRatio;
32+
defaultScale = cropSizeHeight / imageHeight;
33+
}
34+
break;
35+
36+
case CustomImageFit.fitCropSpace:
37+
if (screenWidth <= screenHeight * aspectRatio) {
38+
cropSizeWidth = screenWidth * cropPercentage;
39+
cropSizeHeight = cropSizeWidth / aspectRatio;
40+
defaultScale = cropSizeHeight / imageHeight;
41+
} else {
42+
cropSizeHeight = screenHeight * cropPercentage;
43+
cropSizeWidth = cropSizeHeight * aspectRatio;
44+
defaultScale = cropSizeWidth / imageWidth;
45+
}
46+
break;
47+
48+
case CustomImageFit.fillCropWidth:
49+
if (screenWidth <= screenHeight * aspectRatio) {
50+
cropSizeWidth = screenWidth * cropPercentage;
51+
cropSizeHeight = cropSizeWidth / aspectRatio;
52+
} else {
53+
cropSizeHeight = screenHeight * cropPercentage;
54+
cropSizeWidth = cropSizeHeight * aspectRatio;
55+
}
56+
defaultScale = cropSizeWidth / imageWidth;
57+
break;
58+
59+
case CustomImageFit.fillCropHeight:
60+
if (screenWidth <= screenHeight * aspectRatio) {
61+
cropSizeWidth = screenWidth * cropPercentage;
62+
cropSizeHeight = cropSizeWidth / aspectRatio;
63+
} else {
64+
cropSizeHeight = screenHeight * cropPercentage;
65+
cropSizeWidth = cropSizeHeight * aspectRatio;
66+
}
67+
defaultScale = cropSizeHeight / imageHeight;
68+
break;
69+
70+
case CustomImageFit.fitVisibleSpace:
71+
if (screenWidth <= screenHeight * aspectRatio) {
72+
cropSizeWidth = screenWidth * cropPercentage;
73+
cropSizeHeight = cropSizeWidth / aspectRatio;
74+
defaultScale = screenWidth / imageWidth;
75+
} else {
76+
cropSizeHeight = screenHeight * cropPercentage;
77+
cropSizeWidth = cropSizeHeight * aspectRatio;
78+
defaultScale = screenHeight / imageHeight;
79+
}
80+
break;
81+
82+
case CustomImageFit.fillVisibleSpace:
83+
if (screenWidth <= screenHeight * aspectRatio) {
84+
cropSizeWidth = screenWidth * cropPercentage;
85+
cropSizeHeight = cropSizeWidth / aspectRatio;
86+
defaultScale = screenHeight / imageHeight;
87+
} else {
88+
cropSizeHeight = screenHeight * cropPercentage;
89+
cropSizeWidth = cropSizeHeight * aspectRatio;
90+
defaultScale = screenWidth / imageWidth;
91+
}
92+
break;
93+
94+
case CustomImageFit.fillVisibleHeight:
95+
if (screenWidth <= screenHeight * aspectRatio) {
96+
cropSizeWidth = screenWidth * cropPercentage;
97+
cropSizeHeight = cropSizeWidth / aspectRatio;
98+
} else {
99+
cropSizeHeight = screenHeight * cropPercentage;
100+
cropSizeWidth = cropSizeHeight * aspectRatio;
101+
}
102+
defaultScale = screenHeight / imageHeight;
103+
break;
104+
105+
case CustomImageFit.fillVisibleWidth:
106+
if (screenWidth <= screenHeight * aspectRatio) {
107+
cropSizeWidth = screenWidth * cropPercentage;
108+
cropSizeHeight = cropSizeWidth / aspectRatio;
109+
} else {
110+
cropSizeHeight = screenHeight * cropPercentage;
111+
cropSizeWidth = cropSizeHeight * aspectRatio;
112+
}
113+
defaultScale = screenWidth / imageWidth;
114+
break;
115+
}
116+
117+
return CropFitParams(
118+
cropSizeWidth: cropSizeWidth,
119+
cropSizeHeight: cropSizeHeight,
120+
additionalScale: defaultScale,
121+
);
122+
}

0 commit comments

Comments
 (0)