Android图像处理之图形特效处理

努力尽今夕,少年犹可夸。这篇文章主要讲述Android图像处理之图形特效处理相关的知识,希望能为你提供帮助。
一、android变形矩阵——Matricx:跟Android图像的色彩处理基本一样,只是将ColorMatrix换成了Matrix,ColorMatrix是4*5的矩阵,Matrix是3*3的。每个像素点表达了其坐标的X、Y信息:

Android图像处理之图形特效处理

文章图片

【Android图像处理之图形特效处理】 

当使用变换矩阵去处理每一个像素点的时候,与颜色矩阵的矩阵乘法一样,计算公式如下所示:

Android图像处理之图形特效处理

文章图片




通常情况下,会让g=h=0,i=1,这样就使1=gX+hY+i      恒成立。因此,只需着重关注上面几个参数即可。
与色彩变换矩阵的初始矩阵一样,图形变换矩阵也有一个初始矩阵。就是对角线元素a、e、i为1,其他元素为0的矩阵,如下图所示:
Android图像处理之图形特效处理

文章图片

 

图像的变形处理通常包含以下四类基本变换:
 
  • Translate——平移变换
  • Rotate——旋转变换
  • Scale——缩放变换
  • Skew——错切变换
1、平移变换
平移变换的坐标值变换过程就是将每个像素点都进行平移变换,当从P(x0,y0)平移到P(x1,y1)时,所需的平移矩阵如下所示:
Android图像处理之图形特效处理

文章图片

2、旋转变换
旋转变换即指一个点围绕一个中心旋转到一个新的点。当从P(x0,y0)点,以坐标原点O为旋转中心旋转到P(x1,y1)时,可以将点的坐标都表达成OP与X轴正方向夹角的函数表达式(其中r为线段OP的长度,α为OP(x0,y0)与X轴正方向夹角,θ为OP(x0,y0)与OP(x1,y1)之间夹角),如下所示:
x0=rcosα
y0=rsinα
x1=rcos(α+θ)=rcosαcosθ?rsinαsinθ=x0cosθ?y0sinθ
y1=rsin(α+θ)=rsinαcosθ+rcosαsinθ=y0cosθ+x0sinθ
矩阵形式如下图所示:
Android图像处理之图形特效处理

文章图片


前面是以坐标原点为旋转中心的旋转变换,如果以任意点O为旋转中心来进行旋转变换,通常需要以下三个步骤:
 
  • 将坐标原点平移到O点
  • 使用前面讲的以坐标原点为中心的旋转方法进行旋转变换
  • 将坐标原点还原
3、缩放变换
一个像素点是不存在缩放的概念的,但是由于图像是由很多个像素点组成的,如果将每个点的坐标都进行相同比例的缩放,最终就会形成让整个图像缩放的效果,缩放效果的公式如下
x1=K1x0
y1=K2y0
矩阵形式如下图所示:
Android图像处理之图形特效处理

文章图片

4、错切变换
错切变换(skew)在数学上又称为Shear mapping(可译为“剪切变换“)或者Transvection(缩并),它是一种比较特殊的线性变换。错切变换的效果就是让所有点的X坐标(或者Y坐标)保持不变,而对应的Y坐标(或者X坐标)则按比例发生平移,且平移的大小和该点到Y轴(或者X轴)的距离成正比。错切变换通常包含两种——水平错切与垂直错切。
错切变换的计算公式如下:
  • 水平错切
x1=x0+K1y0
y1=y0
  • 垂直错切
x1=x0
y1=K2x0+y0
矩阵形式如下图
Android图像处理之图形特效处理

文章图片

 
由上面的分析可以发现,这个图形变换3x3的矩阵与色彩变换矩阵一样,每个位置的元素所表示的功能是有规律的,总结如下:板面
Android图像处理之图形特效处理

文章图片


可以发现,a、b、c、d、e、f这六个矩阵元素分别对应以下变换:
 
  • a和e控制Scale——缩放变换
  • b和d控制Skew——错切变换
  • a和e控制Trans——平移变换
  • a、b、d、e共同控制Rotate——旋转变换
通过类似色彩矩阵中模拟矩阵的例子来模拟变形矩阵。在图形变换矩阵中,同样是通过一个一维数组来模拟矩阵,并通过setValues()方法将一个一维数组转换为图形变换矩阵,代码如下所示:
private float[] mImageMatrix = new float[9]; Matrix matrix = new Matrix(); matrix.setValues(mImageMatrix);

  当获得了变换矩阵后,就可以通过以下代码将一个图像以这个变换矩阵的形式绘制出来。
canvas.drawBitmap(mBitmap, mMatrix, null);

  示例代码:
activity:
 
[java] view plain copy print?
  1. package  com.example.androidmatrix;    
  2.    
  3. import  android.app.Activity;    
  4. import  android.graphics.Bitmap;    
  5. import  android.graphics.Bitmap.Config;    
  6. import  android.graphics.BitmapFactory;    
  7. import  android.graphics.Canvas;    
  8. import  android.graphics.Matrix;    
  9. import  android.os.Bundle;    
  10. import  android.view.View;    
  11. import  android.widget.EditText;    
  12. import  android.widget.GridLayout;    
  13. import  android.widget.ImageView;    
  14.    
  15. public  class  TestMatrixActivity  extends  Activity  {   
  16.         //定义组件   
  17.         private  ImageView  imageView;    
  18.         private  GridLayout  group;    
  19.            
  20.         private  Bitmap  bitmap;    
  21.         private  EditText[]  edits  =  new  EditText[9];    
  22.         private  float[]  edittexts  =  new  float[9];    
  23.         protected  void  onCreate(Bundle  savedInstanceState)  {   
  24.                 super.onCreate(savedInstanceState);    
  25.                 setContentView(R.layout.testmatrix);    
  26.                    
  27.                 imageView  =  (ImageView)  findViewById(R.id.imageView);    
  28.                 group  =  (GridLayout)  findViewById(R.id.group);    
  29.                    
  30.                 bitmap  =  BitmapFactory.decodeResource(getResources(),  R.drawable.ic_launcher);    
  31.                 imageView.setImageBitmap(bitmap);    
  32.                    
  33.                 group.post(new  Runnable()  {   
  34.                         public  void  run()  {   
  35.                                 setNineEdits();    
  36.                                 fillNineEdits();    
  37.                         }   
  38.                 });    
  39.         }   
  40.            
  41.         //创建9个编辑框   
  42.         private  void  setNineEdits(){   
  43.                 int  width  =  group.getWidth();    
  44.                 int  height  =  group.getHeight();    
  45.                 for  (int  i  =  0;   i  <   edits.length;   i++)  {   
  46.                         edits[i]  =  new  EditText(TestMatrixActivity.this);    
  47.                         edits[i].setWidth(width  /  3);    
  48.                         edits[i].setHeight(height  /  3);    
  49.                         group.addView(edits[i]);    
  50.                 }   
  51.         }   
  52.         //给九个编辑框赋值   
  53.         private  void  fillNineEdits(){   
  54.                 for  (int  i  =  0;   i  <   edits.length;   i++)  {   
  55.                         if(i  %  4  ==  0){   
  56.                                 edits[i].setText(String.valueOf(1));    
  57.                         }else{   
  58.                                 edits[i].setText(String.valueOf(0));    
  59.                         }   
  60.                 }   
  61.         }   
  62.            
  63.         //重新获取九个编辑框的值   
  64.         private  void  getNineEdits(){   
  65.                 for  (int  i  =  0;   i  <   edits.length;   i++)  {   
  66.                         edittexts[i]  =  Float.valueOf(edits[i].getText().toString().trim());    
  67.                 }   
  68.         }   
  69.            
  70.         private  void  change(){   
  71.                 Matrix  matrix  =  new  Matrix();    
  72.                 Bitmap  bmp  =  Bitmap.createBitmap(bitmap.getWidth(),  bitmap.getHeight(),  Config.ARGB_8888);    
  73.                 matrix.setValues(edittexts);    
  74.                 Canvas  canvas  =  new  Canvas(bmp);    
  75.                 canvas.drawBitmap(bitmap,  matrix,  null);    
  76.                 imageView.setImageBitmap(bmp);    
  77.         }   
  78.            
  79.         public  void  onChange(View  view){   
  80.                 getNineEdits();    
  81.                 change();    
  82.         }   
  83.            
  84.         public  void  onReset(View  view){   
  85.                 fillNineEdits();    
  86.                 change();    
  87.         }   
  88. }   
package com.example.androidmatrix; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.GridLayout; import android.widget.ImageView; public class TestMatrixActivity extends Activity { //定义组件 private ImageView imageView; private GridLayout group; private Bitmap bitmap; private EditText[] edits = new EditText[9]; private float[] edittexts = new float[9]; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.testmatrix); imageView = (ImageView) findViewById(R.id.imageView); group = (GridLayout) findViewById(R.id.group); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); imageView.setImageBitmap(bitmap); group.post(new Runnable() { public void run() { setNineEdits(); fillNineEdits(); } }); } //创建9个编辑框 private void setNineEdits(){ int width = group.getWidth(); int height = group.getHeight(); for (int i = 0; i < edits.length; i++) { edits[i] = new EditText(TestMatrixActivity.this); edits[i].setWidth(width / 3); edits[i].setHeight(height / 3); group.addView(edits[i]); } } //给九个编辑框赋值 private void fillNineEdits(){ for (int i = 0; i < edits.length; i++) { if(i % 4 == 0){ edits[i].setText(String.valueOf(1)); }else{ edits[i].setText(String.valueOf(0)); } } } //重新获取九个编辑框的值 private void getNineEdits(){ for (int i = 0; i < edits.length; i++) { edittexts[i] = Float.valueOf(edits[i].getText().toString().trim()); } } private void change(){ Matrix matrix = new Matrix(); Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); matrix.setValues(edittexts); Canvas canvas = new Canvas(bmp); canvas.drawBitmap(bitmap, matrix, null); imageView.setImageBitmap(bmp); } public void onChange(View view){ getNineEdits(); change(); } public void onReset(View view){ fillNineEdits(); change(); } }


界面:
 
 
[html] view plain copy print?
  1. < ?xml  version="1.0"  encoding="utf-8"?>    
  2. < LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"   
  3.         android:layout_width="match_parent"   
  4.         android:layout_height="match_parent"   
  5.         android:orientation="vertical"  >    
  6.    
  7.         < ImageView   
  8.                 android:id="@+id/imageView"   
  9.                 android:layout_width="fill_parent"   
  10.                 android:layout_height="0dp"   
  11.                 android:layout_weight="2"  />    
  12.    
  13.         < GridLayout   
  14.                 android:id="@+id/group"   
  15.                 android:layout_width="match_parent"   
  16.                 android:layout_height="200dp"   
  17.                 android:layout_weight="3"   
  18.                 android:columnCount="3"   
  19.                 android:rowCount="3"  >    
  20.         < /GridLayout>    
  21.    
  22.         < LinearLayout   
  23.                 android:layout_width="match_parent"   
  24.                 android:layout_height="wrap_content"   
  25.                 android:orientation="horizontal"  >    
  26.    
  27.                 < Button   
  28.                         android:layout_width="wrap_content"   
  29.                         android:layout_height="wrap_content"   
  30.                         android:layout_weight="1"   
  31.                         android:onClick="onChange"   
  32.                         android:text="生效"  />    
  33.    
  34.                 < Button   
  35.                         android:layout_width="wrap_content"   
  36.                         android:layout_height="wrap_content"   
  37.                         android:layout_weight="1"   
  38.                         android:onClick="onReset"   
  39.                         android:text="重置"  />    
  40.         < /LinearLayout>    
  41.    
  42. < /LinearLayout>    
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > < ImageView android:id="@+id/imageView" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="2" /> < GridLayout android:id="@+id/group" android:layout_width="match_parent" android:layout_height="200dp" android:layout_weight="3" android:columnCount="3" android:rowCount="3" > < /GridLayout> < LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > < Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onChange" android:text="生效" /> < Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onReset" android:text="重置" /> < /LinearLayout> < /LinearLayout>

 
 
效果图:
Android图像处理之图形特效处理

文章图片
Android图像处理之图形特效处理

文章图片

Android系统同样提供了一些API来简化矩阵的运算,我们不必每次都去设置矩阵的每一个元素值。Android中使用Matrix类来封装矩阵,并提供了以下几个操作方法来实现上面的四中变换方式:
  • matrix.setRotate()——旋转变换
  • matrix.setTranslate()——平移变换
  • matrix.setScale()——缩放变换
  • matrix.setSkew()——错切变换
  • matrix.preX和matrix.postY——提供矩阵的前乘和后乘运算
Matrix类的set方法会重置矩阵中的值,而post和pre方法不会,这两个方法常用来实现矩阵的混合作用。不过要注意的是,矩阵运算不满足乘法的交换律,所以矩阵乘法的前乘和后乘是两种不同的运算方式。举例说明,比如需要实现以下效果:
  • 先旋转45度
  • 再平移到(200, 200)
如果使用后乘运算,表示当前矩阵乘上参数代表的矩阵,代码如下所示:
matrix.setRotate(45); matrix.postTranslate(200, 200);

Android图像处理之图形特效处理

文章图片
如果使用前乘运算,表示参数代表的矩阵乘上当前矩阵,代码如下所示:
matrix.setTranslate(200, 200); matrix.preRotate(45);

Android图像处理之图形特效处理

文章图片
示例代码:界面代码(就一个ImageView)省略...
 
[java] view plain copy print?
  1. private  ImageView  imageView;    
  2.         private  Bitmap  bitmap;    
  3.         protected  void  onCreate(Bundle  savedInstanceState)  {   
  4.                 super.onCreate(savedInstanceState);    
  5.                 setContentView(R.layout.testmatrixmethod);    
  6.                    
  7.                 imageView  =  (ImageView)  findViewById(R.id.imageView);    
  8.                    
  9.                 bitmap  =  BitmapFactory.decodeResource(getResources(),  R.drawable.ic_launcher);    
  10.                 imageView.setImageBitmap(changeImage());    
  11.         }   
  12.            
  13.         private  Bitmap  changeImage(){   
  14.    
  15.                 Bitmap  bmp  =  Bitmap.createBitmap(bitmap.getWidth(),  bitmap.getHeight(),  Config.ARGB_8888);    
  16.                 Matrix  matrix  =  new  Matrix();    
  17.                 //旋转变换,参数是顺时针旋转角度   
  18.                 matrix.setRotate(45);    
  19.                 //平移变化,参数是要平移到的坐标   
  20.                 //matrix.setTranslate(50,  50);    
  21.                 //缩放变化   
  22.                 //matrix.setScale(10,  10,  10,  10);    
  23.                 //错切变换   
  24.                 //matrix.setSkew(10,  10,  10,  10);    
  25.                 Canvas  canvas  =  new  Canvas(bmp);    
  26.                 canvas.drawBitmap(bitmap,  matrix,  null);    
  27.                 return  bmp;    
  28.         }   
private ImageView imageView; private Bitmap bitmap; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.testmatrixmethod); imageView = (ImageView) findViewById(R.id.imageView); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); imageView.setImageBitmap(changeImage()); } private Bitmap changeImage(){Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); Matrix matrix = new Matrix(); //旋转变换,参数是顺时针旋转角度 matrix.setRotate(45); //平移变化,参数是要平移到的坐标 //matrix.setTranslate(50, 50); //缩放变化 //matrix.setScale(10, 10, 10, 10); //错切变换 //matrix.setSkew(10, 10, 10, 10); Canvas canvas = new Canvas(bmp); canvas.drawBitmap(bitmap, matrix, null); return bmp; }


效果图:
 
Android图像处理之图形特效处理

文章图片

 
二、像素块分析图像的特效处理有两种方式,即使用矩阵来进行图像变换和使用drawBitmapMesh()方法来进行处理。drawBitmapMesh()与操纵像素点来改变色彩的原理类似,只不过是把图像分成了一个个的小块,然后通过改变每一个图像块来修改整个图像。
drawBitmapMesh()方法代码如下:
public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint)

Android图像处理之图形特效处理

文章图片
关键的参数如下:
                      bitmap:将要扭曲的图像
                      meshWidth:需要的横向网格数目
                      meshHeight :需要的纵向网格数目
                      verts:网格交叉点坐标数组
                      vertOffset:verts数组中开始跳过的(x, y)坐标对的数目
要使用drawBitmapMesh()方法就需先将图片分割为若干个图像块。所以,在图像上横纵各画N条线,而这横纵各N条线就交织成了NxN个点,而每个点的坐标则以x1,y1,x2,y2,...,xn,yn的形式保存在verts数组中。也就是说verts数组的每两位用来保存一个交织点,第一个是横坐标,第二个是纵坐标。而整个drawBitmapMesh()方法改变图像的方式,就是靠这些坐标值的改变来重新定义每一个图像块,从而达到图像效果处理的功能。
drawBitmapMesh()方法的功能非常强大,基本上可以实现所有的图像特效,但使用起来也非常复杂,其关键就是在于计算、确定新的交叉点的坐标。下面举例说明如何使用drawBitmapMesh()方法来实现一个旗帜飞扬的效果。
要想达到旗帜飞扬的效果,只需要让图片中每个交叉点的横坐标较之前不发生变化,而纵坐标较之前坐标呈现一个三角函数的周期性变化即可。
首先获取交叉点的坐标,并将坐标保存到orig数组中,其获取交叉点坐标的原理就是通过循环遍历所有的交叉线,并按比例获取其坐标,代码如下所示:
mBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.test); float bitmapWidth = mBitmap.getWidth(); float bitmapHeight = mBitmap.getHeight(); int index = 0; for (int y = 0; y < = HEIGHT ; y++) { float fy = bitmapHeight * y / HEIGHT; for (int x = 0; x < = WIDTH; x++) { float fx = bitmapWidth * x / WIDTH; orig[index * 2] = verts[ index * 2] = fx; //这里人为将坐标+100是为了让图像下移,避免扭曲后被屏幕遮挡 orig[index * 2 + 1] = verts[ index * 2 + 1] = fy + 100; index++; } }

Android图像处理之图形特效处理

文章图片
接下来,在onDraw()方法中改变交叉点的纵坐标的值,为了实现旗帜飘扬的效果,使用一个正弦函数sinx来改变交叉点纵坐标的值,而横坐标不变,并将变化后的值保存到verts数组中,代码如下所示:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); flagWave(); K += 0.1f; //将K的值增加 canvas.drawBitmapMesh(mBitmap, WIDTH, HEIGHT, verts, 0, null, 0, null); invalidate(); }/** * 按当前点所在的横坐标的位置来确定纵坐标的偏移量,其中A代表正弦函数中的振幅大小 */ private void flagWave() { for (int j = 0; j < = HEIGHT; j++) { for (int i = 0; i < = WIDTH; i++) { //在获取纵坐标的偏移量时,利用正弦函数的周期性给函数增加一个周期K * Math.PI,就是为了让图像能够动起来 float offsetY = (float) Math.sin(2 * Math.PI * i / WIDTH + K * Math.PI); verts[(j * (WIDTH + 1) + i) * 2 + 1] = orig[(j * (WIDTH + 1) + i) * 2 + 1] + offsetY * A; } } }

Android图像处理之图形特效处理

文章图片
这样,每次在重绘时,通过改变相位来改变偏移量,从而造成一个动态的效果,就好象旗帜在风中飘扬一样,效果图如下(这里应该是动态的,似乎一个飘扬的旗帜)。
Android图像处理之图形特效处理

文章图片

 
主要代码:
 
[java] view plain copy print?
  1. package  com.mfc.myview;    
  2.    
  3. import  android.content.Context;    
  4. import  android.graphics.Bitmap;    
  5. import  android.graphics.BitmapFactory;    
  6. import  android.graphics.Canvas;    
  7. import  android.util.AttributeSet;    
  8. import  android.view.View;    
  9.    
  10. import  com.example.androidmatrix.R;    
  11.    
  12. public  class  FlagBitmapMeshView  extends  View  {   
  13.    
  14.         private  final  int  WIDTH  =  200;    
  15.         private  final  int  HEIGHT  =  200;    
  16.         private  int  COUNT  =  (WIDTH  +  1)  *  (HEIGHT  +  1);    
  17.         private  float[]  verts  =  new  float[COUNT  *  2];    
  18.         private  float[]  orig  =  new  float[COUNT  *  2];    
  19.         private  Bitmap  bitmap;    
  20.         private  float  A;    
  21.         private  float  k  =  1;    
  22.    
  23.         public  FlagBitmapMeshView(Context  context)  {   
  24.                 super(context);    
  25.                 initView(context);    
  26.         }   
  27.    
  28.         public  FlagBitmapMeshView(Context  context,  AttributeSet  attrs)  {   
  29.                 super(context,  attrs);    
  30.                 initView(context);    
  31.         }   
  32.    
  33.         public  FlagBitmapMeshView(Context  context,  AttributeSet  attrs,   
  34.                                                             int  defStyleAttr)  {   
  35.                 super(context,  attrs,  defStyleAttr);    
  36.                 initView(context);    
  37.         }   
  38.    
  39.         private  void  initView(Context  context)  {   
  40.                 setFocusable(true);    
  41.                 bitmap  =  BitmapFactory.decodeResource(context.getResources(),   
  42.                                 R.drawable.we);    
  43.                 float  bitmapWidth  =  bitmap.getWidth();    
  44.                 float  bitmapHeight  =  bitmap.getHeight();    
  45.                 int  index  =  0;    
  46.                 for  (int  y  =  0;   y  < =  HEIGHT;   y++)  {   
  47.                         float  fy  =  bitmapHeight  *  y  /  HEIGHT;    
  48.                         for  (int  x  =  0;   x  < =  WIDTH;   x++)  {   
  49.                                 float  fx  =  bitmapWidth  *  x  /  WIDTH;    
  50.                                 orig[index  *  2  +  0]  =  verts[index  *  2  +  0]  =  fx;    
  51.                                 orig[index  *  2  +  1]  =  verts[index  *  2  +  1]  =  fy  +  100;    
  52.                                 index  +=  1;    
  53.                         }   
  54.                 }   
  55.                 A  =  50;    
  56.         }   
  57.    
  58.         @Override   
  59.         protected  void  onDraw(Canvas  canvas)  {   
  60.                 flagWave();    
  61.                 k  +=  0.1F;    
  62.                 canvas.drawBitmapMesh(bitmap,  WIDTH,  HEIGHT,   
  63.                                 verts,  0,  null,  0,  null);    
  64.                 invalidate();    
  65.         }   
  66.    
  67.         private  void  flagWave()  {   
  68.                 for  (int  j  =  0;   j  < =  HEIGHT;   j++)  {   
  69.                         for  (int  i  =  0;   i  < =  WIDTH;   i++)  {   
  70.                                 verts[(j  *  (WIDTH  +  1)  +  i)  *  2  +  0]  +=  0;    
  71.                                 float  offsetY  =   
  72.                                                 (float)  Math.sin((float)  i  /  WIDTH  *  2  *  Math.PI  +   
  73.                                                                 Math.PI  *  k);    
  74.                                 verts[(j  *  (WIDTH  +  1)  +  i)  *  2  +  1]  =   
  75.                                                 orig[(j  *  WIDTH  +  i)  *  2  +  1]  +  offsetY  *  A;    
  76.                         }   
  77.                 }   
  78.         }   
  79. }   
package com.mfc.myview; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.View; import com.example.androidmatrix.R; public class FlagBitmapMeshView extends View {private final int WIDTH = 200; private final int HEIGHT = 200; private int COUNT = (WIDTH + 1) * (HEIGHT + 1); private float[] verts = new float[COUNT * 2]; private float[] orig = new float[COUNT * 2]; private Bitmap bitmap; private float A; private float k = 1; public FlagBitmapMeshView(Context context) { super(context); initView(context); }public FlagBitmapMeshView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); }public FlagBitmapMeshView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); }private void initView(Context context) { setFocusable(true); bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.we); float bitmapWidth = bitmap.getWidth(); float bitmapHeight = bitmap.getHeight(); int index = 0; for (int y = 0; y < = HEIGHT; y++) { float fy = bitmapHeight * y / HEIGHT; for (int x = 0; x < = WIDTH; x++) { float fx = bitmapWidth * x / WIDTH; orig[index * 2 + 0] = verts[index * 2 + 0] = fx; orig[index * 2 + 1] = verts[index * 2 + 1] = fy + 100; index += 1; } } A = 50; }@Override protected void onDraw(Canvas canvas) { flagWave(); k += 0.1F; canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT, verts, 0, null, 0, null); invalidate(); }private void flagWave() { for (int j = 0; j < = HEIGHT; j++) { for (int i = 0; i < = WIDTH; i++) { verts[(j * (WIDTH + 1) + i) * 2 + 0] += 0; float offsetY = (float) Math.sin((float) i / WIDTH * 2 * Math.PI + Math.PI * k); verts[(j * (WIDTH + 1) + i) * 2 + 1] = orig[(j * WIDTH + i) * 2 + 1] + offsetY * A; } } } }

 
 
使用drawBitmapMesh()方法可以创建很多复杂的图像效果,但是对它的使用也相对复杂,需要我们对图像处理有很深厚的功底。同时,对算法的要求也比较高,需要计算各种特效下不同的坐标点变化规律,从而设计出不同的特效。


















    推荐阅读