在Android中進行圖像旋轉需要使用Matrix,它包含瞭一個3*3的矩陣,專門用於進行圖像變換匹配。Matrix ,中文裡叫矩陣,高等數學裡有介紹,在圖像處理方面,主要是用於平面的縮放、平移、旋轉等操作。Matrix沒有機構體,它必須初始化,然後通過reset方法和set方法來實現。
首先介紹一下矩陣運算。加法和減法就不用說瞭,太簡單瞭,對應位相加就好。圖像處理,主要用到的是乘法 。下面是一個乘法的公式:
在 Android 裡面, Matrix 由 9 個 float 值構成,是一個 3*3 的矩陣。如下圖。
沒專業工具,畫的挺難看。解釋一下,上面的 sinX 和 cosX ,表示旋轉角度的 cos 值和 sin 值,註意,旋轉角度是按順時針方向計算的。 translateX 和 translateY 表示 x 和 y 的平移量。 scale 是縮放的比例, 1 是不變, 2 是表示縮放 1/2,這樣子。
Matrix的操作,總共分為translate(平移),rotate(旋轉),scale(縮放)和skew(傾斜)四種,每一種變換在Android的API裡都提供瞭set,post和pre三種操作方式,除瞭translate,其他三種操作都可以指定中心點。set是直接設置Matrix的值,每次set一次,整個Matrix的數組都會變掉。
我們現在通過setRotate設置旋轉角度,用creatBitmap創建一個經過旋轉等處理的Bitmap對象,然後將Bitmap繪制到屏幕之上,於是就實現瞭旋轉操作。
下面使用一個示例來說明Matix的使用以及旋轉的方式及運行效果。
package cn.edu.pku;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
public class PictureRotateActivity extends Activity {
/** Called when the activity is first created. */
private GameRotateView1 gameview = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameview = new GameRotateView1(this);
setContentView(gameview);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if ( gameview == null )
{
return false;
}
if ( keyCode == KeyEvent.KEYCODE_BACK)
{
this.finish();
return true;
}
return gameview.onKeyDown(keyCode,event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
super.onKeyUp(keyCode, event);
return true;
}
}
package cn.edu.pku;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
public class PictureRotateActivity extends Activity {
/** Called when the activity is first created. */
private GameRotateView1 gameview = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameview = new GameRotateView1(this);
setContentView(gameview);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if ( gameview == null )
{
return false;
}
if ( keyCode == KeyEvent.KEYCODE_BACK)
{
this.finish();
return true;
}
return gameview.onKeyDown(keyCode,event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
super.onKeyUp(keyCode, event);
return true;
}
}
具體圖像旋轉處理代碼如下:
[java] package cn.edu.pku;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
public class GameRotateView1 extends View implements Runnable {
Bitmap bitmap = null;
int bitmapWidth = 0;
int bitmapHeight = 0;
float angle = 0.0f;
Matrix matrix = new Matrix();
public GameRotateView1(Context context) {
super(context);
// TODO Auto-generated constructor stub
setFocusableInTouchMode(true); //設置可以捕捉鍵盤事件
//獲取圖像資源
bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.cute)).getBitmap();
bitmapWidth = bitmap.getWidth();
bitmapHeight = bitmap.getHeight();
new Thread(this).start();
}
public void run() {
// TODO Auto-generated method stub
while(!Thread.currentThread().isInterrupted()){
try{
Thread.sleep(100);
}catch (InterruptedException e) {
// TODO: handle exception
Thread.currentThread().interrupt();
}
postInvalidate(); //可以直接在線程中更新界面
}
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
matrix.reset();
matrix.setRotate(angle); //設置旋轉
//按照matrix的旋轉構建新的Bitmap
Bitmap bitmapcute = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, true);
//繪制旋轉之後的圖像 www.aiwalls.com
GameRotateView1.DrawImage(canvas, bitmapcute, (320 – bitmapWidth)/2, 10);
bitmapcute = null;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
angle–;
}else if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
angle++;
}
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
// TODO Auto-generated method stub
return true;
}
/**
* 繪制一個Bitmap
* canvas 畫佈
* bitmap 圖片
* x 屏幕上的x坐標
* y 屏幕上的y坐標
*/
public static void DrawImage(Canvas canvas, Bitmap _bitmap, int x, int y)
{
/* 繪制圖像 */
canvas.drawBitmap(_bitmap, x, y, null);
}
package cn.edu.pku;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
public class GameRotateView1 extends View implements Runnable {
Bitmap bitmap = null;
int bitmapWidth = 0;
int bitmapHeight = 0;
float angle = 0.0f;
Matrix matrix = new Matrix();
public GameRotateView1(Context context) {
super(context);
// TODO Auto-generated constructor stub
setFocusableInTouchMode(true); //設置可以捕捉鍵盤事件
//獲取圖像資源
bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.cute)).getBitmap();
bitmapWidth = bitmap.getWidth();
bitmapHeight = bitmap.getHeight();
new Thread(this).start();
}
public void run() {
// TODO Auto-generated method stub
while(!Thread.currentThread().isInterrupted()){
try{
Thread.sleep(100);
}catch (InterruptedException e) {
// TODO: handle exception
Thread.currentThread().interrupt();
}
postInvalidate(); //可以直接在線程中更新界面
}
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
matrix.reset();
matrix.setRotate(angle); //設置旋轉
//按照matrix的旋轉構建新的Bitmap
Bitmap bitmapcute = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, true);
//繪制旋轉之後的圖像
GameRotateView1.DrawImage(canvas, bitmapcute, (320 – bitmapWidth)/2, 10);
bitmapcute = null;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
angle–;
}else if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
angle++;
}
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
// TODO Auto-generated method stub
return true;
}
/**
* 繪制一個Bitmap
* canvas 畫佈
* bitmap 圖片
* x 屏幕上的x坐標
* y 屏幕上的y坐標
*/
public static void DrawImage(Canvas canvas, Bitmap _bitmap, int x, int y)
{
/* 繪制圖像 */
canvas.drawBitmap(_bitmap, x, y, null);
}
最後我們通過鍵盤的左右鍵可以實現圖像的選裝,在這裡實現的圖像的右旋轉:
摘自 北京大學-Google Android實驗室