I was trying to set a bitmap image to a canvas using setBitMap ,at that time I got an IllegalStateException.This canvas have some images on it currently, I am trying to replace it.
Any one have any idea why this happened?
Code Snippet
editBm = Bitmap.createBitmap(951, 552, Bitmap.Config.ARGB_8888);
Canvas mCanvas=new Canvas(editBm);
eBit=LoadBMPsdcard(filePath); ---->returns a bitmap when the file path to the file is provided
Log.i("BM size", editBm.getWidth()+"");
mCanvas.setBitmap(eBit);
I am not getting any NullPointer errors and the method LoadBMPsdcard() is working good.
Please let me know about any ideas you have ...
Thanks in advance
Happy Coding
IllegalStateException could be thrown because you're loading a Bitmap (eBit) and use mCanvas.setBitmap(eBit) without checking if the bitmap is mutable. This is requiered to draw on the Bitmap. To make sure your Bitmap is mutable use:
eBit=LoadBMPsdcard(filePath);
Bitmap bitmap = eBit.copy(Bitmap.Config.ARGB_8888, true);
canvas.setBitmap(bitmap);
Try to use drawBitmap instead of the setBitmap. It looks like you've already set a bitmap to draw into by passing it to the canvas constructor, so now you just need to draw everything onto it.
Canvas.setBitmap() throws IllegalStateException if and only if Bitmap.isMutable() returns true. Bitmap.createBitmap() builds an immutable Bitmap instance only, in all of its forms. To create a mutable bitmap you either use new Bitmap(), or Bitmap.copy(true), depending on whether you have a source bitmap that you want to start with. A typical block for me looks like:
Bitmap image = ...
Canvas c = new Canvas(image.isMutable()?image:image.copy(true));
...
This assumes, of course, that you don't mind clobbering the source Bitmap (which I generally don't but that's by no means universal).
Related
How can I check if a Bitmap object is completely blank, i.e. all its pixels are transparent, without a x-y loop on every pixel?
You can check your Bitmap instance (in the example myBitmap) against an empty one with:
Bitmap emptyBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), myBitmap.getConfig());
if (myBitmap.sameAs(emptyBitmap)) {
// myBitmap is empty/blank
}
You can do this very easy but it depends on the application.
If you have an application that prompts the user for a drawing input, like signature or anything similar, you will usually have an ArrayList of Paths which are drawn to the Canvas of that View. You can do a check when you want to return the BitMap look to see if the ArrayList of Paths is bigger than 0 and return the BitMap if so, or else return null.
Getting a Bitmap from resources using the code below and then drawing it to canvas gives me no error.
mLetterA = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.lettera), mScaledCardW, mScaledCardH, false);
But if I set the Bitmap in a class called Letter for example, then try get the Bitmap using the getter, say, getLetterGetBMP(), then I always get an error when I try to draw it on canvas. Why is that?
How exactly does image recycling work in Android?
Allow me to elaborate:
If I have the following:
myBitmap = BitmapFactory.decodeResource(curView.getResources(), R.drawable.mypic);
And log the following
Log.v("ImageStuff","Image is: "+myBitmap);
I get the following result:
Image is: android.graphics.Bitmap#(ResourceID here)
Which is great, however if I do the same thing but call a recycle like so
myBitmap = BitmapFactory.decodeResource(curView.getResources(), R.drawable.mypic);
myBitmap.recycle()
I get the same results as above. I thought that calling recycle would clear the bitmap so it would log as null?
Also if I have a method that takes a bitmap like so:
public void doStuff(Bitmap pic){
//Code here
}
Create my bitmap as above and send it through to doStuff:
myBitmap = BitmapFactory.decodeResource(curView.getResources(), R.drawable.mypic);
doStuff(myBitmap);
If I want to recycle the image, would I need to call myBitmap.recycle(); as well as pic.recycle (within my doStuff method after I'd finishing with it).?
Bitmap object contains image data (pixel values allocated under the hood), it is not itself the image data. So, Bitmap object can hang around after recycle(), but will throw error when you try to work with data.
You call recycle() when you, or any other object, is no longer going to use Bitmap in any way. You can also set myBitmap = null to have the object itself garbage collected.
To expand upon User117's comments:
1) A Bitmap is just a container for the image data. When you call recycle, it removes all the image data, but still keeps the container.
2) If you pass the Bitmap into your doStuff method that just pass a reference to the bitmap, there is no need to call recycle twice as the objects are the same. Just call recycle on myBitmap after your call to doStuff if you no longer need it.
I'm having trouble cloning a BitmapDrawable. I tried the answer in this post but it creates a "shallow" copy, and I need a "deep" copy so I can alter the pixels in the clone without affecting the original.
I also tried this:
Bitmap bitmap = bdOriginal.getBitmap();
BitmapDrawable bdClone = new BitmapDrawable(getResources(), bitmap.copy(bitmap.getConfig(), true));
But it seems to create an immutable clone even though I set the mutable parameter in Bitmap.copy() to "true". That is, color filters don't appear to change the clone. Am I doing it wrong? (EDIT: I used the debugger to confirm bitmap.mIsMutable = true)
To summarize, I need a clone of a BitmapDrawable that can be altered with color filters without affecting the original. Any suggestions?
Thanks in advance...
Create new Bitmap of the same size.
Create canvas for this new Bitmap
Draw your first Bitmap into this canvas.
Example:
Bitmap copy = Bitmap.createBitmap(original.getWidth(), original.getHeight(), original.getConfig());
Canvas copiedCanvas = new Canvas(copy);
copiedCanvas.drawBitmap(original, 0f, 0f, null);
My app can load quite large images. In an effort to be memory-conservative, I'm attempting to use a temporary bitmap to load and another for the final image after transformation:
.....
finalBitmap.recycle();
finalBitmap = null;
Bitmap tempBitmap = BitmapFactory.decodeStream(fin, ...);
finalBitmap = Bitmap.createBitmap(tempBitmap, ....);
imgview.setImageBitmap(finalBitmap);
.....
Now, at this point we're done with tempBitmap, which was only needed to transport the decoded Bitmap to the transformation step in createBitmap. So:
.....
tempBitmap.recycle();
tempBitmap = null;
.....
And... it crashes with a "trying to use a recycled bitmap" error specifically because of the recycling of tempBitmap. tempBitmap wasn't displayed and is only used right there.
What's going wrong here? Should I just use "finalBitmap" throughout and rely on createBitmap to manage it (finalBitmap = Bitmap.createBitmap(finalBitmap , ....))? I fail to see what ongoing dependency on tempBitmap there would be that would cause such a failure.
Edit: Yes, the null assignment seems to result in the appropriate, eventual garbage collection, but I'm mystified as to why recycle() on a temp Bitmap is so problematic in this case. I get the impression that createBitmap() is holding a reference to it but why, and for how long?
Straight from the Android documentation:
Returns an immutable bitmap from the specified subset of the source
bitmap. The new bitmap may be the same object as source, or a copy may
have been made.
It seems that the createBitmap functions have the potential to re-use the bitmap that you provided. If that is the case, then you shouldn't recycle the temporary bitmap since your final bitmap is using it. One thing you can do is
if(tempBitmap != finalBitmap) {
tempBitmap.recycle();
}
That should only recycle the tempBitmap when it isn't the same as the finalBitmap. At least that seems to be what the documentation is implying.