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 XFile image 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 croppedImage on the home screen
  • crop again using fullImage and cropRectInPixels

Repository

GitHub: https://github.com/umarshyk99/image_cropper_toolkit

Author

Muhammad Umar Farooq
Email: umarshyk99@gmail.com