Android: Cách xoay một bitmap trên một điểm trung tâm


84

Tôi đã tìm kiếm giải pháp cho vấn đề này hơn một ngày nhưng không có gì giúp ích được, ngay cả câu trả lời ở đây. Tài liệu không giải thích bất cứ điều gì quá.

Tôi chỉ đơn giản là đang cố gắng quay theo hướng của một vật thể khác. Vấn đề là bitmap không được xoay quanh một điểm cố định, mà xoay quanh bitmap (0,0).

Đây là mã tôi đang gặp sự cố:

  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;

Phần kỳ lạ là, không quan trọng bằng cách nào tôi thay đổi các giá trị bên trong pre/ postTranslate()và các đối số float trong setRotation(). Ai đó có thể vui lòng giúp đỡ và đẩy tôi đi đúng hướng không? :)


1
Tôi hiểu rằng đoạn mã trên là sau một số biến thể đã thử. Có vẻ như mtx.setRotate (dir, x, y) sẽ tự thực hiện thủ thuật mà không cần tất cả các nội dung trước / sau. Ngoài ra, bạn không cần đặt lại newma trận mới được chỉnh sửa. Nó đã là bản sắc.
Mark Storer

Câu trả lời:


101

Tôi hy vọng chuỗi mã sau đây sẽ giúp bạn:

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());

Nếu bạn kiểm tra phương pháp sau từ ~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)

điều này sẽ giải thích những gì nó làm với xoay và dịch.


1
Bạn có thể làm điều đó với Bitmap.createBitmap có Ma trận không? Bạn đang tính toán targetWidth và targetHeight như thế nào? Tôi giả sử đơn giản, nhưng có cách nào "dễ dàng hơn" không?

Vui lòng kiểm tra câu trả lời bên dưới, (Xin lỗi, tôi không thể thêm mã vào nhận xét)
Sudar Nimalan

chất lượng trở nên tồi tệ khi áp dụng điều này. bất kì giải pháp nào ?
MSaudi

1
thay đổi canvas.drawBitmap (source, matrix, new Paint ()); với canvas.drawBitmap (nguồn, ma trận, Paint mới (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan

3
Chỉ nhận xét rằng quá trình này rất tốn bộ nhớ và không nên được sử dụng trong các phương pháp bước.
MLProgrammer-CiM

79

Đã chỉnh sửa : mã được tối ưu hóa.

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);
}

Để lấy Bitmap từ các tài nguyên:

Bitmap source = BitmapFactory.decodeResource(this.getResources(), R.drawable.your_img);

Hãy thử điều này để xoay một bitmap với bất kỳ w hoặc h nào: Ma trận ma trận = new Matrix (); matrix.postRotate (90); bitmapPicture = Bitmap.createBitmap (bitmapPicture, 0, 0, bitmapPicture.getWidth (), bitmapPicture.getHeight (), matrix, true);
Mark Molina

Điều này hoạt động hoàn hảo đối với tôi vì tôi đang thiết lập các thông số cho các điểm hình ảnh. Bạn chỉ cần đảm bảo sử dụng ma trận khi vẽ bitmap vào canvas.
a54studio

6
Bạn có chắc điều này là hiệu quả? Nếu RotateBitmap () ở trong một vòng lặp thực thi N lần, tùy thuộc vào độ phân giải của bitmap, bạn có thể lãng phí một lượng lớn bộ nhớ cũng như tất cả các phân bổ đối tượng Matrix mới đó.
Ryhan

Chưa được kiểm tra nhưng tài liệu cho biết: "Nếu bitmap nguồn là không thể thay đổi và tập hợp con được yêu cầu giống với bản thân bitmap nguồn, thì bitmap nguồn được trả về và không có bitmap mới nào được tạo." Đối với đối tượng Matrix, nó chỉ là lớp tọa độ biến đổi. Bạn có thể tự do tối ưu hóa mã để lặp lại và sử dụng cùng một đối tượng Ma trận trong các vòng lặp.
Arvis

FYI, bitmap cần phải có thể thay đổi được
kip2

25

Tôi quay lại vấn đề này bây giờ khi chúng tôi đang hoàn thiện trò chơi và tôi chỉ nghĩ rằng hãy đăng những gì phù hợp với tôi.

Đây là phương pháp xoay Ma trận:

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

( this.getCenterX()về cơ bản là vị trí bitmap X + chiều rộng bitmap / 2)

Và phương pháp để Vẽ bitmap (được gọi qua một RenderManagerLớp):

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

Vì vậy, nó rất đẹp về phía trước nhưng tôi thấy lạ là tôi không thể làm cho nó hoạt động setRotatesau đó postTranslate. Có thể một số biết tại sao điều này không hoạt động? Bây giờ tất cả các bitmap đều xoay đúng cách nhưng không phải là không có một số giảm nhỏ về chất lượng bitmap: /

Dù sao, cảm ơn sự giúp đỡ của bạn!


Mã câu trả lời trước đó cũng hoạt động. với cùng một vấn đề về chất lượng.
MSaudi

7

Bạn cũng có thể xoay vòng ImageViewbằng cách sử dụng 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);

4
Bạn đang trả lời câu hỏi sai. Anh ấy không muốn xoay chế độ xem, chỉ một bitmap duy nhất bên trong nó.
Mark Storer

Như tôi đã trải nghiệm, phương thức setFillAfter (bool) không hoạt động như mong đợi trên Android API lvl 11 trở xuống. Do đó, các nhà phát triển không thể sử dụng sự kiện xoay liên tục trên các đối tượng dạng xem, cũng như họ không có được các phiên bản xoay của các dạng xem này sau khi xoay. Vì vậy @ Mark Storer, Macarse trả lời thực sự trên điểm hợp lý xem nếu bạn thiết lập thời gian hoạt hình với 0 hoặc một cái gì đó gần với 0.
Gökhan Barış Aker

5

Bạn có thể sử dụng một cái gì đó như sau:


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());


cùng một vấn đề cho tất cả các giải pháp: giảm chất lượng bitmap
MSaudi

thay đổi canvas.drawBitmap (source, matrix, new Paint ()); với canvas.drawBitmap (nguồn, ma trận, Paint mới (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan

cấu hình bạn đang sử dụng là gì?
Sudar Nimalan,

Tôi đã đăng đoạn mã dưới đây như một câu trả lời. không thể viết nó trong bình luận. Cảm ơn rất nhiều ạ :)
MSaudi 31/10/12/12


1

Tôi đã sử dụng cấu hình này và vẫn gặp sự cố pixel hóa:

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);

1
bạn có thể thử setFilterBitmap, tùy chọn setDither
Sudar Nimalan

1
Có, Điều này hoạt động hoàn hảo. Cảm ơn bạn Sudar rất nhiều, bạn thực sự đã giúp tôi rất nhiều.
MSaudi 31/10/12

1
Thêm liên kết đến followup của riêng bạn với mã Cập nhật: stackoverflow.com/questions/13048953/...
Chris Rae

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); 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.