Bitmapfactory.Decoderesource Returns a Mutable Bitmap in Android 2.2 and an Immutable Bitmap in Android 1.6

BitmapFactory.decodeResource returns a mutable Bitmap in Android 2.2 and an immutable Bitmap in Android 1.6

You can convert your immutable bitmap to a mutable bitmap.

I found an acceptable solution that uses only the memory of one bitmap.

A source bitmap is raw saved (RandomAccessFile) on disk (no ram memory), then source bitmap is released, (now, there's no bitmap at memory), and after that, the file info is loaded to another bitmap. This way is possible to make a bitmap copy having just one bitmap stored in ram memory per time.

See the full solution and implementation here: Android: convert Immutable Bitmap into Mutable

I add a improvement to this solution, that now works with any type of Bitmaps (ARGB_8888, RGB_565, etc), and deletes the temp file. See my method:

/**
* Converts a immutable bitmap to a mutable bitmap. This operation doesn't allocates
* more memory that there is already allocated.
*
* @param imgIn - Source image. It will be released, and should not be used more
* @return a copy of imgIn, but muttable.
*/
public static Bitmap convertToMutable(Bitmap imgIn) {
try {
//this is the file going to use temporally to save the bytes.
// This file will not be a image, it will store the raw image data.
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "temp.tmp");

//Open an RandomAccessFile
//Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
//into AndroidManifest.xml file
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");

// get the width and height of the source bitmap.
int width = imgIn.getWidth();
int height = imgIn.getHeight();
Config type = imgIn.getConfig();

//Copy the byte to the file
//Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888;
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes()*height);
imgIn.copyPixelsToBuffer(map);
//recycle the source bitmap, this will be no longer used.
imgIn.recycle();
System.gc();// try to force the bytes from the imgIn to be released

//Create a new bitmap to load the bitmap again. Probably the memory will be available.
imgIn = Bitmap.createBitmap(width, height, type);
map.position(0);
//load it back from temporary
imgIn.copyPixelsFromBuffer(map);
//close the temporary file and channel , then delete that also
channel.close();
randomAccessFile.close();

// delete the temp file
file.delete();

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return imgIn;
}

Convert immutable Bitmap file to mutable Bitmap

I have found the problem! All of the 3 methods above are working, there was a problem with the resolution of my image, so I thought the code didn't work and it was not mutable but I was wrong. Here is another solution to change immutable image to mutable.

BitmapFactory.decodeResource returns a mutable Bitmap in Android 2.2 and an immutable Bitmap in Android 1.6

Immutable bitmap crash error

You have to convert your workingBitmap to Mutable Bitmap for drawing on Canvas. (Note: this method does not help save memory, it will use extra memory)

Bitmap workingBitmap = Bitmap.createBitmap(chosenFrame);
Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutableBitmap);

This answer helps don't waste memory
Convert immutable bitmap to a mutable bitmap

Is an immutable Bitmap faster then a mutable one?

Romain Guy answered in the comments:

To answer the original question: no, there is no performance
difference. There are some optimizations we could implement for
mutable bitmaps though. Hopefully in a future release :)

How to get mutable bitmap using ImageDecoder?

A bit prettier solution

imageBitmap = imageBitmap.copy(Bitmap.Config.ARGB_8888, true);

Refer this answer

Cannot crop Bitmap

The cropping likely works fine, but the resulting Bitmap object that is cropped is returned from createBitmap(), the original object is not modified (as was mentioned, because the Bitmap instance is immutable). If you want the cropped result, you have to grab the return value.

Bitmap cropped = Bitmap.createBitmap(i_BitmapFromFile, cuttingOffset/2, 0, currentWidth - cuttingOffset, currentHeight);

Then you can do any further work you would like with that result.

HTH



Related Topics



Leave a reply



Submit