Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Conversation

@cyanglaz
Copy link
Contributor

@cyanglaz cyanglaz commented Nov 21, 2019

Description

This PR fixes 2 things:
The scaling is performed even when the quality/maxWidth/maxHeight are null.
When a non-image file is picked, scaling process is performed on the file.

Related Issues

flutter/flutter#38775
flutter/flutter#40233
b/142680906
b/143851555

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.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • My PR includes unit or integration tests for all changed/updated/fixed behaviors (See Contributor Guide).
  • All existing and new tests are passing.
  • I updated/added relevant documentation (doc comments with ///).
  • The analyzer (flutter analyze) does not report any problems on my PR.
  • I read and followed the Flutter Style Guide.
  • The title of the PR starts with the name of the plugin surrounded by square brackets, e.g. [shared_preferences]
  • I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy.
  • I updated CHANGELOG.md to add a description of the change.
  • I signed the CLA.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Does your PR require plugin users to manually update their apps to accommodate your change?

  • Yes, this is a breaking change (please indicate a breaking change in CHANGELOG.md and increment major revision).
  • No, this is not a breaking change.

@cyanglaz cyanglaz requested a review from mklim November 21, 2019 01:31
*/
String resizeImageIfNeeded(
String imagePath, Double maxWidth, Double maxHeight, int imageQuality) {
String imagePath, Double maxWidth, Double maxHeight, Integer imageQuality) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: If we're including androidx.annotation already, it would be nice if imageQuality and the other potentially null params here were tagged with @Nullable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

File scaledImage = resizedImage(imagePath, maxWidth, maxHeight, imageQuality);
exifDataCopier.copyExif(imagePath, scaledImage.getPath());
Bitmap bmp = decodeFile(imagePath);
if (bmp == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Do all of these lines need to be guarded by an IOException, or can they be moved outside of the try/catch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

double originalHeight = bmp.getHeight() * 1.0;

if (imageQuality < 0 || imageQuality > 100) {
if (imageQuality == null || imageQuality < 0 || imageQuality > 100) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: This condition is repeated in a lot of places, and it uses two magic numbers (0 and 100). I think it would help readability a little to extract it out into a helper function called isImageQualityValid that was called in multiple places instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;

public class ImageResizerTest {
Copy link
Contributor

Choose a reason for hiding this comment

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

If we have some time to improve this, it would be better to change the style of testing here so that it's really testing the behavior of ImageResizer's public API instead of the interactions of a bunch of its private methods. The way this test is written right now it's really just verifying that when certain methods are called, other methods also get triggered. This isn't really testing the logic of the class, and it could be broken by trivial method renames. It also exposes a bunch of methods with @VisibleForTesting that would be better kept private.

https://testing.googleblog.com/2013/08/testing-on-toilet-test-behavior-not.html

Here's the approach I would probably take:

  1. Use TemporaryFolder to create a file directory for the unit tests, and pass it into ImageResizer as externalFilesDirectory as its constructed in the tests.
  2. Write a sample bitmap to TemporaryFolder.
  3. Call ImageResizer.resizeImageIfNeeded with a combination of settings. Verify that the bitmap at the returned path exists and has been resized correctly for each one.

What do you think, does that sound workable to you? The catch here is I'm not sure how creating a Bitmap in a test goes, and I'm not sure if it's easy to check a Bitmap's image quality or not. I don't remember that API off the top of my head.

This is still an improvement over what we have so I am happy to merge this if needed, thank you for writing tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will take a look

return null;
}
String[] pathParts = imagePath.split("/");
String imageName = pathParts[pathParts.length - 1];
Copy link
Contributor

Choose a reason for hiding this comment

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

Are all images always guaranteed to have an extension?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the imageName. For example if the imagePath is foo/bar/image.png, the imageName would be image.png.
Or you are asking what we should do if the imageName doesn't contain an extension?

@cyanglaz cyanglaz changed the title [image_picker]f ix a crash when a non-image file is picked. [image_picker]fix a crash when a non-image file is picked. Nov 21, 2019
Copy link
Contributor Author

@cyanglaz cyanglaz left a comment

Choose a reason for hiding this comment

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

Done some changes based on the comments. Will look into improving the tests.

*/
String resizeImageIfNeeded(
String imagePath, Double maxWidth, Double maxHeight, int imageQuality) {
String imagePath, Double maxWidth, Double maxHeight, Integer imageQuality) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

File scaledImage = resizedImage(imagePath, maxWidth, maxHeight, imageQuality);
exifDataCopier.copyExif(imagePath, scaledImage.getPath());
Bitmap bmp = decodeFile(imagePath);
if (bmp == null) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

return null;
}
String[] pathParts = imagePath.split("/");
String imageName = pathParts[pathParts.length - 1];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the imageName. For example if the imagePath is foo/bar/image.png, the imageName would be image.png.
Or you are asking what we should do if the imageName doesn't contain an extension?

double originalHeight = bmp.getHeight() * 1.0;

if (imageQuality < 0 || imageQuality > 100) {
if (imageQuality == null || imageQuality < 0 || imageQuality > 100) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;

public class ImageResizerTest {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will take a look

Copy link
Contributor

@mklim mklim left a comment

Choose a reason for hiding this comment

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

LGTM

Better testing for this isn't feasible right now, Robolectric fakes out too much of Bitmap and decoding it from files/byte streams.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants