1

First off, I have read many posts and articles about out of memory exceptions but none of them have helped with my situation. What I'm trying to do is load an image from the sd card but scale it to an exact pixel size.

I first get the width and height of the image and calculate the sample size:

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(backgroundPath, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, getWidth(), getHeight());

Here's how I get the sample size (although its not really relevant):

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;

    // NOTE: we could use Math.floor here for potential better image quality
    // however, this also results in more out of memory issues
    if (height > reqHeight || width > reqWidth) {
        if (width > height) {
            inSampleSize = Math.round((float)height / (float)reqHeight);
        } else {
            inSampleSize = Math.round((float)width / (float)reqWidth);
        }
    }

    return inSampleSize;
}

Now that I have a sample size I load the image from disk to an approximate size (sample size):

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    options.inPurgeable = true;
    Bitmap bmp = BitmapFactory.decodeFile(backgroundPath, options);

Now, I scale this bitmap that I have created to the exact size I need and clean up:

    // scale the bitmap to the exact size we need
    Bitmap editedBmp = Bitmap.createScaledBitmap(bmp, (int) (width * scaleFactor), (int) (height * scaleFactor), true); 

    // clean up first bitmap
    bmp.recycle();
    bmp = null;
    System.gc();    // I know you shouldnt do this, but I'm desperate 

The above step is usually get my out of memory exception. Does anyone know a way to load an exact size bitmap from disk to avoid having to create two separate bitmaps like above?

Also, it seems like more exceptions occur when the user runs this code for a second time (sets a new image). However, I make sure to unload the drawable that was created from the bitmap which allows it to be garbage collected before this code is run again.

Any suggestions?

Thanks, Nick

11
  • Before creating the editedBmp, log the width and height of it, as well as the scaleFactor to make sure that your parameters are correct. Commented Feb 22, 2013 at 18:16
  • instead of createScaledBitmap can you do what is done here? developer.android.com/training/displaying-bitmaps/… , just changing the decodeResources to decodeFile and passing in the size options? Commented Feb 22, 2013 at 18:17
  • @Jave yes, the width, height, and scaleFactor are correct. A out of memory exception doesnt always happen and when it does not the image is the proper size. Commented Feb 22, 2013 at 18:20
  • @JohnBoker That example uses a sample size (similar to what I'm doing in the first step). This will only give you an approximate size and not the actual size it needs to be. Commented Feb 22, 2013 at 18:24
  • You're doubling the memory usage for bitmap allocation by decoding and then scaling to exact size. Why not just use bmp? If it's going into an ImageView, you can play with ScaleType to compare interpolation vs. crop. Commented Feb 22, 2013 at 18:37

2 Answers 2

2

In your case there's no need to create the intermediate bitmap after you've performed the first decode. Since you're drawing to to a Canvas, you can use either the following methods (whichever you find most convenient) to scale the image to the perfect size.

drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)
Sign up to request clarification or add additional context in comments.

Comments

0

Maybe this method would be helpful, I think I pulled it off of stackoverflow myself. It solved my out of memory exception issue.

private Bitmap decodeFile(File f){
    try {
        //Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f),null,o);

        //The new size we want to scale to
        final int REQUIRED_SIZE=250;

        //Find the correct scale value. It should be the power of 2.
        int scale=1;
        while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
            scale*=2;

        //Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {}

    return null;
} 

2 Comments

This uses a sample size like what I'm doing in the first step in my question. This does not provide you with the exact size of the required size.
I think the Bitmap.createScaledBitmap() call that you are using brings a full bitmap into memory. I use the above method to create a scaled bitmap and then i use Bitmap.createScaledBitmap() on the returned bitmap to size it to the finishe size that I need. Sorry I wasn't of help to you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.