Fix Image.getSize returning downsampled dimensions on Android#56736
Fix Image.getSize returning downsampled dimensions on Android#56736zoontek wants to merge 2 commits intofacebook:mainfrom
Conversation
|
@Abbondanzo has imported this pull request. If you are a Meta employee, you can view this in D104533593. |
| @@ -83,38 +84,9 @@ internal class ImageLoaderModule : NativeImageLoaderAndroidSpec, LifecycleEventL | |||
| } | |||
| val source = ImageSource(reactApplicationContext, uriString) | |||
| val request: ImageRequest = ImageRequestBuilder.newBuilderWithSource(source.uri).build() | |||
There was a problem hiding this comment.
There's a subtle bug/feature of Fresco that will automatically rotate the encoded image based on EXIF data, which happens to perform a slight resizing of the image. I was testing this with the image from the EXIF rotations examples from https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Landscape_6.jpg.
The true dimensions of the image (post rotation) are 1800x1200, but the transcoding from Fresco's ResizeAndRotateProducer make the image 1792x1200. Indeed, you can try with a bit of print debugging on the data source here:
Log.i(
TAG,
"ImageLoaderModule.kt resolved uri=$uriString " +
"bufferSize=${encodedBuffer.size()} " +
"encoded=${encodedImage.width}x${encodedImage.height} " +
"rotation=${encodedImage.rotationAngle} rotated=$rotated " +
"returned=${width}x$height",
)
would yield a log like:
ImageLoaderModule.kt resolved uri=https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Landscape_6.jpg bufferSize=355823 encoded=1792x1200 rotation=0 rotated=false returned=1792x1200
This is Fresco beating ya to the punch. To counter this, you need to disable the default RotationOptions.autoRotate() with .setRotationOptions(RotationOptions.disableRotation()) and you get something like this:
ImageLoaderModule.kt resolved uri=https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Landscape_6.jpg bufferSize=352727 encoded=1200x1800 rotation=90 rotated=true fallbackWouldReturn=1800x1200 returned=1800x1200
| val request: ImageRequest = ImageRequestBuilder.newBuilderWithSource(source.uri).build() | |
| val request: ImageRequest = ImageRequestBuilder.newBuilderWithSource(source.uri) | |
| .setRotationOptions(RotationOptions.disableRotation()) | |
| .build() |
There was a problem hiding this comment.
@Abbondanzo good catch, I wasn't aware of that! I added them.
Summary:
Image.getSizeandgetSizeWithHeaderscall Fresco'sfetchDecodedImage, which returns aCloseableImagewhose width / height reflect the bitmap after Fresco's automatic downsampling (typically capped at the screen size).For sources larger than the screen this returned the wrong dimensions. ex: a 4000x3000 image on a 1920x1080 device came back as 1920x1440.
Switch to
fetchEncodedImageand read the dimensions from the parsed image metadata (JPEG / PNG / WebP / HEIF headers), so the values are the true source dimensions. Swap width / height for 90°/270° EXIF rotation to match the iOS behavior inRCTImageLoader.Fixes #33498
Closes facebook/fresco#2236
Changelog:
[ANDROID] [FIXED] -
Image.getSizeandImage.getSizeWithHeadersnow return the true source dimensions instead of Fresco's downsampled valuesTest Plan:
In the RNTester app, add:
Before
After