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?
Related
Can't get android.graphics.picture objects to rotate, but translates are OK. No camera involved in the following code.
For making dynamic sprites, recording drawing primitives into an android.graphics.picture object for later use seems consistently more efficient than doing individual primitive draws during onDraw. And a Picture object is very similar to a bitmap, (if not the same?) and can be saved and restored to / from a bitmap.
However, just to be able to rotate these Pictures, I'd like to avoid having to save them as Bitmaps after recording() them. That is, just use the Picture objects like bitmaps, which the canvas api seems to imply is possible. Perhaps the Picture API is less sophisticated, but more likely I'm just doing this wrong.
The canvas API for Bitmaps versus Pictures are not parallel, e.g. there is a:
canvas.drawBitmap(bitmap_Sprite, matrix, null); // Draw sprite with matrix, no Paint
And there is a:
canvas.drawPicture(picture_Sprite, destination_rectangle); Draw sprite into rect.
But there isn't a:
canvas.drawPicture(picture_Sprite, matrix ...)
Details:
Imagine both bitmap_Sprite and picture_Sprite are a "compass arrow" indicating where it's pointing during rotation.
In the onDraw() call, using the bitmap version, this works:
matrix = new matrix();
matrix.setRotate(angle); // angle is ++ during onDraw(canvas)
// Draw arrow, matrix rotates it as expected:
canvas.drawBitmap(bitmap_Sprite, matrix, null); // null = no Paint obj
But attempting the same thing using the picture object, the only way I could figure this out was to rotate the the destination_rectangle (containing the arrow) like this:
//destination_rectangle sized correctly to wrap previously recorded picture obj.
matrix2 = new matrix();
matrix2.setRotate(angle); // angle is ++ during onDraw(canvas)
matrix2.mapRect(destination_rectangle); // apply rotation
canvas.drawPicture(picture_Sprite, destination_rectangle);
But all this does is pivot the rectangle around a location, it doesn't rotate the rectangle (and the arrow) itself.
Questions:
Is using the destination rect. the wrong way to do this?
Is rotation even possible using a Picture object?
Certainly, if I can't get Picture objects to rotate, then I could just use previously created bitmaps / mipmaps directly. So then
Generally, assuming it is possible to use Picture objects the same way as Bitmaps, am I really saving overhead using Pictures which are dynamically created once versus dynamically creating them, saving them as bitmaps, and reloading the bitmaps to do the matrix stuff?(!)
just use Canvas.concat, you will probably want save/restore as well
I'm using the matrix.rotate(deg, fx,fy) method to rotate an image.
The image has an alpha channel and only has something visual in the right-hand corner. I want to rotate the canvas, create the new image with that matrix and have the visual part be the only part that is rotating.
At the moment the image rotates but doesn't rotate around the desired axis. It always rotates around the original width of the object.
Here is the code I use:
Matrix matrix = new Matrix();
matrix.setRotate(rotation, xPivot, yPivot);
Bitmap pic1a = Bitmap.createBitmap(pic1, 0, 0, pic1.getWidth(), pic1.getHeight(), matrix, true);
This rotates the image correctly but only seems to rotate within the same location of the original canvas.
What I want is for the point that the image rotates around (xPivot, yPivot) becoming the centre location on the display.
I got success in implementing a pinch zoom in/out and drag/drop functionality in images on the canvas.
Now what I want is re-sizing, that images like below link that based on iPhone App
How to change shape of an image using iPhone SDK?
So how can I achieve that kind of functionality in Android ?
Basically you need to invalidate the image and re-draw on the canvas from the beginning ::
img=(ImageView)findViewById(R.id.yourimageidfromxml);
img.onTouchEvent(MotionEvent me)
{
int X=me.getX();
int Y=me.getY();
img.invalidate();
img.repaint(X,Y);
}
void paint(int X,int Y)
{
img.setWidth(X);
img.setHeight(Y);
}
Scaling image will transform using repaint on canvas from the beginning
If by re-sizing you are referring to "stretching" the Bitmap on the vertical and horizontal plane then you simply modify the rect that the shape (eg. oval) is being drawn into.
For example:
This is your original shape of an oval:
canvas.drawOval(new Rect(0,0,100,100), bluePaint);
This is the same oval, just stretched (resized) on the horizontal plane:
canvas.drawOval(new Rect(0,0,200,100), bluePaint);
I hope this helps.
There are two options, both involving a custom view. The first is to create a custom view that fills your "canvas". You can keep track of 8 blue and 1 green circles in the view as Rect objects. Override onTouchEvent(MotionEvent) and then check if motion events are in any of your controls and update them accordingly (I'm simplifying things a bit here :)). From your onTouchEvent you would call invalidate(). You're onDraw(Canvas) can then handle drawing the controls and update the image according to how your controls have changed since the last call to onDraw.
The other option is to do something similar, but with a view that only encapsulates the circle and controls, meaning that moving the view around would require a container that will let the view change it's layout parameters. Doing this, your onTouchEvent method would need to trigger an invalidate with that layout view because it would need to recalculate the size and position of your view. This would definitely be harder but depending on what you are trying to achieve working with individual views may be better than maintaining representations of your circles in code in a single view.
The resizing of the image can be achieved by using a simple ImageView with scaleType "fitXY".
You have to add the blue resize handles yourself.
Changing the rotation of the image (green handle) can be achieved by using:
public static Bitmap rotate(Bitmap src, float degree) {
// create new matrix
Matrix matrix = new Matrix();
// setup rotation degree
matrix.postRotate(degree);
// return new bitmap rotated using matrix
return Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
}
Source: http://xjaphx.wordpress.com/2011/06/22/image-processing-rotate-image-on-the-fly/
See http://xjaphx.wordpress.com/learning/tutorials/ for more Android Image Processing examples.
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.
I would like to display a transperent PNG of a "light" line shape according to user's sliding path.
I'd like to make similar effect like Fruit Ninja has, and leave a track after user slides his finger.
I already have the x,y points of his finger - using onTouch method, and checking the x,y on MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP but how do i draw an image that will be tilted and displayed at those positions? all i know is to add padding/margin to an image, not how to place it using x,y, or how to rotate it..
For positioning and rotating use a canvas (getSurfaceHolder().lockCanvas()) and draw inside it using drawBitmap.
public void drawBitmap (Bitmap bitmap, Matrix mtx, Rect dst, Paint paint)
the matrix can include the rotation:
Matrix mtx = new Matrix();
mtx.postRotate(90);
You might want to se the code from API demos, FingerPaint.