編輯:關於Android編程
下面我們就通過一個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(); } }
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控件上
}
}
運行效果:
* 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>
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; } } } }
<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(四)的全文介紹,希望對您學習Androidkaifa target=_blank class=infotextkey>Android應用開發有所幫助.
CollapsingToolbarLayout作用是提供了一個可以折疊的Toolbar,它繼承至FrameLayout,給它設置layout_scrollFlags,它可
版本 日期 作者 說明 V1 2016.07.29 韋東山 第1版本,Android部分未寫 表格完畢我是1999年上的大學,物理專業。在大一時,
首先我們在開發一個應用之前,特別是一個android應用,首先要考慮這個系統是運行在android版本為2.3的系統上,還是4.0的系統上或者說是支持所有a
紅米note3介紹:外觀設計紅米Note3金屬機身背面是三段式設計,上下兩端為塑料材質。配置方面紅米Note3采用5.5英寸1080P屏幕,1300萬像素後