studio - Escala y rota el mapa de bits usando Matrix en Android
canvas android (6)
Consulte el siguiente código, parece funcionar. En tu código estás definiendo Matrix como m pero refiriéndote a él como matriz
public class FourthActivity extends Activity {
private static final int WIDTH = 50;
private static final int HEIGHT = 50;
private static final int STRIDE = 64;
private static int[] createColors() {
int[] colors = new int[STRIDE * HEIGHT];
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int r = x * 255 / (WIDTH - 1);
int g = y * 255 / (HEIGHT - 1);
int b = 255 - Math.min(r, g);
int a = Math.max(r, g);
colors[y * STRIDE + x] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
return colors;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
final ImageView view1 = (ImageView) findViewById(R.id.imageView1);
int[] colors = createColors();
final Bitmap bmp1 = Bitmap.createBitmap(colors, 0, STRIDE, WIDTH, HEIGHT,
Bitmap.Config.ARGB_8888);
view1.setImageBitmap(bmp1);
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Matrix matrix = new Matrix();
matrix.setScale(2, 2);
matrix.preRotate(45, (float) WIDTH / 2, (float) HEIGHT / 2);
Bitmap bmp2 = Bitmap.createBitmap(bmp1, 0, 0,
bmp1.getWidth(), bmp1.getHeight(), matrix, true);
ImageView view2 = (ImageView) findViewById(R.id.imageView2);
view2.setImageBitmap(bmp2);
}
});
}
}
Estoy tratando de escalar y rotar en una sola operación antes de crear el mapa de bits final, pero la función PreRotate, postConcat no parece funcionar.
Bitmap bmp = ... original image ...
Matrix m = new Matrix()
m.setScale(x, y);
m.preRotate(degrees, (float) width / 2, (float) height / 2);
Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);
Solo aplica la escala y no la rotación.
El lienzo sostiene una pila de matriz y puedes usarlo con los métodos:
Canvas.save ()
Doc: / ** * Guarda la matriz actual y el clip en una pila privada. *
* Las llamadas subsiguientes para traducir, escalar, rotar, sesgar, concat o clipRect, * clipPath funcionarán como siempre, pero cuando se realice la llamada de balance a * restore (), esas llamadas se olvidarán, y las configuraciones que * existieron antes El guardar () será restablecido. * * @return El valor para pasar a restoreToCount () para equilibrar este guardar () * /
Canvas.restore ()
Doc: / ** * Esta llamada equilibra una llamada anterior a save (), y se usa para eliminar todas las modificaciones * del estado de la matriz / clip desde la última llamada guardada. Es * un error llamar a restore () más veces que a save (). * /
Ejemplo: una vista personalizada (Android) que se parece a un botón giratorio (por ejemplo, un potenciómetro)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewX = getWidth(); //views width
viewY = getHeight(); //views height
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); //a must call for every custom view
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
double tempAngel = 3.6 * barValue;
int deltaX = bitmap.getWidth() / 2;
int deltaY = bitmap.getHeight() / 2;
...
canvas.save();
canvas.translate(viewX / 2, viewY / 2); //translate drawing point to center
canvas.rotate((float) tempAngel); //rotate matrix
canvas.save(); //save matrix. your drawing point is still at (viewX / 2, viewY / 2)
canvas.translate(deltaX * -1, deltaY * -1); //translate drawing point a bit up and left to draw the bitmap in the middle
canvas.drawBitmap(bitmap, 0,0, bitmapPaint); // draw bitmap to the tranlated point at 0,0
canvas.restore(); //must calls...
canvas.restore();
}
La respuesta fue dada, pero para aclarar las cosas a cualquiera que lea esto:
1) Si desea realizar UNA transformación en su mapa de bits, PUEDE usar SET (setRotate, setScale, etc.).
Pero tenga en cuenta que cualquier llamada a un método "conjunto" ANULA otras transformaciones. Es como una nueva matriz. Es por eso que la rotación de OP no estaba funcionando. Estas llamadas no se realizan línea por línea. Es como si estuvieran programados para ser ejecutados en tiempo de ejecución por la GPU cuando se está dibujando el nuevo mapa de bits. Es como cuando resolvemos su matriz, la GPU la giró, pero luego creó una nueva escalada, ignorando la matriz anterior.
2) Si desea realizar más de una transformación, DEBE utilizar los métodos "pre" o "post".
¿Y cuál es la diferencia entre un postRotate y un preRotate, por ejemplo? Bueno, esta matriz matemática no es mi fortaleza, pero lo que sé es que las tarjetas gráficas hacen estas transformaciones utilizando la multiplicación de matrices. Parece ser mucho más eficiente. Y por lo que recuerdo de la escuela, al multiplicar matrices el orden ES importante. AXB! = BX A. Entonces, escalar una matriz y luego rotarla es diferente de rotar y luego escalarla.
BUUUUT, en la medida en que el resultado final en la pantalla es el mismo, nosotros, los programadores de alto nivel, generalmente no necesitamos conocer estas diferencias. La GPU lo hace.
Bueno, en los raros casos en los que estás realizando operaciones de matriz realmente complicadas, y los resultados no son los que esperabas o el rendimiento es terrible y necesitas comprender profundamente estos métodos para corregir tu código, bueno, entonces la documentación de Android no puede ser de mucha utilidad. ayuda de todos modos En cambio, un buen libro de Álgebra Lineal sería tu mejor amigo. ;)
Por favor revise este enlace para más detalles.
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html
Este es el código
public class Bitmaptest extends Activity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout linLayout = new LinearLayout(this);
// load the origial BitMap (500 x 500 px)
Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
R.drawable.android);
int width = bitmapOrg.getWidth();
int height = bitmapOrg.getHeight();
int newWidth = 200;
int newHeight = 200;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
matrix.postRotate(45);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
newWidth, newHeight, matrix, true);
// make a Drawable from Bitmap to allow to set the BitMap
// to the ImageView, ImageButton or what ever
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
ImageView imageView = new ImageView(this);
// set the Drawable on the ImageView
imageView.setImageDrawable(bmd);
// center the Image
imageView.setScaleType(ScaleType.CENTER);
// add ImageView to the Layout
linLayout.addView(imageView,
new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT
)
);
// set LinearLayout as ContentView
setContentView(linLayout);
}
}
Si enfrenta el problema de OutOfMemory con las respuestas anteriores, entonces use a continuación:
Bitmap MyFinalBitmap = Bitmap.createBitmap(CurrentBitmap, 0, 0,CurrentBitmap.getWidth()/2, CurrentBitmap.getHeight()/2,matrix, true);
Todas las respuestas anteriores suponen que este cambio al mapa de bits se está realizando en una vista. Sin embargo, en mi caso estaba haciendo el cambio para ser guardado. Pensé que respondería por aquellos en un barco similar.
Hay dos formas de hacer la traducción. Debajo de dx
está la traducción en el eje X, y dy
es la traducción en el eje Y. Las otras variables deben ser auto explicativas.
1 - Traducción dentro de la imagen (sin rotación).
val newBitmap = Bitmap.createBitmap(originalBitmap, dx, dy, newWidth, newHeight, matrix, false)
2 - Matriz compleja
matrix.postTranslate(dx, dy)
val newBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(newBitmap)
canvas.drawBitmap(originalBitmap, matrix, null)