編輯:關於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應用開發有所幫助.
Android5.0+ CollapsingToolbarLayout使用詳解
CollapsingToolbarLayout作用是提供了一個可以折疊的Toolbar,它繼承至FrameLayout,給它設置layout_scrollFlags,它可
嵌入式Linux+Android學習路線圖
版本 日期 作者 說明 V1 2016.07.29 韋東山 第1版本,Android部分未寫 表格完畢我是1999年上的大學,物理專業。在大一時,
android應用對系統API版本號的選擇介紹
首先我們在開發一個應用之前,特別是一個android應用,首先要考慮這個系統是運行在android版本為2.3的系統上,還是4.0的系統上或者說是支持所有a
紅米note3和樂視1s哪個好 紅米note3和樂1s區別對比評測
紅米note3介紹:外觀設計紅米Note3金屬機身背面是三段式設計,上下兩端為塑料材質。配置方面紅米Note3采用5.5英寸1080P屏幕,1300萬像素後