Once you've captured or selected an image in android or iOS device, you may need to crop it. There are flutter packages or libraries already written to help with this. We examine these in this article.
(a). Image Cropper
A Flutter plugin for Android and iOS supports cropping images. This plugin is based on two different native libraries so it comes with different UI between these platforms.
Image Cropper doesn't manipulate images in Dart codes directly, instead, the plugin uses Platform Channel to expose Dart APIs that Flutter application can use to communicate with two very powerful native libraries (uCrop and TOCropViewController) to crop and rotate images. Because of that, all credits belong to these libraries.
uCrop - Yalantis
This project aims to provide an ultimate and flexible image cropping experience. Made in Made in Yalantis
TOCropViewController - TimOliver
TOCropViewController
is an open-source UIViewController
subclass to crop out sections of UIImage
objects, as well as perform basic rotations. It is excellent for things like editing profile pictures, or sharing parts of a photo online. It has been designed with the iOS Photos app editor in mind, and as such, behaves in a way that should already feel familiar to users of iOS.
How to install
Depend on it:
Run this command:
With Flutter:
$ flutter pub add image_cropper
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
image_cropper: ^1.4.0
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Import it
Now in your Dart code, you can use:
import 'package:image_cropper/image_cropper.dart';
Android
- Add UCropActivity into your AndroidManifest.xml
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
iOS
- No configuration required
Usage
Required parameters
- sourcePath: the absolute path of an image file.
Optional parameters
- maxWidth: maximum cropped image width.
- maxHeight: maximum cropped image height.
- aspectRatio: controls the aspect ratio of crop bounds. If this values is set, the cropper is locked and user can't change the aspect ratio of crop bounds.
-
aspectRatioPresets: controls the list of aspect ratios in the crop menu view. In Android, you can set the initialized aspect ratio when starting the cropper by setting the value of
AndroidUiSettings.initAspectRatio
. -
cropStyle: controls the style of crop bounds, it can be rectangle or circle style (default is
CropStyle.rectangle
). - compressFormat: the format of result image, png or jpg (default is ImageCompressFormat.jpg).
- compressQuality: the value [0 - 100] to control the quality of image compression.
- androidUiSettings: controls UI customization on Android. See Android customization.
- iosUiSettings: controls UI customization on iOS. See iOS customization.
Note
The result file is saved in NSTemporaryDirectory
on iOS and application Cache directory on Android, so it can be lost later, you are responsible for storing it somewhere permanent (if needed).
Full Example
Here's an image cropping example with this library:
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ImageCropper',
theme: ThemeData.light().copyWith(primaryColor: Colors.deepOrange),
home: MyHomePage(
title: 'ImageCropper',
),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({required this.title});
@override
_MyHomePageState createState() => _MyHomePageState();
}
enum AppState {
free,
picked,
cropped,
}
class _MyHomePageState extends State<MyHomePage> {
late AppState state;
File? imageFile;
@override
void initState() {
super.initState();
state = AppState.free;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: imageFile != null ? Image.file(imageFile!) : Container(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.deepOrange,
onPressed: () {
if (state == AppState.free)
_pickImage();
else if (state == AppState.picked)
_cropImage();
else if (state == AppState.cropped) _clearImage();
},
child: _buildButtonIcon(),
),
);
}
Widget _buildButtonIcon() {
if (state == AppState.free)
return Icon(Icons.add);
else if (state == AppState.picked)
return Icon(Icons.crop);
else if (state == AppState.cropped)
return Icon(Icons.clear);
else
return Container();
}
Future<Null> _pickImage() async {
final pickedImage =
await ImagePicker().getImage(source: ImageSource.gallery);
imageFile = pickedImage != null ? File(pickedImage.path) : null;
if (imageFile != null) {
setState(() {
state = AppState.picked;
});
}
}
Future<Null> _cropImage() async {
File? croppedFile = await ImageCropper.cropImage(
sourcePath: imageFile!.path,
aspectRatioPresets: Platform.isAndroid
? [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
]
: [
CropAspectRatioPreset.original,
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio5x3,
CropAspectRatioPreset.ratio5x4,
CropAspectRatioPreset.ratio7x5,
CropAspectRatioPreset.ratio16x9
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
title: 'Cropper',
));
if (croppedFile != null) {
imageFile = croppedFile;
setState(() {
state = AppState.cropped;
});
}
}
void _clearImage() {
imageFile = null;
setState(() {
state = AppState.free;
});
}
}
Reference
Find full reference here.
(b). flutter_native_image
Native Flutter Image tools
This plugin aims to have native tools to resize images and reduce their quality by compression. The code is somewhat hacky (especially the iOS part), but it works for my needs and hasn't crashed on me. Feel free to improve it if you want to.
Right now there are a few functions. Please find some examples below.
Install
Add the following lines to your pubspec.yaml under dependencies
flutter_native_image: ^0.0.6
Usage
Crop an image
File croppedFile = await FlutterNativeImage.cropImage(file.path, originX, originY, width, height);
Returns a file containing the image cropped with the given dimensions.
Other Functionalities
This library provides extra functionalities like:
Compress an image
File compressedFile = await FlutterNativeImage.compressImage(file.path,
quality: quality, percentage: percentage);
You have to give it a file from the file system and optionally provide a quality (1-100) and a resizing percentage (1-100). Each platform will use it's proper tools to handle the resizing.
To resize the image to the certain size, use following code:
ImageProperties properties = await FlutterNativeImage.getImageProperties(file.path);
File compressedFile = await FlutterNativeImage.compressImage(file.path, quality: 80,
targetWidth: 600, targetHeight: 300);
Keep aspect ratio of the file:
ImageProperties properties = await FlutterNativeImage.getImageProperties(file.path);
File compressedFile = await FlutterNativeImage.compressImage(file.path, quality: 80,
targetWidth: 600,
targetHeight: (properties.height * 600 / properties.width).round());
Get image properties
ImageProperties properties = await FlutterNativeImage.getImageProperties(file.path);
It returns an ImageProperties object containing the width and the height of the image.
Reference
Find full reference here.