Varun Agarwal
Varun Agarwal

Reputation: 1587

Out of Memory Error during image compression

I am currently following the tutorial from this site to compress my images. It is working very well on some cellphones such as LG G3, Moto G and a few Samsung models. However, it causes Out-of-Memory error at this line for some phones such as Xiomi Mi4.

options.inTempStorage = new byte[16 * 1024];

The entire code is as follows -

public Bitmap compressImage(String imageLocation) {
    Bitmap scaledBitmap = null;

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    Bitmap bmp = BitmapFactory.decodeFile(imageLocation, options);

    int actualHeight = options.outHeight;
    int actualWidth = options.outWidth;
    float maxHeight = 700.0f;//816.0f;
    float maxWidth = 500.0f; //612.0f;
    float imgRatio = actualWidth / actualHeight;
    float maxRatio = maxWidth / maxHeight;

    if (actualHeight > maxHeight || actualWidth > maxWidth) {
        if (imgRatio < maxRatio) {
            imgRatio = maxHeight / actualHeight;
            actualWidth = (int) (imgRatio * actualWidth);
            actualHeight = (int) maxHeight;
        } else if (imgRatio > maxRatio) {
            imgRatio = maxWidth / actualWidth;
            actualHeight = (int) (imgRatio * actualHeight);
            actualWidth = (int) maxWidth;
        } else {
            actualHeight = (int) maxHeight;
            actualWidth = (int) maxWidth;
        }
    }
    //options.inSampleSize = utils.calculateInSampleSize(options, actualWidth, actualHeight);
    options.inJustDecodeBounds = false;
    options.inDither = false;
    options.inPurgeable = true;
    options.inInputShareable = true;
    options.inTempStorage = new byte[16 * 1024];
    try {
        bmp = BitmapFactory.decodeFile(imageLocation, options);
    } catch (OutOfMemoryError exception) {
        exception.printStackTrace();
    }
    try {
        scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
    } catch (OutOfMemoryError exception) {
        exception.printStackTrace();
    }

    float ratioX = actualWidth / (float) options.outWidth;
    float ratioY = actualHeight / (float) options.outHeight;
    float middleX = actualWidth / 2.0f;
    float middleY = actualHeight / 2.0f;

    Matrix scaleMatrix = new Matrix();
    scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);

    Canvas canvas = new Canvas(scaledBitmap);
    canvas.setMatrix(scaleMatrix);
    canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));


    ExifInterface exif;
    try {
        exif = new ExifInterface(imageLocation);

        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
        Log.d("EXIF", "Exif: " + orientation);
        Matrix matrix = new Matrix();
        if (orientation == 6) {
            matrix.postRotate(90);
            Log.d("EXIF", "Exif: " + orientation);
        } else if (orientation == 3) {
            matrix.postRotate(180);
            Log.d("EXIF", "Exif: " + orientation);
        } else if (orientation == 8) {
            matrix.postRotate(270);
            Log.d("EXIF", "Exif: " + orientation);
        }
        scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
    } catch (IOException e) {
        e.printStackTrace();
    }

    return scaledBitmap;
}

Could someone please help me out/ give suggestions as to how I can improve this code so it takes less memory.

Upvotes: 1

Views: 523

Answers (2)

Chandra Sharma
Chandra Sharma

Reputation: 1340

You should set the sample size on the basis of required size. Try to set options.inSampleSize dynamically. i.e

options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

//Method

public static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and
            // keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

Upvotes: 0

IntelliJ Amiya
IntelliJ Amiya

Reputation: 75788

You are dealing with large bitmaps and loading all of them at run time. You have to deal very carefully with large bitmaps by loading the size that you need not the whole bitmap at once and then do scaling.

Please check below Link

  1. Is it possible to catch out of memory exception in java?

Upvotes: 1

Related Questions