Android: So drehen Sie eine Bitmap auf einem Mittelpunkt

84

Ich habe über einen Tag nach einer Lösung für dieses Problem gesucht, aber nichts hilft, selbst die Antworten hier. Die Dokumentation erklärt auch nichts.

Ich versuche einfach, eine Drehung in Richtung eines anderen Objekts zu bekommen. Das Problem ist, dass die Bitmap nicht um einen festen Punkt gedreht wird, sondern um die Bitmaps (0,0).

Hier ist der Code, mit dem ich Probleme habe:

  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;

Der seltsame Teil ist, dass es keine Rolle spielt, wie ich die Werte in pre/ postTranslate()und die float-Argumente in ändere setRotation(). Kann mir bitte jemand helfen und mich in die richtige Richtung drängen? :) :)

Stefan
quelle
1
Ich nehme an, der obige Code ist nach mehreren versuchten Variationen. Es scheint, als ob mtx.setRotate (dir, x, y) den Trick alleine machen sollte, ohne all das Pre / Post-Zeug. Außerdem müssen Sie eine frisch newbearbeitete Matrix nicht zurücksetzen . Es ist schon die Identität.
Mark Storer

Antworten:

101

Ich hoffe, die folgende Codesequenz hilft Ihnen:

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

Wenn Sie die folgende Methode von überprüfen ~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)

Dies würde erklären, was es mit Rotation und Übersetzung macht.

Sudar Nimalan
quelle
1
Können Sie dies mit der Bitmap.createBitmap tun, die eine Matrix benötigt? Wie berechnen Sie targetWidth und targetHeight? Einfacher Trigger, nehme ich an, aber gibt es einen "einfacheren" Weg?
Bitte überprüfen Sie die unten stehende Antwort (Entschuldigung, ich konnte keinen Code in den Kommentaren hinzufügen)
Sudar Nimalan
Die Qualität wird schlecht, wenn man dies anwendet. irgendeine Lösung ?
MSaudi
1
ändere canvas.drawBitmap (Quelle, Matrix, neues Paint ()); mit canvas.drawBitmap (Quelle, Matrix, neuer Paint (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan
3
Nur zu kommentieren, dass dieser Prozess sehr speicherhungrig ist und nicht in Schrittmethoden verwendet werden sollte.
MLProgrammer-CiM
79

Bearbeitet : optimierter 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);
}

So erhalten Sie Bitmap aus Ressourcen:

Bitmap source = BitmapFactory.decodeResource(this.getResources(), R.drawable.your_img);
Arvis
quelle
Versuchen Sie dies, um eine Bitmap mit einem beliebigen w oder h zu drehen: Matrix matrix = new Matrix (); matrix.postRotate (90); bitmapPicture = Bitmap.createBitmap (bitmapPicture, 0, 0, bitmapPicture.getWidth (), bitmapPicture.getHeight (), Matrix, true);
Mark Molina
Dies hat bei mir perfekt funktioniert, da ich die Parameter für die Bildpunkte einstelle. Sie müssen nur sicherstellen, dass Sie die Matrix verwenden, wenn Sie die Bitmap auf die Leinwand zeichnen.
a54studio
6
Sind Sie sicher, dass dies effizient ist? Wenn sich RotateBitmap () in einer Schleife befindet, die N-mal ausgeführt wird, können Sie abhängig von der Auflösung der Bitmap eine enorme Menge an Speicher sowie all diese neuen Matrix-Objektzuordnungen verschwenden.
Ryhan
Nicht getestet, aber in den Dokumenten heißt es: "Wenn die Quellbitmap unveränderlich ist und die angeforderte Teilmenge mit der Quellbitmap selbst übereinstimmt, wird die Quellbitmap zurückgegeben und keine neue Bitmap erstellt." Das Matrix-Objekt transformiert nur die Koordinatenklasse. Sie können den Code für die Wiederholung frei optimieren und dasselbe Matrix-Objekt in Schleifen verwenden.
Arvis
Zu
Ihrer Information
25

Ich bin jetzt, da wir das Spiel fertigstellen, auf dieses Problem zurückgekommen und habe nur darüber nachgedacht, zu posten, was für mich funktioniert hat.

Dies ist die Methode zum Drehen der Matrix:

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

( this.getCenterX()ist im Grunde die Bitmaps X Position + die Bitmaps Breite / 2)

Und die Methode zum Zeichnen der Bitmap (über eine RenderManagerKlasse aufgerufen ):

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

Es ist also ziemlich einfach, aber ich finde es etwas seltsam, dass ich es nicht zum Laufen bringen konnte, setRotategefolgt von postTranslate. Vielleicht wissen einige, warum das nicht funktioniert? Jetzt drehen sich alle Bitmaps richtig, aber es ist nicht ohne eine geringfügige Abnahme der Bitmap-Qualität: /

Trotzdem danke für deine Hilfe!

Ste
quelle
Der vorherige Antwortcode funktioniert ebenfalls. mit dem gleichen Qualitätsproblem.
MSaudi
7

Sie können das auch drehen ImageViewmit 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
quelle
4
Sie beantworten die falsche Frage. Er möchte die Ansicht nicht drehen, sondern nur eine einzige Bitmap.
Mark Storer
Wie ich erfahren habe, funktioniert die setFillAfter (bool) -Methode nicht wie erwartet auf der Android-API Stufe 11 und darunter. Daher können Entwickler weder ein kontinuierliches Rotationsereignis für Ansichtsobjekte verwenden, noch erhalten sie nach der Rotation gedrehte Versionen dieser Ansichten. Also @Mark Storer, Macarse antwortete wirklich aus logischer Sicht, wenn Sie die Animationsdauer mit 0 oder etwas in der Nähe von 0 einstellen.
Gökhan Barış Aker
5

Sie können Folgendes verwenden:


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
quelle
Gleiches Problem für alle Lösungen: Abnahme der Bitmap-Qualität
MSaudi
change canvas.drawBitmap (Quelle, Matrix, neues Paint ()); mit canvas.drawBitmap (Quelle, Matrix, neuer Paint (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan
Welche Konfiguration verwenden Sie?
Sudar Nimalan
Ich habe den folgenden Code als Antwort gepostet. konnte es nicht in den Kommentar schreiben. Vielen Dank, Sir :)
MSaudi
1

Schauen Sie sich das Beispiel von Google namens Lunar Lander an, das Schiffsbild dort wird dynamisch gedreht.

Lunar Lander Codebeispiel

Sprite
quelle
1

Ich habe diese Konfigurationen verwendet und habe immer noch das Problem der Pixelung:

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
quelle
1
Könnten Sie versuchen, setFilterBitmap, setDither Optionen
Sudar Nimalan
1
Ja, das hat perfekt funktioniert. Vielen Dank Sudar, du hast mir wirklich sehr geholfen.
MSaudi
1
Hinzufügen eines Links zu Ihrem eigenen Follow-up mit aktualisiertem Code: 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); 
Louie Almeda
quelle