-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[image_picker] Do not resize GIF images #2821
Conversation
|
This works a little different on Android than on iOS. There seems to be a gif scaler on iOS, whereas I'm not sure it exists anywhere in the Android SDK. @cyanglaz do you have a suggestion how to test this PR? There are different paths for GIF and other image formats. I was thinking to just extend the FileUtilTest and perhaps check if the response from one of the methods matches the original path, if that is somehow possible to determine. |
|
Is this related to #2982? They seem similar? |
|
@ditman yes - 2982 solves one problem (the returned file extension being jpg for any file) while this PR solves two:
We can either merge 2982 first or confirm this PR. @ponnamkarthik do you think this PR contains the same fix as yours from a technical point of view? |
|
I found another implementation of this fix in #2860 (only the JPG extension part), can we merge these two/grab ideas from both? I've noticed the extension detection seems a little bit more thorough in 2860 than here. (Also, adding some unit tests here would be nice!) |
...r/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java
Outdated
Show resolved
Hide resolved
|
i think this can be fixed too in this PR. We just need to add one more condition for svg images. |
...e_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java
Outdated
Show resolved
Hide resolved
@balvinderz very interesting. Do you know how iOS / Android differ when it comes to SVG? I seem to remember that iOS also supports PDF images? |
|
I am not able to pick svg images on ios. |
|
@ditman lgtm |
| @@ -1,3 +1,7 @@ | |||
| ## 0.8.5 | |||
|
|
|||
| * Android: Disable image resizing for GIF images. | |||
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 should be updated to reflect the actual set of extensions in the PR.
| class ImageResizer { | ||
| /** Extensions that the ImageResizer cannot resize. */ | ||
| private static final Set<String> nonResizeableExtensions = | ||
| new HashSet<>(Arrays.asList("gif", "svg", "apng")); |
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.
Applying this to all gif files seems like a large hammer; not all gifs are animated. Shouldn't we be examining the file's header to determine whether it's an animated gif?
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.
Hm, I'll look into implementing this; however I think the header doesn't contain info about animation, the file needs to be scanned to look for "local image descriptors" (> 1)
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's a promising "Movie" class that might be useful to see if an image is animated or not. I'll use it to check both GIF and PNG (potentially animated), and leave the extensions for APNG (definitely animated) and SVG (vector).
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.
Adding to what Stuart has commented:
For non-animated gif, we should scale it as it works as is.
For animated gif, we can scale it by scale all the frames of the git then combine them again. See: flutter/flutter#34134 (comment)
We can make this PR to exclude file extensions that cannot be scaled, which doesn't include gifs. And create another PR to scale gif.
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.
@cyanglaz in theory there is more than 1 animated file format available on Android:
Animated GIFs, WebP and HEIF via list of Android formats
IMHO, the MR currently resolves a issue in that the GIF file looses animation, which is the No. 1 purpose of using a GIF file. I understand your point to "do it right", but think this would delay the product iteration by a lot. Why not merging this change with determined behaviour (as breaking change) and consider the next step after community feedback?
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.
IMHO, the MR currently resolves a issue in that the GIF file looses animation, which is the No. 1 purpose of using a GIF file.
And the only reason to pass max width/height is to cause the image to be resized. You are proposing breaking something that currently works in order to fix something that is sometimes currently broken. That is not a clear improvement.
I understand your point to "do it right", but think this would delay the product iteration by a lot.
Doing things correctly sometimes takes longer, yes. Rapidly moving between different broken states isn't something clients of software generally view as a feature.
Why not merging this change with determined behaviour (as breaking change) and consider the next step after community feedback?
If we are going to do an interim fix, it would be something along the lines of my non-breaking suggestion, so that we do not:
- actively regress people
- introduce a breaking change for something that is not necessarily a net improvement, and which would need another breaking change to change again later to improve
Breaking changes are disruptive; we do not want to set ourselves up to make several when there's a perfectly good way not 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.
@stuartmorgan OK understood.
| /// image types such as JPEG and on Android PNG and WebP, too. If compression is not supported for the image that is picked, | ||
| /// a warning message will be logged. | ||
| /// | ||
| /// GIF images picked from the gallery will only be scaled on iOS. They'll be returned as-is on Android and the Web. |
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, and would need to be versioned accordingly.
I think a better option would probably be a new, optional boolean to apply resizing only if we're confident that we can do it without destroying information, defaulting to false. That makes this a non-breaking change (and would make things like the animated vs non-animated gif issue something we could punt on).
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.
So, given the current pickImage method signature:
Future<XFile?> pickImage({
required ImageSource source,
double? maxWidth,
double? maxHeight,
int? imageQuality,
CameraDevice preferredCameraDevice = CameraDevice.rear,
}) {
return platform.getImage(
source: source,
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: imageQuality,
preferredCameraDevice: preferredCameraDevice,
);
}
The new boolean would be called safeResizeOnly: false and be described as follows:
When [safeResizeOnly] is set to
trueand a resize would incur a loss of information, the original image will be returned. This applies to animated formats like GIF or APNG, which can not be resized on Android without loosing the animation.
WDYT, @stuartmorgan (naming variables is not easy ;-)).
Side note: When you said:
only if we're confident that we can do it without destroying information
.. I started to wonder what happens to the EXIF metadata on resize. It was on the radar previously https://github.com/flutter/flutter/issues?q=is%3Aissue+exif+image_picker+is%3Aopen so may warrant another check in the future.
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.
The new boolean would be called
safeResizeOnly: falseand be described as follows:When [safeResizeOnly] is set to
trueand a resize would incur a loss of information, the original image will be returned. This applies to animated formats like GIF or APNG, which can not be resized on Android without loosing the animation.
That sounds good, except s/would/could/, and I would explicitly say that it's a heuristic that may be adjusted over time. I think your wording would be misleading about, e.g., the initial planned handling of GIFs (where it will fail to resize them even when not animated).
I started to wonder what happens to the EXIF metadata on resize
You could say something like "fundamentally change the image" instead of "incur a loss of information", to make it clearer that it's not just any loss of information.
That's probably a good idea anyway, because as currently written any resize down would actually be forbidden because it loses information.
| /// image types such as JPEG and on Android PNG and WebP, too. If compression is not supported for the image that is picked, | ||
| /// a warning message will be logged. | ||
| /// | ||
| /// GIF images picked from the gallery will only be scaled on iOS. They'll be returned as-is on Android and the Web. |
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.
Whatever the change ends up being, the doc change will need to be applied to all the methods that take a size.
...e_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java
Show resolved
Hide resolved
| class ImageResizer { | ||
| /** Extensions that the ImageResizer cannot resize. */ | ||
| private static final Set<String> nonResizeableExtensions = | ||
| new HashSet<>(Arrays.asList("gif", "svg", "apng")); |
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.
Adding to what Stuart has commented:
For non-animated gif, we should scale it as it works as is.
For animated gif, we can scale it by scale all the frames of the git then combine them again. See: flutter/flutter#34134 (comment)
We can make this PR to exclude file extensions that cannot be scaled, which doesn't include gifs. And create another PR to scale gif.
@cyanglaz everything that is an image/video can be scaled, right? 😜 we just need to be able to uncompress every frame from every possible format, resize each frame, and then recompose the scaled output. I'm not sure I want to be in the business of knowing how to open and resize every possible image/video format that exists. Do we have a list of the formats that are/aren't supported? |
cyanglaz
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.
Do we have a list of the formats that are/aren't supported?
I don't think we have such list. I think, Ideally, scaling all format should be supported. The priority of supporting each format would vary based on requirements. For example, gif might be a higher priority at the moment.
...e_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java
Show resolved
Hide resolved
|
Hey all, I tried to detect if an image is animated or not, but I broke one of my tests (which should pass after my change) and couldn't setup a decent Android environment to debug the test. Here's my latest change in case somebody wants to keep at it: |
|
Are you still planning on updating this PR based on the last round of discussion? |
This is to make main the default branch.
|
@stuartmorgan I haven't had time to look at this in a few months, somebody with more android experience should tackle it as suggested by @cyanglaz, probably! |
|
@ened Are you planning on updating this per #2821 (comment) and #2821 (comment) ? It seems like that's a way forward here without tackling the larger problem of trying to fully support resizing of animated formats (as in the last bit of discussion). |
|
@ened I see you have updated the branch, but it doesn't look like you've addressed the comments. Is this still something you're planning on finishing? |
|
Thank you for your contribution. I'm going to close this PR for now since there are outstanding comments, just to get this off our PR review queue. Please don't hesitate to submit a new PR if you have the time to address the review comments. Thanks! |

Description
Reenables image picking for .GIF images on Android instead of converting anything to JPG straight away.
Related Issues
Closes flutter/flutter#34134.
Closes flutter/flutter#52419.
Closes flutter/flutter#88461.
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.///).flutter analyze) does not report any problems on my PR.Breaking Change
Does your PR require plugin users to manually update their apps to accommodate your change?