Android Draw Bitmap to Canvas - android

I'm trying to draw a Bitmap to a Canvas in a custom SurfaceView, but it doesn't show up anywhere.
In the SurfaceView, I'm using:
//in the constructor
Bitmap leftUp = BitmapFactory.decodeResources(R.drawable.leftup);
leftCurrent = leftUp; //it's a button - leftUp and leftDown
//in my drawing method
canvas.drawBitmap(leftCurrent, controlsWidth, controlsHeight, new Paint());
It runs OK, no errors, but nothing shows up. Anyone have any ideas?

The problem is with you paint object that you pass to the drawBitmap method. It must be configured properly. Take a look at this
answer.

Related

Way to take screenshot of view faster

In my app I show all errors by taking a screenshot, grayscaling it, and adding error text on it. This is how I take screenshot:
private Bitmap getBitmapFromView(View v) {
Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.draw(canvas);
return bitmap;
}
final ViewGroup root = (ViewGroup) getWindow().getDecorView();
Bitmap bitmap = getBitmapFromView(root);
And then convert bitmap to grayscale, add a text and show.
My problem is that getBitmapFromView on some devices (Galaxy S5 unexpected btw) takes 500-700 ms to complete. My question is if there is any faster way to take screenshot of the view, or of entire screen? I have tried View.getDrawingCache(), and it's the same slow. If I'm right, then it works the same way as my getBitmapFromView method.
EDIT:
Ok, I figured out what caused so slow performance using Android Monitor and method profiling in my case. It was the GradientDrawable taking 80% of time to draw. I have optimized it, and it now takes about 150 ms. to take screenshot. But the question stays the same: Is there any faster way to do it? Maybe using NDK?
Your custome view here
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.buildDrawingCache();
}
To get your CacheBitmap just
view.getDrawingCache();
This works for me ,i can get the CacheBitmap immediately
But it's a bad ideal that may cause some performance problems

Modify bitmap after being drawn but before onDraw() finishes

I'm creating a home made game engine for Android and I'm having some problems with the reuse of a Bitmap canvas:
Visible game objects receive the main Canvas in each frame so they can draw themselves with a static bitmap or with a sprite. So far everything works fine.
The sprite consists in two bitmaps. First contains the complete sequence of drawings, and the second is dynamically drawn through a Canvas(bitmap). The result bitmap and its canvas are created in the sprite constructor to avoid reallocations in the draw loop.
I reuse this sprites for each object that needs the same sequence of drawings. This sprites also have a function that allows to obtain a bitmap containing a different position of the drawings sequence. So, if the object wants the sprite in another position calls its function to get the Bitmap and draws to the main canvas.
So the problem is that all objects using the same sprite end up drawing the same image.
In the visible game object:
if(spriteDelay > 0) img = sprite.getDelayedBitmap(spriteDelay);
else img = sprite.getCurrentBitmap();
canvas.drawBitmap(img, null, focusLocation, null);
In the sprite:
currentBmpCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
currentBmpCanvas.drawBitmap(scaledImage, delayedIni, fin, null);
return currentBmp;
If I create a new result bitmap and a new canvas in the returning function all works fine:
currentBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
currentBmpCanvas = new Canvas(currentBmp);
I assume that all bitmaps are not drawn until onDraw() is finished, so is there some way to solve this without reallocating the bitmap in each loop?
Thanks!
After some hours thinking, I opted to implement a simple solution that didn't cross my mind before.
Like the object game receives the main canvas, why not do the same with the sprite?
So basicly this is the code for the game object:
sprite.smashDelayedCanvas(canvas, focusLocation);
And for the sprite:
canvas.drawBitmap(scaledImage, delayedIni, dest, null);

using canvas.drawBitmap() with canvas.translate()

My code here receives a value for bmpX and bmpY and uses them to draw a bitmap at that location on the screen. This works exactly as I want it to, but I would rather use the canvas.translate() function to handle the movement of the image, rather than just canvas.drawBitmap(), because I will be applying other draw elements to the canvas and I want them all to move the same amount and direction.
My question is: where can I move the canvas.drawBitmap() in the code so that it just draws onto the canvas at the start, but it is moved any time after that using canvas.translate() instead? Anywhere I place the code still freezes the image at that point where I draw it, regardless of how much I change the position of canvas.translate(). I'm imaging its possible to "stick" the image to the canvas, so to speak, and then move the canvas, which also moves the image with it.
public void run() {
// TODO Auto-generated method stub
while(isRunning) {
if(!surfaceHolder.getSurface().isValid()) {
continue;
}
canvas = surfaceHolder.lockCanvas();
canvas.drawRGB(255, 255, 255);
canvas.drawBitmap(bmp, bmpX-(bmp.getWidth()/2),
bmpY-(bmp.getHeight()/2), null);
//canvas.translate(bmpX, bmpY);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
I hope I explained my problem clearly enough. Thanks!
Answering my own question here for clarity, afetr info I got offline. UI cannot be done on a thread like this, I needed to be using an android UI thread instead. runOnUIUpdatethread and async tasks

Canvas draw : not able to render animation with runtime generated Bitmap images

Need a little help here : I'm out of ideas now...
Here's what I need to do :
Render "base" image [ it is created from an ARGB.8888 byte array ]
user clicks 2 points on the screen; I need to perform the the pixel manipulation on a region of pixels around the path taken from one point to another... [ I need to calculate a squre block of pixel for each pixel on the whole path ].
display the modification of the image as the code progresses in animation form.
I am able to display the whole path; I am able to calculate & manipulate the pixels properly .. But what I am unable to do is show the animation as my code is progressing on the path... with the current implementation I am able to display the whole calculated path at the end ...
public void onDraw(Canvas canvas){
canvas.drawColor(Color.WHITE);
Paint p = new Paint();
canvas.drawBitmap(base,0,0,p);
traverse clickEvent1.x -> clickEvent2.x
traverse for clickEvent1.Y -> clickEvent2.Y
{
newBitMap = calculateNewBitMap(base)
// I nee to redraw Canvas with (newBitMap)
// canvas.drawBitMap(newBitMap);
//Doesn't work
//postInvalidate();
//invalidate()
//AnimationDrawable.addFrame(newBitMap)
// I am not calling start here
//but just wanted to let you know that I do call animation start to display the frames stored in it
// animation.start();
}
// obviously wouldn't work here As it is already out of the loop
//invalidate();
}
Please NOTE :
The newBitMap image is generated at runtime, it would not be available to me beforehand...
I tried invalidate() in the loop as well ; but it would only draw the cumulative result after the whole loop has traversed and not the intermediate states of the newBitMaps.
Performance is of critical importance + I am dealing with HUGE image sizes .. so please keep that in mind as well ... if I create multiple bitmaps for temporary storing the JVM crashes due to "OutofMemory" ..
I tried storing the new Images in "AnimationDrawable" form as well; but tht's not solving the problem as well....
AnimationDrawable animDrawable = new AnimationDrawable();
Drawable frame1 = new BitmapDrawable(newCaclBitMap);
animDrawable.addFrame(frame1, 250);
Thanks for any pointers / suggestions ..
It seems like what you are doing is running all of your drawing logic in a single call to onDraw() when I think what you want is to have onDraw() called once for each frame of your animation.
So, instead of something like this in your trace:
onDraw()
drawFrame()
drawFrame()
drawFrame()
...
You would have this:
onDraw()
drawFrame()
onDraw()
drawFrame()
onDraw()
drawFrame()
...
The CubeLiveWallpaper example has an example of this type of thing.
Animation objects are used to animate View objects. What you want to do is animate a canvas. This is more complicated but potentially more powerful. Essentially you need to derive an equation that will govern the movement of you drawing as a function of time. When the animation starts you get the current time stamp and then in you onDraw method you draw what the canvas should look like at that point in time. Basically you have to draw every step.

Android 2.1 View's getDrawingCache() method always returns null

I'm working with Android 2.1 and have the following problem:
Using the method View.getDrawingCache() always returns null. getDrawingCache() should return a Bitmap, which is the presentation of View's content.
Example code:
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final View view = findViewById(R.id.ImageView01);
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
final Bitmap bmp = view.getDrawingCache();
System.out.println(bmp);
}
I've already tried different ways to configure the View object for generating the drawing cache (e.g. View.setWillNotDraw(boolean) and View.setWillNotCacheDrawing(boolean)), but nothing works.
What is the right way, or what I'm doing wrong?
PS: In real code I want to apply getDrawingCache() on a ViewGroup like RelativeLayout. Is the behaviour the same when using a ViewGroup?
Bitmap screenshot;
view.setDrawingCacheEnabled(true);
screenshot = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
You need Bitmap.createBitmap(view.getDrawingCache()); as the Bitmap from which the reference is received by getDrawingCache() gets recycled.
use
onLayout(x, y, width, height);
for ex:
onLayout(0, 0, 100, 100);
before calling getDrawingCache
Never do these things in onCreate!
You can do it in a View.onClickListener or other place.
I know this doesn't answer your question, but....
Just as an aside for other developers reading this, if what you are really trying to do is have access to a custom view's contents, derive your custom view from an ImageView. And then create a canvas and bitmap that you are going to control/draw into/read and use setImageBitmap() to set your bitmap into the view object. From there on in you can ignore the canvas passed to you in the onDraw(canvas) method and just draw into your local canvas/bitmap instead.
Why would you need this? There is an oversight in the Canvas class in my opinion. The Canvas class gives you no way to read the canvas contents nor to get at the bitmap behind it. So if you ever need to read from a bitmap, for example to acquire an image dump of the view contents, there's no way I know of to do it, other than the method described above.
This won't work for the RelativeView problem originally described here in this thread but this might be of interest to new Android developers.
As far as I read the last days in the documentation you should onlycall setDrawingCacheEnabled or buildDrawingChache() but not both.
had the same problem and finally this partly works for me:
view.layout(0, 0, 1000, 100);
Bitmap b = view.getDrawingCache();
try {
b.compress(CompressFormat.JPEG, 95,
new FileOutputStream( Environment.getExternalStorageDirectory() + "/folder/name.jpg"));
catch (FileNotFoundException e) {
Log.e(LOGTAG, "error:" + e.getMessage());
}
the only problem is, that I can't get the full dimensions of my view.
view.getwidth returns null ...
Check out if your view is not bigger than the screen size. I found this and switched the dimensions of my view so, now it works =)
Android get full View as Bitmap

Categories

Resources