我們都知道一個App的成敗,首先取決於是否具有優秀的UI,而除了交互功能之外還需要豐富的圖片背景和動畫去支撐。在開發中我們應用到的圖片不僅僅包括.png、.gif、.9.png、.jpg和各種Drawable系對象,還包括位圖Bitmap,而且圖片的處理也經常是影響着一個程序的高效性和健壯性。
一、Bitmap概述
Bitmap代表一張位圖,擴展名可以是.bmp或者.dib。位圖是Windows標准格式圖形文件,它將圖像定義為由點(像素)組成,每個點可以由多種色彩表示,包括2、4、8、16、24和32位色彩。例如,一幅1024×768分辨率的32位真彩圖片,其所占存儲字節數為:1024×768×32/8=3072KB,雖然位圖文件圖像效果好,但是非壓縮格式的,需要占用較大存儲空間,不利於在網絡上傳送Android系統當中,Bitmap是圖像處理最重要的中轉類之一。用它可以獲取圖像文件信息,借助Matrix進行圖像剪切、旋轉、縮放等操作,再以指定格式保存圖像文件。
二、構造Bitmap對象
通常我們構造一個類的對象,都是可以通過其對應的構造方法。然而Bitmap是采用了工廠的設計模式,所以一般不會直接調用構造方法。
1、通過Bitmap的靜態方法static Bitmap createBitmap()系
方法名(只列出部分方法) | 用法說明 |
---|---|
createBitmap(Bitmap src) | 復制位圖 |
createBitmap(Bitmap src,int x ,int y,int w,int h) | 從源位圖src的指定坐標(x,y)開始,截取寬w,高h的部分,用於創建新的位圖對象 |
createScaledBitmap(Bitmap src,int w ,int h,boolean filter) | 對源位圖src縮放成寬為w,高為h的新位圖 |
createBitmap(int w ,int h,Bitmap.Config config) | 創建一個寬w,高h的新位圖(config為位圖的內部配置枚舉類) |
createBitmap(Bitmap src,int x ,int y,int w,int h,Matrix m,boolean filter) | 從源位圖src的指定坐標(x,y)開始,截取寬w,高h的部分,按照Matrix變換創建新的位圖對象 |
2、通過BitmapFactory工廠類的static Bitmap decodeXxx()系
方法名(只列出部分方法) | 參數及解釋 |
---|---|
decodeByteArray(byte[] data, int offset, int length) | 從指定字節數組的offset位置開始,將長度為length的數據解析成位圖 |
decodeFile(String pathName) | 從pathName對應的文件解析成的位圖對象 |
decodeFileDescriptor(FileDescriptor fd) | 從FileDescriptor中解析成的位圖對象 |
decodeResource(Resource res,int id) | 根據給定的資源Id解析成位圖 |
decodeStream(InputStream in) | 把輸入流解析成位圖 |
三、Bitmap相關類之Path、Matrix
1、Path類的應用
有使用PS經驗的都知道”路徑”這么一個概念,可以把幾個點連成一條“路徑”,Android里的Path也是如此。在實際應用中我們可以調用Canvas的drawPath方法即可繪制圖形,為了實現豐富的繪制效果,Android還定義了一個PathEffect系列類(ComposePathEffect, CornerPathEffect, DashPathEffect, DiscretePathEffect, PathDashPathEffect, SumPathEffect)
1.1、Path類的構造方法
Path(); Path(Path src);
1.2、Path類的一些常用方法
部分方法 | 用法說明 |
---|---|
public void addArc (RectF oval, float startAngle, float sweepAngle) | 繪制弧形路徑 |
public void addCircle (float x, float y, float radius, Path.Direction dir) | 繪制圓形路徑 |
public void addOval (RectF oval, Path.Direction dir) | 繪制橢圓路徑 |
public void lineTo (float x, float y) | 把(x,y)連接到一起成為一條折線 |
public void moveTo (float x, float y) |
1.3、Path的實際應用
繪制跟隨路徑顯示的字符串
package com.crazymo.graphicsdemo; public class MyPathView extends View { final String STR_TITLE="跟隨路徑顯示的字符串"; Path[] paths=new Path[3]; Paint paint; public MyPathView(Context ctx){ super(ctx); paths[0]=new Path(); paths[0].moveTo(0,0); for(int i=1;i<7;i++){ //隨機生成7個點的Y坐標並將他們煉成一條路徑 paths[0].lineTo(i*30,(float)Math.random()*30); } paths[1]=new Path(); RectF rectF=new RectF(0,0,200,120); paths[1].addOval(rectF,Path.Direction.CCW); paths[2]=new Path(); paths[2].addArc(rectF,60,180); //初始化畫筆 paint=new Paint(); paint.setAntiAlias(true); paint.setColor(Color.GREEN); paint.setStrokeWidth(1); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); canvas.translate(40, 40); //從右邊開始繪制即右對齊 paint.setTextAlign(Paint.Align.RIGHT); paint.setTextSize(20); //繪制路徑 paint.setStyle(Paint.Style.STROKE); canvas.drawPath(paths[0], paint); paint.setStyle(Paint.Style.FILL); canvas.drawTextOnPath(STR_TITLE, paths[0], -8, 20, paint);//沿着路徑繪制文字 //畫布下移120 canvas.translate(0,60); paint.setStyle(Paint.Style.STROKE); canvas.drawPath(paths[1], paint); paint.setStyle(Paint.Style.FILL); canvas.drawTextOnPath(STR_TITLE, paths[1], -20,20,paint); canvas.translate(0,120); paint.setStyle(Paint.Style.STROKE); canvas.drawPath(paths[2], paint); paint.setStyle(Paint.Style.FILL); canvas.drawTextOnPath(STR_TITLE,paths[2],-10,20,paint); } }
2、使用Matrix控制圖片和View的平移、旋轉、縮放等。
2.1、構造Matrix對象
public Matrix(); public Matrix(Matrix src);
2.2、Matrix一些常用的方法
部分方法 | 用法說明 |
---|---|
public void setTranslate(float dx, float dy) | 繪制弧形路徑 |
public void setSkew(float kx, float ky, float px, float py) | 控制Matrix以(px,py)為軸心進行傾斜,kx,ky為X,Y方向上的傾斜距離 |
public void setSkew(float px, float py) | kx,ky為X,Y方向上的傾斜距離 |
public void setRotate(float degree) | 控制Matrix旋轉degree度 |
public void setRotate(float degree,float px,float py) | 控制Matrix以軸心(px,py)旋轉degree度 |
setScale(float sx, float sy, float px, float py) | 控制Matrix以(px,py)為軸心縮放,sx,sy為X,Y方向上的縮放距離 |
void setScale(float sx, float sy) |
2.3、Marix的簡單應用
自定義一個使用Matrix的View
/** * Created by cmo on 16-4-1. */ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.util.AttributeSet; public class CostomView extends View { private Bitmap mBitmap; private Matrix matrix; public CostomView(Context context) { super(context); matrix = new Matrix(); } public CostomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); matrix = new Matrix(); } public CostomView(Context context, AttributeSet attrs) { super(context, attrs); matrix = new Matrix(); } public Bitmap getmBitmap() { return mBitmap; } public void setmBitmap(Bitmap mBitmap) { this.mBitmap = mBitmap; invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mBitmap != null) { canvas.drawBitmap(mBitmap, matrix, null); } } public void rotate(float degree) { if (mBitmap != null) { matrix.preRotate(degree, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2); invalidate(); } } //平移 public void translate(float dx, float dy) { if (mBitmap != null) { matrix.postTranslate(dx, dy); invalidate(); } } //縮放 public void scale(float sx, float sy) { if (mBitmap != null) { matrix.postScale(sx, sy); invalidate(); } } //鏡像(相當於是照鏡子里的自己) public void mirror() { if (mBitmap != null) { matrix.postScale(-1, 1); matrix.postTranslate(mBitmap.getWidth(), 0); invalidate(); } } //倒影 public void shadow() { if (mBitmap != null) { matrix.postScale(1, -1); matrix.postTranslate(0, mBitmap.getHeight()); invalidate(); } } public void skew(float kx, float ky){ if (mBitmap != null) { matrix.postSkew(kx, ky); invalidate(); } } }
<?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"> <com.crazymo.matrixdemo.CostomView android:id="@+id/costomview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btn_translate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="平移"/> <Button android:id="@+id/btn_scale" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="縮放"/> <Button android:id="@+id/btn_rotate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="旋轉"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btn_skew" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="傾斜"/> <Button android:id="@+id/btn_mirro" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="鏡像"/> <Button android:id="@+id/btn_shadow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="倒影"/> </LinearLayout> </LinearLayout>
package com.crazymo.matrixdemo; /** * Created by cmo on 16-4-1. */ public class CostViewActivity extends Activity { private CostomView mCostomView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_cotomview); mCostomView = (CostomView) findViewById(R.id.costomview); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.bcg); mCostomView.setmBitmap(bitmap); ((Button) findViewById(R.id.btn_rotate)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.rotate(15); } }); ((Button) findViewById(R.id.btn_scale)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.scale(1.8f, 1.8f); } }); ((Button) findViewById(R.id.btn_translate)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.translate(100, 100); } }); ((Button) findViewById(R.id.btn_skew)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.skew(-0.3f, 0.3f); } }); ((Button) findViewById(R.id.btn_mirro)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.mirror(); } }); ((Button) findViewById(R.id.btn_shadow)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.shadow(); } }); } }
四、Bitmap的簡單應用
1、從資源文件中獲取Bitmap
Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.bcg);
2、從SD卡里獲取Bitmap
String SDCarePath=Environment.getExternalStorageDirectory().toString(); String filePath=SDCarePath+"/"+"demo.jpg"; Bitmap rawBitmap1 = BitmapFactory.decodeFile(filePath, null);
InputStream inputStream=getBitmapInputStreamFromSDCard("demo.jpg"); Bitmap rawBitmap2 = BitmapFactory.decodeStream(inputStream);
3、設置圖片的圓角,返回設置后的Bitmap
public Bitmap toRoundCorner(Bitmap bitmap, int pixels) { Bitmap roundCornerBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(roundCornerBitmap); int color = 0xff424242;// int color = 0xff424242; Paint paint = new Paint(); paint.setColor(color); // 防止鋸齒 paint.setAntiAlias(true); Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); RectF rectF = new RectF(rect); float roundPx = pixels; // 相當於清屏 canvas.drawARGB(0, 0, 0, 0); // 先畫了一個帶圓角的矩形 canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); // 再把原來的bitmap畫到現在的bitmap!!!注意這個理解 canvas.drawBitmap(bitmap, rect, rect, paint); return roundCornerBitmap; }
4、將圖片高寬和的大小kB壓縮
//得到圖片原始的高寬 int rawHeight = rawBitmap.getHeight(); int rawWidth = rawBitmap.getWidth(); // 設定圖片新的高寬 int newHeight = 500; int newWidth = 500; // 計算縮放因子 float heightScale = ((float) newHeight) / rawHeight; float widthScale = ((float) newWidth) / rawWidth; // 新建立矩陣 Matrix matrix = new Matrix(); matrix.postScale(heightScale, widthScale); // 設置圖片的旋轉角度 // matrix.postRotate(-30); // 設置圖片的傾斜 // matrix.postSkew(0.1f, 0.1f); // 將圖片大小壓縮 // 壓縮后圖片的寬和高以及kB大小均會變化 Bitmap newBitmap = Bitmap.createBitmap(rawBitmap, 0, 0, rawWidth,rawWidth, matrix, true);
5、將Bitmap轉換為Drawable Drawable轉Bitmap
Drawable newBitmapDrawable = new BitmapDrawable(Bitmap); //如果要獲取BitMapDrawable中所包裝的BitMap對象,可以用getBitMap()方法; Bitmap bitmap = newBitmapDrawable.getBitmap();