image_cropper_toolkit 0.0.1
image_cropper_toolkit: ^0.0.1 copied to clipboard
A reusable Flutter image cropper screen with rotate, flip, and repeat-crop support.
image_cropper_toolkit #
A reusable Flutter image cropper package with a ready-made crop screen, rotate and flip controls, custom toolbar widgets, and repeat-crop support.
The package keeps the original/full image available after every crop. This lets users crop again later without losing the full image area.
Features #
- Pick any
XFileimage and open a full-screen crop UI. - Drag the crop box, resize it from the corners, rotate left, rotate right, and flip.
- Save a cropped PNG file to temporary storage.
- Reopen the cropper with the previous crop rectangle selected.
- Customize save button color, crop line color, labels, padding, and toolbar items.
- Use any toolbar widget:
Icon,Image, SVG widget, or a custom widget. - Replace or hide the default header and bottom toolbar.
- No
GetX, no camera dependency, and no SVG dependency.
Installation #
dependencies:
image_cropper_toolkit: ^0.0.1
import 'package:image_cropper_toolkit/image_cropper_toolkit.dart';
Basic Usage #
Future<void> cropImage(BuildContext context, XFile image) async {
final CropImageResult? result = await ImageCropperToolkit.cropImage(
context: context,
imageItem: CropImageItem.fromXFile(image),
);
if (result == null) {
return;
}
final XFile croppedImage = result.croppedImage;
final XFile fullImage = result.fullImage;
final Rect cropRectInPixels = result.cropRectInPixels;
}
Pick Image and Crop #
This example uses image_picker in the host app:
import 'package:flutter/material.dart';
import 'package:image_cropper_toolkit/image_cropper_toolkit.dart';
import 'package:image_picker/image_picker.dart';
final ImagePicker picker = ImagePicker();
Future<void> pickAndCrop(BuildContext context) async {
final XFile? pickedImage = await picker.pickImage(
source: ImageSource.gallery,
);
if (pickedImage == null || !context.mounted) {
return;
}
final CropImageResult? result = await ImageCropperToolkit.cropImage(
context: context,
imageItem: CropImageItem.fromXFile(pickedImage),
);
if (result == null) {
return;
}
// Use result.croppedImage as the preview/output.
}
Crop Again Without Losing Full Image #
Store fullImage and cropRectInPixels after saving. Pass them back when the
user wants to crop again:
Future<void> cropAgain(
BuildContext context,
CropImageResult previousResult,
) async {
final CropImageResult? result = await ImageCropperToolkit.cropImage(
context: context,
imageItem: CropImageItem(
fullImage: previousResult.fullImage,
previewImage: previousResult.croppedImage,
cropRectInPixels: previousResult.cropRectInPixels,
),
);
if (result == null) {
return;
}
// The cropper shows the full image again with the previous crop selected.
}
Customize Colors #
final CropImageResult? result = await ImageCropperToolkit.cropImage(
context: context,
imageItem: CropImageItem.fromXFile(image),
config: const CropImageConfig(
title: 'Crop Image',
saveLabel: 'Save',
backgroundColor: Colors.white,
canvasBackgroundColor: Color(0xFFF1F1F1),
saveButtonColor: Color(0xFF2563EB),
saveButtonForegroundColor: Colors.white,
cropLineColor: Color(0xFF2563EB),
textColor: Color(0xFF111827),
disabledColor: Color(0xFF9CA3AF),
),
);
cropLineColor is used for the crop border, grid lines, and corner handles.
Customize Toolbar Widgets and Titles #
Use child for any static widget:
config: const CropImageConfig(
rotateLeftItem: CropToolbarItemConfig(
child: Icon(Icons.rotate_left_rounded),
title: 'Left',
tooltip: 'Rotate left',
),
rotateRightItem: CropToolbarItemConfig(
child: Icon(Icons.rotate_right_rounded),
title: 'Right',
tooltip: 'Rotate right',
),
flipItem: CropToolbarItemConfig(
child: Icon(Icons.flip_rounded),
title: 'Flip',
tooltip: 'Flip image',
),
),
Use builder when the toolbar widget needs disabled/tablet styling:
config: CropImageConfig(
flipItem: CropToolbarItemConfig(
title: 'Flip',
tooltip: 'Flip image',
builder: (context, isDisabled, isTablet) {
return Image.asset(
'assets/flip.png',
width: isTablet ? 56 : 36,
height: isTablet ? 56 : 36,
color: isDisabled ? Colors.grey : Colors.black,
);
},
),
),
The child or builder can return an Icon, Image, SVG widget from your
app, or any custom widget. This package does not depend on any SVG package.
Hide Default Header or Bottom Toolbar #
final CropImageResult? result = await ImageCropperToolkit.cropImage(
context: context,
imageItem: CropImageItem.fromXFile(image),
showHeader: false,
showBottomBar: false,
);
Custom Header or Bottom Toolbar #
final CropImageResult? result = await ImageCropperToolkit.cropImage(
context: context,
imageItem: CropImageItem.fromXFile(image),
headerBuilder: (context, actions, isProcessing) {
return AppBar(
leading: BackButton(onPressed: actions.cancel),
title: const Text('Adjust image'),
actions: [
TextButton(
onPressed: isProcessing ? null : actions.save,
child: const Text('Done'),
),
],
);
},
bottomBarBuilder: (context, actions, isProcessing) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: isProcessing ? null : actions.rotateLeft,
icon: const Icon(Icons.rotate_left_rounded),
),
IconButton(
onPressed: isProcessing ? null : actions.rotateRight,
icon: const Icon(Icons.rotate_right_rounded),
),
IconButton(
onPressed: isProcessing ? null : actions.flip,
icon: const Icon(Icons.flip_rounded),
),
],
);
},
);
Result Fields #
| Field | Description |
|---|---|
fullImage |
Full working image after rotate/flip transforms. Store it for crop-again flows. |
croppedImage |
Cropped PNG output file. Show this as the preview/result. |
cropRectInPixels |
Crop rectangle in fullImage pixel coordinates. |
Example #
See the example/ app for a complete flow:
- pick image using
image_picker - open the crop screen
- show
croppedImageon the home screen - crop again using
fullImageandcropRectInPixels
Repository #
GitHub: https://github.com/umarshyk99/image_cropper_toolkit
Author #
Muhammad Umar Farooq
Email: umarshyk99@gmail.com