Android development-image operations using Matrix,
Today, I would like to share with you the simple usage of Matrix in Android. Matrix is actually a 3*3 Matrix, which is used to operate images. In Android, some encapsulated methods can be used for some simple image operations, which can be divided into rotate, scale, translate, and skew) four, each of which provides three operations: set, post, and pre. Except for translate, the center point can be specified for all the other three operations. The post method is post multiplication of the original matrix, and the pre method is forward multiplication of the original matrix,In addition, each call through the set method will perform a reset, and the previous operations will be destroyed. Pay attention to the changes in the combination.
Rotation operation
There are 6 methods related to the rotation operation in Matrix,
public boolean preRotate (float degrees)public boolean preRotate (float degrees, float px, float py)public boolean postRotate (float degrees)public boolean postRotate (float degrees, float px, float py)public void setRotate (float degrees)public void setRotate (float degrees, float px, float py)
The degrees parameter specifies the rotation angle. If it is greater than zero, it is clockwise. If it is less than zero, it is counterclockwise. The px parameter and py parameter are used to specify the center of rotation. The default value is (0, 0), that is, the upper left corner.
Scaling operation
There are 6 methods related to the scaling operation in Matrix,
public boolean postScale (float sx, float sy)public boolean postScale (float sx, float sy, float px, float py)public boolean preScale (float sx, float sy)public boolean preScale (float sx, float sy, float px, float py)public void setScale (float sx, float sy)public void setScale (float sx, float sy, float px, float py)
Here, the sx and sy parameters indicate the tensile variation of the X axis and Y axis respectively. If the value is greater than 1, the extension is used. If the value is smaller than 1, the extension is used, if it is a negative value, it indicates a symmetric change (we will use it in subsequent combination changes to achieve the mirror and reflection effect). The px parameter, py is used to specify the center of the scaling (that is, the coordinates of the position of the point will not change after the scaling changes). The default value is (0, 0), that is, the upper left corner.
Translation operation
There are three translation methods in Matrix.
public boolean postTranslate (float dx, float dy)public boolean preTranslate (float dx, float dy)public void setTranslate (float dx, float dy)
The dx parameter, dy indicates the translation distance, dx greater than zero indicates the right, less than zero indicates the left, dy greater than zero indicates the downward, less than zero indicates the upward.
Tilt operation
There are 6 methods for Skewed operations in Matrix.
public boolean postSkew (float kx, float ky)public boolean postSkew (float kx, float ky, float px, float py)public boolean preSkew (float kx, float ky)public boolean preSkew (float kx, float ky, float px, float py)public void setSkew (float kx, float ky)public void setSkew (float kx, float ky, float px, float py)
After the point (x, y) is transformed by skew (kx, ky, px, py), the coordinates are (kx * (y-py) + px, ky * (x-px) + py). If px and py do not exist, the default value is 0.
Combination change
1. image changes: For scale changes, if a negative number is scaled, the image will be drawn to the negative space of the coordinate system. Because (0, 0) points are in the upper left corner, using a negative number on the X axis will cause the image to be drawn to the left. Therefore, we need to use the postTranslate method to move the image to the Right to achieve image changes.
matrix.setScale(-1, 1);matrix.postTranslate(mBitmap.getWidth(),0);
2. Reflection changes: if the image changes, we can do the same thing on the Y axis to get the reflection effect.
matrix.postScale(1, -1);matrix.postTranslate(0, mBitmap.getHeight());
Sample Code
Based on the above Matrix operations, I made a small experiment with the following results:
MainActivity class:
package com.example.matrixtest;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;public class MainActivity extends Activity { private TestView testView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); testView = (TestView) findViewById(R.id.testview); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ttt); testView.setmBitmap(bitmap); ((Button) findViewById(R.id.button_rotate)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub testView.rotate(15); } }); ((Button) findViewById(R.id.button_scale)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub testView.scale(0.8f, 0.8f); } }); ((Button) findViewById(R.id.button_translate)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub testView.translate(1, 1); } }); ((Button) findViewById(R.id.button_skew)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub testView.skew(-0.3f, 0.3f); } }); ((Button) findViewById(R.id.button_mirror)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub testView.mirror(); } }); ((Button) findViewById(R.id.button_shadow)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub testView.shadow(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; }}
TestView class. I wrote a new View to draw an image:
package com.example.matrixtest;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Matrix;import android.util.AttributeSet;import android.view.View;public class TestView extends View { private Bitmap mBitmap; private Matrix matrix; public TestView(Context context) { super(context); // TODO Auto-generated constructor stub matrix = new Matrix(); } public TestView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub matrix = new Matrix(); } public TestView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub matrix = new Matrix(); } public Bitmap getmBitmap() { return mBitmap; } public void setmBitmap(Bitmap mBitmap) { this.mBitmap = mBitmap; invalidate(); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); if (mBitmap != null) { canvas.drawBitmap(mBitmap, matrix, null); } } public void rotate(float degree) { if (mBitmap != null) { matrix.preRotate(degree, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2); invalidate(); } } public void translate(float dx, float dy) { if (mBitmap != null) { matrix.postTranslate(dx, dy); invalidate(); } } public void scale(float sx, float sy) { if (mBitmap != null) { matrix.postScale(sx, sy); invalidate(); } } public void mirror() { if (mBitmap != null) { matrix.postScale(-1, 1); matrix.postTranslate(mBitmap.getWidth(), 0); invalidate(); } } public void shadow() { if (mBitmap != null) { matrix.postScale(1, -1); matrix.postTranslate(0, mBitmap.getHeight()); invalidate(); } } public void skew(float kx, float ky){ if (mBitmap != null) { matrix.postSkew(kx, ky); invalidate(); } }}
Click to download source code