How to avoid "memory exception" when processing Bitmap?

In onPictureTaken , I want to do the following:

 Bitmap decodedPicture = BitmapFactory.decodeByteArray(data, 0, data.length); Matrix matrix = new Matrix(); matrix.preScale(-1.0f, 1.0f); Bitmap picture = Bitmap.createBitmap(decodedPicture, 0, 0, decodedPicture.getWidth(), decodedPicture.getHeight(), matrix, false); View v1 = mainLayout.getRootView(); v1.setDrawingCacheEnabled(true); Bitmap screenshot = Bitmap.createBitmap(v1.getDrawingCache()); v1.setDrawingCacheEnabled(false); Bitmap scaledPicture = Bitmap.createScaledBitmap(picture, screenshot.getWidth(), screenshot.getHeight(), true); Bitmap compos = Bitmap.createBitmap(scaledPicture.getWidth(), scaledPicture.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(compos); canvas.drawBitmap(scaledPicture, new Matrix(), null); canvas.drawBitmap(screenshot, new Matrix(), null); MediaStore.Images.Media.insertImage(getContentResolver(), compos, "name" , "description"); sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 

My only requirement is that I would like to keep a high-quality photograph ... It seems I may have to sacrifice this.

On my Nexus 4 and newer devices, this code works just fine and as expected. But on older devices that have less memory, I run out of RAM !: (

How do I do the same image manipulation without encountering memory limitations? I am not trying to display these images on the screen, so the solutions that are related to the thumbnail do not really apply here ...

+6
source share
4 answers

you need to read a bitmap with a larger sample size. the trick is to find the right sample size that will not result in a reduced resolution when you ultimately scale the image. I wrote a blog post about it here, which includes a nice utility class for scaling,

http://zerocredibility.wordpress.com/2011/01/27/android-bitmap-scaling/

perhaps you may simplify this class depending on your specific needs.

jist should read only the size of the bitmap. calculate the optimal sample size based on the desired scaled size, read the bitmap using that sample size, and then scale it accurately to the desired size.

+3
source

You have so many Bitmap objects. try reusing / reusing some of this.

It’s not entirely clear what your requirement is, but I see that you can save memory just by doing this.

  Bitmap decodedPicture = BitmapFactory.decodeByteArray(data, 0, data.length); Matrix matrix = new Matrix(); matrix.preScale(-1.0f, 1.0f); Bitmap picture = Bitmap.createBitmap(decodedPicture, 0, 0, decodedPicture.getWidth(), decodedPicture.getHeight(), matrix, false); decodedPicture.recycle(); decodedPicture=null; View v1 = mainLayout.getRootView(); v1.setDrawingCacheEnabled(true); Bitmap screenshot = Bitmap.createBitmap(v1.getDrawingCache()); v1.setDrawingCacheEnabled(false); Bitmap scaledPicture = Bitmap.createScaledBitmap(picture, screenshot.getWidth(), screenshot.getHeight(), true); picture.recycle(); picture=null; Bitmap compos = Bitmap.createBitmap(scaledPicture.getWidth(), scaledPicture.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(compos); canvas.drawBitmap(scaledPicture, new Matrix(), null); canvas.drawBitmap(screenshot, new Matrix(), null); MediaStore.Images.Media.insertImage(getContentResolver(), compos, "name" , "description"); sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 

Also look into the memory area, make sure that the reasonable memory of the device you are using is not too large.

FYI, on post-Soviet devices, a bitmap image highlighted on its own layer. You need recycle() or finalizer() recover memory

0
source

Given that you do not want to resize the bitmap and do not want to display it, I would do something like this:

  • Download the bitmap using inJustDecodeBounds to see its original height and width (code here )

     final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 
  • Depending on the size and memory, you have the option to directly process it (i.e. load Bitmap) or start downloading several fragments of the specified Bitmap using Bitmap.createBitmap , which allows you to download only a piece of data. Optional: consider converting it to an array of bytes (see code below) and null + recycle() before processing the block.

code

 ByteArrayOutputStream byteArrayBitmapStream = new ByteArrayOutputStream(); bitmapPicture.compress(Bitmap.CompressFormat.PNG, COMPRESSION_QUALITY, byteArrayBitmapStream); byte[] b = byteArrayBitmapStream.toByteArray(); 
0
source

I use WeakReference for working with the Bitmap class and after I always call recycle on the WeakReference instance object, the fragment code for rotating the image:

 BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; options.inPurgeable = true; options.inInputShareable = true; options.inPreferredConfig = Bitmap.Config.RGB_565; WeakReference<Bitmap> imageBitmapReference = new WeakReference<Bitmap>(BitmapFactory.decodeByteArray(params[0], 0, params[0].length, options)); Matrix mat = new Matrix(); mat.postRotate(90.0f); imageBitmapReference = new WeakReference<Bitmap (Bitmap.createBitmap(imageBitmapReference.get(), 0, 0, resolution[0], resolution[1], mat, true)); FileOutputStream fos = new FileOutputStream(filename); imageBitmapReference.get().compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); imageBitmapReference.get().recycle(); 

And the second solution, how to work with Bitmap and not get an OutOfMemory Exception, is to use the Universal Image Loader library

(Of course, this is the third solution installed in your AndroidManifest property android: largeHeap = "true" and really DON'T USE THIS property).

The ideal material is at http://developer.android.com/training/displaying-bitmaps/index.html and a video https://www.youtube.com/watch?v=_CruQY55HOk

0
source

Source: https://habr.com/ru/post/943895/


All Articles