android 图片操作
Android中圖片的讀取,修改,顯示和保存涉及到的類大致如圖所示。
在讀取圖片文件時,先將圖片文件轉換為InputStream對象,然后通過BitmapFactory將其轉換為Bitmap對象。?
在圖片保存時,先將Bitmap對象轉換為OutputStream對象,然后再將OutputStream輸出到文件中。?
如果要對圖片進行修改,可以通過將Bitmap對象轉換為顏色數組(int[])來修改,也可以通過Canvas來修改。此外Bitmap類提供了一個createBitmap的靜態方法,可以對Bitmap對象做一些轉換。?
顯示圖片時,可以將Bitmap對象轉換為Drawable對象,然后設置給ImageView。?
本文介紹圖片文件的讀取。
Android支持的圖片格式
目前在Android中支持的圖片文件格式如下。其中WebP格式是從Android4.0開始支持,但在Android4.0到Android4.2.1之間的Android系統不支持無損壓縮和有透明度的WebP格式圖片,Android4.2.1之后才開始支持所有的WebP格式圖片。?
下圖截取自http://developer.android.com/guide/appendix/media-formats.html?
讀取圖片文件到InputStream
1、讀取SD卡中的圖片到InputStream?
對SD卡中的文件,獲取到文件的路徑之后便可以通過FileInputStream類來生成InputStream。FileInputStream類是InputStream類的派生類。代碼示例如下。
- 1
- 1
2、讀取resource中的圖片到InputStream?
對resource/drawable目錄下的圖片,每個文件都會在R文件中生成一個對應的整數id,通過“R.drawable.文件名”來得到id值,然后通過Resource類的openRawResource()來得到該文件對應的InputStream對象。代碼示例如下。
- 1
- 1
3、讀取assets中的圖片到InputStream?
對assets目錄中的圖片,先通過getAssets()得到AssetManager對象,然后通過AssetManager對象的open方法來打開文件,得到該文件對應的InputStream對象。代碼示例如下。
- 1
- 1
注意:如果圖片在assets根目錄,讀取時只需要加圖片文件名,不需要加/assets/,圖片文件名需要包含擴展名。如果圖片在assets的子目錄中,需要加上子目錄的路徑,例如apple.png在/assert/fruit/spring/目錄中,則open參數為”/fruit/spring/apple.png”。
4、 通過Uri讀取圖片到InputStream?
Uri全寫是Universal Resource Identifier(通用資源標志符),Android系統中所有資源都可以用Uri來表示。在獲取到資源的Uri后可以通過ContentResolver將其解析成InputStream對象。代碼示例如下。
- 1
- 1
openInputStream()核心代碼如下。
String scheme = uri.getScheme(); if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {OpenResourceIdResult r = getResourceId(uri);InputStream stream = r.r.openRawResource(r.id);return stream; } else if (SCHEME_FILE.equals(scheme)) {return new FileInputStream(uri.getPath()); } else {AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);return fd.createInputStream(); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
這里openInputStream()內先判斷Uri的scheme類型,如果是resource類型,則先調用getResourceId()得到該Uri對應的資源id,然后調用openRawResource()讀取文件到InputStream對象。如果是文件類型,則調用uri.getPath()得到文件路徑,然后調用FileInputStream()讀取文件到InputStream對象。對其他類型(即assets類型)則調用openAssetFileDescriptor()先得到一個AssetFileDescriptor對象,然后再得到一個InputStream對象。?
可以看到,通過Uri讀取圖片的流程和上述根據類型直接讀取大體是一樣的(assets類型稍有不同)。
將InputStream轉換為Bitmap
通過BitmapFactory的decodeStream()方法可以將InputStream轉換為Bitmap對象。代碼示例如下。
Bitmap bitmap = BitmapFactory.decodeStream(stream);- 1
- 1
直接讀取圖片文件到Bitmap
上述流程是先將圖片文件讀取到InputStream中,然后將InputStream轉換為Bitmap對象,需要兩步。BitmapFactory提供了一些靜態類可以直接將圖片文件轉換為Bitmap對象。?
直接讀取SD卡中的圖片到Bitmap示例代碼如下。
- 1
- 1
直接讀取resource中的圖片到Bitmap示例代碼如下。
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), id);- 1
- 1
BitmapFactory并沒有提供直接讀取assets中圖片的api。?
查看BitmapFactory源碼可以看到,BitmapFactory.decodeFile()和BitmapFactory.decodeResource()兩個api都是先將SD卡或resource中的圖片讀取到InputStream,然后再調用BitmapFactory.decodeStream()來解析。由此可以看出,直接讀取圖片到Bitmap和先讀取圖片到InputStream,然后將InputStream轉換為Bitmap本質上是一樣的,只是BitmapFactory將這兩步封裝在一起。因此,如果要將非assets中的圖片文件轉換為Bitmap,一般就直接使用BitmapFactory即可。
BitmapFactory.Options
BitmapFactory在decode時可以傳遞一個Options參數,用來設置轉換到Bitmap時的一些參數。?
BitmapFactory.Options中包含了一系列的public成員變量,每個成員變量代表一個轉換參數。這里列出了BitmapFactory.Options類中定義的全部public成員變量。在BitmapFactory.Options類的注釋中詳細的描述了每個成員變量的含義。這里只介紹幾個常用的成員變量的用法。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
inJustDecodeBounds:此變量默認為false。當此變量被設置為true時,表示只對圖片的Bound(圖片的范圍,也就是長寬包含的像素大小)進行解析,不生成Bitmap對象。在BitmapFactory.Options定義中可以看到有三個out開頭的成員變量,outWidth,outHeight和outMimeType。當inJustDecodeBounds設置為true時,會分別將圖片的寬度,高度和Mime類型保存到這三個成員變量中。?
inSampleSize:inSampleSize是一個整數,表示對圖片像素的取樣比例,即圖片中每inSampleSize個像素取樣后對應Bitmap中的一個像素。例如inSampleSize=2,表示圖片中每兩個像素對應Bitmap中的一個像素,轉換后Bitmap的寬和高包含的像素個數是原圖片的1/2,總像素個數是原圖的1/4。inSampleSize=4,表示圖片中每四個像素對應Bitmap中的一個像素,轉換后Bitmap的寬和高包含的像素個數是原圖片的1/4,總像素個數是原圖的1/16。如果它小于1等于1,則表示完全取樣,即圖片中每個像素都會被提取保存到Bitmap中,轉換后Bitmap的寬和高包含的像素個數和原圖片相等。圖片取樣時只能按照2的整數次冪來取樣,比如1,2,4,8,16……,如果inSampleSize不是2的整數次冪,則實際取樣時使用和inSampleSize最接近的2的整數次冪來取樣,比如inSampleSize= 10,和10最接近的2的整數次冪是8,因此會每8個像素取樣一次。?
inPreferredConfig:表示圖片中每個像素的保存方式。默認為Bitmap.Config.ARGB_8888,表示每個像素需要包含Alpha,R,G,B四個通道的信息,每個通道用8位來表示,也就是需要4個字節來保存一個像素。
圖片文件讀取注意事項
1、WebP圖片格式問題?
雖然Android官方描述是在4.0之后開始支持WebP格式,但在4.0到4.2.1不支持有透明度設置和無損壓縮的WebP格式圖片。所以如果簡單的判斷,圖片如果是WebP格式,且是4.0以上的系統,就通過BitmapFactory來解析,很可能會出現有些圖片能解析,有些又不能解析的情況。此外,還有一些特殊機型,例如NokiaXL雖然是Android4.1的系統,但并不支持WebP編解碼。因此,最好是從4.2系統開始用BitmapFactory來解析WebP格式的圖片。?
2、解析大圖時的OOM問題?
Android為每個應用分配的堆內存空間是有限的,如果應用請求的內存超過了限制,就會導致OOM。根據手機內存大小的不同,一般應用能夠使用的堆內存在幾十兆到兩三百兆之間。然后應用在讀取圖片文件時非常消耗內存的,一張手機相機拍出的照片都有3M左右,如果每張圖都直接讀取,即使不造成OOM,也會導致頻繁GC。還有些超大圖一張就有幾個G,如果直接讀取肯定會導致OOM。為了避免讀取大圖時造成的OOM問題,并減少內存消耗,一般在讀取圖片時都需要根據圖片尺寸來取樣。也就是設置BitmapFactory.Options的inSampleSize屬性。示例代碼如下。
總結
以上是生活随笔為你收集整理的android 图片操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: anroid 图片处理加载对比(ima
- 下一篇: android 手机投影演示 ——vys