Maps: merging multiple different-size drawables - android

I have a problem. I need to merge two different sized pictures (drawables). The idea is to have a picture of someone (loaded dynamically) that is 100x100px and have a transparent background that is bigger (e.g. 100x120). In those last 20 pixels I have an arrow that is supposed to point to a person's location on a map. Then I think I could do something like this:
Drawable[] layers = new Drawable[2];
layers[0] = res.getDrawable(R.drawable.background_img);
layers[1] = res.getDrawable(R.drawable.icon);
LayerDrawable layerDrawable = new LayerDrawable(layers);
But this simply overlays one image onto another ignoring their bounds.
Thanks in advance,
Vaidas
-- UPDATE: Finally solved the problem. Works like a charm :)
private Drawable createPersonDrawable(Bitmap personImage)
{
Bitmap resultingBitmap = Bitmap.createBitmap(drawableWidth,
drawableHeight, Bitmap.Config.ARGB_8888);
Canvas comboCanvas = new Canvas(resultingBitmap);
comboCanvas.drawBitmap(personImage, 0, 0, null);
// Get the bottom part of the image from resources
Bitmap bottomPart = BitmapFactory.decodeResource(getResources(),
R.drawable.person_map_icon_bottom);
comboCanvas.drawBitmap(bottomPart, 0, drawablePersonImageHeight, null);
comboCanvas.save();
return new BitmapDrawable(resultingBitmap);
}
I found the description here: http://www.jondev.net/articles/Combining_2_Images_in_Android_using_Canvas

I don't have the exact commands here but you should do:
Create a Bitmap with the total size you want.
Create a Canvas passing the created Bitmap
Draw the two images on the Canvas.
Add the Bitmap to the view you are using.

if you want to change Drawable size and position at LayerDrawable, you can use setLayerSize to change drawable size ,and you can use setLayerInset to control position.

Related

SeekBar: getting empty bitmap from Drawable until set it to ImageView OR how to get resulting Bitmap from 9patch

So I want to set a Bitmap created from drawable into a SeekBar's progress. And I make it so:
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Drawable drawable = getResources().getDrawable(R.drawable.seekbar_bg_full);
Canvas canvas = new Canvas(bmp);
drawable.setBounds(0, 0, width, height);
drawable.draw(canvas); // I assume here drawable must be drawn but its not
// canvas.drawBitmap(bmp, 0 , 0, null); // does nothing as 4 me
// encode/decode to detach bitmap from 9patch
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmp.compress(CompressFormat.PNG, 0, baos);
final byte[] bytes = baos.toByteArray();
bmp.recycle();
bmp = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
// ClipDrawable is intented to be used as progressDrawable in SeekBar
ClipDrawable progressDrawable = new ClipDrawable(new BitmapDrawable(getResources(),bmp), Gravity.LEFT, ClipDrawable.HORIZONTAL);
// if not set this drawable to an ImageView then no progress will be shown by SeekBar at all
//ImageView imgFake = (ImageView) findViewById(R.id.fakeImageView);
//imgFake.setImageDrawable(progressDrawable);
mySeekBar.setProgressDrawable(progressDrawable);
width and height are valid values here (like 460 and 30). As you can see there are 2 code lines about ImageView are commented. This ImageView persists on a layout and its visibility is INVISIBLE. If I comment those 2 lines like shown then there will be no visible progress, like drawable is empty or transparent. Looks like this ImageView makes drawable to really draw itself. But I don't like to use a fake ImageView just to make the "magic" happen so the question is - how to make it work without this fake ImageView.
Please don't suggest me ways how to properly set SeekBar progress like:
ClipDrawable progressDrawable = new ClipDrawable(getResources().getDrawable(R.drawable.seekbar_bg_full), Gravity.LEFT, ClipDrawable.HORIZONTAL);
mySeekBar.setProgressDrawable(progressDrawable);
or xml selectors ways or any altrnative ways since I know about it already and my quiestion is not really about it. I just need to make it work my way.
I just need to make my bitmap or canvas or whatever really drawn.
A bit more details if you want (optional to read). The problem is about the drawable seekbar_bg_full - its a 9-patch png. And all need is to obtain a not NinePatchDrawable-linked resulting Bitmap. Assume I have a 460x30px view with 9patch image set as src or background and the 9patch image is stretched just like it should to. So I need to get a Bitmap this view contains and this Bitmap should not be linked somehow to a 9patch. Thats why I encode bitmap to an byte-array and then decode it back - its just to get rid of 9patch. If there is a more esay way to get a resulting bitmap from 9patch (some magic around NinePatchDrawable) - I would like to know about it.
Ok, I figured out how to get rid of fake ImageView and make drawable to draw itself: all I have to do is to call setBounds() method on a drawable:
ClipDrawable progressDrawable = new ClipDrawable(new BitmapDrawable(getResources(),bmp), Gravity.LEFT, ClipDrawable.HORIZONTAL);
progressDrawable.setBounds(0, 0, width, height);
mySeekBar.setProgressDrawable(progressDrawable);
Now I don't have to use ImageView, at last!
However my code is a really long story to get rid of 9patch features in drawable.

Set Picture into RemoteViews

I have some SVGs in my assets folder and I need to dynamically set them in my widget (on an ImageView).
I am using this library: http://code.google.com/p/svg-android/
This library returns a Picture or a PictureDrawable.
The only methods I can see to use on RemoteViews are setImageViewBitmap which obviously takes a bitmap.
I tried looking for code to convert a Drawable to a Bitmap like this:
PictureDrawable pictureDrawable = svg.createPictureDrawable();
Bitmap bitmap = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(), pictureDrawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawPicture(pictureDrawable.getPicture());
currentBitmap = bitmap;
But the bitmap is too small. When I create the bitmap in Illustrator I set the artboard size to 65 which is what comes through on the intrinsic width/height.
My widgets can be resized so the ImageView sizes are variable. Even if I set the width and height statically to some large number like this...
Bitmap bitmap = Bitmap.createBitmap(300, 300, Config.ARGB_8888);
then the resulting bitmap just has a bunch of whitespace below and to the right of a tiny image.
I guess I need to somehow draw the picture at a scaled up value as well as creating the Bitmap at size 300. Ideally I could figure out the size of the ImageView at runtime and set the proper sized Bitmap if I knew that. Is this the best approach and how would I do this? Perhaps there is a better approach I don't even know about?
I've not used android-svg but if it's using vanilla PictureDrawables, then it should be just a matter of not using the intrinsic bounds.
Try the following:
PictureDrawable pictureDrawable = svg.createPictureDrawable();
Bitmap bitmap = Bitmap.createBitmap(300, 300, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
pictureDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
pictureDrawable.draw(canvas); // do not access the Picture directly, that defeats the purpose
currentBitmap = bitmap;
In short, use the Drawable, not its Picture and set the Drawable's bounds to be the full canvas.
Have you tried createScaledBitmap?
createScaledBitmap()
I have tried svg-android and it has not worked for me for this very reason. Not to mention its severely limited feature set.
The point of using vector graphics is that I can generate images of any appropriate size to fit the UI View size. Which means the generation method must accept the size requirements at run-time, and not always use width,height declared in <svg> tag.
Hence I used the native implementation: libsvg-android, which exactly does that.
It directly renders to a canvas with given size:
long objId = SvgRaster.svgAndroidCreate();
SvgRaster.svgAndroidParseBuffer(objId, readString(mInputStream, "UTF-8"));
SvgRaster.svgAndroidSetAntialiasing(objId, true);
SvgRaster.svgAndroidRenderToArea(objId, mCanvas, 0, 0, mWidth, mHeight);
I ended up modifying the underlying Artboard size to be 300. None of the scaling up methods worked. So the final code I used was that which I originally posted:
PictureDrawable pictureDrawable = svg.createPictureDrawable();
Bitmap bitmap = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(), pictureDrawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawPicture(pictureDrawable.getPicture());
currentBitmap = bitmap;
Once I had a 300x300 Bitmap I was able to set it into the RemoteViews using setImageViewBitmap .
This kind of defeated the purpose of using SVGs in the first place (at least as far as using them in widgets was concerned).
My problem was not the same as User117. Perhaps he did not name the outer layer 'bounds' as was required in the library. Either way, I managed to get the library working, albeit by having to modify the SVG Artboard size.
Hopefully with the increase in screen resolution Android will introduce SVGs as part of the platform soon.

Android: BitmapDrawable.Draw(Canvas) Doesn't seem to work

I am trying to tile a 20x20 background onto my Custom View but for some reason I am unable too.
BitmapDrawable background;
background = new BitmapDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.back));
background.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
background.draw(canvas);
Does anyone have an idea why it isn't working?
You can use BitmapDrawable, but you have to set the bounds first so it knows how much tiling to do:
BitmapDrawable background;
background = new BitmapDrawable(BitmapFactory.decodeResource(getResources(),R.drawable.back));
//in this case, you want to tile the entire view
background.setBounds(0, 0, myView.getWidth(), myView.getHeight());
background.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
background.draw(canvas);
You are probably getting warnings in your log regarding SKImageDecoder failing. If you are creating the resource via xml you need to retreive it via (BitmapDrawable) getResources().getdrawable(id)
You have it backwards. Instead of passing your View's canvas to the bitmap's draw method, draw your Bitmap to the View's canvas using Canvas.drawBitmap

Android: how to simply draw a bitmap on another bitmap

I'm new to Android dev and I'm having a hard time trying to do something which seems obvious to me: drawing little images on top of a bigger image.
Let's say that I have a 500x500 image and I want to draw icons at different locations. Icons are png files that I load with:
Bitmap img =
BitmapFactory.decodeResource(getResources(),
R.drawable.idIcon1)
My "background image" is a LayerDrawable.
Then, I am totally lost... Do I have to create a canvas ? How to draw on my "background image" my icons at different positions?
int positionLeft=0;
int positionTop=0;
Bitmap newBitmap =Bitmap.createBitmap(backgroundBitmap.getWidth(),bitmap.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(backgroundBitmap, positionLeft, positionTop,null);
positionLeft=100;
positionTop=100;
canvas.drawBitmap(iconBitmap,positionLeft,positionTop,null);
imageView.setImageBitmap(newBitmap);
You're making simple things difficult. Just use a layout with android:background attribute, and then add ImageViews dynamically with the necessary bitmaps inside.

multiple images in a one single image

I want to create a bitmap / image which has many images like "Collage" which has more then one images in a single picture.
I have stored all my images in a grid view but now i want to create a single image from all those images. And even i want to make few images click able
so what can be the road map to do this ? any sort of help / example will be helpful.
reference image
Bitmap pic1 = BitmapFactory.decodeResource(getResources(), R.drawable.pic1);
Bitmap pic2 = BitmapFactory.decodeResource(getResources(), R.drawable.pic2);
Bitmap bg= BitmapFactory.decodeResource(getResources(), R.drawable.background);
Bitmap out1 = Bitmap.createBitmap(bg) ;
Canvas comboImage = new Canvas(out1);
comboImage.drawBitmap(pic1, 10f, 20f, null);
comboImage.drawBitmap(pic2, 30f, 40f, null);
out1 will have pic1 & pic2, with a background image bg.
To create a single image from multiple images look at using Canvas. You can put bitmaps (and drawables) on a canvas. You can commit the changes and then push then to a single bitmap that you can then use. As far as making certain sections clickable after making it one single image, I will leave this up to someone else to explain, I am not worked directly with the ontouch() functions.

Categories

Resources