Bitmap from View not displayed on Android - android

I am trying to create a bitmap from a View that is not displayed yet to set it as a texture with OpenGL in android.
The problem is that when I create my bitmap the layout parameters of my View have 0 value cause the onLayout() function has not been called yet.
Is there a way to "simulate" a layout or do a "background layout" to get the right layout params ?
I was thinking about a Frame layout having two views, the background one would be used to create my bitmap as the layout would have been done.
Thanks.

You indeed need to layout your View before drawing it into a Bitmap. Simply call
myView.measure(...);
then
myView.layout(0, 0, myView.getMeasuredWidth(), myView.getMeasuredHeight());
I have posted an example on how to do this in one of the following presentations: http://www.curious-creature.org/2010/12/02/android-graphics-animations-and-tips-tricks/

So, some edits after the question was clarified :)
I suggest you create the bitmap independently of the view, then scale it to the same size as the view once the view is created. Create an arbitrary size bitmap that allows you to render what you want to it ..
// This in some class that renders your bitmap independently, and can be
// queried to get the bitmap ...
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_4444);
// render something to your bitmap here
Then after your view is created, take the precreated bitmap and rescale it to the right size (I've not actually checked this by compiling it -- might be errors):
Rect original = new Rect(0, 0, 100, 100);
RectF destination = new RectF(0.0, 0.0, (float)myView.getWidth(), (float)myView.getHeight());
Canvas canvas = new Canvas();
canvas.drawBitmap(myRenderingClass.b, original, destination, null);
myView.draw(canvas);

Related

create part of bitmap as a new bitmap

i have a problem and i don't know how to solve it. What i'm trying to do is, to create a Bitmap which is a part of another Bitmap.
I tried already this
Bitmap newBitmap = Bitmap.createBitmap(bitmap, (int)x, (int) y, (int)width, (int)height);
The width/height of the new bitmap is alright, but it's empty, every pixel is just transparent.
So i searched and found that i have to use canvas to draw the part again, because the return of createBitmap is a empty once. But i'm not sure since the call up here returns an immutable Bitmap, which Canvas doesn't like. I also not know which constructor i have to use with canvas.
Could someone help me?
Thanks and greetings
That one will create an INMUTABLE bitmap. Please, refer to http://developer.android.com/reference/android/graphics/Bitmap.html and read about that method.
To create a mutable one, use createBitmap(DisplayMetrics display, int width, int height, Bitmap.Config config). Pass in the widht and height of the part u wanna render in and the displayMetrics you get from yourActivity.getResources().getDisplayMetrics().
To render the area you want in the newly created bitmap, yes, use the Canvas. There are lots of methods. You can use this one: http://developer.android.com/reference/android/graphics/Canvas.html#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint)
You pass in a rect with the source area and the destination area.

Draw on a large canvas, scroll it, save it, reload it ... works, but only the viewport part is saved

My program can draw 2D shapes on a canvas. The result can be scrolled. , When I save the result, then ONLY the image in the viewport is saved.
I use a View and draw on it's canvas.
Saving the drawing/updated result is:
setDrawingCacheEnabled(true);
buildDrawingCache();
Bitmap bmp = Bitmap.createBitmap( this.getDrawingCache());
setDrawingCacheEnabled( false);
// the bitmap I can save into a file
bm.compress( Bitmap.CompressFormat.PNG, 90, new FileOutputStream( new File( filepath)));
When I use a large view/canvas, then I get errors that my drawingCache is not big enough. When I use a regualar view/canvas size, then nearly all drawings outside the viewport are clipped.
==> Can I draw on a bitmap and have that bitmap immediately drawn on the view's canvas?
So, after some drawing, the initial bitmap is updated with the newly added drawing?
Happily, there is a simple solution to this question.
Create a large bitmap with your own size;
Create your own cachedCanvas = new Canvas( largeBitmap);
Draw first on the cachedCanvas'.
In onDraw() do: canvas.drawBitmap( cachedBitmap, 0, 0, null);
Saving your own largeBitmap is easy!

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.

How to convert custom view to Bitmap?

I have prepared a custom view. My view contains one alphabet which i have drawn using drawText in onDraw().Now i need to change this view to bitmap.
Here my OnDraw() is,
public void onDraw(Canvas canvas) {
drawText("A",100,200,mPaint);
}
I need to convert this view to bitmap...please help me...thanks in advance .
For those that already have their views set up and want a shorter solution than AutoCoders:
Bitmap result = Bitmap.createBitmap(dst.getWidth(), dst.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(result);
dst.draw(c);
After this the Bitmap 'result' will contain your view.
'dst' is the View you want as a bitmap.
Bitmap viewCapture = null;
theViewYouWantToCapture.setDrawingCacheEnabled(true);
viewCapture = Bitmap.createBitmap(theViewYouWantToCapture.getDrawingCache());
theViewYouWantToCapture.setDrawingCacheEnabled(false);
In Android, the word “bitmap”, is a class that help us to work with images as a map of bits or an array of bits. This Bitmap class is very useful when we are working with graphics interfaces like Canvas or OpenGL.
Canvas, is another known class in Java, and is used to draw things. In Canvas we have control of all the pixels.
We need to have some variables initialized,
This is the Canvas we are going to draw in.
Canvas canvas = null
This is the layout we are going to use to create our view.
RelativeLayout relativeView ;
This is the background we are going to set in our view, we get it from a resource file (R.drawable.blackBgrnd). The BitmapFactory.decodeResource method is used to get a resource image and convert it in a Bitmap (we will use the Bitmap class). The object mContext (context) must be passed from the Activity we are working on.
Bitmap viewBgrnd = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.blackBgrnd);
We need another bitmap, to draw it on the canvas. We set the width and the height of this bitmap relative to the width and height we have created in our layout. Now this Bitmap is empty, but we are going to associate it with the canvas, so every time we draw in the canvas, it will be drawn in this bitmap object.
Bitmap returnedBitmap = Bitmap.createBitmap(relativeView .width, relativeView.height,Bitmap.Config.ARGB_8888);
First of all, we had the canvas = null, now we create a Canvas object using the auxiliary bitmap we had created before.
canvas = new Canvas(auxBitmap);
Now its time to create our view.
We can add Images, for example:
ImageView newImage = new ImageView(mContext);
newImage.setImageBitmap(bitmapWithImage)
We can set the imageView position in the view using “layout” method:
newImage.layout(l,t,r,b);
l Left position, relative to parent
t Top position, relative to parent
r Right position, relative to parent
b Bottom position, relative to parent
and finally adding it to our layout:
relativeView.addView(newImage);
or we can add text:
TextView newText = new TextView(mContext);
newText.setText(“This is the text that its going to appear”);
adding it to the layout in the same way:
relativeView.addView(newText);
Once we have added all elements we want to our layout, we have to create a paint object:
Paint paint = new Paint();
just to define default values of painting.
We use the “drawBitmap” method from the canvas:
canvas.drawBitmap(ViewBgrnd, 0, 0, paint);
and finally we call dispatchDraw in the layout to draw the children views (imageView, textView) in the canvas.
relativeView.dispatchDraw(canvas);
The returnedBitmap is the bitmap that contains the drawing of the views in the canvas, on it, we have the layout and its childrens as a Bitmap, after painting them in the Canvas.
Conclusion
This is really tricky and maybe difficult to understand. It took me time to understand how it worked. I will try to summarize it:
We need to create a empty bitmap. This bitmap will be the final bitmap with the views on it.
We create the canvas using that bitmap.
We create a layout and we add as many elements as we want.
We attach the layout to the canvas.
Because we have created the canvas using a bitmap object, all that is drawn in the canvas, will be drawn in the bitmap.
From: Bright hub

Android: Canvas gives garbage when shifting a Bitmap?

I would like to use Canvas to "shift a bitmap"; to create a Bitmap from a Bitmap, but with a y offset such that all the pixels in the Bitmap are either shifted down (with blank pixels at the top) or shifted up (with blank pixels at the bottom). I am using the below code to do this. The code works fine as long as I am shifting up (shiftY is negative), but it gives a garbage bitmap if I try to shift down.
The second set of code is my work around for this, but this has the very undesirable effect of doubling my memory usage.
Is there any way to shift a Bitmap whitout using a second Bitmap?
//create canvas from the current Bitmap.
Canvas canvas = new Canvas (m_Bitmap);
/*draw into the current Bitmap into the canvas with an offset, thereby drawing over itself
shifted pixels*/
canvas.drawBitmap(m_Bitmap, 0, shiftY, null);
`
//create the canvas from a temp bitmap
Canvas canvas = new Canvas (m_2ndBitmap);
//draw the shifted pixels into the temp bitmap
canvas.drawBitmap(m_BackBuffer, shiftX, shiftY, null);
//swap the bitmaps
Bitmap temp = m_Bitmap;
m_Bitmap = m_2ndBitmap;
m_2ndBitmap = temp;
You can do it yourself if you copy row by row from the bottom. The problem is that your source and destination are the same and it's copying from the top, destroying the rows beneath before you can copy them lower.
When you are referencing a "new" or new Bitmap to an already existing Bitmap, the already existing Bitmap will be available for garbage collection.
However, do not create objects during runtime: just use two Bitmaps that you are allocating up front, when your Canvas has been created and skip creating the new Canvas.
Try:
canvas.drawBitmap(Bitmap.createBitmap(m_BackBuffer), shiftX, shiftY, null);
instead of:
canvas.drawBitmap(m_BackBuffer, shiftX, shiftY, null);

Categories

Resources