這是一篇比較簡(jiǎn)單的處理圖片的應(yīng)用文,我們先看一下具體的場(chǎng)景:
這里實(shí)現(xiàn)了上傳圖片的功能,圖片限制在紅色框框內(nèi)且比例為4/3,標(biāo)準(zhǔn)的照片比例。但是如果用戶上傳了其他比例的圖片,為了照顧觀感肯定是要對(duì)圖片進(jìn)行一個(gè)等比壓縮處理,最后的效果和ImageView中ScareType的FitCenter效果是一樣的,也就是保持圖片的比例,并且最大化的顯示在時(shí)框中。
那么對(duì)于自定義View如何實(shí)現(xiàn)這一效果呢?首先分析一下圖片是如何被處理的。
三種情況:
-
比例小于視框
也就是圖片比較“高”,例如上圖左邊,是一張16比9的照片,9/16 < 3/4。
顯示高度 = 視框高度
-
比例等于視框
也就是4比3的圖片,可以完美的貼合視框不留空白
顯示寬高 = 視框?qū)捀?/p>
-
比例大于視框
也就是圖片比較“寬”,例如上圖右邊,比例為1比1, 1 > 3/4
對(duì)于圖片的處理就比較簡(jiǎn)單了,計(jì)算圖片和視框的比例,按照比例進(jìn)行縮放即可。
那么知道圖片處理的判斷情況以及處理方式后,接下來(lái)就是具體代碼實(shí)現(xiàn)了:
//取得圖片和圖片所處空間的比例
float scaleBitmap = ((float) bitmap.getWidth()) / bitmap.getHeight();
float scaleView = ((float)getWidth()) / getHeight();
// 空間的大小 / bitmap 的大小 = bitmap 縮放的倍數(shù)
float scaleWidth = ((float) getWidth()) / bitmap.getWidth();
float scaleHeight = ((float) getHeight()) / bitmap.getHeight();
Matrix matrix = new Matrix();
//按照比例選擇縮放參照
if (scaleBitmap < scaleView) {
//比例小于視框時(shí),全部按照?qǐng)D片高度和視框高度的比例進(jìn)行縮放
matrix.postScale(scaleHeight, scaleHeight);
}else {
//比例大于視框時(shí),全部按照?qǐng)D片寬度和視框?qū)挾鹊谋壤M(jìn)行縮放
matrix.postScale(scaleWidth, scaleWidth);
}
//bitmap 縮放
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//draw 上去
//canvas.drawBitmap(bitmap, 0, 0, paint);
//居中顯示
canvas.drawBitmap(bitmap,
(getWidth() - bitmap.getWidth()) / 2,
(getHeight() - bitmap.getHeight()) / 2, paint);
canvas.restore();
這里要注意一個(gè)問題就是,Java中進(jìn)行除法運(yùn)算并獲得帶小數(shù)點(diǎn)的結(jié)果,需要將算式中的一個(gè)值轉(zhuǎn)為float才可以取得。
在最后將bitmap畫入畫布時(shí),也要記得計(jì)算一下位置,居中顯示才算完整實(shí)現(xiàn)效果。
然后簡(jiǎn)單介紹一下Android中縮放圖像生成縮略圖的三種方式:
1、BitmapFactory和 BitmapFactory.Options
在設(shè)定好縮放值inSampleSize 后,通過BitmapFactory.decodeFile或者decode其他形式,生成縮放后的Bitmap位圖。如果已經(jīng)有Bitmap圖了,可以轉(zhuǎn)成File地址來(lái)實(shí)現(xiàn)。
而縮放值inSampleSize 可以直接設(shè)定具體倍數(shù),比如2就是2分之一倍,或者通過計(jì)算原圖寬高和設(shè)定的想達(dá)到的寬高得到比例。
其中很實(shí)用的一點(diǎn)是,在獲取圖片的寬高的時(shí)候,可以將inJustDecodeBounds設(shè)成true,此時(shí)bitmap不會(huì)加載到內(nèi)存,而只是獲取到圖片的height和width,節(jié)省內(nèi)存提高效率。
示例:
//使用BitmapFactory.Options的inSampleSize參數(shù)來(lái)縮放
public static Drawable resizeImage2(String path,
int width,int height)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//不加載bitmap到內(nèi)存中
BitmapFactory.decodeFile(path,options);
int outWidth = options.outWidth;
int outHeight = options.outHeight;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inSampleSize = 1;
if (outWidth != 0 && outHeight != 0 && width != 0 && height != 0)
{
int sampleSize=(outWidth/width+outHeight/height)/2;
Log.d(tag, "sampleSize = " + sampleSize);
options.inSampleSize = sampleSize;
}
options.inJustDecodeBounds = false;
return new BitmapDrawable(BitmapFactory.decodeFile(path, options));
}
2、使用Bitmap加Matrix來(lái)縮放
首先要獲得原bitmap,創(chuàng)建一個(gè)Matrix對(duì)象,包含想要達(dá)到的寬和高,最后在原Bitmap的基礎(chǔ)上生成新圖片。效率比較低。
示例:
//使用Bitmap加Matrix來(lái)縮放
public static Drawable resizeImage(Bitmap bitmap, int w, int h)
{
Bitmap BitmapOrg = bitmap;
int width = BitmapOrg.getWidth();
int height = BitmapOrg.getHeight();
int newWidth = w;
int newHeight = h;
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// if you want to rotate the Bitmap
// matrix.postRotate(45);
Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width,
height, matrix, true);
return new BitmapDrawable(resizedBitmap);
}
3、Android自帶的ThumbnailUtils
Android自帶的處理方法,會(huì)結(jié)合第一種和第二種方法和一些其他算法對(duì)圖片進(jìn)行加工,效率會(huì)比第二種高一點(diǎn),使用也比較方便,一行代碼就可以了:
imView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap,200,100));
關(guān)于圖片壓縮
最后在三種圖片的處理方式中都發(fā)現(xiàn)了一個(gè)問題,也是以前我對(duì)圖片處理的一個(gè)知識(shí)盲區(qū):圖片不僅在拉大的時(shí)候會(huì)模糊,在縮小的時(shí)候同樣也可能模糊。一張照片,壓縮10倍之后,其分辨率已經(jīng)不足以看清細(xì)節(jié),鋸齒非常嚴(yán)重。所以這三種圖片的壓縮,是會(huì)降低顯示效果的,如果需要尺寸減小畫質(zhì)不變,應(yīng)該需要其他的算法來(lái)解決。