1.落筆緣由
在開發(fā)過程中,對大圖進(jìn)行圖片壓縮是很常見的,因?yàn)槿绻麑⒁粋€未壓縮過的上M的大圖直接讀到內(nèi)存中,是很占內(nèi)存的。在上傳圖片的時候,如果為了節(jié)省上傳流量,也需要對圖片進(jìn)行壓縮。不管出于什么原因,反正壓縮圖片用得很頻繁就對了。
2.壓縮的方式
從了解的情況來看,壓縮一般有兩種方式分別是質(zhì)量壓縮和尺寸壓縮。
(1)質(zhì)量壓縮
圖片有三種存在方式,一種是保存在硬盤或U盤等以文件file的形式存在的;一種是以流的形式存在的;還有一種是以bitmap的形式。質(zhì)量壓縮實(shí)現(xiàn)的是將以file形式存在的圖片進(jìn)行壓縮,并不會對圖片的像素進(jìn)行壓縮,所以質(zhì)量壓縮只會對以file形式存在的圖片有作用。但是如果將file形式的圖片讀入內(nèi)存中,以bitmap的形式存在,會發(fā)現(xiàn)壓縮前后的bitmap大小是沒有改變的,因?yàn)閎igmap在內(nèi)存中的大小是按像素計算的,而質(zhì)量壓縮不會改變像素。
質(zhì)量壓縮主要是通過在保持像素的前提下改變圖片的位深及透明度等,來達(dá)到壓縮圖片的目的。這種情況就相對于像素點(diǎn)能表現(xiàn)得顏色變少了,所有通過質(zhì)量壓縮是有可能照成圖片失真的。
質(zhì)量壓縮主要借助Bitmap中的compress方法實(shí)現(xiàn):
public boolean compress(CompressFormat format, int quality, OutputStream stream)
- format是壓縮后的圖片的格式,可取值:Bitmap.CompressFormat .JPEG、.PNG、.WEBP。
- quality的取值范圍為[0,100],值越小,經(jīng)過壓縮后圖片失真越嚴(yán)重,圖片文件也會越小,100表示不壓縮(PNG格式的圖片會忽略quality值的設(shè)定,quality值無效)
- stream指定壓縮的圖片輸出的地方,比如某文件
1)質(zhì)量壓縮的步驟
<1>先獲取bitmap的byte值
<2>用bitmap的byte除以用戶給定的要壓縮到的byte值,計算出要壓縮的次數(shù)
2)具體實(shí)現(xiàn)
public void compressImage(Bitmap image, String outPath, int maxSize) throws IOException
{
ByteArrayOutputStream os = new ByteArrayOutputStream();
int options = 100;//100表示不壓縮圖片,這里是想將圖片讀到ByteArrayOutputStream流中
image.compress(Bitmap.CompressFormat.JPEG, options, os);
//maxSize是用戶希望將圖片壓縮成 多少kb,因?yàn)閛ptions的范圍在0到100所以不能這里需要 //對options的值做一個判斷
//循環(huán)對圖片進(jìn)行壓縮
while (options>10&&os.toByteArray().length / 1024 > maxSize)
{
os.reset();
options -= 10;
image.compress(Bitmap.CompressFormat.JPEG, options, os);
}
FileOutputStream fos = new FileOutputStream(outPath);
fos.write(os.toByteArray());
fos.flush();
fos.close();
}
(2)尺寸壓縮
尺寸壓縮會直接改變圖片的像素,會改變圖片在內(nèi)存中的大小,所以以bitmap形式存在的圖片經(jīng)過尺寸壓縮后占用內(nèi)存會變小。
1)尺寸壓縮步驟
<1>先獲取圖片的寬高,為了省內(nèi)存,以只讀去圖片的邊的形式獲取寬高
將BitmapFactory.Options的options.inJustDecodeBounds=true,再通過BitmapFactory.decodeFile(imgPath, options)方法,將圖片的寬高像素保存到options中,就可以通過options.outWidth和options.outHeight獲取寬高。
<2>根據(jù)用戶提供的寬高,與原圖的寬高進(jìn)行對比,計算出縮放比
<3>將獲取的縮放比賦值給inSampleSize
2)具體實(shí)現(xiàn)
public Bitmap compressImage(String imgPath, float pixelW, float pixelH)
{
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 開始讀入圖片,此時把options.inJustDecodeBounds 設(shè)回true,即只讀邊不讀內(nèi)容
newOpts.inJustDecodeBounds = true;
newOpts.inPreferredConfig = Config.RGB_565;
// 將file形式的圖片轉(zhuǎn)為bitmap
Bitmap bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
newOpts.inJustDecodeBounds = false;
//原圖的寬高
int w = newOpts.outWidth;
int h = newOpts.outHeight;
// 想要縮放的目標(biāo)尺寸
float hh = pixelH;
float ww = pixelW;
// 縮放比。由于是固定比例縮放,只用高或者寬其中一個數(shù)據(jù)進(jìn)行計算即可
int be = 1;// be=1表示不縮放
if (w > h && w > ww)
{// 如果寬度大的話根據(jù)寬度固定大小縮放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh)
{// 如果高度高的話根據(jù)寬度固定大小縮放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;// 設(shè)置縮放比例
// 開始壓縮圖片,要讀取整張圖片內(nèi)存,要將options.inJustDecodeBounds 設(shè)回false
bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
return bitmap;
}
3.需要了解的知識
(1)BitmapFactory.Option的inSampleSize值
inSampleSize值表示縮略圖大小為原圖大小的幾分之一。例如,inSampleSize==4時則縮略圖的寬和高都為原圖的1/4,相應(yīng)的圖片大小就為原始大小的1/16,如果inSampleSize值<=1時則取1。需要注意的是,inSampleSize值只能是2的整數(shù)次冪,如果不是的話則會向下取得最大的2的整數(shù)次冪(整數(shù)次冪這個沒驗(yàn)證過,有時間再驗(yàn)證)。
(2)compress(Bitmap.CompressFormat format, int quality, OutputStream stream)的quality
compress(Bitmap.CompressFormat format, int quality, OutputStream stream)方法中quality代表的是圖片的質(zhì)量,取值范圍為0~100, 0表示壓縮為最小質(zhì)量,100表示壓縮為最大質(zhì)量(即保持原圖質(zhì)量)
(3)位深以及色深
網(wǎng)上很多說法,有人說位深和色深是同一個概念,但更多的是說他們是兩個不同的概念,從百度百科兩篇關(guān)于位深和色深的文章,
位深度
色深度
就我個人理解,其實(shí)他們描述的都是像素能夠表現(xiàn)得顏色有多少種,我覺得他們應(yīng)該指的是同一個概念。網(wǎng)上看到一個評論,“像素才可以表現(xiàn)出數(shù)字色彩,像素的色彩由RGB通道決定。位深度的描述對象是通道,色彩深度的描述對象是像素(或者圖像)”。前面一句是對的,但是后面這句“位深度的描述對象是通道,色彩深度的描述對象是像素(或者圖像)”,我感覺有問題。下面舉例子來理解。
色深(Color Depth),也稱之為色位深度,在某一分辨率下,每一個像素點(diǎn)可以有多少種色彩來描述,它的單位是“bit”(位)。典型的色深是8-bit、16-bit、24-bit和32-bit。深度數(shù)值越高,可以獲得更多的色彩。
如果R,G,B三個通道可描述顏色位數(shù)分別8,8,8,,一個像素點(diǎn)的色彩深度是24-bit。如果R,G,B三個通道可描述顏色位數(shù)分別4,4,2,,一個像素點(diǎn)的色彩深度是10-bit。
從目前查的資料來看,我認(rèn)為網(wǎng)上所說的位深度和色深是一個概念。
這個是Android studio里的,

對這張圖片,在電腦上右擊點(diǎn)擊屬性查看該圖片,可以看到也是32bit

如下,A代表透明度;R代表紅色;G代表綠色;B代表藍(lán)色。
ALPHA_8
表示8位Alpha位圖,即A=8,一個像素點(diǎn)占用1個字節(jié),它沒有顏色,只有透明度
ARGB_4444
表示16位ARGB位圖,即A=4,R=4,G=4,B=4,一個像素點(diǎn)占4+4+4+4=16位,2個字節(jié)
ARGB_8888
表示32位ARGB位圖,即A=8,R=8,G=8,B=8,一個像素點(diǎn)占8+8+8+8=32位,4個字節(jié)
RGB_565
表示16位RGB位圖,即R=5,G=6,B=5,它沒有透明度,一個像素點(diǎn)占5+6+5=16位,2個字節(jié)
4.總結(jié)
(1)尺寸壓縮不會失真,質(zhì)量壓縮有可能會失真(未驗(yàn)證過)
(2)圖片格式,對應(yīng)Bitmap的compress(Bitmap.CompressFormat format, int quality, OutputStream stream)方法中第一個參數(shù)。CompressFormat類是個枚舉,有三個取值:JPEG、PNG和WEBP。
1)PNG是無損格式(忽略質(zhì)量設(shè)置),會導(dǎo)致方法中的第二個參數(shù)壓縮質(zhì)量失效。
2)JPEG是一種針對相片影像而廣泛使用的一種失真壓縮標(biāo)準(zhǔn)方法。JPEG的壓縮方式通常是破壞性資料壓縮(lossy compression),意即在壓縮過程中圖像的品質(zhì)會遭受到可見的破壞。
3) WEBP格式是Google新推出的,據(jù)官方資料稱“在質(zhì)量相同的情況下,WEBP格式圖像的體積要比JPEG格式圖像小40%?!?br>
(3)質(zhì)量壓縮對三種格式的圖片的影響:
1)PNG格式的確是忽略質(zhì)量設(shè)置的,不同壓縮質(zhì)量下圖片大小不變,所以PNG格式的圖片只能通過改變圖片尺寸進(jìn)行壓縮。
2)quality越?。磯嚎s質(zhì)量值越?。?,JPEG格式和WEBP格式的圖片有較為明顯的失真,但JPEG格式的圖片失真更為嚴(yán)重。
(4)Bitmap一定要在使用完后調(diào)用recycle()回收,否則占用內(nèi)存會不斷增大
if (bitmap!=null&&!bitmap.isRecycled())
{
bitmap.recycle();
bitmap = null;
}
5.參考文章
http://blog.csdn.net/ymangu666/article/details/37729109
http://blog.csdn.net/alfred_c/article/details/50542741
http://blog.csdn.net/ymangu666/article/details/37729109
https://www.liangzl.com/get-article-detail-28355.html