Android: cómo rotar un mapa de bits en un punto central

84

He estado buscando una solución a este problema durante más de un día, pero nada ayuda, incluso las respuestas aquí. La documentación tampoco explica nada.

Simplemente estoy tratando de obtener una rotación en la dirección de otro objeto. El problema es que el mapa de bits no gira alrededor de un punto fijo, sino alrededor de los mapas de bits (0,0).

Aquí está el código con el que tengo problemas:

  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 extraña es que no importa cómo cambie los valores dentro de pre/ postTranslate()y los argumentos flotantes en setRotation(). ¿Puede alguien ayudarme y empujarme en la dirección correcta? :)

Stefan
fuente
1
Supongo que el código anterior es después de varios intentos de variaciones. Parece que mtx.setRotate (dir, x, y) debería hacer el truco por sí solo, sin todas las cosas pre / post. Además, no es necesario restablecer una newmatriz recién editada. Ya es la identidad.
Mark Storer

Respuestas:

101

Espero que la siguiente secuencia de código te ayude:

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

Si marca el siguiente método de ~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)

esto explicaría lo que hace con la rotación y la traducción.

Sudar Nimalan
fuente
1
¿Puedes hacerlo con Bitmap.createBitmap que toma una matriz? ¿Cómo calcula targetWidth y targetHeight? Disparo simple, supongo, pero ¿hay una forma "más fácil"?
Verifique la respuesta a continuación, (Lo siento, no pude agregar el código en los comentarios)
Sudar Nimalan
la calidad empeora al aplicar esto. alguna solución ?
MSaudi
1
cambiar canvas.drawBitmap (fuente, matriz, nuevo Paint ()); con canvas.drawBitmap (fuente, matriz, nueva pintura (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan
3
Solo comentando que este proceso consume mucha memoria y no debe usarse en métodos de pasos.
MLProgrammer-CiM
79

Editado : código optimizado.

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

Para obtener mapa de bits de los recursos:

Bitmap source = BitmapFactory.decodeResource(this.getResources(), R.drawable.your_img);
Arvis
fuente
Pruebe esto para rotar un mapa de bits con cualquier w o h: Matrix matrix = new Matrix (); matrix.postRotate (90); bitmapPicture = Bitmap.createBitmap (bitmapPicture, 0, 0, bitmapPicture.getWidth (), bitmapPicture.getHeight (), matriz, verdadero);
Mark Molina
Esto funcionó perfectamente para mí ya que estoy configurando los parámetros para los puntos de la imagen. Solo debe asegurarse de usar la matriz al dibujar el mapa de bits en el lienzo.
a54studio
6
¿Estás seguro de que esto es eficaz? Si RotateBitmap () estuviera en un bucle ejecutándose N veces, dependiendo de la resolución del mapa de bits, podría estar desperdiciando una enorme cantidad de memoria, así como todas esas nuevas asignaciones de objetos Matrix.
Ryhan
No probado, pero los documentos dicen: "Si el mapa de bits de origen es inmutable y el subconjunto solicitado es el mismo que el mapa de bits de origen, entonces se devuelve el mapa de bits de origen y no se crea ningún mapa de bits nuevo". En cuanto al objeto Matrix, solo está transformando la clase de coordenadas. Puede optimizar libremente el código para la repetición y utilizar el mismo objeto Matrix en bucles.
Arvis
Para su información, el mapa de bits debe ser mutable
kip2
25

Volví a este problema ahora que estamos finalizando el juego y solo pensé en publicar lo que funcionó para mí.

Este es el método para rotar la matriz:

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

(this.getCenterX() es básicamente la posición X del mapa de bits + el ancho del mapa de bits / 2)

Y el método para dibujar el mapa de bits (llamado a través de una RenderManagerclase):

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

Así que es bastante sencillo, pero me parece un poco extraño que no pude hacerlo funcionar setRotateseguido de postTranslate. ¿Quizás algunos saben por qué esto no funciona? Ahora todos los mapas de bits giran correctamente, pero no sin una pequeña disminución en la calidad del mapa de bits: /

¡De todas formas, gracias por su ayuda!

Ste
fuente
El código de respuesta anterior también funciona. con el mismo problema de calidad.
MSaudi
7

También puede rotar el 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);
Macarse
fuente
4
Estás respondiendo la pregunta incorrecta. No quiere rotar la vista, solo un mapa de bits dentro de ella.
Mark Storer
Como experimenté, el método setFillAfter (bool) no funciona como se esperaba en la API de Android lvl 11 y versiones anteriores. Por lo tanto, los desarrolladores no pueden utilizar el evento de rotación continua en los objetos de vista, ni obtienen versiones rotadas de estas vistas después de la rotación. Entonces @Mark Storer, Macarse respondió verdaderamente desde un punto de vista lógico si establece la duración de la animación con 0 o algo cercano a 0.
Gökhan Barış Aker
5

Puede usar algo como lo siguiente:


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
fuente
mismo problema para todas las soluciones: disminución de la calidad del mapa de bits
MSaudi
cambiar canvas.drawBitmap (fuente, matriz, nuevo Paint ()); con canvas.drawBitmap (fuente, matriz, nueva pintura (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan
¿Cuál es la configuración que estás usando?
Sudar Nimalan
Publiqué el código a continuación como respuesta. No pude escribirlo en el comentario. Muchas gracias señor :)
MSaudi
1

Usé estas configuraciones y todavía tengo el problema de la pixelización:

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
fuente
1
¿Podría probar setFilterBitmap, setDither opciones
Sudar Nimalan
1
Sí, esto funcionó perfectamente. Muchas gracias Sudar, realmente me ayudaste mucho.
MSaudi
1
Agregar un enlace a su propio seguimiento con el código actualizado: 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
fuente