Skip to content

Add ResizeImagePolicy.cover - #194665

Merged
auto-submit[bot] merged 6 commits into
flutter:masterfrom
YeungKC:resize-image-policy-cover
Nov 6, 2026
Merged

auto-submit[bot] merged 6 commits into
flutter:masterfrom
YeungKC:resize-image-policy-cover

Conversation

@YeungKC

@YeungKC YeungKC commented Oct 18, 2026

Copy link
Copy Markdown
Member

This PR adds ResizeImagePolicy.cover. With this policy, ResizeImage decodes the image at the smallest size that covers the width x height box and keeps the aspect ratio of the image, like BoxFit.cover.

Problem

There is no resize policy that matches BoxFit.cover. A caller that paints with BoxFit.cover and does not know the aspect ratio of the image before the decode has two options:

  • Use ResizeImagePolicy.fit, or set only one of cacheWidth and cacheHeight. For many aspect ratios, the decoded image is smaller than the box, so it is blurry when it is painted.
  • Do not resize. The image is decoded at full size, which uses much more memory than necessary.

Change

  • Add ResizeImagePolicy.cover. It requires both width and height (assert in the ResizeImage constructor).
  • The aspect ratio comes from the intrinsic size that the decoder gives to getTargetSize, so the caller does not need to know the image size.
  • The size calculation uses integer math and rounds up. The decoded image always covers the box, and a box that matches the aspect ratio of the image does not get an extra pixel. (With a double scale, a 3000x3000 image in a 448x256 box decodes at 449x449.)
  • The image is not scaled up unless allowUpscaling is true. This is the same as the fit policy.
  • Update the ResizeImagePolicy and ResizeImage docs.

Decoded sizes for a 640x360 box (physical pixels), with synthetic images:

Image No resize cacheWidth: 640 fit (640x360) cover (640x360)
884x1920 884x1920 (6.79 MB) 640x1390 (3.56 MB) 165x360 (0.24 MB), too small 640x1391 (3.56 MB)
1920x884 1920x884 (6.79 MB) 640x294 (0.75 MB), too small 640x294 (0.75 MB), too small 782x360 (1.13 MB)
4032x3024 4032x3024 (48.77 MB) 640x480 (1.23 MB) 480x360 (0.69 MB), too small 640x480 (1.23 MB)
4000x1000 4000x1000 (16.00 MB) 640x160 (0.41 MB), too small 640x160 (0.41 MB), too small 1440x360 (2.07 MB)

cover is the only option that fills the box in all cases without a full-size decode. On a macOS host, a 4032x3024 JPEG decodes in approximately 102 ms with no resize (48.77 MB) and approximately 46 ms with cover into a 200x200 box (267x200, 0.21 MB), median of 25 runs.

Compatibility

This adds a value to a public enum. Code outside the framework that has a switch on ResizeImagePolicy with no default gets a compile-time error (non-exhaustive switch). In this repository (packages/ and dev/), only ResizeImage itself switches on ResizeImagePolicy.

Tests

Added tests in test/painting/image_provider_resize_image_test.dart for the cover policy: square, portrait, and landscape images in square, wide, and tall boxes, round-up of the other side, no extra pixel when the scale is exact, no upscaling by default, upscaling with allowUpscaling: true, and the assert when width or height is null.

Fixes #61987

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Add a cover policy to ResizeImage. It decodes the image at the smallest
size that covers the width x height box and keeps the aspect ratio of
the image, like BoxFit.cover. The aspect ratio comes from the intrinsic
size that the decoder gives, so the caller does not need to know the
image size.

Before this change, a caller that paints with BoxFit.cover and does not
know the aspect ratio had two options: decode at full size, or use
ResizeImagePolicy.fit or one cacheWidth/cacheHeight value, which can
decode an image that is too small for the box.

The policy requires both width and height. It uses integer math with
round-up, so the decoded image always covers the box and a box that
matches the aspect ratio does not get one extra pixel. It does not scale
up unless allowUpscaling is true.

Fixes flutter#61987
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Oct 18, 2026
@github-actions github-actions Bot added the framework flutter/packages/flutter repository. See also f: labels. label Oct 18, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a new ResizeImagePolicy.cover policy to ResizeImage, which scales an image to cover a specified bounding box while maintaining its aspect ratio. The changes include adding the enum value, enforcing that both width and height are non-null via assertions when using this policy, implementing the cover scaling logic, and adding corresponding unit tests. I have no feedback to provide.

victorsanni
victorsanni previously approved these changes Oct 28, 2026

@victorsanni victorsanni left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some comments.

Adding new enum value is a breaking change, cc @chunhtai who has an RFC for exactly this.

@YeungKC

YeungKC commented Oct 28, 2026

Copy link
Copy Markdown
Member Author

Thanks, added both tests.

On the enum value: Google testing passes, so this is not a breaking change under the current Tree hygiene rules. It can still break code that has an exhaustive switch on ResizeImagePolicy. @chunhtai, should I add the c: API break label and announce it, or wait for the enum RFC?

@victorsanni

Copy link
Copy Markdown
Contributor

Hi, is this ready for re-review? Please remember to request a review if it is, so it gets back into the review queue.

@YeungKC
YeungKC requested a review from victorsanni October 30, 2026 13:48
- Assert that the cover box is not empty, and test a width or height of 0.
- Keep the intrinsic size when either derived side reaches it, so that
  mirrored inputs give mirrored outputs.
- Document that cover needs both width and height.
- Run the null width or height assertion test on web too.
- Test that a different policy makes ResizeImage unequal.
@YeungKC
YeungKC requested a review from victorsanni November 5, 2026 14:39

@victorsanni victorsanni left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the fix!

@victorsanni victorsanni added CICD Run CI/CD autosubmit Merge PR when tree becomes green via auto submit App and removed CICD Run CI/CD labels Nov 5, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Nov 5, 2026
@auto-submit

auto-submit Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/194665, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@YeungKC YeungKC added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 6, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Nov 6, 2026
Merged via the queue into flutter:master with commit 94f4471 Nov 6, 2026
23 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Nov 6, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Nov 7, 2026
flutter/flutter@09175cd...e36b370

2026-11-07 [email protected] Roll Fuchsia Linux SDK from KIc0XZbhLmvDpTluZ... to Sf2yvdTiFXAKkfLkD... (flutter/flutter#196160)
2026-11-07 [email protected] Roll pub packages (flutter/flutter#196155)
2026-11-07 [email protected] [iOS a11y] Use a real `UIScrollView` as a11y scrollable container (flutter/flutter#195731)
2026-11-07 [email protected] Add ParagraphStyle.hyphenCharacter to dart:ui (flutter/flutter#195345)
2026-11-07 [email protected] Roll pub packages (flutter/flutter#196143)
2026-11-06 [email protected] [Linux] Fix layer position when compositing without glBlitFramebuffer (flutter/flutter#196083)
2026-11-06 [email protected] Add support for riscv64 desktop linux engine (flutter/flutter#178712)
2026-11-06 [email protected] Add ResizeImagePolicy.cover (flutter/flutter#194665)
2026-11-06 [email protected] Roll Skia from f533d4034900 to b11315d0a096 (6 revisions) (flutter/flutter#196138)
2026-11-06 [email protected] iOS: Remove dead code/unused imports from FlutterPlatformViewsController (flutter/flutter#196084)
2026-11-06 [email protected] Replace pull_request_target workflows with pull_request + workflow_run (flutter/flutter#195536)
2026-11-06 [email protected] [master] Update Flutter DEPS to Dart 3b174b7217fe09b21da836ea623932b5f041b091 (flutter/flutter#196004)
2026-11-06 [email protected] Fix android_hardware_smoke_test retry mechanisms (flutter/flutter#195708)
2026-11-06 [email protected] Roll Skia from 452b9c1e5db6 to f533d4034900 (1 revision) (flutter/flutter#196129)
2026-11-06 [email protected] [flutter_tools] Use `ErrorHandlingFileSystem.deleteIfExists` for `IOSCoreDeviceControl` temp directory cleanup (flutter/flutter#195913)
2026-11-06 [email protected] Adds guideline tests to flutter create samples (flutter/flutter#195827)
2026-11-06 [email protected] refactor(flutter_tools): unify OptionDescriptor identity and addTo (flutter/flutter#196076)
2026-11-06 [email protected] Roll pub packages (flutter/flutter#196114)
2026-11-06 [email protected] Roll Skia from 5ce64e63a0e7 to 452b9c1e5db6 (5 revisions) (flutter/flutter#196111)
2026-11-06 [email protected] Add PlatformDispatcher.onAlwaysUse24HourFormatChanged callback (flutter/flutter#194670)
2026-11-06 [email protected] Roll Packages from 0478162 to 63881f9 (10 revisions) (flutter/flutter#196108)
2026-11-06 [email protected] Roll Skia from 793b8ac73d4b to 5ce64e63a0e7 (4 revisions) (flutter/flutter#196107)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Utilize new ImageDescriptor logic to allow for aspect ratio maintaining ResizeImages

2 participants