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? :)


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.


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

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!


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

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


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

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); 
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.