-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make upscaling opt in for image decoding #19067
Make upscaling opt in for image decoding #19067
Conversation
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 w/ nits.
lib/ui/painting.dart
Outdated
_ImageInfo? imageInfo, | ||
int targetWidth, | ||
int targetHeight, | ||
bool allowUpscaling) native 'instantiateImageCodec'; |
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.
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.
lib/ui/painting/image_decoder.cc
Outdated
@@ -42,11 +42,22 @@ static double AspectRatio(const SkISize& size) { | |||
// intrinsic dimensions of the image. | |||
static SkISize GetResizedDimensions(SkISize current_size, | |||
std::optional<uint32_t> target_width, | |||
std::optional<uint32_t> target_height) { | |||
std::optional<uint32_t> target_height, | |||
bool allow_upscaling) { |
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.
style nit: Consider replacing bool argument with an enum: https://google.github.io/styleguide/cppguide.html#Function_Argument_Comments
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.
Other than the undefined behavior around explicitly aspect-ratio overriding decodes, looks good. Thanks.
lib/ui/painting/image_decoder.cc
Outdated
target_width = std::min(current_size.width(), | ||
static_cast<int32_t>(target_width.value())); | ||
} | ||
if (target_height) |
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.
Nit: Missing braces.
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.
if (current_size.isEmpty()) { | ||
return SkISize::MakeEmpty(); | ||
} | ||
|
||
if (image_upscaling == ImageUpscalingMode::kNotAllowed) { | ||
if (target_width) { |
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.
This is a breaking change for this one (admittedly obscure) use case: If the user explicitly wants to decode the image at a non-native aspect ratio, they would specify both the target width and height. Before, the decoder would always return images at that aspect ratio. Now, that aspect ratio will not be preserved if the dimensions along either axis exceed the intrinsic value.
I think a clarification of whether the scaling will be done in an aspect ratio preserving manner is warranted in the documentation as well as a test case in image_decoder_unittests.cc
(let's add a test even if decide not to preserve the aspect ratio just so the behavior is not undefined).
If you do decide to preserve scale, you can account the specification of both in another conditional check here.
I know this is an obscure case, but let's avoid undefined behavior as much as possible.
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.
This is a good point.
My grand plan is to follow this up with another PR to add something to control how aspect ratios are or are not preserved. I was originally thinking that this could be separated out from that, but I think you're right that it can't.
I'll take a quick look at how much more complicated this PR gets to add that extra parameter, otherwise I'll look to clarify the docs.
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.
Actually, if a user wants that case they have to just set the allowUpscaling
bit to true right?
But yes, we should document and test this.
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.
Yeah, we have sort of tacked on stuff to this original simple API in bits and pieces as we went along. This has understandably become a bit unwieldy.
I'll take a quick look at how much more complicated this PR gets to add that extra parameter...
Instead of doing all the design work to further update this API with additional options, I am fine if we just say "this will/won't preserve aspect ratio if both dimensions are specified" and add a test for this. As I said, my comment was more about the undefined behavior. This is still an improvement for a vast majority of the cases.
In the long run, an API that works with image descriptors without decompression is the way to go. But that is a lot more work to write and migrate to.
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.
if a user wants that case they have to just set the allowUpscaling bit to true right?
Yeah, there is a workaround. Let's just document and test the default. My only concern still is that since the default has changed, earlier, they didn't need to specify the argument but now they have to.
How about just preserving the aspect ratio while scaling down if both width and height are specified? That ought to be really straightforward.
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.
Ok, the more I look at this, the more I think it's just a doc and test thing. Whether or how we add other aspect ratio parameters here will still be relevant to this case.
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.
Sounds good.
->dimensions(), | ||
SkISize::Make(6, 2)); | ||
} | ||
|
||
TEST(ImageDecoderTest, VerifySimpleDecodingNoUpscaling) { |
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.
Per my comment earlier, a test case here about aspect ratio overwriting scales. So something like decode at 1200x100 with ImageUpscalingMode::kNotAllowed
.
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.
lib/ui/painting.dart
Outdated
int? targetWidth, | ||
int? targetHeight, | ||
bool allowUpscaling = false, |
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.
This is going to be a breaking change. Not sure we want to do the dance of keeping it true and flip it later. Your call.
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.
For the Flutter compatibility policy, we would have to break a contributed test (including internal). I did not do a full tgp but I believe this is not breaking by that definition. I understand that is a change in default behavior though.
I suppose to prevent any need to roll back I can default it to true for now, and then we can go back and default it to false once we can test it internally a bit more easily.
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.
This is a new API, so there can't be a test that breaks right? Just felt it might be in violation of the "spirit" of the compatibility policy if not the letter. Either way, your call. It was just an observation about the defaults changing.
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.
There could be a test somewhere that's using the targetWidth/Height to upscale the image currently, and that test would start failing. If that test is registered in flutter/tests or in google3, it counts as a breaking change.
I'm going to see if I can run this through a TGP and make sure it doesn't break anything. If not, I'm going to avoid the dance of changing defaults around - this is clearly what most users want.
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.
Sounds good.
if (current_size.isEmpty()) { | ||
return SkISize::MakeEmpty(); | ||
} | ||
|
||
if (image_upscaling == ImageUpscalingMode::kNotAllowed) { | ||
if (target_width) { |
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.
Sounds good.
This is failing a framework side test that explicitly upscales the image. I'm going to swap this so that it's defaulting to true, then we can opt that test in, and change this to false. |
Description
Make upscaling images using the
targetWidth
andtargetHeight
opt-in.Users are encouraged to use this API to have better memory management of their images. They don't typically want the image to be upscaled - this patch adds a parameter for that and defaults it to false.
It would be nice to land #19062 before this to avoid merge conflicts, but this is otherwise ready for review.
Related Issues
flutter/flutter#59578
flutter/flutter#48885
Tests
I added the following tests:
C++ test for image decoding using the parameter set to true and false
Dart tests opted in and out
Breaking Change
Did any tests fail when you ran them? Please read handling breaking changes.
Based on my understanding of the current compatibility policy, this is not breaking - although I did change some existing tests. However, this will not break third policies or google3 AFAICT.