Skip to content

Commit ec45040

Browse files
author
Alister Stevens
committed
fix(android): Prevent out of memory errors on Android when selecting large media (video) files from the gallery picker.
Changes from #906 resulted in all gallery picker results being read in full into a byte array. This works fine when dealing with images, however when larger files (videos for example) are selected it will nearly always result in an out of memory error (reading too much data in one go). With videos no transformation is required, the URI simply need to be returned.
1 parent b002b48 commit ec45040

File tree

1 file changed

+54
-89
lines changed

1 file changed

+54
-89
lines changed

src/android/CameraLauncher.java

Lines changed: 54 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,23 @@ private void processResultFromGallery(int destType, Intent intent) {
741741

742742
String uriString = uri.toString();
743743
String mimeTypeOfGalleryFile = FileHelper.getMimeType(uriString, this.cordova);
744+
745+
// If you ask for video or the selected file cannot be processed
746+
// there will be no attempt to resize any returned data.
747+
if (this.mediaType == VIDEO || !isImageMimeTypeProcessable(mimeTypeOfGalleryFile)) {
748+
this.callbackContext.success(uriString);
749+
return;
750+
}
751+
752+
// This is a special case to just return the path as no scaling,
753+
// rotating, nor compressing needs to be done
754+
if (this.targetHeight == -1 && this.targetWidth == -1 &&
755+
destType == FILE_URI && !this.correctOrientation &&
756+
getMimetypeForEncodingType().equalsIgnoreCase(mimeTypeOfGalleryFile)) {
757+
this.callbackContext.success(uriString);
758+
return;
759+
}
760+
744761
InputStream input;
745762
try {
746763
input = cordova.getActivity().getContentResolver().openInputStream(uri);
@@ -756,105 +773,53 @@ private void processResultFromGallery(int destType, Intent intent) {
756773

757774
try {
758775
byte[] data = readData(input);
776+
Bitmap bitmap = null;
759777

760-
// If you ask for video or the selected file cannot be processed
761-
// there will be no attempt to resize any returned data.
762-
if (this.mediaType == VIDEO || !isImageMimeTypeProcessable(mimeTypeOfGalleryFile)) {
763-
this.callbackContext.success(uriString);
764-
} else {
765-
Bitmap bitmap = null;
778+
try {
779+
bitmap = getScaledAndRotatedBitmap(data, mimeTypeOfGalleryFile);
780+
} catch (IOException e) {
781+
e.printStackTrace();
782+
}
766783

767-
// This is a special case to just return the path as no scaling,
768-
// rotating, nor compressing needs to be done
769-
if (this.targetHeight == -1 && this.targetWidth == -1 &&
770-
destType == FILE_URI && !this.correctOrientation &&
771-
getMimetypeForEncodingType().equalsIgnoreCase(mimeTypeOfGalleryFile)) {
772-
this.callbackContext.success(uriString);
773-
} else {
774-
try {
775-
bitmap = getScaledAndRotatedBitmap(data, mimeTypeOfGalleryFile);
776-
} catch (IOException e) {
777-
e.printStackTrace();
778-
}
779-
if (bitmap == null) {
780-
LOG.d(LOG_TAG, "I either have an unreadable uri or null bitmap");
781-
this.failPicture("Unable to create bitmap!");
782-
return;
783-
}
784+
if (bitmap == null) {
785+
LOG.d(LOG_TAG, "I either have an unreadable uri or null bitmap");
786+
this.failPicture("Unable to create bitmap!");
787+
return;
788+
}
784789

785-
// If sending base64 image back
786-
if (destType == DATA_URL) {
787-
this.processPicture(bitmap, this.encodingType);
788-
}
790+
// If sending base64 image back
791+
if (destType == DATA_URL) {
792+
this.processPicture(bitmap, this.encodingType);
793+
}
794+
// If sending filename back
795+
else if (destType == FILE_URI) {
796+
// Did we modify the image?
797+
if ((this.targetHeight > 0 && this.targetWidth > 0) ||
798+
(this.correctOrientation && this.orientationCorrected) ||
799+
!mimeTypeOfGalleryFile.equalsIgnoreCase(getMimetypeForEncodingType())) {
800+
try {
801+
String modifiedPath = this.outputModifiedBitmap(bitmap, uri, mimeTypeOfGalleryFile);
802+
// The modified image is cached by the app in order to get around this and not have to delete you
803+
// application cache I'm adding the current system time to the end of the file url.
804+
this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
789805

790-
// If sending filename back
791-
else if (destType == FILE_URI) {
792-
// Did we modify the image?
793-
if ((this.targetHeight > 0 && this.targetWidth > 0) ||
794-
(this.correctOrientation && this.orientationCorrected) ||
795-
!mimeTypeOfGalleryFile.equalsIgnoreCase(getMimetypeForEncodingType())) {
796-
try {
797-
String modifiedPath = this.outputModifiedBitmap(bitmap, uri, mimeTypeOfGalleryFile);
798-
// The modified image is cached by the app in order to get around this and not have to delete you
799-
// application cache I'm adding the current system time to the end of the file url.
800-
this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
801-
802-
} catch (Exception e) {
803-
e.printStackTrace();
804-
this.failPicture("Error retrieving image: " + e.getLocalizedMessage());
805-
}
806-
} else {
807-
this.callbackContext.success(uriString);
808-
}
809-
}
810-
if (bitmap != null) {
811-
bitmap.recycle();
812-
bitmap = null;
806+
} catch (Exception e) {
807+
e.printStackTrace();
808+
this.failPicture("Error retrieving image: " + e.getLocalizedMessage());
813809
}
814-
System.gc();
815-
}
816-
if (bitmap == null) {
817-
LOG.d(LOG_TAG, "I either have an unreadable uri or null bitmap");
818-
this.failPicture("Unable to create bitmap!");
819-
return;
820-
}
821-
822-
// If sending base64 image back
823-
if (destType == DATA_URL) {
824-
this.processPicture(bitmap, this.encodingType);
810+
} else {
811+
this.callbackContext.success(uriString);
825812
}
813+
}
826814

827-
// If sending filename back
828-
else if (destType == FILE_URI) {
829-
// Did we modify the image?
830-
if ( (this.targetHeight > 0 && this.targetWidth > 0) ||
831-
(this.correctOrientation && this.orientationCorrected) ||
832-
!mimeTypeOfGalleryFile.equalsIgnoreCase(getMimetypeForEncodingType()))
833-
{
834-
try {
835-
String modifiedPath = this.outputModifiedBitmap(bitmap, uri, mimeTypeOfGalleryFile);
836-
// The modified image is cached by the app in order to get around this and not have to delete you
837-
// application cache I'm adding the current system time to the end of the file url.
838-
this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
839-
840-
} catch (Exception e) {
841-
e.printStackTrace();
842-
this.failPicture("Error retrieving image: "+e.getLocalizedMessage());
843-
}
844-
} else {
845-
this.callbackContext.success(uriString);
846-
}
847-
}
848-
if (bitmap != null) {
849-
bitmap.recycle();
850-
bitmap = null;
851-
}
852-
System.gc();
815+
if (bitmap != null) {
816+
bitmap.recycle();
817+
bitmap = null;
853818
}
854819

820+
System.gc();
855821
input.close();
856-
}
857-
catch (Exception e) {
822+
} catch (Exception e) {
858823
try {
859824
input.close();
860825
} catch (IOException ex) {

0 commit comments

Comments
 (0)