Android自定義控件(八)——詳解創建bitmap的方式

      網友投稿 1247 2025-04-03

      本文目錄

      什么是Bitmap

      Bitmap格式

      它是如何存儲每個像素點的

      如何進行壓縮防止OOM

      創建Bitmap

      BitmapFactory創建

      BitmapFactory.Options參數詳解

      直接通過Bitmap創建

      什么是Bitmap

      Bitmap是繪圖中非常重要的概念,在我們前面自定義的所有View中,他們的畫布Canvas說到底都其實是Bitmap,我們先來看看我們常用的代碼片段:

      Bitmap bgBitmap=Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);//創建一個新空白位圖 Canvas canvasBg=new Canvas(bgBitmap); canvasBg.drawColor(Color.RED);

      1

      2

      3

      這段代碼中,我們先利用bitmap創建一個空白位圖,然后在利用Bitmap在創建一個Canvas對象,后續的所有操作其實都是繪制在這個bitmap上的。其實這也間接說明了,bitmap就是由一個個像素點構成的,你可以通過Canvas繪制任何東西在這款bitmap上。

      Bitmap格式

      既然Bitmap是由一個一個像素點構成的,那么就我們需要知道兩個概念:

      1.它是如何存儲每個像素點的

      2.如何進行壓縮防止OOM

      它是如何存儲每個像素點的

      一張位圖所占用的內存=圖片的長度(px)*圖片的寬度(px)*一個像素占用的字節數。

      而這里一個像素所占用的字節數,就是上面代碼中最后一個參數Bitmap.Config.ARGB_8888。

      其中A代表透明度,R代表紅色,G代表綠色,B代表藍色。這個參數其實有四種,分別是:

      1.ALPHA_8:表示8位的alpha位圖,表示只存儲圖片的透明度,不存儲顏色值,一個像素占8位,也就是一個字節。

      2.ARGB_4444:表示16位的ARGB位圖,即透明度A,紅色R,綠色G,藍色B各占4位,一個像素點占4+4+4+4=16位,2個字節。

      3.ARGB_8888:這個是我們最常用的,表示32位的ARGB位圖,即透明度A,紅色R,綠色G,藍色B各占8位,一個像素點占8+8+8+8=32位,4個字節。

      4.RGB_565:表示16位的RGB位圖,沒有透明度值,R紅色占5位,G綠色占6位,B藍色占5位,一個像素點占5+6+5=16位,2個字節。

      上面的四種格式中,ARGB_444因為畫質慘不忍睹,所以在API13中已經棄用,而ARGB_8888一個顏色占了8位,所以畫質最高,但如果你的項目中對透明度沒什么要求的畫,建議使用RGB_565,能節省一半的內存開銷。

      如何進行壓縮防止OOM

      如果有需要將bitmap存儲在硬盤上,那么必然會考慮到壓縮的問題,所以Android也給我們提供了壓縮的方案,分別是JPEG,PNG以及WEBP三種。

      1.CompressFormat.JPEG:采用JPEG壓縮算法,這是一種有損壓縮,而且不支持透明度。

      2.CompressFormat.PNG:采用PNG壓縮算法,這是一種支持透明度的無損壓縮方式。

      3.CompressFormat.WEBP:這種提供了有損壓縮和無損壓縮兩種,在API14到API17中,是一種有損壓縮格式,不支持透明度,在API18以后是無損壓縮,支持透明度。在相同質量下,WEBP比JPEG小40%,比PNG小26%,但是都是犧牲壓縮時間來減小文件大小,是JPEG編碼長8倍,是PNG的5倍。

      創建Bitmap

      創建Bitmap的方式有兩種,一種是通過BitmapFactory進行創建,一種是bitmap的靜態方法。

      BitmapFactory創建

      我們先來介紹BitmapFactory的創建方式,下面是Bitmap的所有函數:

      public static Bitmap decodeResource(Resources res,int id) public static Bitmap decodeResource(Resources res,int id,Options opts) public static Bitmap decodeFile(String pathName) public static Bitmap decodeFile(String pathName,Options opts) public static Bitmap decodeByteArray(byte[] data,int offset,int length) public static Bitmap decodeByteArray(byte[] data,int offset,int length,Options opts) public static Bitmap decodeFileDescriptor(FileDescriptor fd) public static Bitmap decodeFileDescriptor(FileDescriptor fd,Options opts) public static Bitmap decodeStream(InputStream is) public static Bitmap decodeStream(InputStream is,Options opts) public static Bitmap decodeResourceStream(Resources res,TypedValue value,InputStream is,Rect pad,Options opts)

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      從這些函數可以看出來BitmapFactory的功能很強大,可以針對資源,文件,字節數組,FileDescriptor和InputStream數據流解析出對應的Bitmap對象,而且基本上,每個函數都有兩種實現,而多的按個參數就是Options opts(這個參數,最后這標題最后講解)

      其實上面的函數基本都很好理解,有一定Java文件操作經驗的應該都能很好的使用,這里我們只要先介紹decodeFileDescriptor這個函數,我們先來看看它的使用代碼:

      String path="/data/data/background.jpg"; FileInputStream is=new FileInputStream(path) Bitmap bitmap=BitmapFactory.decodeFileDescriptor(is.getFD());

      1

      2

      3

      這里實現起來也很簡單,但有一個疑問,就是這里已經有文件路徑,可以直接調用decodeFile()直接生成,為何還要多此一舉呢?

      小編就直接告訴大家把,因為這樣更節約內存空間,而decodeFile比decodeFileDescriptor更容易OOM,至于為什么,直接查看源碼大家就知道了,因為decodeFile內部調用了decodeStream,并且調用了如下代碼,申請了兩次空間:

      is=new BufferedInputStream(is,16*1024); tempStorage=new byte[16*2024];

      1

      2

      接著,我們來看看decodeByteArray如何生成Bitmap,假如這張圖片來自網絡,我們看看先如何獲取這個byte[],代碼如下:

      public class LYJMethod { public static byte[] getImage(String path) throws Exception { URL url=new URL(path); HttpURLConnection httpURLConnection=(HttpURLConnection)url.openConnection(); httpURLConnection.setRequestMethod("GET"); httpURLConnection.setReadTimeout(6000); InputStream is=null; if(httpURLConnection.getResponseCode()==200){ is=httpURLConnection.getInputStream(); byte[] result=readStream(is); is.close(); return result; } return null; } public static byte[] readStream(InputStream is) throws Exception{ ByteArrayOutputStream baos=new ByteArrayOutputStream(); byte[] buffer=new byte[1024]; int len=-1; while((len=is.read(buffer))!=-1){ baos.write(buffer,0,len); } baos.close(); is.close(); return baos.toByteArray(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      Android自定義控件(八)——詳解創建bitmap的方式

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      這里可能大家有個疑問,為何明明已經獲取了buffer數組,為何還要轉換位toByteArray呢?這是因為這個函數所需要的字節數組,以大家想象中的不一樣,而是把輸入流轉換位字節內存輸出流的字節數組格式。如果不轉換返回結果會一直為null,大家可以在程序中調試試試。

      這些生成bitmap函數也就這兩個函數需要額外注意,其他的基本都差不多,這里就不再贅述了。

      BitmapFactory.Options參數詳解

      接著我們講解每個函數最后多出來的一個參數Options,這個是設置Bitmap的采樣率,通過改變圖片的寬度,高度,縮放比例等,以達到減少圖片像素的目的。簡單的說,通過這個參數,可以更好的控制bimap。下面是這個參數部分成員變量:

      public boolean injustDecodeBounds; public int inSampleSize; public int inDensity; public int inTargetDensity; public int inScreenDensity; public boolean inScaled; public Bitmap.Config inPreFerredConfig; public int outWidht; public int outHeight; public String outMimeType;

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      1.injustDecodeBounds:這個參數用于獲取圖片信息,如果設置為true,表示只獲取圖片的信息,不分配內存,也就是說調用如下代碼后,bitmap為空(默認為false):

      BitmapFactory.Options options=new BitmapFactory.Options(); options.inJustDecodeBounds=true; Bitmap bitmap=BitmapFactory.decodeRecource(getResources(),R.drawable.backgroud,options);

      1

      2

      3

      2.inSampleSize:這個參數用于壓縮圖片,比如將這個字段設置為4,意思就是從原來圖片每4個像素中取一個像素作為返回結果,也就是圖片縮小了4倍。

      3.inScaled:這個參數用于設置是否縮放圖片,我們都知道,我們的安裝項目中圖片文件夾有很多,如下圖所示:

      drawable文件夾同樣也是如此,比如mdpi為240,其中有一張圖片,但其他文件夾都沒有對應大小的圖片,如果應用到xhdpi的屏幕中,那么這個參數設置true,就將這個240下完美顯示的圖片,縮放成480在當前屏幕顯示, 這樣就會造成圖片模糊,如果不縮放就設置為false(默認為true)。

      4.inDensity,inTargetDensity

      這二個參數是相互關聯的所以,有必要在一起講解,同樣,我們先來看看這二個參數的意思:

      inDensity:用于設置文件所在資源文件夾的屏幕分辨率。

      inTargetDensity:表示真實顯示的屏幕分辨率。

      scale=inTargetDensity/inDensity,這個公式就是手動設置文件所在資源文件夾的分辨率和真實顯示屏幕分辨率來指定圖片的縮放比例,也就是說,可以通過這兩個參數,自己掌握縮放的大小,對于第三個參數理解。

      5.inPreferredConfig

      這個參數用來設置像素的存儲格式,我們在前面已經介紹過了Android手機的4中存儲格式,分別為ALPAH_8,RGB_565,ARGB_8888,ARGB_4444,這個參數默認ARGB_8888。

      這里詳細講解最常用的6個成員變量,還有3個成員變量,其中outWidht,outHeight就是圖片的詳細寬高信息,outMimeType就是圖片的格式,也就是如果你要獲取圖片信息直接使用這3個參數即可。inScreenDensity根本用不到,所以這里就不講解。

      直接通過Bitmap創建

      同樣,我們直接看看Bitmap自帶的靜態方法:

      static Bitmap createBitmap(int widht,int height,Bitmap.Config config) static Bitmao createBitmap(Bitmap src) static Bitmap createBitmap(Bitmap Source,int x int y,int width,int height) static Bitmap createBitmap(Bitmap Source,int x int y,int width,int height,Matrix m,boolean filter) static Bitmap createBitmap(int[] colors,int widht,int height,Bitmap.Config config) static Bitmap createBitmap(int[] colors,int offset,int stride,int width,int height,Bitmap.Config config) static Bitmap createScaledBitmap(Bitmap src,int dstWidht,int dstHeight,boolean filter)

      1

      2

      3

      4

      5

      6

      7

      最后一個方法我們放大鏡那章已經用到過,就是按比例放大縮小圖片,這里就不在贅述,同樣的createBitmap就是創建一個空白位圖,前面也用到過,這里也不在講解。這里主要講解第3個到底6個方法。我們先來看一段代碼:

      //createBitmap(Bitmap Source,int x int y,int width,int height) Bitmap src=BitmapFactory.decodeResource(getResources(),R.drawable,backgroud); Bitmap bitmap=Bitmap.createBitmap(src,src.getWidth()/3,src.getHeight()/3,src.getWidth()/3,src.getHeight()/3)

      1

      2

      3

      這個方法用于裁剪圖片,其中x,y用于定義裁剪圖片的左上角坐標,width和height用于設置裁剪圖片的寬高,source就是源圖像,這里我們獲取了原圖片中間的1/9圖像。

      static Bitmap createBitmap(Bitmap Source,int x int y,int width,int height,Matrix m,boolean filter)

      1

      第4個方法多了兩個參數分別是Matrix m,這個參數用于給裁剪后的圖片添加矩陣,boolean filter用于是否給圖片添加濾波效果,如果設置為true,能夠減少圖像中由于噪聲引起的突兀的孤立的像素塊。比如我這樣設置上面的代碼:

      //createBitmap(Bitmap Source,int x int y,int width,int height) Bitmap src=BitmapFactory.decodeResource(getResources(),R.drawable,backgroud); Matrix matrix=new Matrix(); matrix.setScale(2,1); Bitmap bitmap=Bitmap.createBitmap(src,src.getWidth()/3,src.getHeight()/3,src.getWidth()/3,src.getHeight()/3,matrix,true)

      1

      2

      3

      4

      5

      將是將裁剪后的圖片寬度方法兩倍。

      接著我們再來看看,下面兩個方法:

      static Bitmap createBitmap(int[] colors,int widht,int height,Bitmap.Config config) static Bitmap createBitmap(int[] colors,int offset,int stride,int width,int height,Bitmap.Config config)

      1

      2

      1.colors:當前圖像所對應的每個像素的數組,它的數組長度必須是圖片的widht*height。

      2.width,height:當前圖像的寬高。

      3.config:用于指定圖像的存儲格式,比如:ARGB_888。

      這種兩個方法使用起來難度非常大,你需要設置每一個像素點的ARGB四個顏色,所以這里不再講解,我們將結合下一節,詳細bitmap的應用,教你如何讓圖片變得更鮮艷。

      Android 數據結構

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:自動化機械生產,助推工業革命的新時代
      下一篇:查找文檔內容(wps怎么查找文檔內容)
      相關文章
      亚洲成年网站在线观看| 亚洲校园春色小说| 亚洲精品无码不卡在线播放| 亚洲妇女水蜜桃av网网站| 亚洲人成影院在线| 亚洲av无码不卡一区二区三区| 亚洲码国产精品高潮在线| a级亚洲片精品久久久久久久| 亚洲成aⅴ人片久青草影院| 国产精品亚洲专区无码唯爱网| 亚洲AV成人无码久久WWW| 亚洲欧美成人综合久久久| 亚洲精品色播一区二区| 亚洲国产精品无码久久| 亚洲AV色欲色欲WWW| AV激情亚洲男人的天堂国语| 色偷偷噜噜噜亚洲男人| vvvv99日韩精品亚洲| 亚洲国产一成久久精品国产成人综合| 五月天婷亚洲天综合网精品偷| 亚洲成aⅴ人片久青草影院按摩| 亚洲av无码专区在线观看下载| 色偷偷亚洲男人天堂| 亚洲第一视频在线观看免费| 亚洲女人被黑人巨大进入| 久久精品国产精品亚洲下载| 亚洲无码在线播放| 久久精品国产亚洲AV网站| 亚洲AV成人无码久久精品老人| 久久精品国产亚洲av高清漫画| 亚洲激情校园春色| 亚洲天堂2017无码中文| 亚洲精品9999久久久久无码| 国产精品亚洲精品日韩电影| 亚洲欧洲精品成人久久奇米网| 亚洲国产另类久久久精品黑人| 亚洲va在线va天堂va888www| 亚洲欧洲高清有无| 亚洲色无码专区一区| 亚洲av手机在线观看| 亚洲三区在线观看无套内射|