Search code examples
javaandroidbitmapout-of-memorycrop

OutOfMemoryError when trying to compress bitmap


I am using android-crop library. I am dealing with frustrating out of memory exception if users try to crop from a large image (the images from the phone camera).

I have tried to compress the resulting bitmap but I still get OutOfMemoryError when trying to compress the bitmap. here goes my code: please let me know what I am doing wrong and/or how can I prevent this out of memory error?

private void handleCrop(int resultCode, Intent result) {
    if (resultCode == RESULT_OK) {

        if (mBitmap != null) {
            mBitmap.recycle();
            mBitmap = null;
        }

        Bitmap temp; //temporary bitmap

        try {
            temp = MediaStore.Images.Media.getBitmap(getContentResolver()
                    , Crop.getOutput(result)); //load image from URI

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            temp.compress(Bitmap.CompressFormat.JPEG, 60, out);
            mBitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));

            out.close();
            temp.recycle();
            temp = null;
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(this, "error loading photo. please try with another photo"
                    , Toast.LENGTH_SHORT).show();
            return;
        }

        if (mBitmap != null) {
            mImageViewProfilePhoto.setImageBitmap(mBitmap);
            enableFinalization();
        }

    }
}

Thanks to the Gabe's point I could fix the problem like so:

private void handleCrop(int resultCode, Intent result) {
    if (resultCode == RESULT_OK) {

        if (mBitmap != null) {
            mBitmap.recycle();
            mBitmap = null;
        }

        try {
            mBitmap = MediaStore.Images.Media.getBitmap(getContentResolver()
                    , Crop.getOutput(result)); //load image from URI

            File tempImageFile = new File(mContext.getFilesDir().getAbsolutePath()
                    , "temp_1311_14_hahahah_lol_WTF_shit_1414.bin");

            FileOutputStream out = new FileOutputStream (tempImageFile);
            mBitmap.compress(Bitmap.CompressFormat.JPEG, 30, out);
            mBitmap.recycle();
            mBitmap = null;

            mBitmap = BitmapFactory.decodeFile(tempImageFile.getPath());
            boolean deleted = tempImageFile.delete();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(this, "error loading photo. please try with another photo"
                    , Toast.LENGTH_SHORT).show();
            return;
        }

        if (mBitmap != null) {
            mImageViewProfilePhoto.setImageBitmap(mBitmap);
            enableFinalization();
        }

    } else if (resultCode == Crop.RESULT_ERROR) {
        Toast.makeText(this, Crop.getError(result).getMessage(), Toast.LENGTH_SHORT).show();
        disableFinalization();
    }
}

Hope it will be useful for others.


Solution

  • Assuming the problem isn't elsewhere in your app (and it always can be with OOM)- if you have a large image, you're basically making 3 copies of it. The first is the original, the second is in your ByteArrayOutputStream, and the 3rd is in your decodeStream. If the image is large (like 10MB+) that alone can cause issues. I'd suggest using a disk based output stream and seeing if that gets you through the problem. Also, you can then put the decodeStream call after temp.recycle, to make sure you never have 2 full copies at a time.