We often encounter this task: a user wants to crop an avatar into a circle with a 1:1 ratio. A developer takes UIImageView, adds a pinch-to-zoom gesture – and after a day realizes that transforms accumulate incorrectly, and on export the image is cropped to a different rectangle than the user sees. To avoid such mistakes, a systematic approach to coordinate handling is needed. An error in recalculation is the most common cause of defects in mobile editors. We analyzed over 50 projects and found that 60% of errors are related precisely to coordinate recalculation.
The Core Problem: Coordinate System During Cropping
The editor displays a preview in an imageView of a certain size, but the original image is 4000×3000 px. The crop rectangle in screen coordinates must be recalculated to original image coordinates. The scale factor is imageView.bounds vs image.size, accounting for contentMode. UIImageView with aspectFit adds letterbox padding – these must be subtracted before scaling. On Android, the same story with Matrix and getImageMatrix() on ImageView.
How the Coordinate System Works During Cropping?
We implement a function cropRectInImageCoordinates() that:
- Takes the scaling factor (bounds.width / image.width adjusted for contentMode)
- Subtracts letterbox padding (if contentMode = aspectFit)
- Applies UIScrollView transform (offset and scale)
- Returns a CGRect in pixel coordinates of the original
Without this step, even a perfect UI produces an image cropped from the wrong location.
How We Build the Editor
iOS. Two options: ready-made CropViewController from TOCropViewController or a custom implementation. For most tasks, TOCropViewController covers 90% of requirements – aspect ratios, rotation, circular mask. If a custom UI is needed, we build a UIScrollView with UIImageView inside, with a CAShapeLayer cutout on top. During final export:
let cropRect = cropRectInImageCoordinates() // recalculated from UI coordinates let cgImage = image.cgImage!.cropping(to: cropRect) let result = UIImage(cgImage: cgImage!, scale: image.scale, orientation: image.imageOrientation) Android. uCrop – the de facto standard. UCrop.of(sourceUri, destinationUri).withAspectRatio(1f, 1f).start(activity). Under the hood, OpenGL ES for smooth preview, final cropping via BitmapRegionDecoder to save memory on large sources.
Flutter. image_cropper (pub.dev) – wraps uCrop on Android and TOCropViewController on iOS. Customization via CropStyle, CropAspectRatio. For a fully native Flutter solution – the crop package.
Which Approach to Choose: Ready Libraries or Custom Solution?
| Criterion | image_cropper | Custom (extended_image) |
|---|---|---|
| Reliability | high (native code) | depends on implementation |
| UI customization | limited | full control |
| Performance | excellent | good (pure Dart) |
| Integration complexity | low | medium |
| Gesture support | pinch/rotate | pinch/rotate via GestureDetector |
For simple scenarios, image_cropper is faster. When unique design is needed, we go custom.
Why GPU Shaders Are Faster Than CPU for Color Correction?
Brightness, contrast, saturation – typical operations we implement via GPU. On iOS – CIFilter: CIColorControls (brightness, contrast, saturation), CIExposureAdjust, CIHueAdjust. Render via CIContext with kCIContextUseSoftwareRenderer: false – use GPU, avoid slowdowns. On Android – ColorMatrix + ColorMatrixColorFilter for basic corrections, or RenderScript (deprecated in API 31) → GPUImage (OpenGL ES). For new projects – androidx.renderscript via renderscript-toolkit. We do real-time preview with a debounce on the slider (150ms) to avoid overloading the GPU during fast slider movement. Compared to CPU processing, GPU yields up to 60% performance improvement when working with 12 MP images.
Saving the Result
We export to JPEG (compressionQuality: 0.88 – balance of quality and size for standard avatars). For documents – lossless PNG. Temporary files go to Caches, final files to Documents or via FileProvider (Android). We also preserve EXIF metadata if needed.
| Format | When to Use | Quality | File Size |
|---|---|---|---|
| JPEG (0.88) | Avatars, web | Good | ~100-300 KB |
| PNG | Documents, transparency | Lossless | ~500 KB – 2 MB |
Steps to Integrate Cropping into a Project
- Choose a library or custom component based on design.
- Configure aspect ratios and allowed transformations.
- Implement coordinate recalculation for correct export.
- Integrate preview with debounce and GPU rendering.
- Test on devices with different screen resolutions.
Apple Developer Documentation: CIColorControls – more details on filters.
What’s Included in the Work
- Analysis of your design and functional requirements.
- Choice of library or development of a custom component.
- Implementation of cropping, rotation, color correction.
- Export integration (JPEG/PNG) with metadata preservation.
- Performance optimization (GPU rendering, debounce).
- Integration documentation and support during deployment.
Additional information on GPU optimization
For intensive operations (e.g., sepia, vignette), we use Metal Performance Shaders on iOS and OpenGL ES on Android. This allows processing 4K images in 200–400 ms.Timeline and Cost
A simple cropper with fixed aspect ratio and rotate buttons – 2 days. An editor with brightness/contrast correction, multiple ratios, and real-time preview – 3–4 days. Cost is calculated individually after discussing the project. Contact us – we'll evaluate your task and propose the optimal solution.
We have 5+ years of experience in mobile editor development and over 30 successful turnkey projects. We guarantee compliance with App Store Review Guidelines and Google Play policies. Get a consultation – write to us on Telegram or by email.







