Bitmap(位圖)全解析 Part 1
本節(jié)引言:
在上一節(jié)中我們對Android中的13種類型的Drawable的類型進行了講解,有沒有應(yīng)用到自己的 項目當中呢?而本節(jié)我們來探討的是Bitmap(位圖)的一些使用,而在開始本節(jié)的內(nèi)容之前我們 先來區(qū)分幾個名詞的概念:
- Drawable:通用的圖形對象,用于裝載常用格式的圖像,既可以是PNG,JPG這樣的圖像, 也是前面學的那13種Drawable類型的可視化對象!我們可以理解成一個用來放畫的——畫框!
- Bitmap(位圖):我們可以把他看作一個畫架,我們先把畫放到上面,然后我們可以 進行一些處理,比如獲取圖像文件信息,做旋轉(zhuǎn)切割,放大縮小等操作!
- Canvas(畫布):如其名,畫布,我們可以在上面作畫(繪制),你既可以用Paint(畫筆), 來畫各種形狀或者寫字,又可以用Path(路徑)來繪制多個點,然后連接成各種圖形!
- Matrix(矩陣):用于圖形特效處理的,顏色矩陣(ColorMatrix),還有使用Matrix進行圖像的 平移,縮放,旋轉(zhuǎn),傾斜等!
而上述的這些都是Android中的底層圖形類:android.graphics給我們提供的接口! 嗯,話不多說開始本節(jié)內(nèi)容! PS:官方文檔:Bitmap
1.了解Bitmap,BitmapFactory,BitmapFacotry.Options
如題,本來可以直接說著三個東東的關(guān)系的,但是我就是要傲嬌,就要看代碼!
如果你打開Bitmap類的源碼,你會看到Bitmap的構(gòu)造方法上有這樣一段東東:
大概想說的就是:Bitmap的構(gòu)造方法是私有的,外面不能實例化,只能通過JNI實例化! 當然,肯定也會給我們提供一個接口給我們來創(chuàng)建Bitmap的,而這個接口類就是:BitmapFactory! 來來來,打開BitmapFactory類,我們點下左邊的Structure可以看到BitmapFactory給我們 提供了這些方法,大部分都是decodeXxx,通過各種形式來創(chuàng)建Bitmap的!
接著我們又發(fā)現(xiàn)了,每一種方法,都會有一個Options類型的參數(shù),點進去看看: 于是乎我們發(fā)現(xiàn)了這貨是一個靜態(tài)內(nèi)部類:BitmapFacotry.Options! 而他是用來設(shè)置decode時的選項的!
我們對這里的某些參數(shù)的值進行設(shè)置,比如inJustDecodeBounds設(shè)置為true避免OOM(內(nèi)存溢出), 什么,不知道OOM,沒事,等下一點點跟你說清楚!最后回到我們的Bitmap!嗯,Bitmap中的 方法比較多,就不一一進行講解了,我們從中挑幾個用得較多的來講解! 中文文檔:Android中文API(136) —— Bitmap
2.Bitmap常用方法
普通方法
- public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream) 將位圖的壓縮到指定的OutputStream,可以理解成將Bitmap保存到文件中!format:格式,PNG,JPG等;quality:壓縮質(zhì)量,0-100,0表示最低畫質(zhì)壓縮,100最大質(zhì)量(PNG無損,會忽略品質(zhì)設(shè)定)stream:輸出流 返回值代表是否成功壓縮到指定流!
- void recycle():回收位圖占用的內(nèi)存空間,把位圖標記為Dead
- boolean isRecycled():判斷位圖內(nèi)存是否已釋放
- int getWidth():獲取位圖的寬度
- int getHeight():獲取位圖的高度
- boolean isMutable():圖片是否可修改
- int getScaledWidth(Canvas canvas):獲取指定密度轉(zhuǎn)換后的圖像的寬度
- int getScaledHeight(Canvas canvas):獲取指定密度轉(zhuǎn)換后的圖像的高度
靜態(tài)方法:
- Bitmap createBitmap(Bitmap src):以src為原圖生成不可變得新圖像
- Bitmap createScaledBitmap(Bitmap src, int dstWidth,int dstHeight, boolean filter):以src為原圖,創(chuàng)建新的圖像,指定新圖像的高寬以及是否變。
- Bitmap createBitmap(int width, int height, Config config):創(chuàng)建指定格式、大小的位圖
- Bitmap createBitmap(Bitmap source, int x, int y, int width, int height)以source為原圖,創(chuàng)建新的圖片,指定起始坐標以及新圖像的高寬。
- public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
BitmapFactory.Option可設(shè)置參數(shù):
- boolean inJustDecodeBounds——如果設(shè)置為true,不獲取圖片,不分配內(nèi)存,但會返回圖片的高寬度信息。
- int inSampleSize——圖片縮放的倍數(shù)。如果設(shè)為4,則寬和高都為原來的1/4,則圖是原來的1/16。
- int outWidth——獲取圖片的寬度值
- int outHeight——獲取圖片的高度值
- int inDensity——用于位圖的像素壓縮比
- int inTargetDensity——用于目標位圖的像素壓縮比(要生成的位圖)
- boolean inScaled——設(shè)置為true時進行圖片壓縮,從inDensity到inTargetDensity。
好吧,就貼這么多吧,要用自己查文檔~
3.獲取Bitmap位圖
從資源中獲取位圖的方式有兩種:通過BitmapDrawable或者BitmapFactory,下面演示下: 我們首先得獲得這個
BitmapDrawable方法:
你可以創(chuàng)建一個構(gòu)造一個BitmapDrawable對象,比如通過流構(gòu)建BitmapDrawable:
BitmapDrawable bmpMeizi = new BitmapDrawable(getAssets().open("pic_meizi.jpg")); Bitmap mBitmap = bmpMeizi.getBitmap(); img_bg.setImageBitmap(mBitmap);
BitmapFactory方法:
都是靜態(tài)方法,直接調(diào),可以通過資源ID、路徑、文件、數(shù)據(jù)流等方式來獲取位圖!
//通過資源ID private Bitmap getBitmapFromResource(Resources res, int resId) { return BitmapFactory.decodeResource(res, resId); } //文件 private Bitmap getBitmapFromFile(String pathName) { return BitmapFactory.decodeFile(pathName); } //字節(jié)數(shù)組 public Bitmap Bytes2Bimap(byte[] b) { if (b.length != 0) { return BitmapFactory.decodeByteArray(b, 0, b.length); } else { return null; } } //輸入流 private Bitmap getBitmapFromStream(InputStream inputStream) { return BitmapFactory.decodeStream(inputStream); }
4.獲取Bitmap的相關(guān)信息:
這個,只要我們獲取了Bitmap對象,就可以調(diào)用相關(guān)方法來獲取對應(yīng)的參數(shù)了,getByteCount獲得大小, getHeight和getWidth這些~這里就不寫了,自己查文檔!
5.摳圖片上的某一角下來
有時,可能你想把圖片上的某一角扣下來,直接通過Bitmap的createBitmap()扣下來即可 參數(shù)依次為:處理的bitmap對象,起始x,y坐標,以及截取的寬高
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_meizi); Bitmap bitmap2 = Bitmap.createBitmap(bitmap1,100,100,200,200); img_bg = (ImageView) findViewById(R.id.img_bg); img_bg.setImageBitmap(bitmap2);
運行效果圖:
原圖:
切下來的一角:
6.對Bitmap進行縮放
我們這里不用Matrix來對Bitmap,而是直接使用Bitmap給我們提供的createScaledBitmap來實現(xiàn), 參數(shù)依次是:處理的bitmap對象,縮放后的寬高,
7.使用Bitmap進行截屏
運行效果圖:
實現(xiàn)代碼:
public class MainActivity extends AppCompatActivity { static ByteArrayOutputStream byteOut = null; private Bitmap bitmap = null; private Button btn_cut; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_cut = (Button) findViewById(R.id.btn_cut); btn_cut.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { captureScreen(); } }); } public void captureScreen() { Runnable action = new Runnable() { @Override public void run() { final View contentView = getWindow().getDecorView(); try{ Log.e("HEHE",contentView.getHeight()+":"+contentView.getWidth()); bitmap = Bitmap.createBitmap(contentView.getWidth(), contentView.getHeight(), Bitmap.Config.ARGB_4444); contentView.draw(new Canvas(bitmap)); ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteOut); savePic(bitmap, "sdcard/short.png"); }catch (Exception e){e.printStackTrace();} finally { try{ if (null != byteOut) byteOut.close(); if (null != bitmap && !bitmap.isRecycled()) { // bitmap.recycle(); bitmap = null; } }catch (IOException e){e.printStackTrace();} } } }; try { action.run(); } catch (Exception e) { e.printStackTrace(); } } private void savePic(Bitmap b, String strFileName) { FileOutputStream fos = null; try { fos = new FileOutputStream(strFileName); if (null != fos) { boolean success= b.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); if(success) Toast.makeText(MainActivity.this, "截屏成功", Toast.LENGTH_SHORT).show(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
代碼分析:
代碼非常簡單,final View contentView = getWindow().getDecorView();這句代碼是獲取當前XML 根節(jié)點的View!然后設(shè)置截屏的大小,調(diào)用下contentView.draw(new Canvas(bitmap));好了,然后 bitmap轉(zhuǎn)換成流,接著寫入SD卡,沒了~當然從結(jié)果我們也可以看出,截圖截取的是改APP的內(nèi)容而已! 如果要截全屏,自行谷歌~!
本節(jié)小結(jié):
本節(jié)給大家講解下Bitmap,BitmapFactory和他的靜態(tài)內(nèi)部類Options,以及BitmapDrawable的 基本使用,其實Bitmap我們知道怎么創(chuàng)建就好了,他的擴展一般是通過Matrix和Canvas來實現(xiàn)的, Bitmap,我們更多的時候關(guān)注的是OOM問題,下一節(jié)我們就來學習下如何避免Bitmap的OOM問題! 謝謝~