-
Notifications
You must be signed in to change notification settings - Fork 6k
[canvaskit] Decode images using <img> tag decoding #53201
[canvaskit] Decode images using <img> tag decoding #53201
Conversation
|
This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold. |
|
This change causes the CanvasKit renderer to default to decoding using |
| } | ||
|
|
||
| final int scaledWidth = scaledSize.width.toInt(); | ||
| final int scaledHeight = scaledSize.height.toInt(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe scaledImageSize should switch to BitmapSize to avoid rounding? There's also the issue that we check for allowUpscaling before calling toInt, which may end up upscaling anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to BitmapSize to avoid ugly .toInt() and .toDouble() calls where possible. Checking for allowUpscaling before calling toInt() should be okay here since we're only working with ints for the width and height.
| scaledHeight, | ||
| ); | ||
| final DomImageData imageData = | ||
| ctx.getImageData(0, 0, scaledWidth, scaledHeight); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Safari can run out 2D canvas memory easily. To prevent that set the size of the htmlCanvas to 0x0. That forces Safari to reclaim the underlying image buffer eagerly. Alternatively, maybe the htmlCanvas could be reused. If the app scaled an image once, it may do it again, but that's speculative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| height: scaledHeight, | ||
| ); | ||
| final DomCanvasRenderingContext2D ctx = | ||
| htmlCanvas.getContext('2d')! as DomCanvasRenderingContext2D; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing that despite the slowness (due to https://bugs.webkit.org/show_bug.cgi?id=267291) a 2d OffscreenCanvas with transferToImageBitmap would still be faster than an on-screen 2d canvas + getImageData. The latter is guaranteed to always copy, in addition to other copying that happens in canvasKit.MakeImage.
However, if use ImageBitmap as the source, then we'd have to use MakeLazyImageFromTextureSource, which has been a bit unreliable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unreliable how? I think we should try to avoid explicitly pulling the bytes out of the image. Is there a reason we can't just create an ImageBitmap and use that, instead of grabbing the image data? I also should mention that createImageBitmap actually allows you to scale the image while extracting it from the image source: https://developer.mozilla.org/en-US/docs/Web/API/createImageBitmap
| /// For images which are decoded via an HTML Image element, this field holds | ||
| /// the image element from which this image was created. | ||
| /// | ||
| /// Skia owns the image element and will close it when it's no longer used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does Skia close the image element? VideoFrame and ImageBitmap provide the close() method, but is there something equivalent for <img> tag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked the Skia code and it only automatically disposes the VideoFrame. We should manually dispose of the ImageBitmap when dispose is called. As for the <img> tag, I think the best we can do is let it be garbage collected with this Image.
| return CkImage.cloneOf( | ||
| box, | ||
| videoFrame: videoFrame?.clone(), | ||
| imageElement: imageElement, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to do anything with bitmapImage? If not, it would be good to explain why not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should. I overlooked the clone call when adding ImageBitmap here.
…erkelsen/engine into pr/harryterkelsen/53201
0b426fe to
b207ee7
Compare
| final int scaledWidth = scaledSize.width; | ||
| final int scaledHeight = scaledSize.height; | ||
|
|
||
| final DomOffscreenCanvas offscreenCanvas = createDomOffscreenCanvas( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can avoid creating an offscreen canvas and so on here by just using createImageBitmap instead. https://developer.mozilla.org/en-US/docs/Web/API/createImageBitmap It has resizeWidth and resizeHeight options which will to the rescaling for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Harry pointed out that createImageBitmap is async, which makes this much less clean. So we should leave it as is.
eyebrowsoffire
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
| final int scaledWidth = scaledSize.width; | ||
| final int scaledHeight = scaledSize.height; | ||
|
|
||
| final DomOffscreenCanvas offscreenCanvas = createDomOffscreenCanvas( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Harry pointed out that createImageBitmap is async, which makes this much less clean. So we should leave it as is.
|
Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change). If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review. |
…152046) flutter/engine@9739d92...6312dfc 2024-07-19 [email protected] [canvaskit] Decode images using <img> tag decoding (flutter/engine#53201) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: 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
…lutter#152046) flutter/engine@9739d92...6312dfc 2024-07-19 [email protected] [canvaskit] Decode images using <img> tag decoding (flutter/engine#53201) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: 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
…lutter#152046) flutter/engine@9739d92...6312dfc 2024-07-19 [email protected] [canvaskit] Decode images using <img> tag decoding (flutter/engine#53201) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: 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
Prefer to decode images using the browser API rather than with CanvasKit to avoid jank when decoding.
Part of deprecating the HTML renderer: flutter/flutter#145954
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.