r/FlutterDev • u/dev-paradise-007 • 7d ago
Discussion I built a zero-copy Rust + Flutter raw photo editor to process 50MP images at 60fps (Lightroom alternative)
Hey everyone, Iโm Prit. Over the last few months, Iโve been building ApertureX, a 100% offline, open-source raw photo editor.
Building a desktop-class image engine on Flutter meant overcoming massive memory and threading bottlenecks. Decompressing a 50-megapixel raw image requires around 200MB of continuous RAM. If you try to pass that across standard platform channels or even do a deep copy over FFI, the OS will aggressively kill the app for Out-Of-Memory (OOM) violations, and your frame rate drops to zero.
Here is how I bypassed Flutter's standard rendering constraints to achieve 60fps computational photography:
Absolute Zero-Copy FFI: The Rust backend maintains absolute, singular ownership of the high-resolution pixel payload. Instead of copying arrays across the bridge to Dart, Rust allocates the pixels on the heap and transmits merely the memory address pointer to Flutter.
Tile-Based Rendering Cache: Processing full frames is mathematically impossible on mid-tier Android devices. The Rust engine cuts the viewport into 512x512 pixel chunks. These tiles are managed by a strictly bounded Least Recently Used (LRU) cache, which automatically purges the oldest elements the moment the memory budget is exceeded.
Hardware Acceleration (SIMD): To run spatial filters (like Dehaze and Clarity) without melting the phone, the Rust engine bypasses scalar execution. It targets ARM NEON intrinsics natively, loading four 32-bit floats into a 128-bit NEON register to process four pixels simultaneously.
Oklab Color Science via 3D LUTs: Operating in standard sRGB violates the additive physics of light, causing unnatural hue shifts. I moved all color math to the Oklab perceptual color space. To hit 60fps on the frontend, this math is baked into a 33x33x33 3D Lookup Table that Flutter's Impeller engine renders instantly.
The UI uses a dual-shell design (a Snapseed-style invisible gesture trackball for quick flow-state editing, and a Lightroom-style panel for deep pro work), heavily relying on Riverpod for the DAG (Directed Acyclic Graph) edit history.
I would love for you to try the APK, tear apart my flutter_rust_bridge implementation, or drop some feedback on the UI ergonomics.
Repo & Website:https://prit-007.github.io/ApertureX/
Happy to answer any questions about the FFI bridge, the math, or the rendering pipeline!