How to blit() in android?
Asked Answered
I

2

14

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?

Infallible answered 11/4, 2010 at 19:17 Comment(0)
N
18

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.

Naranjo answered 21/4, 2010 at 13:41 Comment(6)
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.Ungraceful
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.Naranjo
so, if I get the Canvas from a SurfaceHolder using lockCanvas, I have no way to access that bitmap for reading?Ungraceful
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.Ungraceful
@SteveHaley in my drawing function, I am drawing on 4 different bitmaps, which I intend to use like layers. And they are very less updated. Another reason is that I wanted to speed up things by drawing one bitmap instead of hundreds of smaller ones. Problem is: while drawing these stored bitmaps on a (surface, runnable) canvas, the screen is flashing and affecting everything else that I draw on the canvas. I don't want to start another question. Could we start a discussion on this instead?Oncoming
@SteveHaley I just remembered the reason for this, was extreme lag on my part. Since I had accidently removed the line where the canvas draws a background colour, so it resulted in heavy GPU OVER-DRAWING. So problem solved nowOncoming
D
-1

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.

Donner answered 21/4, 2010 at 13:27 Comment(2)
yes but what if I want to draw a bitmap into another bitmap, and post the second one in the canvas?Ungraceful
Why not draw them both onto canvas? The canvas isn't update until the invalidate is called.Donner

© 2022 - 2024 — McMap. All rights reserved.