Skip to content

Fix maxBitmapSize calculation with FILL for preventing too large bitmap crash on Android platform#3259

Merged
colinrtwhite merged 3 commits into
coil-kt:mainfrom
irgaly:fix_maxbitmapsize_fill
Feb 10, 2026
Merged

Fix maxBitmapSize calculation with FILL for preventing too large bitmap crash on Android platform#3259
colinrtwhite merged 3 commits into
coil-kt:mainfrom
irgaly:fix_maxbitmapsize_fill

Conversation

@irgaly
Copy link
Copy Markdown
Contributor

@irgaly irgaly commented Dec 13, 2025

AsyncImage on Compose will exceeds maxBitmapSize limitation, and leads crash on some Android platforms.

Reproducer

  • platform: Android 14 Emulator
  • coil v3.3.0
  • Reproducer condition:
    • The image has larger size than maxBitmapSize
    • The incoming constraints of AsyncImage are Infinity
    • The Scale config is FILL
Box(Modifier.padding(padding)) {
    Column(
        Modifier
            // IntrinsicSize leads the constraints to Infinity
            .width(IntrinsicSize.Max)
            .background(Color.Yellow.copy(alpha = 0.4f))
    ) {
        AsyncImage(
            model = ImageRequest.Builder(LocalPlatformContext.current)
                // 8000px x 4000px image
                .data("https://placehold.jp/8000x4000.png")
                .build(),
            contentDescription = null,
            Modifier.fillMaxWidth().aspectRatio(4f / 1f),
            // ContentScale.Crop is used on calculation as FILL
            contentScale = ContentScale.Crop,
        )
        Text("Title text")
        Text("Body text. Body text. Body text.")
    }
}

This layout is like this:

image

In this example, the AsyncImage receives Infinity constraints in ConstraintsSizeResolver.

image

Then, resolved size is Size(width = Undefined, height = Undefined) (Size.ORIGINAL).

image

Then, DecodeUtils.computeSizeMultiplier() will calculate as Scale.FILL to (dstWidth, dstHeight) = (4096, 4000). dstWidth is limited to maxBitmapSize. So the multiplier = 1.0f will be used.

image

Finally, AsyncImage will draw the bitmap with 8000px x 4000px, and this will cause crash on some Android versions (old versions or hardware limitation?).

java.lang.RuntimeException: Canvas: trying to draw too large(128000000bytes) bitmap.

image

Fix

The problem is DecodeUtils.computeSizeMultiplier(). When it computes with Scale.FILL, the multiplier and resulting bitmap will be larger than the size of maxBitmapSize.

I fixed computeSizeMultiplier() on this PR, by limiting the multiplier after calculating that with FILL or FIT. The multiplier will be limited to the both of the maxBitmapSize.width and the maxBitmapSize.height.

image

fun veryLargeImageWithFill() = runTest {
val request = ImageRequest.Builder(context)
.data(R.drawable.very_large)
.scale(Scale.FILL)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The test with FILL scaling.

@irgaly
Copy link
Copy Markdown
Contributor Author

irgaly commented Dec 14, 2025

I fixed lint error and updated API dump.

@irgaly
Copy link
Copy Markdown
Contributor Author

irgaly commented Dec 15, 2025

./gradlew iosSimulatorArm64Test macosArm64Test is passed on my local Mac and my forked repository https://github.com/irgaly/coil/actions/runs/20220087681/job/58040384774

Copy link
Copy Markdown
Member

@colinrtwhite colinrtwhite left a comment

Choose a reason for hiding this comment

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

Thanks!

@colinrtwhite colinrtwhite merged commit 94cd859 into coil-kt:main Feb 10, 2026
37 of 40 checks passed
@irgaly irgaly deleted the fix_maxbitmapsize_fill branch February 11, 2026 04:06
colinrtwhite added a commit that referenced this pull request Feb 19, 2026
* origin/main: (197 commits)
  Update ktlint to 1.8.0. (#3324)
  Publish coil-lint with coil-core. Improve coil-lint test coverage. (#3323)
  Fix use of deprecated computeSizeMultiplier overload. (#3321)
  fix(deps): update androidx.benchmark to v1.5.0-alpha03 (#3314)
  fix(deps): update roborazzi to v1.59.0 (#3320)
  fix(deps): update lint to v32.0.1 (#3316)
  fix(deps): update dependency com.android.tools.build:gradle to v9.0.1 (#3315)
  Update sonatype snapshot repo link in faq (#3312)
  Migrate to built in Kotlin. (#3311)
  Attempt to make JS and WASM tests less flaky. (#3310)
  Disable flaky test on apple targets. (#3309)
  Use web worker to decode images on Web (#3305)
  Fix DecodeUtils binary compatibility and guard against more maxSize cases. (#3307)
  Update lint and roborazzi. (#3308)
  Fix maxBitmapSize calculation with FILL for preventing too large bitmap crash on Android platform (#3259)
  Update AGENTS.md and add CLAUDE.md and GEMINI.md. (#3306)
  Add lint check for kotlin.error() misuse inside ImageRequest.Builder (#2887) (#3304)
  Update Dokka to 2.2.0-Beta. (#3303)
  Set Kotlin language version to 2.1. (#3302)
  Migrate to the new Android KMP Gradle plugin. (#3301)
  ...
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