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.