Skip to content

[mob][photos] Use file-derived dimensions for large images#10393

Open
AmanRajSinghMourya wants to merge 2 commits into
mainfrom
aman/photos-file-derived-image-dimensions
Open

[mob][photos] Use file-derived dimensions for large images#10393
AmanRajSinghMourya wants to merge 2 commits into
mainfrom
aman/photos-file-derived-image-dimensions

Conversation

@AmanRajSinghMourya
Copy link
Copy Markdown
Contributor

Issue

Some Samsung Galaxy S24/S25 Ultra 200MP portrait photos can render squished in the mobile Photos viewer.

The viewer already avoids full-resolution decode for very large images to prevent Flutter OOMs. That path passes cacheWidth and cacheHeight to Image.file. For affected portrait images, the stored w/h metadata can be wrong or missing, so the viewer computes a landscape-shaped decode target for a portrait image.

Observed cases:

  • Stored dimensions are swapped, e.g. 16320x12240 instead of display 12240x16320.
  • Stored dimensions are missing, so app-side dimensions resolve to 0x0.
  • 0x0 bypasses the large-image guard and can attempt a full-resolution decode.

Root Cause

Android MediaStore/photo manager dimensions are not always a reliable source of display dimensions for rotated media. On affected Samsung files, MediaStore can already report display-oriented dimensions, and then the Android upload path applies another EXIF-orientation swap.

For normal images this usually goes unnoticed. For 200MP images, the viewer takes the large-image path and uses stored dimensions to compute cacheWidth/cacheHeight. If those dimensions are wrong, Flutter decodes/scales with the wrong aspect ratio and the image appears squished.

Fix

This adds an internal-only path to derive image dimensions from the file itself instead of relying only on stored MediaStore dimensions.

Behind useFileDerivedImageDimensions:

  • Read raw image dimensions and EXIF orientation from the file.
  • Derive display dimensions from raw dimensions + rotation.
  • Store display dimensions as existing w/h.
  • Store raw dimensions and rotation as new public magic metadata keys:
    • rw
    • rh
    • rot
  • Use file-derived dimensions in the viewer when stored dimensions are missing, raw dimensions are available, or the image is very large.
  • Lazily backfill corrected metadata for owned images above 100MP.
  • Skip backfill for shared/read-only files, while still correcting viewer decode locally.

How It Works

For new uploads, the upload path now prefers EXIF/file-derived dimensions when the internal flag is enabled.

Example Samsung 200MP portrait:

raw pixels:      16320x12240
EXIF rotation:   90
display size:    12240x16320

The uploaded public metadata becomes:

{
  "w": 12240,
  "h": 16320,
  "rw": 16320,
  "rh": 12240,
  "rot": 90
}

If EXIF raw dimension tags are unavailable, we fall back to the previous asset dimensions. On Android, if EXIF orientation is still available, we apply the same orientation swap behavior to the fallback dimensions so the existing behavior does not regress.

For existing files, the viewer resolves dimensions in this order:

  1. Use stored raw dimensions + rotation if available.
  2. Else read dimensions from the local file EXIF.
  3. Else fall back to stored w/h.

For large images, the viewer computes cacheWidth/cacheHeight from the resolved display dimensions, so portrait images stay portrait-shaped during reduced-resolution decode.

Backfill is intentionally conservative:

  • only behind the internal flag
  • only for images above 100MP
  • only when raw dimensions are available
  • only when the current user can edit metadata
  • only writes keys that are missing or different

Shared files are not mutated by viewers.

Tests

  • flutter test test/utils/image_dimension_util_test.dart test/models/metadata/file_magic_test.dart
  • flutter analyze
  • git diff --check

Note: the clean PR branch is based on main, which expects Flutter 3.32.8. Local validation was done on the Flutter-up branch where the current local Flutter SDK resolves.

References

@AmanRajSinghMourya AmanRajSinghMourya marked this pull request as ready for review May 12, 2026 09:59
@ua741
Copy link
Copy Markdown
Member

ua741 commented May 14, 2026

Let's also test for this #10429

@ua741
Copy link
Copy Markdown
Member

ua741 commented May 20, 2026

Whenever we resume work on this, we should also think about how (in the future), we can handle just rotation edit, without re-uploading or saving duplicate for file. We don't have to make that change right away, but we should have clarity about the way forward.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants