86

I've been looking for over a day for a solution to this problem but nothing helps, even the answers here. Documentation doesn't explain anything too.

I am simply trying to get a rotation in the direction of another object. The problem is that the bitmap is not rotated around a fixed point, but rather around the bitmaps (0,0).

Here is the code I am having troubles with:

  Matrix mtx = new Matrix();
  mtx.reset();
  mtx.preTranslate(-centerX, -centerY);
  mtx.setRotate((float)direction, -centerX, -centerY);
  mtx.postTranslate(pivotX, pivotY);
  Bitmap rotatedBMP = Bitmap.createBitmap(bitmap, 0, 0, spriteWidth, spriteHeight, mtx, true);
  this.bitmap = rotatedBMP;

The weird part is, it doesn't matter how I change the values within pre/postTranslate() and the float arguments in setRotation(). Can someone please help and push me in the right direction? :)

Adam Stelmaszczyk
  • 19,665
  • 4
  • 70
  • 110
Stefan
  • 861
  • 1
  • 7
  • 4
  • 1
    I take it the above code is after several attempted variations. It seems like mtx.setRotate(dir, x, y) should do the trick by itself, without all the pre/post stuff. Also, you don't need to reset a freshly `new`ed matrix. Its already the identity. – Mark Storer Dec 03 '10 at 21:53

8 Answers8

101

I hope the following sequence of code will help you:

Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight, config);
Canvas canvas = new Canvas(targetBitmap);
Matrix matrix = new Matrix();
matrix.setRotate(mRotation,source.getWidth()/2,source.getHeight()/2);
canvas.drawBitmap(source, matrix, new Paint());

If you check the following method from ~frameworks\base\graphics\java\android\graphics\Bitmap.java

public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
        Matrix m, boolean filter)

this would explain what it does with rotation and translate.

lambda
  • 3,295
  • 1
  • 26
  • 32
Sudar Nimalan
  • 3,962
  • 2
  • 20
  • 28
79

Edited: optimized code.

public static Bitmap RotateBitmap(Bitmap source, float angle)
{
      Matrix matrix = new Matrix();
      matrix.postRotate(angle);
      return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}

To get Bitmap from resources:

Bitmap source = BitmapFactory.decodeResource(this.getResources(), R.drawable.your_img);
Arvis
  • 8,273
  • 5
  • 33
  • 46
  • Try this for rotating a bitmap with any w or h: Matrix matrix = new Matrix(); matrix.postRotate(90); bitmapPicture = Bitmap.createBitmap(bitmapPicture, 0, 0, bitmapPicture.getWidth(), bitmapPicture.getHeight(), matrix, true); – Mark Molina Apr 25 '13 at 15:39
  • This worked perfectly for me as I am setting the parameters for the image points. You just have to make sure to use the matrix when drawing the bitmap to the canvas. – a54studio May 15 '13 at 12:53
  • 7
    Are you sure this is efficient? If RotateBitmap() was in a loop executing N times, depending on the resolution of the bitmap you could be wasting a tremendous amount of memory as well as all those new Matrix object allocations. – Ryhan Jan 13 '14 at 23:51
  • Not tested but docs says: " If the source bitmap is immutable and the requested subset is the same as the source bitmap itself, then the source bitmap is returned and no new bitmap is created." As for Matrix object it's just transforming coordinates class. You can freely optimize code for repetition and use same Matrix object in loops. – Arvis Jan 14 '14 at 09:00
  • FYI, the bitmap needs to be mutable – kip2 Mar 29 '15 at 00:05
  • For me it is not rotating but is moving side to side. – Ajay Nov 01 '15 at 17:39
25

I came back to this problem now that we are finalizing the game and I just thought to post what worked for me.

This is the method for rotating the Matrix:

this.matrix.reset();
this.matrix.setTranslate(this.floatXpos, this.floatYpos);
this.matrix.postRotate((float)this.direction, this.getCenterX(), this.getCenterY()); 

(this.getCenterX() is basically the bitmaps X position + the bitmaps width / 2)

And the method for Drawing the bitmap (called via a RenderManager Class):

canvas.drawBitmap(this.bitmap, this.matrix, null);

So it is prettey straight forward but I find it abit strange that I couldn't get it to work by setRotate followed by postTranslate. Maybe some knows why this doesn't work? Now all the bitmaps rotate properly but it is not without some minor decrease in bitmap quality :/

Anyways, thanks for your help!

Ross Drew
  • 8,163
  • 2
  • 41
  • 53
Ste
  • 369
  • 2
  • 5
7

You can also rotate the ImageView using a RotateAnimation:

RotateAnimation rotateAnimation = new RotateAnimation(from, to,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setDuration(ANIMATION_DURATION);
rotateAnimation.setFillAfter(true);

imageView.startAnimation(rotateAnimation);
Macarse
  • 91,829
  • 44
  • 175
  • 230
  • 5
    You're answering the wrong question. He doesn't want to rotate the view, just a single bitmap within it. – Mark Storer Dec 03 '10 at 21:47
  • As i experienced, setFillAfter(bool) method not working as it expected to be on Android API lvl 11 and below. Therefore, developers are unable to use continuous rotation event on view objects, nor they obtain rotated versions of these views after rotation. So @Mark Storer , Macarse answered truly on logical point of view if you set animation duration with 0 or something close to 0. – Gökhan Barış Aker Mar 21 '12 at 13:14
5

You can use something like following:


Matrix matrix = new Matrix();
matrix.setRotate(mRotation,source.getWidth()/2,source.getHeight()/2);
RectF rectF = new RectF(0, 0, source.getWidth(), source.getHeight());
matrix.mapRect(rectF);
Bitmap targetBitmap = Bitmap.createBitmap(rectF.width(), rectF.height(), config);
Canvas canvas = new Canvas(targetBitmap);
canvas.drawBitmap(source, matrix, new Paint());
Sudar Nimalan
  • 3,962
  • 2
  • 20
  • 28
1

I used this configurations and still have the problem of pixelization :

Bitmap bmpOriginal = BitmapFactory.decodeResource(this.getResources(), R.drawable.map_pin);
        Bitmap targetBitmap = Bitmap.createBitmap((bmpOriginal.getWidth()),
                (bmpOriginal.getHeight()), 
                Bitmap.Config.ARGB_8888);
        Paint p = new Paint();
        p.setAntiAlias(true);

        Matrix matrix = new Matrix();       
        matrix.setRotate((float) lock.getDirection(),(float) (bmpOriginal.getWidth()/2),
                (float)(bmpOriginal.getHeight()/2));

        RectF rectF = new RectF(0, 0, bmpOriginal.getWidth(), bmpOriginal.getHeight());
        matrix.mapRect(rectF);

        targetBitmap = Bitmap.createBitmap((int)rectF.width(), (int)rectF.height(), Bitmap.Config.ARGB_8888);


        Canvas tempCanvas = new Canvas(targetBitmap); 
        tempCanvas.drawBitmap(bmpOriginal, matrix, p);
MSaudi
  • 4,442
  • 2
  • 40
  • 65
1

Look at the sample from Google called Lunar Lander, the ship image there is rotated dynamically.

Lunar Lander code sample

sprite
  • 3,724
  • 3
  • 28
  • 30
0
matrix.reset();
matrix.setTranslate( anchor.x, anchor.y );
matrix.postRotate((float) rotation , 0,0);
matrix.postTranslate(positionOfAnchor.x, positionOfAnchor.x);
c.drawBitmap(bitmap, matrix, null); 
Louie Almeda
  • 5,366
  • 30
  • 38