Fastest way to rotate big size bitmap - android

I am working with large size images and when I try to rotate them (applying matrix on the bitmap) a lot of seconds occurs.
I've seen that android system gallery can accomplish this task in a very fast manner instead. How is it possible?
I thought to perform the rotation on an asyncTask, applying only the ImageView rotation (which doesn't take long time) on the main thread, but if the app is killed before the asyncTask get to the end, the app fall in an inconsistent state.
This is my bitmap rotation code, which takes long time execution for large bitmaps:
Matrix mat = new Matrix();
mat.setRotate(90);
bMap = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(), bMap.getHeight(), mat, true);

When doing modifications to a large image, create a low quality bitmap copy of it and use it for showing instant rotation or other editing effects. Once user is stopped motion (or left slider control) replace the low quality bitmap with the original image with same effects applied to it. This will significantly improve user experience. Try and let me know.
This might sound like a deviation from the original requirement- you can draw a rectangle instead of rotating the whole image in real time. In the end, what user needs is an indication of how much his image has rotated. This will be faster and can easily be done on UI thread without lag.
This is the simplest rotation on canvas code
canvas.save(); //save the position of the canvas
canvas.rotate(angle, X + (imageW / 2), Y + (imageH / 2)); //rotate the canvas
canvas.drawBitmap(imageBmp, X, Y, null); //draw the image on the rotated canvas
canvas.restore(); // restore the canvas position.

Related

Android. How to effective frequently create bitmap?

I'm using library which takes bitmap.
At first I'm showing bitmap in ZoomableImageView. But after scale, zoom I need to send to the library only visible part of image view.
Here is my code to create scaled bitmap with matrix:
Bitmap result = Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.getWidth(), originalBitmap.getHeight(), matrix, true);
However, the user may be constantly zooming in on the image, and what happens is that this code is executed frequently and my application freezes. Is there any way to prevent this or is there a better way to create scaled bitmap ?
Please help me.

rotating and cropping a bitmap accurately and effiently in android

I'm writing an android application.By using it,a user can crop the bitmap image.But I want to add more function,that is to rotate the image before cropping.
I followed the below steps to accomplish this purpose.
built a custom view.
initialized BitmapDrawable() and a cropping rectangle(Rect()) [the rectangle determines where to cop in the bitmap]
override onTouch(MotionEvent) method for two functions
a. user can move the bitmap over the screen
b. user can transform the cropping rectangle
override onDraw(Canvas) method to update the screen.This code is for showing bitmap.
bitmap_drawable.draw(canvas,_bitmap_paint);
Problem:1
This step ,that I don't know how to do, is to show a rotated properly. I used this code to rotate the canvas in the onDraw(Canvas) method.
canvas.rotate(_angle);
But it makes all the things on the screen (including the cropping rectangle) to rotate.
Question:2
Is it a wise way to initialize my own Canvas() object to draw the bitmap on?
Note:
Here,the rotation that I want,is very accurate up to 1 degree and is performed by two-finger rotation gesture so that performance is very important and the following code(using matrix) is bad.
Matrix mat = new Matrix();
mat.preRotate(_degree, _one_finger_x, _one_finger_y);
Bitmap _new_bitmap = Bitmap.createBitmap(_old_bitmap, 0, 0, bmWidth, bmHeight, mat, true);
Therefore,I think initializing a separate Canvas() and using canvas.rotate(_degree) is very appropriate.However,this makes controlling touch events quite difficult.Any ideas?Please help.
Problem:2
Suppose that I can now rotate the bitmap separately from all objects,i.e. the cropping rectangle,etc.This step is to crop the bitmap and show the cropped result to the user efficiently.When rotate function is not included, I simply copy the color bytes within the cropping rectangle on the old bitmap as follow.
Bitmap _new_bitmap = Bitmap.createBitmap( _old_bitmap, _cropRectx, _cropRecty, _cropRectWidth, _cropRectHeight, null);
But here,from a rotated bitmap, how can I clone the color bytes through a crossing crop rectangle?
Question:2
How can I crop a rotated bitmap?

Speeding Up Bitmap Animation

I'm making a game, while a friend of mine is designing all the graphics. All graphics are PNG files, and drawn and animated using Bitmaps and Canvas in SurfaceView.
One piece of animation involves the main character moving around during the menu, which uses 35 large PNG files. It's too big to have it all loaded in memory, and loading each file when needed is too slow for what he wants. So, what can I do to make this work?
OPTIONS THAT DON'T WORK
Making the image smaller. Making the image smaller than what he wanted won't fly. Anything less than original quality won't fly either.
OPTIONS WE'RE LOOKING INTO
Making the animation a video. However, I don't know how to take a video and turn it into an interface.
My code:
Matrix matrix = new Matrix();
matrix.postScale(scaleFactorX, scaleFactorY);
penguin = BitmapFactory.decodeResource(getResources(), R.drawable.fish_01);
penguin = Bitmap.createBitmap(penguin, 0, 0, penguin.getWidth(), penguin.getHeight(), matrix, true);
canvas.drawBitmap(penguin, canvasWidth - penguin.getWidth(), canvasHeight*0.02f, null);

When translating a matrix used to draw a bitmap, it draws multiple bitmaps

In my Android project, I have a matrix that I use to draw a bitmap on a canvas. During my drawFrame method, I translate the matrix in the Y direction so it looks like the bitmap is moving up. It does move up, but it is also drawn in the previous position leaving multiples of itself behind. Here is my drawFrame code:
Canvas canvas = null;
canvas = holder.lockCanvas();
Matrix moveMatrix = new Matrix ();
moveMatrix.postTranslate(0, 10);
matrix.preConcat(moveMatrix);
canvas.drawBitmap(bitmap, matrix, null);
holder.unlockCanvasAndPost(canvas);
"matrix" is a global Matrix member.
Does anyone know why this leaves a "streaking" trail of bitmaps across the screen?
Thanks!
I forgot to mention that each previous bitmap position seems to shift up and down in the y direction every time the bitmap moves. So it ends up with a string of bitmaps that look like they are jittering up and down. This would mean that every bitmap would have to be redrawn every frame otherwise they would all be standing still.
You need to clear the Canvas at the previous position of the bitmap :)

Animating and rotating an image in a Surface View

I would like to animate movement on a SurfaceView . Ideally I would like to also be notified once the animation had finished.
For example:
I might have a car facing North. If I wanted to animate it so that it faces South for a duration of 500ms, how could I do that?
I am using a SurfaceView so all animation must be handled manually, I don't think I can use XML or the android Animator classes.
Also, I would like to know the best way to animate something continuously inside a SurfaceView (ie. a walk cycle)
Rotating images manually can be a bit of a pain, but here's how I've done it.
private void animateRotation(int degrees, float durationOfAnimation){
long startTime = SystemClock.elapsedRealtime();
long currentTime;
float elapsedRatio = 0;
Bitmap bufferBitmap = carBitmap;
Matrix matrix = new Matrix();
while (elapsedRatio < 1){
matrix.setRotate(elapsedRatio * degrees);
carBitmap = Bitmap.createBitmap(bufferBitmap, 0, 0, width, height, matrix, true);
//draw your canvas here using whatever method you've defined
currentTime = SystemClock.elapsedRealtime();
elapsedRatio = (currentTime - startTime) / durationOfAnimation;
}
// As elapsed ratio will never exactly equal 1, you have to manually draw the last frame
matrix = new Matrix();
matrix.setRotate(degrees);
carBitmap = Bitmap.createBitmap(bufferBitmap, 0, 0, width, height, matrix, true);
// draw the canvas again here as before
// And you can now set whatever other notification or action you wanted to do at the end of your animation
}
This will rotate your carBitmap to whatever angle you specify in the time specified + the time to draw the last frame. However, there is a catch. This rotates your carBitmap without adjusting its position on screen properly. Depending on how you're drawing your bitmaps, you could end up with your carBitmap rotating while the top-left corner of the bitmap stays in place. As the car rotates, the bitmap will stretch and adjust to fit the new car size, filling the gaps around it with transparent pixels. It's hard to describe how this would look, so here's an example rotating a square:
The grey area represents the full size of the bitmap, and is filled with transparent pixels. To solve this problem, you need to use trigonometry. It's a bit complicated... if this ends up being a problem for you (I don't know how you're drawing your bitmaps to the canvas so it might not be), and you can't work out the solution, let me know and I'll post up how I did it.
(I don't know if this is the most efficient way of doing it, but it works smoothly for me as long as the bitmap is less than 300x300 or so. Perhaps if someone knows of a better way, they could tell us!)
Do you want multiple independent animated object? If so, then you should use a game loop. (One master while loop that incrementally updates all game objects.) Here's a good discussion on various loop implementations. (I'm currently using "FPS dependent on Constant Game Speed" for my Android game project.)
So then your Car will look something like this (lots of code missing):
class Car {
final Matrix transform = new Matrix();
final Bitmap image;
Car(Bitmap sprite) {
image = sprite; // Created by BitmapFactory.decodeResource in SurfaceView
}
void update() {
this.transform.preRotate(turnDegrees, width, height);
}
void display(Canvas canvas) {
canvas.drawBitmap(this.image, this.transform, null);
}
}
You only need to load your bitmap once. So if you have multiple Cars, you may want to give them each the same Bitmap object (cache the Bitmap in your SurfaceView).
I haven't got into walk animations yet, but the simplest solution is to have multiple Bitmaps and just draw a different bitmap each time display is called.
Have a look at lunarlander.LunarView in the Android docs if you haven't already.
If you want to be notified when the animation is complete, you should make a callback.
interface CompletedTurnCallback {
void turnCompleted(Car turningCar);
}
Have your logic class implement the callback and have your Car call it when the turn's complete (in update()). Note that you'll get a ConcurrentModificationException if you are iterating over a list of Cars in update_game() and you try to remove a Car from that list in your callback. (You can solve this with a command queue.)

Categories

Resources