views:

885

answers:

2

I'm used to handle graphics with old-school libraries (allegro, GD, pygame), where if I want to copy a part of a bitmap into another... I just use blit.

I'm trying to figure out how to do that in android, and I got very confused. So... we have these Canvas that are write-only, and Bitmaps that are read-only? It seems too stupid to be real, there must be something I'm missing, but I really can't figure it out.

edit: to be more precise... if bitmaps are read only, and canvas are write only, I can't blit A into B, and then B into C?

A: 

In android you draw to the canvas, and when you want it to update you call invalidate which will the redraw this canvas to the screen. So I'm guessing you have overridden the onDraw method of your view so just add invalidate();

@Override
public void onDraw(Canvas canvas) {
    // Draw a bitmap to the canvas at 0,0
    canvas.drawBitmap(mBitmap, 0, 0, null);
    // Add in your drawing functions here
    super.onDraw(canvas);
    // Call invalidate to draw to screen
    invalidate();
}

The above code simply redraws the bitmap constantly, of course you want to add in extra thing to draw and consider using a timing function that calls invalidate so that it is not constantly running. I'd advice having a look at the lunarlander sources.

stealthcopter
yes but what if I want to draw a bitmap into another bitmap, and post the second one in the canvas?
Lo'oris
Why not draw them both onto canvas? The canvas isn't update until the invalidate is called.
stealthcopter
+1  A: 

The code to copy one bitmap into another is like this:

Rect src = new Rect(0, 0, 50, 50); 
Rect dst = new Rect(50, 50, 200, 200);  
canvas.drawBitmap(originalBitmap, src, dst, null);

That specifies that you want to copy the top left corner (50x50) of a bitmap, and then stretch that into a 150x150 Bitmap and write it 50px offset from the top left corner of your canvas.

You can trigger drawing via invalidate() but I recommend using a SurfaceView if you're doing animation. The problem with invalidate is that it only draws once the thread goes idle, so you can't use it in a loop - it would only draw the last frame. Here are some links to other questions I've answered about graphics, they might be of use to explain what I mean.


In response to the comments, here is more information: If you get the Canvas from a SurfaceHolder.lockCanvas() then I don't think you can copy the residual data that was in it into a Bitmap. But that's not what that control is for - you only use than when you've sorted everything out and you're ready to draw.

What you want to do is create a canvas that draws into a bitmap using

Canvas canvas = new Canvas(yourBitmap)

You can then do whatever transformations and drawing ops you want. yourBitmap will contain all the newest information. Then you use the surface holder like so:

Canvas someOtherCanvas = surfaceHolder.lockCanvas()
someOtherCanvas.drawBitmap(yourBitmap, ....)

That way you've always got yourBitmap which has whatever information in it you're trying to preserve.

Steve H
I'm sorry, I still don't get one thing: you are drawing into a canvas, not into a bitmap. Since canvas are, as far as I understand, read-only, you can't then draw the destination to a NEW one.
Lo'oris
Yes, you don't draw directly into Bitmaps, but through the intermediary of a Canvas. Use something like this: `Bitmap someBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);` to create a bitmap with specified dimensions and color space, then `Canvas canvas = new Canvas(someBitmap);` to make drawing commands to that canvas modify the bitmap.
Steve H
so, if I get the Canvas from a SurfaceHolder using lockCanvas, I have no way to access that bitmap for reading?
Lo'oris
I've edited my answer to try to help this confusion.
Steve H
ooh, thanks man!
Lo'oris
Mmmmh. While this approach works, it is very slow on slow devices. My emulator dropped from ~25fps to barely 14. My Nx1 instead had apparently almost no problem and is still running at 55-60fps.
Lo'oris