I pass the image from drawable reference like follows
Bitmap bitmap = mImageGenerator.generateDateImage(calendar,
R.drawable.data);
it throws
java.lang.IllegalStateException: Immutable bitmap passed to Canvas
constructor
I use same exact statement in other activity and it works fine.
Problem :
mImageGenerator.generateDateImage is locked class from caldroid
(https://github.com/roomorama/Caldroid)
so cant change anything in it.
I just noticed that this occurs on NOUGAT
How do I solve this issue?
So the solution is to add
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inMutable = true;<<<<<<
in custom created class ownImageGenerator
Related
Can anybody point me at resources with best practice on clearing sensitive runtime images?
Consider a scenario where a sensitive image is downloaded from a server at runtime, loaded into a Bitmap object, and is then displayed in an ImageView in a Fragment.
When the user leaves that screen, or the app is exited/put in the background for a long time, then I want to clear that image data so that it isn't easy to recover.
I was wondering if there is a reliable way to zero out the bitmap data as soon as the Fragment containing the image is destroyed?
This feel tricky to me, as Bitmaps are usually returned as immutable objects, e.g. BitmapFactory.decodeByteArray says:
Decode an immutable bitmap from the specified byte array.
Presumably I would have to create a mutable Bitmap and then copy over its data?
It looks like recycle() won't help me, as that will just mark the data as available for garbage collection, it won't wipe it.
You can simply clear the Bitmap using
someBitmap.eraseColor(android.graphics.Color.TRANSPARENT);
It will fill the bitmap with TRANSPARENT color and erase everything on it.
However, if you have no any references to your bitmap (e.g. you've set null to ImageView that was containing your Bitmap like this
someImageView.setDrawable(null)
the garbage collector should collect it shortly.
Thanks to #IlyaGulya for the eraseColor suggestion. Below is the code I've written so far.
Creating the mutable Bitmap:
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inMutable = true;
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, bitmapOptions);
The code to clear the image data in my Fragment (I save the BitmapDrawable into a myBitmapDrawable field when the Fragment receives it):
#Override
public void onDestroy() {
myImageView.setImageDrawable(null);
try {
MyUtils.zeroOutBitmapData(myBitmapDrawable.getBitmap());
} catch (Exception e) {
loggingUtil.logHandledException(e);
}
super.onDestroy();
}
My utility for zeroing out a Bitmap:
public static void zeroOutBitmapData(Bitmap mutableBitmap) {
if (mutableBitmap.isMutable()) {
mutableBitmap.eraseColor(android.graphics.Color.TRANSPARENT);
} else {
logger.error("Expected bitmap to be mutable");
}
}
...and here is a unit test (well, an ApplicationTestCase since I want to test with a real Bitmap):
public void testZeroOutBitmap() throws Exception {
Resources resources = getContext().getResources();
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inMutable = true;
Bitmap mutableBitmap = BitmapFactory.decodeResource(resources, R.drawable.an_example_image);
// Assert that some pixels start out with non zero colors
assertEquals(-789517, mutableBitmap.getPixel(0, 0));
assertEquals(-723724, mutableBitmap.getPixel(10, 10));
MyUtils.zeroOutBitmapData(mutableBitmap);
// Check that pixel data has now been cleared out
assertEquals(android.graphics.Color.TRANSPARENT, mutableBitmap.getPixel(0, 0));
assertEquals(android.graphics.Color.TRANSPARENT, mutableBitmap.getPixel(10, 10));
}
I tried to do this:
Path pathForSpriteSheet = Paths.get("/PicFolder/TheSpriteSheet.png");
Then I put it in this method like this:
loadImage(pathForSpriteSheet);
public void loadImage(BufferedImage image){
theImage = image;
}
It says "The method loadImage(BufferedImage) in the type BufferedImageLoader is not applicable for the arguments"
To further what Tom said, you cannot pass a Path variable to the method loadImage when it requires a BufferedImage. What you need to do is create a BufferedImage based off of the path you already have and send that to the method. Something like:
BufferedImage img = ImageIO.read(pathForSpriteSheet.toFile());
loadImage(img);
I'm new to AndEngine and programming in general. I'm using ADT.
I have refactored some code into my Resource Manager, so it will load an animated sprite for me.
The image file is in the correct asset folder, and animated fine before I moved the code into the ResourceManager.java file.
Inside my onCreateResources (in GameActivity.java), I have this:
ResourceManager.getInstance().loadSpriteSheetTextures(mEngine, this);
pOnCreateResourcesCallback.onCreateResourcesFinished();
In the onCreateScene method of my GameActivity.java file, I have this:
animatedSprite = new AnimatedSprite(positionX,positionY,mTiledTextureRegion,mEngine.getVertexBufferObjectManager());
animatedSprite.animate(25);
mScene.attachChild(animatedSprite);
In my ResourceManager.java, I have this method:
public synchronized void loadSpriteSheetTextures(Engine engine, Context context){
//set our gfx asset folder
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
//create a animated sprite
BuildableBitmapTextureAtlas mBitmapTextureAtlas = new BuildableBitmapTextureAtlas(engine.getTextureManager(),512,512,TextureOptions.BILINEAR);
mTiledTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mBitmapTextureAtlas, context, "plus.png", 6, 4);
try{
//
mBitmapTextureAtlas.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource,BitmapTextureAtlas>(0,0,0));
mBitmapTextureAtlas.load();
}catch(TextureAtlasBuilderException e){Debug.e(e);}
}
I should get a spinning top, but I get the spritesheet printed to screen, with the top right borders cut off, no animation..
In LogCat, I get an error about Null pointer exception (I guess it's related).
It worked fine until I 'refactored' it into a mess ...
Please help.. What am I doing wrong?
(edited typos)
.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
OutOfMemory Exception when handling images
I have a Bitmap creation within a AsyncTask, which goes like this:
private WeakReference<Bitmap> myBitmap;
private WeakReference<Bitmap> endResultBitmap;
private ImageView imv;
...
private class SendBitmap extends AsyncTask<Integer, Void, Bitmap> {
public SendBitmap(Bitmap bitmap) {
myBitmap = new WeakReference<Bitmap>(bitmap);
}
#Override
protected Bitmap doInBackground(Integer... params) {
Bitmap bm = null;
bm = getBitmapFromNet(params[0]);
return bm;
}
And then I want to create Bitmap on which the received Bitmap would appear twice (one next to another)
protected void onPostExecute(Bitmap result) {
endResultBitmap = new WeakReference<Bitmap>(Bitmap.createBitmap(result.getWidth() * 2, result.getHeight(), result.getConf()));
Canvas canvas = new Canvas(endResultBitmap.get());
canvas.drawBitmap(result, 0, 0, null);
canvas.drawBitmap(result, result.getWidth(), 0, null);
imv.setImageBitmap(endResultBitmap);
}
then I have my onCancelled() method:
#Override
protected void onCancelled(Bitmap result) {
if(endResultBitmap!=null) {
endResultBitmap.recycle();
endResultBitmap = null;
}
}
The thing is that if I execute this AsyncTask couple of times, the heap grows as mad.
I execute the AsyncTask when a button is pressed, but at first I do:
public void onClicked(View v) {
if(asyncTaskInstance != null)
asyncTaskInstance.cancel();
asynctaskInstance.execute(2);
}
But again, the Heap grows as mad and at some point it will crash with OutOfMemoryError.
Any idea? Do I have something wrong in my Design of the task?
Android has some memory limits for apps (16 MB if i remember correctly), and that image is too big in an uncompressed format. Theres some interesting discussion in this question.
To solve it, there are afaik only two ways:
1. Reduce the size of the image to consume less memory
2. Load the image in native code using the NDK.
To 1.: I don't know what exactly you are trying to do and can't tell if thats really a viable option. If it is, you may want download the image file from the net and open it with the BitmapFactory class. There are some static functions that take an BitmapFactory.Options object. Use inSampleSize from this Options object to reduce the image size by a certain factor at loading time (inSampleSize should be a power of two by the way).
To 2.: The memory limits that I mentioned above don't apply to native code. So you may be able to load the image and display in a native way. I don't have any experience with that, I just know that it's possible, but googling around should turn up a few results.
I have a getViewBitmap() method that creates a Bitmap with a 3rd party library (which is proprietary) and goes like this:
public Bitmap getViewBitmap(int index) {
Bitmap retBitmap = null;
int width = 400;
int height = 200;
try {
retBitmap = lib.createBitmap(width, height, index);
} catch(BMException e) {
e.printStacktrace();
}
return retBitmap;
}
This method is used for creating two page view bitmap in another method:
public Bitmap getTwoPageBitmap(int firstPageIndex, intSecondPageIndex) {
Bitmap first = getViewBitmap(firstPageIndex);
Bitmap second = getViewBitmap(secondPageIndex);
Bitmap retBitmap = Bitmap.create(800, 400, first.getConfig());
Canvas helperCanvas = new Canvas(splitViewBm);
helperCanvas.drawBitmap(leftPageBitmap, 0, 0, null);
helperCanvas.drawBitmap(rightPageBitmap, leftPageBitmap.getWidth(), 0, null);
return retBitmap;
}
And then finally in initiated method, I have this:
public View createView() {
MyView v = new MyView();
if(pagePortratit) {
v.setPageView(getViewBitmap(0));
} else {
// if page is landscape
v.setPageView(getTwoPageBitmap(0, 1));
}
return v;
}
Now - I wanna make the getViewBitmap(int) method Asynchronous. Since the "lib.createBitmap(int, int, int)" is pretty slow and it blocks the UI, I want the creation of the bitmap (getViewBitmap(int)) to be in another thread, with possibility to interrupt it's work.
What is the correct design for such design so that the method that is actually heavy goes async?
You likely want to subclass AsyncTask (read here) and put your getBitmapView code in the doInBackground() method (#Override). When it's done, have the onPostExecute() method update the View/UI. The logic for determining landscape or portrait will want to be outside the AsyncTask and you'll just want to farm out to the task (using .execute()) which ever view is needed.
That might be one approach.
I think the best thing that you can do is to use AysncTask which allows u to update the UI Directly without special handling for UI Thread update.