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.
Related
I'm trying to add one bitmap (png file) on top of another and then save it to the device. Everything works fine except for the first part.
Bits of my code:
1 converting loaded file to bitmap
loadedBitmap = e.target.content as Bitmap;
clonedBitmap = new Bitmap(loadedBitmap.bitmapData.clone());
bitmapData = new BitmapData(e.target.content.width, e.target.content.height);
bitmapData.draw(clonedBitmap);
2 second Bitmap generated within the app
genBitmapData = new BitmapData(bgWidth, bgHeight, false);
genBitmap = new Bitmap(genBitmapData);
3 adding clonedBitmap (external file) to the bitmapdata
var positionMatrix : Matrix = new Matrix(1,0,0,1,0,0);
genBitmapData.draw(clonedBitmap, positionMatrix);
The problem with the step three is that the loaded file clonedBitmap end up being under the bitmap generated by the app upon saving it to the device's storage. When I reverse the order:
bitmapData.draw(genBitmap, positionMatrix);
Only the generated bitmap is displayed/visible while the loaded bitmap isn't visible at all upon saving the file. What I'd like to achieve is to have clonedBitmap (external png file) to be on top of the genBitmap and saved withing a BitmapData object, so I could be able to save it to my device.
I'd be grateful for any tips.
When you draw a bitmap over a bitmap, you need the bitmap being overlayed to be transparent somewhere, otherwise all the lower bitmap's pixels would be overwritten with the upper layer. Therefore, create those bitmaps with alpha channel (transparency=true), make sure the upper layer bitmap is also transparent after you draw a something on it (at least somewhere), then draw first lower layer then upper layer on a single BitmapData object.
Note that since you don't transform any bitmaps, you'd better use BitmapData.copyPixels() method.
It turns out the code works fine. I just overlooked and placed it in the wrong function, which caused the issue.
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.
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.
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).
I am able to draw a signature on my canvas. Now after that I want to save this signature as an image which can be used later.
I am unable to implement an onClicklistener on this canvas. Also I am unclear as to how this signature can be stored as an image. Please suggest?
Try this:
Bitmap bmp = Bitmap.createBitmap(...);
Canvas can = new Canvas(bmp);
When you change your canvas, bitmap bmp will change too. Canvas is only raference to Bitmap canvas, and you have no need to save canvas. Save only Bitmap (bmp).
To save the canvas drawing as an image, you need to convert it to a data url using the toDataURL method. Once you have the data url, you can use it to set the source of an image element so the user can right click and download the image.:
// save canvas image as data url (png format by default)
var dataURL = canvas.toDataURL();
// set canvasImg image src to dataURL
// so it can be saved as an image
document.getElementById("canvasImg").src = dataURL;
Reference: http://www.html5canvastutorials.com/advanced/html5-canvas-save-drawing-as-an-image/