Repository navigation
[web] Decode images once in instantiateImageCodecWithSize - #196029
Open
TeddyYeung wants to merge 5 commits into
Open
TeddyYeung wants to merge 5 commits into
TeddyYeung wants to merge 5 commits into
Conversation
…is available Read the intrinsic size from the first frame of a single BrowserImageDecoder and return that frame as the first frame of the codec, instead of creating a codec, decoding a full-size image, and creating a second codec at the target size.
…ith getTargetSize
TeddyYeung
marked this pull request as ready for review
November 5, 2026 08:33
Contributor
Author
|
cc @harryterkelsen, since this touches |
Contributor
There was a problem hiding this comment.
Code Review
This pull request refactors image codec instantiation with target sizing in the Flutter Web engine. It introduces engineInstantiateImageCodecWithSize and updates BrowserImageDecoder to decode and cache the first frame's size via decodeFirstFrameSize(), preventing the first frame from being decoded twice when the browser supports ImageDecoder. Additionally, corresponding unit tests have been added to verify the caching, disposal, and frame ordering behaviors. I have no feedback to provide.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On the web,
instantiateImageCodecWithSizewith agetTargetSizecallback (the pathResizeImage, and soImage.network(cacheWidth: ...), goes through) decoded every image twice. It created a codec, decoded a full-size first frame into aui.Imageonly to readwidthandheight, disposed it, and then created a second codec at the target size. On Chromium, the full-size frame was also copied into a full-sizeImageBitmapbefore upload, so a resized image still allocated its full-size bitmap for a moment.This PR adds
engineInstantiateImageCodecWithSize. WhenImageDecoderis available, it creates oneBrowserImageDecoder, decodes the first frame, passes its size togetTargetSize, and returns a codec at the target size that reuses that decoder. The decoded first frame is kept by the newBrowserImageDecoder.decodeFirstFrameSizeand returned by the nextgetNextFrame, so it is not decoded again. Later frames of animated images are decoded in order as before. A kept frame is closed if the decoder is disposed first. WithoutImageDecoder, the behavior is unchanged (decode once for the size, then again at the target size).Measurements in Chrome 154 on an Apple Silicon Mac, with a script that makes the same browser calls as the old and new paths (
ImageDecodersetup and decode,createImageBitmap, resize to 400 px wide), median of 7 runs:iphone_15.jpeg(3024x4032)mandrill_1600.png(1600x1600)example_3_12bit.avif(512x512)Tests:
image_test.dart:instantiateImageCodecWithSizecreates noui.ImagebeforegetNextFrame, and exactly one after it.image_decoder_test.dart:decodeFirstFrameSizekeeps the first frame forgetNextFrame;disposecloses a kept frame; an animated GIF decoded throughinstantiateImageCodecWithSizereturns the same number of frames, with the same durations in the same order, as the unsized codec.instantiateImageCodecWithSizetests (buffer disposal, temporary image disposal, upscaling) cover the unchanged behavior.dart analyzeanddart formatpass on the changed files.felt testwas not run locally, because there is no full engine checkout here.Fixes #118985
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.