Skip to main content
RapidDev - Software Development Agency
App Featuresai-features18 min read

How to Add AI-Powered Image Resizing to Your App — Copy-Paste Prompts Included

AI-powered image resizing uses smart crop to keep faces and focal objects centered across multiple output sizes — not just a center crop. You need three pieces: an image picker, a Cloudinary or AWS Rekognition smart crop API called from a Supabase Edge Function, and a before/after comparison UI. With FlutterFlow you can ship a working build in 3–5 hours. Costs run $0–25/month at 100 users on Cloudinary's free tier; $89–115/month at 1,000 users on the Plus plan.

4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members

Feature spec

Intermediate

Category

ai-features

Build with AI

3–6 hours with FlutterFlow + custom backend

Custom build

1–2 weeks custom dev

Running cost

$0–25/mo up to 100 users; $89–115/mo at 1K users

Works on

Mobile

Everything it takes to ship AI-Powered Image Resizing — parts, prompts, and real costs.

TL;DR

AI-powered image resizing uses smart crop to keep faces and focal objects centered across multiple output sizes — not just a center crop. You need three pieces: an image picker, a Cloudinary or AWS Rekognition smart crop API called from a Supabase Edge Function, and a before/after comparison UI. With FlutterFlow you can ship a working build in 3–5 hours. Costs run $0–25/month at 100 users on Cloudinary's free tier; $89–115/month at 1,000 users on the Plus plan.

What AI-Powered Image Resizing Actually Is

Standard image resizing crops from the center — which works for landscapes but cuts off faces in portrait photos and misses the subject in product shots. AI-powered smart crop uses computer vision to detect the most important region (faces, primary objects) and crops around it, so the output looks intentional rather than accidental. Cloudinary's g_auto transformation handles face detection and focal point selection server-side with a single URL parameter. AWS Rekognition returns face bounding boxes you use to calculate the crop coordinates in sharp.js. The real engineering work is the pipeline: image picker → user-scoped Supabase Storage upload → smart crop API call → status tracking in an image_jobs table → before/after comparison UI → signed URL download.

What users consider table stakes in 2026

  • Smart crop that keeps faces and focal subjects centered, not a simple center-crop at a different aspect ratio
  • Before/after comparison slider so users can see exactly what the AI changed before saving
  • Multiple preset output sizes: square 1:1, story 9:16, banner 16:9, and thumbnail 4:3
  • Progress indicator during AI processing — the Cloudinary transformation takes 1–3 seconds and users need feedback that something is happening
  • Download or share the resized result directly from the app without re-uploading
  • Batch mode for processing multiple images from a gallery selection in one operation

Anatomy of the Feature

Seven components across UI, backend, and service layers. AI tools correctly generate the file picker and storage upload. The smart crop API routing and the before/after comparison widget are where first builds fail.

Layers:UIBackendService

Image Picker

UI

Flutter image_picker package on mobile (FlutterFlow native action) or HTML input[type=file] with accept='image/*' on web (Lovable). Accepts JPEG, PNG, and WEBP. Should apply imageQuality: 80 and maxWidth: 2048 constraints before upload to prevent out-of-memory crashes on high-resolution devices.

Note: FlutterFlow's in-browser preview does not expose the native image_picker. Test on a real iOS or Android device build, not the FlutterFlow web preview.

Upload Layer

Backend

Supabase Storage bucket receives the original image at path originals/{user_id}/{uuid}.jpg using a signed upload URL pattern. The client uploads directly to Storage; the Edge Function receives only the storage path, not the image bytes — this avoids the 6MB Edge Function request body limit.

Note: Use the signed upload URL pattern: call supabase.storage.from('originals').createSignedUploadUrl(path) on the server, return the URL to the client, then the client uploads directly to Supabase Storage without going through the Edge Function.

Smart Crop API

Service

Cloudinary AI crop via the g_auto:face or g_auto:subject transformation URL parameter. The transformation URL is constructed server-side: https://res.cloudinary.com/{cloud_name}/image/upload/c_fill,g_auto:face,w_{width},h_{height}/{public_id}. Alternatively, AWS Rekognition DetectFaces returns bounding box coordinates that you pass to sharp.js for precise crop math.

Note: g_auto:faces (plural) detects multiple faces in group photos. Always set a fallback gravity (g_center) explicitly so images without detected faces fall back to center crop rather than an error.

Transformation Queue

Backend

A Supabase Edge Function orchestrates the pipeline: receives the storage path and output dimensions, constructs the Cloudinary transformation URL or calls AWS Rekognition, stores the result URL in image_jobs, and returns the processed image URL. Job status (pending/processing/done/failed) is tracked per row.

Note: For batch processing, the Edge Function should accept an array of paths and process them sequentially; parallel processing risks hitting Cloudinary rate limits on the free tier.

Before/After Slider

UI

react-compare-slider on web displays the original and processed images side by side with a draggable divider. On Flutter, a custom Stack widget with a GestureDetector handles horizontal drag to reveal the processed image using a ClipRect with varying width.

Note: Both images must be fully loaded before the slider renders, or users will see a blank before-state on initial display. Use loading state to defer rendering the comparison until both image URLs are resolved.

Output Size Presets

UI

A toggle button group with four presets — Square 1:1 (1080×1080), Story 9:16 (1080×1920), Banner 16:9 (1920×1080), Thumbnail 4:3 (800×600). The selected preset passes target width and height to the Transformation Queue Edge Function as query parameters.

Note: Presets should be displayed with visual ratio previews (small rectangles in the correct aspect ratio) so users understand the output shape before processing.

Download/Share Button

UI

On web, triggers a Supabase Storage createSignedUrl() (3600-second expiry) for the processed image path, then uses an anchor[download] tag to initiate the browser download. On Flutter, uses the flutter_share package to share the signed URL or saves to photo gallery via gallery_saver.

Note: The processed images bucket must be private. Never use a public bucket for user-uploaded processed content — use signed URLs with short expiry times.

The data model

One table tracks each image processing job with status and output paths. Run this in the Supabase SQL editor:

schema.sql
1create table public.image_jobs (
2 id uuid primary key default gen_random_uuid(),
3 user_id uuid references auth.users(id) on delete cascade not null,
4 original_path text not null,
5 output_path text,
6 status text not null default 'pending'
7 check (status in ('pending', 'processing', 'done', 'failed')),
8 width int,
9 height int,
10 crop_mode text not null default 'g_auto:face',
11 error_message text,
12 created_at timestamptz not null default now()
13);
14
15alter table public.image_jobs enable row level security;
16
17create policy "Users see own jobs"
18 on public.image_jobs for select
19 using (auth.uid() = user_id);
20
21create policy "Users insert own jobs"
22 on public.image_jobs for insert
23 with check (auth.uid() = user_id);
24
25create policy "Users update own jobs"
26 on public.image_jobs for update
27 using (auth.uid() = user_id);
28
29create index image_jobs_user_status_idx
30 on public.image_jobs (user_id, status, created_at desc);

Heads up: The storage bucket policies should also be configured: originals bucket — authenticated users read and write their own path prefix ({user_id}/); processed bucket — authenticated users read their own path prefix only. Set up these bucket policies in the Supabase Dashboard under Storage → Policies.

Build it — pick your path

Each tool fits this feature differently. Switch tabs to compare fit, time, the exact steps, and a copy-paste prompt.

Hand-built by developersFit for this feature:

The right choice for batch processing, on-device inference, or integrating into an existing CDN or Digital Asset Management pipeline. Eliminates per-image API cost with a self-hosted sharp.js + face-api.js pipeline.

Step by step

  1. 1Build the image picker → Supabase Storage upload pipeline with client-side image compression (canvas drawImage + toBlob at 0.85 quality) before upload
  2. 2Deploy a Node.js server (or Supabase Edge Function with WASM sharp.js build) that runs: face-api.js DetectAllFaces for bounding boxes → calculate optimal crop rectangle → sharp.js resize + crop to target dimensions
  3. 3Implement batch processing: accept an array of storage paths, process sequentially, update image_jobs status per item, and emit real-time progress via Supabase Realtime channel
  4. 4Integrate with CDN: after processing, push the result to Cloudflare R2 or Cloudinary via their upload API; return the CDN URL for fast global delivery

Where this path bites

  • Running sharp.js in Deno Edge Functions requires a WASM build of libvips; for high-volume processing, a dedicated Node.js server is more reliable
  • face-api.js models are 5–30MB each — loading them on each Edge Function cold start adds significant latency; a persistent Node.js server with models pre-loaded is required for sub-second processing

Third-party services you'll need

Smart crop is an API-driven feature. Three viable services at different cost and accuracy levels:

ServiceWhat it doesFree tierPaid from
CloudinarySmart crop via g_auto:face/subject transformation URL; handles resize and format conversion in one step25 credits/month (~25 unique transformations); unlimited delivery of cached transformsPlus $89/mo (1,000 credits); Advanced $224/mo (3,000 credits) (approx)
AWS RekognitionFace detection returning bounding box coordinates; combined with sharp.js for actual crop math5,000 images/month for 12 months (trial); pay-as-you-go after$0.001 per image + S3 storage costs (approx)
ImaggaSmart Cropping API with subject-aware crop for non-face images (products, landscapes)1,000 API calls/monthBasic $29/mo (10K calls); Standard $99/mo (50K calls) (approx)
Supabase StorageStores original uploads and processed output; provides signed URLs for private access1GB includedPro plan $25/mo includes 100GB; $0.021/GB beyond
sharp.js (WASM)Open-source image processing; crop, resize, format conversion; zero API costOpen-source, freeCompute cost only (server/Edge Function runtime)

Swipe the table sideways to see pricing.

What it costs to run

Drag through the tiers to see how your monthly bill scales with users — no surprises later.

Estimated monthly running cost

$0/mo

Cloudinary free tier (25 credits/mo) covers low-volume testing. Supabase free tier covers Storage and Edge Functions. Most transformations are cached by Cloudinary after first request.

Estimates use verified 2026 pricing and assume typical usage per user. Your real bill depends on activity, storage, and third-party plans.

What breaks when AI tools build this

The failures people actually hit on their first build — the symptom, why it happens, and the exact fix.

Image upload works in browser but fails silently in FlutterFlow preview

Symptom: FlutterFlow's browser-based preview runs as a web app, which means the image_picker package falls back to HTML file input. The native iOS/Android image picker (with camera access, gallery browsing, and quality controls) only activates in a real device build. Users testing in the browser preview see a broken or unresponsive picker that appears to work but doesn't produce a usable image.

Fix: Test image picker functionality on a real device via TestFlight (iOS) or an APK install (Android), never in the FlutterFlow browser preview. Use the FlutterFlow mobile test app on your phone as a quick first check.

Cloudinary returns cropped image with faces cut off

Symptom: The g_auto:face parameter (singular) detects a single primary face. In group photos or images where a face is partially obscured, Cloudinary may fall back to center gravity silently without indicating that face detection failed. The result is a crop that looks like a default center crop — which is exactly the behavior the user wanted to avoid.

Fix: Use g_auto:faces (plural) to detect multiple faces. Add an explicit fallback gravity: gravity_center so the fallback behavior is predictable. Show the before/after comparison slider before confirming the save, so users can see if the smart crop failed and choose a different preset or manual crop.

Large image uploads fail with 413 error from Edge Function

Symptom: Supabase Edge Functions have a 6MB request body limit. A 10MB RAW photo uploaded directly as base64 or multipart to the Edge Function exceeds this limit. The 413 error often appears as a generic network error in the client rather than a clear message, making it hard to diagnose.

Fix: Use the signed upload URL pattern: the Edge Function generates a Supabase Storage signed upload URL and returns it to the client. The client uploads directly to Supabase Storage, bypassing the Edge Function entirely. The Edge Function only receives the storage path once the upload completes.

Processed image URL is publicly accessible to anyone with the link

Symptom: If the Supabase Storage bucket containing processed images is set to public, anyone who obtains the URL (from browser history, network logs, or a shared screenshot) can access any user's processed images permanently. This is a privacy issue for apps where users process personal photos.

Fix: Set the processed images bucket to private. Generate short-lived signed URLs using supabase.storage.from('processed').createSignedUrl(path, 3600) — the URL expires after 1 hour. For downloads, generate a fresh signed URL at the moment the user clicks Download.

FlutterFlow app crashes when processing a 10MB photo

Symptom: The image_picker package returns the full-resolution image from the device gallery. A 10MB+ photo loaded entirely into memory on the device causes an OutOfMemoryError on phones with limited RAM, particularly older Android devices. The app crashes without a useful error message.

Fix: Configure image_picker with imageQuality: 80 and maxWidth: 2048 (or maxHeight for portrait). These constraints compress and resize the image before it enters app memory. For most smart crop use cases, a 2048px wide image is more than sufficient quality and weighs 200–500KB rather than 10MB.

Best practices

1

Apply imageQuality: 80 and maxWidth: 2048 in image_picker before upload — prevents OOM crashes and reduces storage costs without visible quality loss

2

Use the signed upload URL pattern to bypass the 6MB Edge Function body limit for all file uploads

3

Set processed images bucket to private with short-lived signed URLs; never expose user photo processing results publicly

4

Use g_auto:faces (plural) with explicit g_center fallback so group photos and non-face images degrade gracefully

5

Show a before/after comparison slider before the user confirms the save — let them see the smart crop result and choose a different preset if the AI missed the subject

6

Track every processing job in the image_jobs table with status so users can resume failed batch jobs without re-uploading

7

Cache Cloudinary transformation URLs by storing the output_url in image_jobs — the same transformation on the same image is free on delivery from Cloudinary's CDN

When You Need Custom Development

AI tools with Cloudinary handle smart crop for standard portrait and product photography. These workloads need a custom pipeline:

  • Batch processing of 100+ images per session for content creators or e-commerce catalog teams — requires a queued job system and real-time progress tracking
  • On-device inference required for privacy-first apps where images must never leave the device — needs TensorFlow Lite face detection model bundled in the app
  • Custom-trained crop model for a specific subject type: product photography where labels must stay visible, real estate where the exterior facade must be centered, food photography where the hero dish is rarely the image center
  • Integration with an existing CDN pipeline or Digital Asset Management system (Bynder, Canto, Widen) that has its own upload and transformation API

RapidDev builds these features for production

Real auth, database, and payments — fixed price, delivered in weeks. You own 100% of the code.

Get a fixed-price quote

Frequently asked questions

What is smart cropping versus regular cropping?

Regular cropping cuts a rectangular region from a fixed position — typically the center of the image. Smart cropping uses computer vision to detect the most important region (faces, primary objects, focal points) and crops around that instead. A portrait photo center-cropped to 1:1 might cut off the top of the head; smart crop detects the face and adjusts the crop window to keep it centered and fully visible.

Does Cloudinary work with FlutterFlow?

Not directly. FlutterFlow cannot call Cloudinary's transformation API with authentication credentials from the client side without exposing your API secret. The correct pattern is a Supabase Edge Function that constructs the Cloudinary transformation URL using the API secret from Secrets, then returns the result URL to the FlutterFlow app. The Edge Function acts as a secure proxy.

How do I keep user images private?

Set your Supabase Storage buckets (both originals and processed) to private. Use Supabase RLS storage policies that restrict access to the uploading user's own path prefix (user_id/). Generate signed URLs with short expiry (1 hour) for downloads. Never put processed image URLs in a public-readable database column without access control.

What file sizes are supported?

Supabase Storage accepts files up to 50MB on the free tier. However, the Edge Function body limit is 6MB, so always use the signed upload URL pattern to upload directly from the client to Storage. For practical purposes, apply imageQuality: 80 and maxWidth: 2048 before upload — this keeps files under 2MB without noticeable quality loss for smart crop use cases.

Can I process images without uploading them to a server?

For basic resize without smart crop: yes. The canvas API on web can resize images in the browser using drawImage() with target dimensions. On Flutter, the image package's copyResize() function works on-device. Smart crop with AI face detection requires a server-side call to Cloudinary or AWS Rekognition — these models don't run in the browser without a WASM build, which is a significant engineering effort.

How do I add batch image resizing?

The image_jobs table already supports batch: submit multiple jobs with individual rows, each tracking their own status. The Edge Function can accept an array of storage paths and process them sequentially, updating status per row. On the client, poll the image_jobs table (or use a Supabase Realtime subscription) to show progress per image. At scale, consider a Supabase Database Function triggered by new image_jobs rows to avoid the Edge Function timeout limit.

What happens if no face is detected?

Cloudinary's g_auto:face falls back to center gravity silently when no face is detected. To make the fallback explicit, always include a gravity parameter: set gravity_center as the fallback. The before/after comparison slider lets users see the result before confirming — if the AI chose a poor crop, they can switch to a manual preset. Alternatively, g_auto:subject (not g_auto:face) detects non-face focal points like products and landmarks.

How much does Cloudinary cost at scale?

Cloudinary charges per transformation credit: one credit = one unique transformation (unique image + unique output dimensions). The free tier is 25 credits per month. Critically, Cloudinary caches every transformation — so if 1,000 users view the same processed image, that's 1 credit, not 1,000. At 1,000 active users generating unique crops, the Plus plan at $89/month (1,000 credits) is the right tier. At 10,000 users the Advanced tier (~$224/mo) or a self-hosted sharp.js pipeline becomes more economical.

RapidDev

Need this feature production-ready?

RapidDev builds ai-powered image resizing into real apps — auth, database, payments — at $13K–$25K.

Book a free consultation

30-min call. No commitment.

Want this built for you?

We ship production apps at a fixed price — $13K–$25K, 6–10 weeks, source code yours. You've seen what it takes; we do it every week.

Get a fixed-price quote

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.