Skip to content

Fix for problem when produced photo is zoomed and is smaller than in preview. ViewPort in CameraXState crops ImageCapture on real Android devices #637

Description

@Nashev

Steps to Reproduce

  1. Use CameraAwesomeBuilder.awesome with SaveConfig.photo and previewFit: CameraPreviewFit.contain on a real Android device with a high-resolution sensor
  2. Take a photo
  3. Compare the field of view of the preview with the saved JPEG

Expected results

The saved photo should cover the same field of view as shown in the camera preview.

Actual results

The saved photo is cropped on all four sides compared to what was visible in the preview. Skia logs show the crop explicitly:

D/skia: multi onDecodeSubset, rect=(240, 320, 1440, 1920)
D/ImageCapture: createPipeline(... resolution=2560x1920 ...)
D/CameraX: Preview size: width=720.0, height=960.0

The sensor captures 2560×1920, but the saved JPEG is only 1440×1920 with offset (240, 320) — 240px cropped on left/right, 320px on top/bottom.

Root cause

In CameraXState.kt, ImageCapture is added to a UseCaseGroup with a hardcoded ViewPort:

useCaseGroupBuilder.setViewPort(ViewPort.Builder(rational, Surface.ROTATION_0).build())

There is even a comment in the code acknowledging this: // TODO Orientation might be wrong, to be verified.

Surface.ROTATION_0 is hardcoded regardless of actual device orientation. On real devices with a physically landscape-oriented sensor, CameraX applies this ViewPort and crops ImageCapture to a center region. The Preview texture appears unaffected because Flutter's rendering pipeline scales it independently — so the user sees the full native preview, but the saved photo is cropped.

Does not reproduce on emulators (Pixel 4, Pixel 9 AVD).

Fix

Remove setViewPort from the UseCaseGroup in both the single-camera and multi-camera paths in CameraXState.kt. Each use case then uses its own native resolution without any cropping:

// Remove this line in both single-camera and multi-camera paths:
useCaseGroupBuilder.setViewPort(ViewPort.Builder(rational, Surface.ROTATION_0).build())

Result after fix on my TCL T521K:

Before: photo saved as 1440×1920 (cropped from 2560×1920)

After: photo saved as 2560×1920 ✅

Note: ResolutionSelector with AspectRatioStrategy already ensures both Preview and ImageCapture select resolutions with the same aspect ratio, so the ViewPort crop is redundant.

About your device

Brand Model OS
TCL T521K Android 16

Your flutter version

Flutter 3.29.0 • channel stable
Framework • revision ea121f8f9e (12 days ago) • 2026-02-10 21:24:00 -0800
Engine • revision cf56914b32
Tools • Dart 3.7.0 • DevTools 2.42.2

Disclamer

This text and fix produced with Github Copilot over Claude Sonnet 4.6 LLM, but this fix really helps for me in my app.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions