[] [Android] maxWidth/maxHeight silently fail to resize large images (full-res decode returns original)
Description
On Android, the maxWidth / maxHeight options do not reliably resize picked images. The same options work correctly on iOS. For large source photos (e.g. 12 MP camera images), the returned asset keeps its original full resolution instead of being downscaled to fit within maxWidth × maxHeight.
Root cause is in Utils.resizeOrConvertImage() (android/src/main/java/com/imagepicker/Utils.java). The resize decodes the entire full-resolution bitmap into memory with no downsampling, then scales it down afterward:
try (InputStream imageStream = context.getContentResolver().openInputStream(uri)) {
Bitmap b = BitmapFactory.decodeStream(imageStream); // full-res, no inSampleSize
...
b = Bitmap.createScaledBitmap(b, newDimens[0], newDimens[1], true);
...
} catch (Exception e) {
e.printStackTrace();
return uri; // cannot resize the image, return the ORIGINAL uri
}For large images, BitmapFactory.decodeStream returns null (Android's documented behavior when it cannot allocate the full bitmap). Bitmap.createScaledBitmap(null, …) then throws a NullPointerException, which is swallowed by the broad catch (Exception e) and the method silently returns the original, un-resized URI. The failure is invisible to the JS caller — no error, just an unresized image.
Notably, the library already uses the memory-safe pattern (BitmapFactory.Options.inJustDecodeBounds = true) in getImageDimensions(), but does not apply inSampleSize in the actual resize decode. iOS uses ImageIO/Core Image thumbnailing, which downsamples during decode, so it is unaffected.
This is not fixed in any released version. The current main branch contains the identical naive implementation.
How to repeat issue and example
- Use a physical Android device with a high-resolution camera (or a large gallery image, e.g. 4000×3000).
- Call
launchImageLibrary(orlaunchCamera) with resize constraints:launchImageLibrary({ mediaType: 'photo', maxWidth: 1024, maxHeight: 1024, quality: 1, }); - Inspect the returned asset's
width/height(and file size). - Expected: the image is downscaled so the longest side is ≤ 1024.
- Actual (Android): the returned asset keeps its original dimensions (e.g. 4000×3000). The same code on iOS returns a correctly resized ~1024 px image.
Reproducible reliably with large source images; smaller images (already within the max bounds) are unaffected because no resize is attempted.
Solution
Decode the bitmap with downsampling instead of loading it at full resolution. Compute an appropriate inSampleSize from the source dimensions and the target constraints, then decode:
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri), null, bounds);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = calculateInSampleSize(bounds, targetWidth, targetHeight);
Bitmap b = BitmapFactory.decodeStream(
context.getContentResolver().openInputStream(uri), null, opts);Additionally:
- Narrow the
catch (Exception e)so genuine decode failures are surfaced rather than silently returning the original image, and/or return an explicit error to JS. - Consider guarding against
OutOfMemoryError(subtype ofError, currently not caught).
Additional Information
- Image Picker version: 8.2.1 (also confirmed present in current
main) - React Native version: 0.83.1 (New Architecture / TurboModules enabled)
- Platform: Android (iOS works correctly)
- Development Operating System: macOS
- Dev tools: Android Gradle Plugin with
compileSdkVersion/targetSdkVersion36,minSdkVersion29, NDK 27.1.12297006, Kotlin 2.1.20. Reproduced on a physical Android device picking large gallery/camera images.
Note: This issue report was authored with the assistance of Claude Opus 4.8.
Source: react-native-image-picker/react-native-image-picker