trocchietto
trocchietto

Reputation: 2617

outofmemory exception for Large Bitmap

I found a lot of documentation on how to load large Bitmaps and avoid outofmemory exception. but the problem is that I have to take the image from my MediaStore.Images.media so the classical decodeFile(path,options) indicated in the google documentation does not work to me

As you can see below I decommented the line // Bitmap photo= Mediastore.Images, that is the one that triggers the out of memory. on the other side adding the line Bitmap bm=BitmapFactory.decodeFile(selectedImageToUri,options) returns null, although the compiler can see both the path in selectedImageToUri (that indicates the content provider where the pics are) than the options value, that I set to 8, because I want to subscale all the images

My question is how can I insert in bm the bitmap that is referring to the image selected by the user in the gallery. in the line BitMap photo does not return null and work really well, but I decommented because after I change a couple of images gives me outofmemory exception.

@Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable final Bundle savedInstanceState) {


        if (flagVariable) {

            if (selectedImageToUri != null) {


                // BitMap photo = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), Uri.parse(selectedImageToUri));


                final BitmapFactory.Options options= new BitmapFactory.Options();
                options.inSampleSize=8;


                Bitmap bm = BitmapFactory.decodeFile(selectedImageToUri, options);

                pic = new BitmapDrawable(bm);


                getActivity().getWindow().setBackgroundDrawable(pic);


            } else {
                getDefaultImageBackground(inflater, container);

            }


            hiddenList = inflater.inflate(R.layout.fragment_as_list_layout_temp, container, false);

        } else {
            getDefaultImageBackground(inflater, container);
        }

        listView = (ListView) hiddenList.findViewById(R.id.list_hidden);

Upvotes: 1

Views: 819

Answers (2)

Attaullah
Attaullah

Reputation: 4021

I spent a lot of time on this problem, but no one will give me exact answer and finally i solved it. First create method and provide Image URI as argument, and this will return bitmap basically here i calculated image size on bases of, we can manage memory as well as image and get exact image in bitmap form.

you can even display 5000×8000 and 12MiB picture without any error code is tested just copy paste in your class and enjoy.

Use

Bitmap mBitmap = getPhoto(MYIMAGEURI);

Provide URI to method and get Bitmap

Bitmap getPhoto(Uri selectedImage) {
    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    int height = metrics.heightPixels;
    int width = metrics.widthPixels;
    Bitmap photoBitmap = null;
    InputStream inputStream = null;
    try {
        inputStream = getContentResolver().openInputStream(selectedImage);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
    bitmapOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(inputStream, null, bitmapOptions);
    int imageWidth = bitmapOptions.outWidth;
    int imageHeight = bitmapOptions.outHeight;

    @SuppressWarnings("unused")
    InputStream is = null;
    try {
        is = getContentResolver().openInputStream(selectedImage);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    float scale = 1.0f;

    if (imageWidth < imageHeight) {
        if (imageHeight > width * 1.0f) {
            scale = width * 1.0f / (imageHeight * 1.0f);
        }

    } else {
        if (imageWidth > width * 1.0f) {
            scale = width * 1.0f / (imageWidth * 1.0f);
        }

    }

    photoBitmap = decodeSampledBitmapFromResource(this,
            selectedImage, (int) (imageWidth * scale),
            (int) (imageHeight * scale));
    return photoBitmap;
}

Decode Bitmap Sample using image size

public static Bitmap decodeSampledBitmapFromResource(Context context,
            Uri uri, int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    InputStream is = null;
    try {
        is = context.getContentResolver().openInputStream(uri);
    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    BitmapFactory.decodeStream(is, null, options);

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

    // Decode editBitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    InputStream inputs = null;
    try {
        inputs = context.getContentResolver().openInputStream(uri);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    return BitmapFactory.decodeStream(inputs, null, options);
}

Calculate Sample Size

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) {

        // Calculate ratios of height and width to requested height and
        // width
        final int heightRatio = Math.round((float) height
                / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will
        // guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = Math.min(heightRatio, widthRatio);
        // inSampleSize = heightRatio < widthRatio ? heightRatio :
        // widthRatio;
    }

    return inSampleSize;
}

Or may be possible to solved using one line of code in manifiest.xml is in application tag use this

android:largeHeap="true"

Upvotes: 2

weston
weston

Reputation: 54811

MediaStore.getBitmap is just a simple convienence method, it looks like this:

public static final Bitmap getBitmap(ContentResolver cr, Uri url)
                throws FileNotFoundException, IOException {
    InputStream input = cr.openInputStream(url);
    Bitmap bitmap = BitmapFactory.decodeStream(input);
    input.close();
    return bitmap;
}

You can create your own method based on this that takes the options and calls a different overload on BitmapFactory:

public static final Bitmap getBitmap(ContentResolver cr,
                                     Uri url,
                                     BitmapFactory.Options options)
                throws FileNotFoundException, IOException {
    InputStream input = cr.openInputStream(url);
    Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);
    input.close();
    return bitmap;
}

Usage:

final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;

Bitmap bm = getBitmap(getActivity().getContentResolver(),
                      Uri.parse(selectedImageToUri),
                      options);

Upvotes: 3

Related Questions