# image_cropper, the Flutter plugin that delegates cropping to three native libraries

> image_cropper is a Flutter plugin for Android, iOS and Web that does not crop in Dart at all. It uses a platform channel to hand the work to uCrop on Android, TOCropViewController on iOS and Cropper.js in the browser, which is why the cropping interface looks different on each platform. The cost of that approach is that some parameters behave differently depending on where the app runs.

**hnvn/flutter_image_cropper** — A Flutter plugin for Android and iOS supports cropping images

- Repository: https://github.com/hnvn/flutter_image_cropper
- Stars: 1,057 · Forks: 479
- Language: Dart
- License: not declared
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/hnvn-flutter-image-cropper

## Three libraries, three different crop screens

The design of this plugin is unusual enough to state first. Image Cropper does not manipulate images in Dart code at all. Instead it uses the platform channel to expose Dart APIs, and those APIs talk to three different native libraries, one per platform: uCrop on Android, TOCropViewController on iOS, and Cropper.js in the browser. The project is explicit that all the credit belongs to those libraries, and the documentation describes each of them in turn, with the licence each is under, from the Apache 2.0 of uCrop to the MIT licences of the other two. The consequence for users is stated plainly in the same breath: the plugin comes with a different UI between these platforms. What you get on Android is a different cropping interface from what you get on iOS, and what you get in the browser is different again. For an application where the crop screen is a minor step, that is a reasonable trade. For one where the crop result is compared byte for byte across platforms, it is not. On Android, the uCrop activity has to be declared in the manifest.

```xml
<activity
  android:name="com.yalantis.ucrop.UCropActivity"
  android:screenOrientation="portrait"
  android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
```

## What uCrop and TOCropViewController bring to the table

The two mobile libraries are what make the platform feel native rather than translated. uCrop, by Yalantis, describes itself as aiming to provide an ultimate and flexible image cropping experience, and it is the one you get on Android, with the activity declared in the manifest as shown. The iOS library, TOCropViewController by Tim Oliver, is an open source UIViewController subclass to crop sections of UIImage objects and perform basic rotations, and the project documentation notes it was designed with the iOS Photos app editor in mind, so it behaves in a way that should feel familiar to iOS users. That last point is the real argument for delegating rather than reimplementing. A hand written crop screen in Flutter will look the same everywhere, which is often precisely the problem, because a user who has cropped a photo on their phone expects the phone's own interaction. The web path, Cropper.js by Fengyuan Chen, is a JavaScript image cropper, which you have to load from a CDN yourself in the page.

## The web path needs the library in your page

The web integration is the one that requires manual work, and the documentation is explicit about it. You have to add the cropperjs stylesheet and script inside the head tag of your web/index.html file, and the version pinned in the example is 1.6.2 served from cdnjs.cloudflare.com. That is a real difference in kind from the mobile setup, where the native library is bundled with the plugin. It also means the web build depends on a third-party CDN being reachable at runtime, which is worth considering if your web deployment is offline-first or has a strict content policy. The plugin is published on pub.dev under the name image_cropper, and the repository is split into three packages at the top level: the main `image_cropper` package, `image_cropper_for_web`, and `image_cropper_platform_interface`, which is the standard Flutter arrangement for a federated plugin where the platform implementations are separate packages.

## The parameter list, and where it quietly stops working

The API is small. The one required parameter is `sourcePath`, the absolute path of an image file. The optional ones are `maxWidth` and `maxHeight` for the cropped output size, `aspectRatio`, which locks the crop bounds to a fixed ratio when set so the user cannot change it, `compressFormat` for png or jpg with jpg as the default, `compressQuality` as a number between 0 and 100, and `uiSettings` for per-platform interface customization, with separate classes for Android, iOS and Web. Two of the notes are the ones to read before you rely on the API. `compressQuality` is ignored on Web. And the web implementation is described as much different from the mobile one, which is what causes configuration fields to stop working there. The documentation also says `WebUiSettings` is required on Web. In other words, one call signature covers three platforms, but the behavioural contract does not, and the differences are in the fields you would most expect to be portable.

## The result file is temporary, and that is your problem

The single most likely bug in an application built on this plugin comes from the note about where the result lands. The result file is saved in the temporary directory on iOS and in the application cache directory on Android, so it can be lost later, and you are responsible for storing it somewhere permanent if you need it. Neither location is a durable store, and both are subject to the operating system's own housekeeping. The correct pattern is to copy the cropped output to your own application storage or upload it immediately, and to treat the returned path as a short-lived handle rather than a saved asset. This is not a documentation nitpick; it is the kind of detail that produces an intermittent failure in production, where the image was cropped fine and then disappeared some time later, and where the reproduction depends on the device's storage pressure rather than on anything in your code.

## Customisation is per platform, and the classes differ

Interface customisation is handled by a set of helper classes, one per platform, and each wraps the properties the underlying native library accepts. The Android one is `AndroidUiSettings`, described as a helper class that wraps all the properties that can be used to customise the interface in the uCrop library, and the documentation links to per platform detail sections for Android, iOS and Web. Because the wrappers mirror the native libraries rather than a common abstraction, the options that exist on one platform generally do not exist on the others, and a designer asking for a consistent look across the three is asking for something the architecture does not offer. The trade-off follows from the whole design: you get the platform's own look and feel, which is what most product teams want, in exchange for a smaller common surface. The repository also carries a GitHub Actions workflow for continuous integration, and the plugin publishes its own screenshots of the Android, iOS and web croppers in the documentation, which is a quick way to see how much the three differ before you commit to the dependency.

## Conclusion

Adopt image_cropper if you want a cropping experience that matches each platform's own conventions, users on iOS who expect the Photos-style editor, and you are willing to test the result on three platforms, and skip it if you need identical pixel output everywhere, because three different libraries produce three different results. Verify three things before you ship: that you move the cropped file out of its temporary location, since it is saved in the temporary directory on iOS and the cache directory on Android and can be lost; that you supply WebUiSettings on Web, which is required there; and that you do not rely on compressQuality in the browser, where the field is ignored.

## FAQ

### Does the image_cropper Flutter plugin crop images in Dart?

No. It uses a platform channel to expose Dart APIs that communicate with three native libraries: uCrop on Android, TOCropViewController on iOS and Cropper.js in the browser, and the project states that all credits belong to those libraries. The result is a different interface on each platform.

### What configuration does the image_cropper plugin need on Android and Web?

On Android you add the UCropActivity to your AndroidManifest.xml, and from v1.2.0 the Android project must be migrated to v2 embedding. On iOS no configuration is required. On Web you add the cropperjs stylesheet and script inside the head tag of your web/index.html file.

### Where does the cropped image file end up?

In the temporary directory on iOS and in the application cache directory on Android, so it can be lost later. You are responsible for storing it somewhere permanent if you need it.

### Which image_cropper parameters work on the Web?

The web implementation differs from the mobile one, and `compressQuality` is ignored there. `WebUiSettings` is required on Web, while the general settings are `sourcePath` as the only required parameter, plus the optional `maxWidth`, `maxHeight`, `aspectRatio`, `compressFormat` and `uiSettings`.

## Sources

- [hnvn/flutter_image_cropper on GitHub](https://github.com/hnvn/flutter_image_cropper)
- [Issues](https://github.com/hnvn/flutter_image_cropper/issues)
- [README](https://github.com/hnvn/flutter_image_cropper/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hnvn-flutter-image-cropper
