I have a PNG file in my drawable folder.
I need to modify it merging on it a smaller image.
I use this code for create a new Bitmap
Bitmap bigImage = BitmapFactory.decodeResource(getResources(), R.drawable.i10);
Bitmap smallImage = BitmapFactory.decodeResource(getResources(), R.drawable.i11);
Bitmap result = Bitmap.createBitmap(bigImage.getWidth(), bigImage.getHeight(), bigImage.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(bigImage, 0f, 0f, null);
canvas.drawBitmap(smallImage, 10, 10, null);
That I miss is the final part. Assign the new bitmap (bigImage) to "R.drawable.i10"
Resources are static, you cannot change those files once they are shipped in the app (Apk)...
However you can create/manipulate the existing ones & save it as a new file on Storage but that's a different thing & not related with the question!
Related
I'm trying to merge several png files during runtime and displaying the resulting Bitmap. But the performance seems bad (it takes around half a second to display the image). Are there are alternate methods to improve the performance?
All the images are Full Screen PNG images where some images have different transparent areas so the order of merging is important.
I have tried pre-loading the resources by decodeResource but I'm running out of memory after loading at around 40 PNG files into Bitmap files. Even though the PNG file is just 10KB when I decode it into a Bitmap its size is in couple of MB. I have hundreds of PNG files so pre-loading the resources is not possible and crashing the app due to memory exhaustion.
Sample code:
Bitmap background = decodeResource(context.getResources(), R.drawable.background);
Bitmap bmp1 = decodeResource(context.getResources(), R.drawable.png1);
Bitmap bmp2 = decodeResource(context.getResources(), R.drawable.png2);
Bitmap bmp3 = decodeResource(context.getResources(), R.drawable.png3);
Bitmap bmp4 = decodeResource(context.getResources(), R.drawable.png4);
Bitmap bmp5 = decodeResource(context.getResources(), R.drawable.png5);
Bitmap bmp6 = decodeResource(context.getResources(), R.drawable.png6);
Bitmap bmp7 = decodeResource(context.getResources(), R.drawable.png7);
Bitmap bmp8 = decodeResource(context.getResources(), R.drawable.png8);
Bitmap bmp9 = decodeResource(context.getResources(), R.drawable.png9);
Bitmap bmp10 = decodeResource(context.getResources(), R.drawable.png10);
Bitmap bmp11 = decodeResource(context.getResources(), R.drawable.png11);
Bitmap bmp12 = decodeResource(context.getResources(), R.drawable.png12);
Bitmap bmOverlay = Bitmap.createBitmap(background.getWidth(), background.getHeight(), background.getConfig());
canvas = new Canvas(bmOverlay);
canvas.drawBitmap(background, new Matrix(), null);
canvas.drawBitmap(bmp1, 0, 0, null);
canvas.drawBitmap(bmp2, 0, 0, null);
canvas.drawBitmap(bmp3, 0, 0, null);
canvas.drawBitmap(bmp4, 0, 0, null);
canvas.drawBitmap(bmp5, 0, 0, null);
canvas.drawBitmap(bmp6, 0, 0, null);
canvas.drawBitmap(bmp7, 0, 0, null);
canvas.drawBitmap(bmp8, 0, 0, null);
canvas.drawBitmap(bmp9, 0, 0, null);
canvas.drawBitmap(bmp10, 0, 0, null);
canvas.drawBitmap(bmp11, 0, 0, null);
canvas.drawBitmap(bmp12, 0, 0, null);
Drawable drawable =new BitmapDrawable(context.getResources(),bmOverlay);
ImageView image.setImageDrawable(drawable);
Any other clever techniques that I can use to solve this problem?
First things first, pngs and jpegs are compressed format of image and hence they are smaller in size but bitmaps, as name suggests, are mapping of each bit of the image and its size depends on the actual resolution of the image and hence a 10kb jpeg can turn into 10mb bitmap.
Now the solution part,
As you mentioned that your pngs have transparency and order of merging is important, you can make a method something like
public static Bitmap mergePng(Bitmap baseBitmap, Bitmap newBitmap){
Bitmap targetBitmap; //use target bitmap to store the result of merging
//your login to merge the newBitmap on top of base bitmap
newBitmap.recycle;
baseBitmap.recycle;
return targetBitmap;
}
if you dont want this method to be used from multiple classes, then make the target bitmap as global in your class and make the method as private void, this will save more memory.
And then call this method in a loop passing two Bitmaps at a time. This approach will help you to merge the Bitmaps in your desired order that too by having at most 3 instance of active Bitmaps at a time.
Do not create so many bitmaps at once from resource. On!y one. Then draw it. And recycle. Then take the next from resource, draw and recycle.
You should of course make a loop for it.
The file size of your png does not say all. Its the resolution of the image which determines the amount of memory needed for the bitmap.
I'm trying to merge up to around 200 images. I'm using the following code but on attempting to merge the 3rd image, the first 2 go away and all that I'm shown is only the 3rd image. In reality, when I'm merging the 50th image, I'm really only dealing w/ 2 images: the one that has 49 images merged and the new image to merge. Here is an excert from my hello world project:
InputStream inputStream = getAssets().open(filename);
Bitmap newBitmap = BitmapFactory.decodeStream(inputStream);
Drawable drawable = imageButtonFrameView.getDrawable();
boolean isBitmapDrawable = (drawable instanceof BitmapDrawable);
if (isBitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap existingBitmap = bitmapDrawable.getBitmap();
Paint paint = new Paint();
paint.setAlpha(95);
Bitmap bmOverlay = Bitmap.createBitmap(existingBitmap.getWidth(), existingBitmap.getHeight(), existingBitmap.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(existingBitmap, new Matrix(), paint);
canvas.drawBitmap(newBitmap, 0,0,paint);
newBitmap = bmOverlay;
}
imageButtonFrameView.setImageBitmap(newBitmap);
Im writing a widget and I need to download and set a bitmap on the layout. Everything I've tried doesn't seem to work.
I've created a test bitmap now to set on the view, [update] this works.
Bitmap.Config config = Bitmap.Config.ARGB_8888;
Bitmap bitmap = Bitmap.createBitmap(imageActiveWidth, imageHeight, config);
Canvas canvas = new Canvas(bitmap); // Load the Bitmap to the Canvas
Paint paint = new Paint();
paint.setColor(0xFFFFCCFF);
canvas.drawRect(0, 0, imageActiveWidth, imageHeight, paint);
views.setImageViewBitmap(resId, bitmap);
using a resource file does work:
Bitmap placeholderBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.placeholder_medium);
views.setImageViewBitmap(imageSlotId, placeholderBitmap);
However using a downloaded bitmap does not seem work.
(after async task has downloaded bitmap, I have a method setBitmap which is one line:
views.setImageViewBitmap(resId, proxy);
Result - screen is just white, no bitmap
I'm really stumped on how to get this to work, because I need to be able to download bitmaps and set them.
Found a solution. I think its related to this bug:
http://code.google.com/p/android/issues/detail?id=8489
Solved by changing by setBitmap method to the following:
private void setBitmap(RemoteViews views, int resId, Bitmap bitmap){
Bitmap proxy = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(proxy);
c.drawBitmap(bitmap, new Matrix(), null);
views.setImageViewBitmap(resId, proxy);
}
And I needed to call:
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, views);
AFTER the bitmaps had been set.
For some reason this wasn't working when I came back to it. My view was an AdapterViewFlipper, so i used the above method with a call to widgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.content); which caused the bitmaps to render.
In android, I'm trying to create a bitmap from a jpeg that I downloaded and copied to a drawable folder under res.
attached is my code:
public void draw(Canvas g, Resources res, int x, int y, int w, int h) {
Bitmap im = BitmapFactory.decodeResource(res, R.drawable.green_dragon);
Bitmap im = BitmapFactory.decodeFile(R.drawable.green_dragon);
g.drawBitmap(im, null, new Rect(x*w, y*h, (x*w)+w, (y*h)+h), new Paint());
}
Android does not recognize the R.drawable.green_dragon in either the decodeResource or decodeFile lines. I have also tried both refreshing and cleaning the application. Neither helped. When I looked up the image properties the type is File and the path is .jpg.
Thanks in advance for your assistance.
Only resources that are packaged with the application can be referenced using the R object.
Anything you download must either be saved to a database or a file. I'm assuming you've already downloaded and saved the file. At which point you either need the a String that has the Path of the jpg or a FileDescriptor for the jpg.
Once you have either you can load the bitmap using:
Bitmap bmp = BitmapFactory.decodeFile( PathToFileString );
or
Bitmap bmp = BitmapFactory.decodeFileDescriptor( fileDescriptorObject );
Maybe the srcRect for drawBitmap should not be null but this:
Rect srcRect = new Rect(0, 0, im.getWidth(), im.getHeight());
My problem is this:
I need to create a re-scaled bitmap created using a NinePatch.
My current system creates a Bitmap from a NinePatch file. This then gets fed into a NinePatch (or NinePatchDrawable). I then need to resize it and output to another Bitmap.
I have reviewed this and it helped quite a bit.
Here is my current code:
try {
Bitmap bitmap1 = BitmapFactory.decodeStream(getAssets().open("gfx/head.9.png"));
// Using NinePatch?
NinePatch patch = new NinePatch(bitmap1, bitmap1.getNinePatchChunk(), null);
// Or NinePatchDrawable?
NinePatchDrawable patch = new NinePatchDrawable(bitmap1, bitmap1.getNinePatchChunk(), new Rect(), null);
// Set dimensions from NinePatch and create new bitmap
// Bitmap bitmap2 = ?
}
catch (IOException e) {
e.printStackTrace();
}
public static Bitmap get_ninepatch(int id,int x, int y, Context context){
// id is a resource id for a valid ninepatch
Bitmap bitmap = BitmapFactory.decodeResource(
context.getResources(), id);
byte[] chunk = bitmap.getNinePatchChunk();
NinePatchDrawable np_drawable = new NinePatchDrawable(bitmap,
chunk, new Rect(), null);
np_drawable.setBounds(0, 0,x, y);
Bitmap output_bitmap = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output_bitmap);
np_drawable.draw(canvas);
return output_bitmap;
}
X and Y are how big you want the ninepatch to be, context is your application context so you can get your ninepatch resource located at id
Please Note if you intend to use this bitmap in OpenGL X and Y must be powers of 2
Are you asking how to draw the NinePatchDrawable? If so, create a Canvas pointing to the Bitmap you want to draw in to, and render the NinePatchDrawable into the Canvas with Drawable.draw(). Be sure to use Drawable.setBounds to set the size you want.
Tasomaniac - To get my x and y for that method I am using the window or size of layout or what ever is needed for the nine-patch. If your window or layout is re-sizable just plug in x and y with the width and height maybe with:
(eg popwindow)object.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()... and then every time something changes with that particular object or layout, just get the x and y into integers.