Android: come ruotare una bitmap su un punto centrale


84

Ho cercato per più di un giorno una soluzione a questo problema ma niente aiuta, anche le risposte qui. Anche la documentazione non spiega nulla.

Sto semplicemente cercando di ottenere una rotazione nella direzione di un altro oggetto. Il problema è che la bitmap non viene ruotata attorno a un punto fisso, ma piuttosto attorno alle bitmap (0,0).

Ecco il codice con cui sto avendo problemi:

  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;

La parte strana è che non importa come cambio i valori all'interno di pre/ postTranslate()e gli argomenti float in setRotation(). Qualcuno può aiutarmi e spingermi nella giusta direzione? :)


1
Presumo che il codice sopra sia dopo diversi tentativi di variazioni. Sembra che mtx.setRotate (dir, x, y) dovrebbe fare il trucco da solo, senza tutte le cose pre / post. Inoltre, non è necessario reimpostare una newmatrice appena modificata . È già l'identità.
Mark Storer

Risposte:


101

Spero che la seguente sequenza di codice ti possa aiutare:

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

Se controlli il seguente metodo da ~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)

questo spiegherebbe cosa fa con la rotazione e la traduzione.


1
Puoi farlo con Bitmap.createBitmap che prende una matrice? Come si calcolano targetWidth e targetHeight? Trigger semplice, presumo, ma esiste un modo "più semplice"?

Si prega di controllare la risposta seguente, (Mi dispiace, non ho potuto aggiungere il codice nei commenti)
Sudar Nimalan

la qualità peggiora durante l'applicazione. qualche soluzione?
MSaudi

1
cambia canvas.drawBitmap (source, matrix, new Paint ()); con canvas.drawBitmap (source, matrix, new Paint (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan

3
Semplicemente commentando che questo processo è molto affamato di memoria e non dovrebbe essere usato nei metodi step.
MLProgrammer-CiM

79

Modificato : codice ottimizzato.

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

Per ottenere bitmap dalle risorse:

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

Prova questo per ruotare una bitmap con qualsiasi w o h: Matrix matrix = new Matrix (); matrix.postRotate (90); bitmapPicture = Bitmap.createBitmap (bitmapPicture, 0, 0, bitmapPicture.getWidth (), bitmapPicture.getHeight (), matrix, true);
Mark Molina

Questo ha funzionato perfettamente per me mentre sto impostando i parametri per i punti dell'immagine. Devi solo assicurarti di usare la matrice quando disegni la bitmap sulla tela.
a54studio

6
Sei sicuro che sia efficiente? Se RotateBitmap () fosse in un ciclo in esecuzione N volte, a seconda della risoluzione della bitmap potresti sprecare un'enorme quantità di memoria così come tutte quelle nuove allocazioni di oggetti Matrix.
Ryhan

Non testato, ma docs dice: "Se la bitmap di origine non è modificabile e il sottoinsieme richiesto è uguale alla bitmap di origine stessa, viene restituita la bitmap di origine e non viene creata alcuna nuova bitmap." Per quanto riguarda l'oggetto Matrix, sta solo trasformando la classe delle coordinate. È possibile ottimizzare liberamente il codice per la ripetizione e utilizzare lo stesso oggetto Matrix nei cicli.
Arvis

Cordiali saluti, la bitmap deve essere modificabile
kip2

25

Sono tornato su questo problema ora che stiamo finalizzando il gioco e ho pensato di pubblicare ciò che ha funzionato per me.

Questo è il metodo per ruotare la matrice:

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

( this.getCenterX()è fondamentalmente la posizione X delle bitmap + la larghezza delle bitmap / 2)

E il metodo per disegnare la bitmap (chiamato tramite una RenderManagerclasse):

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

Quindi è piuttosto semplice, ma trovo un po 'strano che non sia riuscito a farlo funzionare setRotateseguito da postTranslate. Forse qualcuno sa perché questo non funziona? Ora tutte le bitmap ruotano correttamente ma non è senza una piccola diminuzione della qualità della bitmap: /

Comunque, grazie per il tuo aiuto!


Anche il codice di risposta precedente funziona. con lo stesso problema di qualità.
MSaudi

7

Puoi anche ruotare ImageViewusando 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);

4
Stai rispondendo alla domanda sbagliata. Non vuole ruotare la vista, solo una singola bitmap al suo interno.
Mark Storer

Come ho sperimentato, il metodo setFillAfter (bool) non funziona come previsto sull'API Android lvl 11 e inferiore. Pertanto, gli sviluppatori non sono in grado di utilizzare l'evento di rotazione continua sugli oggetti della vista, né ottengono versioni ruotate di queste viste dopo la rotazione. Quindi @Mark Storer, Macarse ha risposto veramente dal punto di vista logico se si imposta la durata dell'animazione con 0 o qualcosa di simile a 0.
Gökhan Barış Aker

5

Puoi usare qualcosa come segue:


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


stesso problema per tutte le soluzioni: diminuzione della qualità bitmap
MSaudi

cambia canvas.drawBitmap (source, matrix, new Paint ()); con canvas.drawBitmap (source, matrix, new Paint (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan

qual è la configurazione che stai usando?
Sudar Nimalan

Ho pubblicato il codice qui sotto come risposta. non riuscivo a scriverlo nel commento. Grazie mille signore :)
MSaudi


1

Ho usato queste configurazioni e ho ancora il problema della pixelizzazione:

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
potresti provare setFilterBitmap, setDither opzioni
Sudar Nimalan

1
Sì, ha funzionato perfettamente. Grazie mille Sudar, mi hai davvero aiutato molto.
MSaudi

1
Aggiunta di link al tuo follow-up con codice aggiornato: 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); 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.