Android 基于Bitmap的四種圖片壓縮方式
知識點介紹
Android 中圖片主要以 Bitmap 的形式存在,所以壓縮圖片主要就是減少 Bitmap 的大小。Bitmap 的大小可以通過如下的公式計算得到:size = width * height * 單個像素所占字節(jié)數(shù)。因此壓縮圖片通過改變公式中的三個變量即可實現(xiàn)。
單個像素所占空間大小在 Android 中有多種,詳見如下
| 格式 | 所占空間 | 說明 |
|---|---|---|
| Bitmap.Config.ALPHA_8 | 1B | 該種格式表示圖片只有透明度沒有顏色,1個像素占用8位 |
| Bitmap.Config.ARGB_4444 | 2B | 該種格式表示圖片透明通道 A 及顏色 R、G、B 各占用4位,共16位 |
| Bitmap.Config.ARGB_8888 | 4B | 該種格式表示圖片透明通道 A 及顏色 R、G、B 各占用8位,共32位 |
| Bitmap.Config.RGB_565 | 2B | 該種格式表示圖片沒有透明通道,顏色 R、G、B 各占用5、6、6位,共16位 |
Android 中加載圖片默認用的是 ARGB_8888 格式,所以加載一張3000 * 4000 的圖片默認占用的空間為 45MB 左右,這個值還是很大的😂
測試代碼
fun showBitmapInfo(bitmap: Bitmap){
Log.d("Tag","壓縮后的圖片大?。?{bitmap.byteCount/1024/1024}MB,寬度:${bitmap.width},高度:${bitmap.height}")
}
結果

正文
接下來介紹四種壓縮方式
1、質量壓縮
質量壓縮主要通過 Bitmap.compress()實現(xiàn),方法介紹
/**
*
* @param format 壓縮圖像的格式
* @param quality 提示壓縮機,0-100。 根據(jù)Bitmap.CompressFormat不同,該值的解釋也不同。
* @param stream –寫入壓縮數(shù)據(jù)的輸出流。
* @return 如果成功壓縮到指定的流,則為true
*/
public boolean compress(CompressFormat format, int quality, OutputStream stream) {
}
CompressFormat 表示圖片壓縮格式,Android 源碼中包含了五種格式
| 格式名 | 解釋 |
|---|---|
| CompressFormat.JPEG | 壓縮為JPEG格式。 quality 0表示壓縮為最小大小。 100表示壓縮以獲得最大視覺質量。 |
| CompressFormat.PNG | 壓縮為PNG格式。 PNG是無損的,因此quality被忽略。 |
| CompressFormat.WEBP | 壓縮為WEBP格式。 quality 0表示壓縮為最小大小。 100表示壓縮以獲得最大視覺質量。 從Build.VERSION_CODES.Q ,值100導致文件采用無損WEBP格式。 否則,文件將為有損WEBP格式 |
| CompressFormat.WEBP_LOSSY | 壓縮為WEBP有損格式。 quality 0表示壓縮為最小大小。 100表示壓縮以獲得最大視覺質量。 |
| CompressFormat.WEBP_LOSSLESS | 壓縮為WEBP無損格式。 quality是指投入多少精力進行壓縮。 值0表示快速壓縮,導致文件大小相對較大。 100表示要花費更多時間進行壓縮,從而使文件更小。 |
測試代碼
/**
* 壓縮圖片質量
*/
fun getCompressBitmap(bitmap: Bitmap,quality:Int): Bitmap {
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos)
val byte = baos.toByteArray()
val ins = ByteArrayInputStream(byte)
val bm = BitmapFactory.decodeStream(ins)
ins.close()
baos.close()
return bm
}
效果


根據(jù)上面的日志,你會看到質量壓縮并不能改變圖片在內存中的大小,因為質量壓縮既不能改變圖片分辨率也不能改變圖片的單個像素大小。
那么你可能有些疑問:既然不能改變大小,那么還費這么大功夫轉化而且圖片還失真是為了什么?
答:源碼中對于compress方法的解釋是,將位圖的壓縮版本寫入指定的輸出流。所以應該是對輸出流中的字節(jié)數(shù)有影響
驗證
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos)
val byte = baos.toByteArray()
Log.d("Tag","quality=$quality,byte-size=${byte.size}")
結果真的是對輸出流的字節(jié)數(shù)有影響

2、采樣率壓縮
BitmapFactory.Options 中有個屬性 inSampleSize,系統(tǒng)中采樣率壓縮就是通過該屬性
/** * 如果設置為大于1的值,則請求解碼器對原始圖像進行二次采樣,返回較小的圖像以節(jié)省內存。 * 樣本大小是任一維度中與解碼后的位圖中的單個像素相對應的像素數(shù)。 例如,inSampleSize == 4 * 返回的圖像為原始寬度/高度的1/4,像素數(shù)目的1/16。 任何小于等于1的值都與1相同。 * 注意:解碼器使用基于2的冪的最終值,任何其他值將四舍五入為最接近的2的冪。 **/ public int inSampleSize;
直接上代碼
/**
* 根據(jù)設定的寬高計算縮放比
*/
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
val height = options.outHeight
val width = options.outWidth
var inSampleSize = 1
if (height > reqHeight || width > reqWidth) {
val heightRatio = round(height.toFloat() / reqHeight.toFloat()).toInt()
val widthRatio = round(width.toFloat() / reqWidth.toFloat()).toInt()
inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio
}
return inSampleSize
}
/**
* 獲取縮放后的圖片
*/
fun getSmallBitmap(filePath: String,reqWidth: Int,reqHeight: Int): Bitmap {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true //不加載 bitmap 進內存,只獲取他的基本信息
BitmapFactory.decodeFile(filePath, options)
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
options.inJustDecodeBounds = false
return BitmapFactory.decodeFile(filePath, options)
}
結果

采樣率壓縮的方式使用的還是挺多的,因為我們獲取到的圖片它的尺寸可能很大,但是我們在手機上顯示的可能不需要那么大,那我們就將圖片縮放成我們需要的大小。
3、縮放法壓縮
這種方法主要是依賴 Matrix 矩陣變換的方式對圖片進行處理。Matrix 中有很多對圖片變換的 api 這里只使用它的縮放功能,其他功能可以自行了解
代碼
/**
* 通過矩陣縮放
*/
fun matrixBitmap(bitmap: Bitmap,scale:Float):Bitmap{
val matrix = Matrix()
matrix.setScale(scale,scale)
var bm = Bitmap.createBitmap(bitmap,0,0,bitmap.width,bitmap.height,matrix,true)
return bm
}
當設置縮放比為0.5時,圖片整體就縮放為原來的1/4

4、RGB_565 通過改變圖片格式來實現(xiàn)壓縮
系統(tǒng)默認使用的是ARGB_8888的格式,所以我們只要改變這個 options 值就能實現(xiàn)
fun rgb565Bitmap(filePath: String):Bitmap{
val options = BitmapFactory.Options()
options.inPreferredConfig = Bitmap.Config.RGB_565
var bitmap = BitmapFactory.decodeFile(filePath,options)
return bitmap
}
結果圖片變成了原圖的一半

總結
對于圖片的壓縮,首先可以先將圖片格式改為 RGB_565,這樣圖片先減小一半,然后對于圖片的顯示可以使用采樣率壓縮或者縮放壓縮的方式將圖片的分辨率改為我們顯示的大小,如果是要將圖片上傳服務器那么可以使用質量壓縮的方式,但是這種方式不支持 png 格式的圖片。
以上就是Android 基于Bitmap的四種圖片壓縮方式的詳細內容,更多關于Android Bitmap圖片壓縮的資料請關注腳本之家其它相關文章!
相關文章
Android?DialogFragment使用之底部彈窗封裝示例
這篇文章主要為大家介紹了Android?DialogFragment使用之底部彈窗封裝示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
c++ mk文件出錯Jni調用產(chǎn)生java.lang.UnsatisfiedLinkError錯誤解決方法
錯誤產(chǎn)生在我把方法從c語言轉為c++語言后產(chǎn)生的,后來檢查到這種錯誤是因為mk文件出錯,加載c文件和加載c++的文件所用的代碼不一樣,下面請看2013-11-11
Android實現(xiàn)CoverFlow效果控件的實例代碼
這篇文章主要介紹了Android實現(xiàn)CoverFlow效果控件的實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05
詳解android在mob平臺實現(xiàn)qq登陸和分享
這篇文章主要介紹了詳解android在mob平臺實現(xiàn)qq登陸和分享,對接入第三方平臺SDK感興趣的同學們,可以參考下2021-04-04
Android ListView實現(xiàn)單選及多選等功能示例
這篇文章主要介紹了Android ListView實現(xiàn)單選及多選等功能的方法,結合實例形式分析了ListView單選、多選及長按多選等功能相關實現(xiàn)技巧,需要的朋友可以參考下2017-08-08

