Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 淺談android中圖片處理之圖形變換特效Matrix(四)

淺談android中圖片處理之圖形變換特效Matrix(四)

編輯:關於Android編程

今天,我們就來談下android中圖片的變形的特效,在上講博客中我們談到android中圖片中的色彩特效來實現的。改變它的顏色主要通過ColorMatrix類來實現。
現在今天所講的圖片變形的特效主要就是通過Matrix類來實現,我們通過上篇博客知道,改變色彩特效,主要是通過ColorMatrxi矩陣的系數,以及每個像素點上所對應的顏色偏移量。而今天的圖形變換與那個也是非常的類似。它是一個3*3矩陣,而顏色矩陣則是一個4*5的矩陣。在這個3*3矩陣中則表述出了每個像素點的XY坐標信息。然後通過修改這個矩陣,就可達到修改圖片中的每個像素點的XY坐標,即改變每個像素點的位置信息,通過對特定的矩陣元素值的修改就可以達到實現圖片的中的
圖形變換特效如:平移變換特效,旋轉變換特效,縮放變換特效,錯切變換特效。那麼接下來我們就通過從原理的角度來一一分析下每個特效對應的矩陣是怎麼樣的。
默認的圖形變換的初始矩陣是:
1 0 0
0 1 0
0 0 1
  第一、平移變換特效:
我們很容易知道這個,在一個平面中,將一個像素點從位置A(x0,y0)移到另一個位置B(x,y)
很容易得到如下的公式:
x=x0+X方向的偏移量(xt);
y=y0+Y方向的偏移量(yt);
依據上面的等式我們很容易得到如下矩陣:


      |x| |1 0 xt|  |x0|
|y| = |0 1 yt| × |y0|
|1| |0 0 1| | 1 |
然後我們通過如上的矩陣乘法計算得到等式(與我們得出的結論一致,所以也就是我們通過改變初始矩陣中那個矩陣元素的值就可以實現圖片在X,Y方向上的平移):
x=x0+X方向的偏移量(xt);
 y=y0+Y方向的偏移量(yt);
 第二、旋轉變換特效:


所謂旋轉變換就相當於一個像素點圍繞某個中心點O旋轉到一個新的點,在高中學過三角函數的都知道,通過從初始點A(x0,y0)旋轉到B點(x,y)
初始點與X軸正方向夾角為a,旋轉過的角度為t,通過三角函數的計算得出如下公式:
設:旋轉軸長為:r
x0=r*cosa; y0=r*sina;
x=r*cos(a+t)=r*cosa*cost-rsina*sint=x0*cost-y0*sint;
y=r*sin(a+t)=r*sina*cost+r*cosa*sint=y0*cost+x0*sint;
從而可以得出如下矩陣:
|x| |cost -sint 0| |x0|
|y| = |sint cost 0| ×|y0|
|1| |0 0 1| | 1 |
然後我們通過如上的矩陣乘法計算得到等式(與我們得出的結論一致,所以也就是我們通過改變初始矩陣中那個矩陣元素的值就可以實現圖片旋轉):


                  x=x0*cost-y0*sint;
y=y0*cost+x0*sint;
注意:前面所講的旋轉都是以坐標的原點為旋轉中心的,我們還可以以任意點O為旋轉中心來進行旋轉的變換但是通常需要如下三個步驟:
首先第一需要將坐標的原點平移到任意指定的點O,然後再使用上述我們的所講的旋轉方法來進行旋轉,最後就需要將我們的原點還原回去。
第三、縮放變換特效:
所謂像素點的縮放,實際上並不會對像素點縮放,因為像素點已經夠小了,不存在什麼縮放的概念,那我們這裡所說的縮放是怎麼樣的呢?
我們是通過將每個像素點所在的XY坐標按一定的比例縮放,然後使得圖片整體看起來的有一個縮放的效果。
                    x=K1*x0
               y=K2*y0 
通過以上公式反映到我們的變換矩陣中的形式:
|x| |K1 0 0| |x0|
    |y| = |0 K2 0| ×|y0|
    |1| |0 0 1| | 1 |
通過矩陣乘法驗證得到等式(與我們得出的結論一致,所以也就是我們通過改變初始矩陣中那兩個矩陣元素的值就可以實現圖片在X,Y方向上的縮放)
第四、錯切變換特效:
所謂錯切變換的效果很類似數學上的Shear mapping.錯切主要分兩種形式:
第一水平錯切變換:就是在正常圖片的基礎上,讓每個像素點的Y軸坐標保持不變,而讓他們的X坐標按一定比例的縮放,第二就是垂直錯切變換:就是在原圖的基礎上,讓讓每個像素點的X坐標保持不變,讓Y坐標按一定比例的縮放。從而可以得到如下的變換公式:
  x=x0+K1*y0;y=x0+K2*y0;
通過以上的公式反應到我們的變換矩陣中的形式:

      |x| |1 K1 0| |x0|
|y| = |K2 1 0| ×|y0|
|1| |0 0 1| | 1 |
通過矩陣乘法驗證得到等式(與我們得出的結論一致,所以也就是我們通過改變初始矩陣中那兩個矩陣元素的值就可以實現圖片在X,Y方向上的錯切)
綜合上述:將得出我們最後的矩陣變換公式:
|Scale_X Skew_X Trans_X|
|Skew_Y Scale_Y Trans_Y|
| 0 0 1 |
也就是我只需要改變矩陣中對應的元素的值,我們就可以實現各種變換的特效。
如果用A,B,C,D,E,F來一次標示那些區的話,A和E決定縮放變換,B和D決定了錯切變換,C和F決定了平移變換

下面我們就通過一個Demo來驗證一下我們的觀點。

package com.mikyou.matrix;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;


public class MainActivity extends Activity {
	private ImageView iv;
	private Canvas canvas;
	private Paint paint;
	private Bitmap baseBitmap;
	private Bitmap copyBitmap;
	private Matrix matrix;
	private EditText e1,e2,e3,e4,e5,e6,e7,e8,e9;
	private float t1,t2,t3,t4,t5,t6,t7,t8,t9;
	private List<Float> valueList;
	public void ok(View view){
		valueList=new ArrayList<Float>();
		valueList.clear();
		iv.setImageBitmap(null);
		t1=Float.valueOf(e1.getText().toString());
		valueList.add(t1);
		t2=Float.valueOf(e2.getText().toString());
		valueList.add(t2);
		t3=Float.valueOf(e3.getText().toString());
		valueList.add(t3);
		t4=Float.valueOf(e4.getText().toString());
		valueList.add(t4);
		t5=Float.valueOf(e5.getText().toString());
		valueList.add(t5);
		t6=Float.valueOf(e6.getText().toString());
		valueList.add(t6);
		t7=Float.valueOf(e7.getText().toString());
		valueList.add(t7);
		t8=Float.valueOf(e8.getText().toString());
		valueList.add(t8);
		t9=Float.valueOf(e9.getText().toString());
		valueList.add(t9);
		float[] imageMatrix=new float[9];
		for (int i = 0; i <valueList.size(); i++) {
			imageMatrix[i]=valueList.get(i);
		}
		matrix=new Matrix();
		matrix.setValues(imageMatrix);//類似ColorMatrix中的setColorFilter方法
		canvas.drawBitmap(baseBitmap, matrix, paint);
		iv.setImageBitmap(copyBitmap);
	}
	public void reset(View view){
		iv.setImageBitmap(null);
		e1.setText("1");
		e2.setText("0");
		e3.setText("0");
		e4.setText("0");
		e5.setText("1");
		e6.setText("0");
		e7.setText("0");
		e8.setText("0");
		e9.setText("1");
	}
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
		initData();
	}
	private void initView() {
		registerAllViewId();
		registerAllViewEvent();
	}
	private void registerAllViewEvent() {

	}
	private void registerAllViewId() {
		iv=(ImageView) findViewById(R.id.iv);
		e1=(EditText) findViewById(R.id.e1);
		e2=(EditText) findViewById(R.id.e2);
		e3=(EditText) findViewById(R.id.e3);
		e4=(EditText) findViewById(R.id.e4);
		e5=(EditText) findViewById(R.id.e5);
		e6=(EditText) findViewById(R.id.e6);
		e7=(EditText) findViewById(R.id.e7);
		e8=(EditText) findViewById(R.id.e8);
		e9=(EditText) findViewById(R.id.e9);
	}
	private void initData() {
		baseBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.pre);
		copyBitmap=Bitmap.createBitmap(baseBitmap.getWidth(), baseBitmap.getHeight(), baseBitmap.getConfig());
		canvas=new Canvas(copyBitmap);
		paint=new Paint();

	}

}

運行結果:

淺談android中圖片處理之圖形變換特效Matrix(四)

淺談android中圖片處理之圖形變換特效Matrix(四)

淺談android中圖片處理之圖形變換特效Matrix(四)vcSz1tax5Lu7tcTQp7n7o6zKtbzKyc9hbmRyb2lk0tG+rbfi17DSu9CpseS7u7XEQVBJvdO/2jxicj4NCsD9yOc6PGJyPg0K0P3XqrHku7s6bWF0cml4LnNldFJvdGF0ZSgpIMa90sax5Lu7oaFtYXRyaXguc2V0VHJhbnNsYXRlKCmhocv1t8Wx5Lu7IG1hdHJpeC5zZXRTY2FsZSgpoaG07cfQseS7uyBtYXRyaXguc2V0U2tldygpPGJyPg0Ksru5/WFuZHJvaWTW0Lu5zOG5qcG9uPa3x7Oj1tjSqrXEt723qNK7uPbKx3ByZSgpLNK7uPbKx3Bvc3QoKSDM4bmpvtjV87XEx7Czy7rNuvOzy9TLy+Ohozxicj4NCtei0uI6INLUyc+1xLy4uPZzZXS3vbeotry74dbY0MLH5b/V1tjWw77Y1fPW0LXEJiMyMDU0MDujrLb409DKsbryztLQ6NKqyrXP1rX+vNO1xNCnufujrL7NtaW1pdPDc2V0t723qMrHzt63qM3qs8mjrNLyzqq12rb+tM61/rzTtcSx5Lu7o6y74bDRyc/Su7TOtcQ8YnI+DQq12tK7tM6x5Lu7tcS+2NXzJiMyMDU0MDu4+Mflv9WjrNa7u+Gxo7Tm1+69/NK7tM61xL7Y1fPW0LXEJiMyMDU0MDuho8v50tRhbmRyb2lkIL7NuPjO0sPHzOG5qXByZbrNcG9zdLe9t6ijrNXiwb249re9t6i/ycq1z9a+2NXzu+y6z9CnufujrLTTtvjKtc/WzbzQzrHku7u1xDxicj4NCrX+vNOho8D9yOc6PGJyPg0Kz8jSxravtb214yg0MDAsNDAwKSzU2tD916o0NbbIo6zX7rrzxr3SxrW9KDIwMCwyMDApPGJyPg0K08PS1MnPwP3X08C0y7XD93ByZSjPyLPLKbrNcG9zdCi687PLKdTLy+O1xMf4sfAs0vLOqtTavtjV87PLt6jW0LK71qez1r27u7vCyaOsy/nS1M7Sw8fQ6NKq08PV4sG9uPa3vbeowLTH+LHwyrXP1jxicj4NCnByZdTLy+PKtc/WOjxicj4NCiAgICAgICAgICAgICAgICAgbWF0cml4LnNldFRyYW5zbGF0ZSgyMDAsMjAwKSBtYXRyaXgucHJlUm90YXRlKDQ1KTxicj4NCnBvc3TUy8vjyrXP1qO6PGJyPg0KoaGhoaGhoaGhoaGhoaGhoaGhoaFtYXRyaXguc2V0Um90YXRlKDQ1KSBtYXRyaXgucG9zdFRyYW5zbGF0ZSgyMDAsMjAwKTxicj4NCtfuuvPO0sPHzai5/dK7uPawuMD9wLTKtc/W0ru49tfpus+1/rzTseS7u7XE0Ke5+zxicj4NCjwvcD4NCg0KPHByZSBjbGFzcz0="html" name="code">package com.mikyou.dealImage; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.os.Bundle; import android.view.View; import android.widget.ImageView; public class MainActivity extends Activity { /** *@author zhongqihong *圖片的繪制的個人總結: *如何去仿照一張原圖去重新繪制一張圖片呢?? *需要如下材料: *1、需要參考的原圖 *2、畫紙(實際上就是一張沒有任何內容的圖片,空白圖片) *3、畫布(就是用於固定畫紙的) *4、畫筆(就是用於繪制圖片的工具) *其實一般分為如下幾步: *1、首先必須拿到原圖構造出一張空畫紙(即空白圖片),知道原圖的大小,分辨率等信息,從而就可以確定我的畫紙的大小,及所確定的分辨率(默認使用原圖的分辨率)。 * baseBitmap= BitmapFactory.decodeResource(getResources(),R.drawable.img_small_1);//拿到原圖對象 * copyBitmap=Bitmap.createBitmap(baseBitmap.getWidth(),baseBitmap.getHeight(), baseBitmap.getConfig());//根據原圖對象的相關信息,得到同大小的畫紙,包括原圖分辨率 *2、然後,確定了一個空白的畫紙後,就需要將我們的畫紙固定在我們的畫布上 * Canvas canvas=new Canvas(copyBitmap); *3、接著就是構造一個畫筆對象 * Paint paint=new Paint(); * 4、接著對圖片進行一系列的操作,諸如:縮放、平移、旋轉等操作 * Matrix matrix =new Matrix(); * 縮放:(縮放中心點:默認是畫紙左上角點的坐標) * matrix.setScale(1.5f,1.5f);//第一個參數為X軸上的縮放比例為1.5(>1表示放大,<1表示縮小)此處就表示在XY軸上分別放大為原圖1.5倍 * matrix.setScale(-1f,1f);//表示在X軸反向縮放,Y軸不變,即相當於把原圖往X軸負方向反向翻轉了一下,即相當於處理後的圖片與原圖位置(即現在的畫紙位置)關於Y負半軸對稱 * matrix.setScale(1f,-1f);//表示在X軸不變,Y軸的,即相當於把原圖往Y軸負方向反向翻轉了一下,即相當於處理後的圖片與原圖位置(即現在的畫紙位置)關於X正半軸對稱 * 5、處理完後,就需要把我們處理好的圖片繪制在畫布上形成最後的圖片 * canvas.drawBitmap(baseBitmap,matrix,paint);//第一個參數表示原圖的Bitmap對象,表示按照原圖的樣式內容在原來相同規格空白的紙上畫出圖片內容 iv.setImageBitmap(copyBitmap);//最後將圖片的顯示在ImageView控件上 * 個人理解:感覺整個過程很像PS中置入一張圖片到一張空白畫紙上,首先我們 * 需要去設置一張空白的畫紙,然後將我們的原圖置入,在置入之前我們可以做些對圖片的操作 * 包括縮放,平移,旋轉,確定一些操作後,點擊確定就相當於調用繪制方法,從而就形成一張處理後的圖片 * * */ private ImageView iv; private Bitmap baseBitmap;//原圖 private Bitmap copyBitmap;//畫紙 private Canvas canvas;//畫布 private Paint paint;//畫筆 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); iv= (ImageView) findViewById(R.id.iv2); } public void btn(View view){ //拿到原圖:得到原圖大小 baseBitmap= BitmapFactory.decodeResource(getResources(),R.drawable.img_small_1); //1、拿到一張與原圖一樣大小的紙,並沒有內容 copyBitmap=Bitmap.createBitmap(1200,1300, baseBitmap.getConfig());//拿到原圖的分辨率和原圖的Config //2、將這張紙固定在畫布上 Canvas canvas=new Canvas(copyBitmap); //3、畫筆 paint=new Paint(); paint.setAlpha(100); //4、加入一些處理的規則 Matrix matrix=new Matrix(); //1、縮放規則 //matrix.setScale(1.5f,1.5f); //2、位移, // matrix.setTranslate(50f,50f);//分別在x軸和Y軸上位移50,針對圖片的左上角為原點來移動 //3、旋轉 //matrix.setRotate(45f);//代表順時針旋轉45度,默認以左上角為原點 // matrix.setRotate(45, baseBitmap.getWidth()/2, baseBitmap.getHeight()/2);//第二個參數和第三個參數表示旋轉中心的點的X,Y坐標 //4、翻轉鏡面效果 // matrix.setScale(-1f, 1f); // matrix.setTranslate(baseBitmap.getWidth(), 0); // matrix.postTranslate(baseBitmap.getWidth(), 0);//如果要對圖片進行多次操作,就要用post的方法來操作 //5、倒影效果 matrix.setScale(1f, -1f);//先把圖片在y軸方向反向縮放 matrix.postTranslate(0, baseBitmap.getHeight());//然後再把反向縮放後的圖片移到canvas上顯示即可 matrix.postTranslate(baseBitmap.getWidth()+160, 0); matrix.postSkew(-1, 0); //5、將處理過的圖片畫出來 canvas.drawBitmap(baseBitmap,matrix,paint);//第一個參數表示原圖的Bitmap對象,表示按照原圖的樣式內容在原來相同規格空白的紙上畫出圖片內容 iv.setImageBitmap(copyBitmap);//最後將圖片的顯示在ImageView控件上 } }
運行效果:

淺談android中圖片處理之圖形變換特效Matrix(四) * Draw the bitmap through the mesh, where mesh vertices are evenly
* distributed across the bitmap. There are meshWidth+1 vertices across, and
* meshHeight+1 vertices down. The verts array is accessed in row-major
* order, so that the first meshWidth+1 vertices are distributed across the
* top of the bitmap from left to right. A more general version of this
* method is drawVertices().
*
* @param bitmap The bitmap to draw using the mesh
* @param meshWidth The number of columns in the mesh. Nothing is drawn if
* this is 0
* @param meshHeight The number of rows in the mesh. Nothing is drawn if
* this is 0
* @param verts Array of x,y pairs, specifying where the mesh should be
* drawn. There must be at least
* (meshWidth+1) * (meshHeight+1) * 2 + vertOffset values
* in the array
* @param vertOffset Number of verts elements to skip before drawing
* @param colors May be null. Specifies a color at each vertex, which is
* interpolated across the cell, and whose values are
* multiplied by the corresponding bitmap colors. If not null,
* there must be at least (meshWidth+1) * (meshHeight+1) +
* colorOffset values in the array.
* @param colorOffset Number of color elements to skip before drawing
* @param paint May be null. The paint used to draw the bitmap
*/
它大概的意思的是這樣的,通過網格來繪制圖片,那麼這張圖片將會被meshWidth畫出橫向格子,meshHeight畫出縱向的格子
那麼在橫向上將會產生meshWidth+1個交叉點,在縱向上會產生meshHeight+1個交叉點,最後總的交叉點個數為(meshWidth+1)*(meshHeight+1)
bitmap: 需要繪制在網格上的圖像。
meshWidth: 網格的寬度方向的數目(列數),為0時不繪制圖像。
meshHeight:網格的高度方向的數目(含數),為0時不繪制圖像。
verts: (x,y)對的數組,表示網格頂點的坐標,至少需要有(meshWidth+1) * (meshHeight+1) * 2 + meshOffset 個(x,y)坐標。
vertOffset: verts數組中開始跳過的(x,y)對的數目。
Colors: 可以為空,不為空為沒個頂點定義對應的顏色值,至少需要有(meshWidth+1) * (meshHeight+1) * 2 + meshOffset 個(x,y)坐標。
colorOffset: colors數組中開始跳過的(x,y)對的數目。
paint: 可以為空。
下面將通過一個自定義View方法來實現,旗幟飄揚的圖片控件。並且添加自定義屬性,下次使用可以方便的在XMl中更換圖片
修改劃分方格數,振幅大小,頻率大小
實現整體思路如下:
針對像素塊來實現圖形扭曲的原理:
它的原理就是通過修改劃分後的小方格產生交叉點的坐標,來實現圖片的扭曲
本案例實現一個旗幟飄動形狀的圖片
大致的思路如下:
實現思路整體分兩部分,第一部分取得所有扭曲前圖片的所有交叉點的坐標
並把這些交叉點坐標保存在orig數組中;第二部分修改原圖中方格每個交叉點的坐標,遍歷這個數組,然後通過某種算法
使得這些交叉點的坐標,呈某種規律函數曲線變化。這裡就以三角函數中的正弦函數
來改變這些交叉點坐標,從而產生每個交叉點新的坐標,然後再將這些新的坐標保存在verts數組中,最後通過drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint)
實現圖片的繪制。

自定義屬性:attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="Src" format="reference"></attr>
    <attr name="Amplitude" format="integer"></attr>
    <attr name="RowNum" format="integer"></attr>
    <attr name="ColumnNum" format="integer"></attr>
    <attr name="Frequency" format="float"></attr>

    <declare-styleable name="MikyouBannerView">
        <attr name="Src"></attr>
        <attr name="Amplitude"></attr>
        <attr name="Frequency"></attr>
        <attr name="RowNum"></attr>
        <attr name="ColumnNum"></attr>
    </declare-styleable>

</resources>

自定義View的MyBannerImageView類:
package com.mikyou.myview;

import com.mikyou.piexkuai.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.Window;
import android.widget.ImageView;
/**
 * @author mikyou
 * 針對像素塊來實現圖形扭曲的原理:
 * 它的原理就是通過修改劃分後的小方格產生交叉點的坐標,來實現圖片的扭曲
 * 本案例實現一個旗幟飄動形狀的圖片
 * 大致的思路如下:
 * 實現思路整體分兩部分,第一部分取得所有扭曲前圖片的所有交叉點的坐標
 * 並把這些交叉點坐標保存在orig數組中;第二部分修改原圖中方格每個交叉點的坐標,遍歷這個數組,然後通過某種算法
 * 使得這些交叉點的坐標,呈某種規律函數曲線變化。這裡就以三角函數中的正弦函數
 * 來改變這些交叉點坐標,從而產生每個交叉點新的坐標,然後再將這些新的坐標保存在
 * verts數組中,最後通過drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint)
 * 實現圖片的繪制。
 * */
public class MyBannerImageView extends View{
	//定義兩個常量表示需要將這張圖片劃分成20*20=400個小方格,//定義兩個常量,這兩個常量指定該圖片橫向,縱向上都被劃分為20格  
	private  int WIDTH=40;//橫向劃分的方格數目
	private  int HEIGHT=40;//縱向劃分的方格數目
	private float FREQUENCY=0.1f;//三角函數的頻率大小
	private int AMPLITUDE=60;//三角函數的振幅大小
	//那麼將會產生21*21=421個交叉點
	private  int POINT_COUNT=(WIDTH+1)*(HEIGHT+1);
	//由於,我要儲存一個坐標信息,一個坐標包括x,y兩個值的信息,相鄰2個值儲存為一個坐標點
	//其實大家應該都認為這樣不好吧,還不如直接寫一個類來直接保存一個點的信息,但是沒辦法
	// 但是在drawBitmapMesh方法中傳入的是一個verts數組,該數組就是保存所有點的x,y坐標全都放在一起
	//所以,我就只能這樣去控制定義orig和verts數組了,
	private Bitmap baseBitmap;
	private float[] orig=new float[POINT_COUNT*2];//乘以2是因為x,y值是一對的。
	private float[] verts=new float[POINT_COUNT*2];
	private float k;
	public MyBannerImageView(Context context, AttributeSet attrs,
			int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		//接收自定義屬性值
		TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.MikyouBannerView);
		for (int i = 0; i < array.getIndexCount(); i++) {
			int attr=array.getIndex(i);
			switch (attr) {
			case R.styleable.MikyouBannerView_Src:
				baseBitmap=BitmapFactory.decodeResource(getResources(), array.getResourceId(attr, R.drawable.ic_launcher));
				break;
			case R.styleable.MikyouBannerView_ColumnNum:
				HEIGHT=array.getInt(attr, 40);
				break;
			case R.styleable.MikyouBannerView_RowNum:
				WIDTH=array.getInt(attr, 40);
				break;
			case R.styleable.MikyouBannerView_Amplitude:
				AMPLITUDE=array.getInt(attr, 60);
				break;
			case R.styleable.MikyouBannerView_Frequency:
				FREQUENCY=array.getFloat(attr, 0.1f);
				break;
			default:
				break;
			}
		}
		array.recycle();
		initData();
	}
	public MyBannerImageView(Context context, AttributeSet attrs) {
		this(context, attrs,0);
	}
	public MyBannerImageView(Context context) {
		this(context,null);
	}
	
	//set,gfanfg
	public int getWIDTH() {
		return WIDTH;
	}
	public void setWIDTH(int wIDTH) {
		WIDTH = wIDTH;
	}
	public int getHEIGHT() {
		return HEIGHT;
	}
	public void setHEIGHT(int hEIGHT) {
		HEIGHT = hEIGHT;
	}
	public float getFREQUENCY() {
		return FREQUENCY;
	}
	public void setFREQUENCY(float fREQUENCY) {
		FREQUENCY = fREQUENCY;
	}
	public int getAMPLITUDE() {
		return AMPLITUDE;
	}
	public void setAMPLITUDE(int aMPLITUDE) {
		AMPLITUDE = aMPLITUDE;
	}
	public Bitmap getBaseBitmap() {
		return baseBitmap;
	}
	public void setBaseBitmap(Bitmap baseBitmap) {
		this.baseBitmap = baseBitmap;
	}
	@Override
	protected void onDraw(Canvas canvas) {
		flagWave();
		k+=FREQUENCY;
		canvas.drawBitmapMesh(baseBitmap, WIDTH, HEIGHT, verts, 0, null, 0, null);
		invalidate();
	}
	private void initData() {
		float baseBitmapWidth=baseBitmap.getWidth();
		float baseBitmapHeight=baseBitmap.getHeight();
		int index=0;
		//通過遍歷所有的劃分後得到的像素塊,得到原圖中每個交叉點的坐標,並把它們保存在orig數組中
		for (int i = 0; i <= HEIGHT; i++) {//因為這個數組是采取行優先原則儲存點的坐標,所以最外層為縱向的格子數,然後一行一行的遍歷
			float fy=baseBitmapHeight*i/HEIGHT;//得到每行中每個交叉點的y坐標,同一行的y坐標一樣
			for (int j = 0; j <= WIDTH; j++) {
				float fx=baseBitmapHeight*j/WIDTH;//得到每行中的每個交叉點的x坐標,同一列的x坐標一樣
				orig[index*2+0]=verts[index*2+0]=fx;//存儲每行中每個交叉點的x坐標,為什麼是index*2+0作為數組的序號呢??
				//因為我們之前也說過這個數組既存儲x坐標也存儲y坐標,所以每個點就占有2個單位數組空間
				orig[index*2+1]=verts[index*2+1]=fy+200;//存儲每行中每個交叉點的y坐標.為什麼需要+1呢?正好取x坐標相鄰的下標的元素的值
				//+200是為了避免等下在正弦函數扭曲下,會把上部分給擋住所以下移200
				index++;
			}
		}	
	}
	/**
	 * @author mikyou
	 * 加入三角函數正弦函數Sinx的算法,來修改原圖數組保存的交叉點的坐標
	 * 從而得到旗幟飄揚的效果,這裡我們只修改y坐標,x坐標保持不變
	 * */
	public void flagWave(){
		for (int i = 0; i <=HEIGHT ; i++) {
			for (int j = 0; j <WIDTH; j++) {
				verts[(i*(WIDTH+1)+j)*2+0]+=0;
				float offSetY=(float)Math.sin((float)j/WIDTH*2*Math.PI+Math.PI*k);
				verts[(i*(WIDTH+1)+j)*2+1]=orig[(i*(WIDTH+1)+j)*2+1]+offSetY*AMPLITUDE;
			}
		}
	}
}

activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:mikyou="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <com.mikyou.myview.MyBannerImageView
        android:id="@+id/iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        mikyou:Amplitude="100"
        mikyou:ColumnNum="20"
        mikyou:Frequency="0.1"
        mikyou:RowNum="20"
        mikyou:Src="@drawable/pre" />

</LinearLayout>
運行的結果;

淺談android中圖片處理之圖形變換特效Matrix(四)以上就是淺談android中圖片處理之圖形變換特效Matrix(四)的全文介紹,希望對您學習Androidkaifa target=_blank class=infotextkey>Android應用開發有所幫助.

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved