這裏實現了上傳圖片的功能,圖片限制在紅色框框內且比例爲4/3,標準的照片比例。可是若是用戶上傳了其餘比例的圖片,爲了照顧觀感確定是要對圖片進行一個等比壓縮處理,最後的效果和ImageView中ScareType的FitCenter效果是同樣的,也就是保持圖片的比例,而且最大化的顯示在時框中。java
那麼對於自定義View如何實現這一效果呢?首先分析一下圖片是如何被處理的。算法
三種狀況:canvas
比例小於視框post
也就是圖片比較「高」,例如上圖左邊,是一張16比9的照片,9/16 < 3/4。spa
顯示高度 = 視框高度rest
比例等於視框code
也就是4比3的圖片,能夠完美的貼合視框不留空白cdn
顯示寬高 = 視框寬高對象
比例大於視框blog
也就是圖片比較「寬」,例如上圖右邊,比例爲1比1, 1 > 3/4
對於圖片的處理就比較簡單了,計算圖片和視框的比例,按照比例進行縮放便可。
那麼知道圖片處理的判斷狀況以及處理方式後,接下來就是具體代碼實現了:
//取得圖片和圖片所處空間的比例
float scaleBitmap = ((float) bitmap.getWidth()) / bitmap.getHeight();
float scaleView = ((float)getWidth()) / getHeight();
// 空間的大小 / bitmap 的大小 = bitmap 縮放的倍數
float scaleWidth = ((float) getWidth()) / bitmap.getWidth();
float scaleHeight = ((float) getHeight()) / bitmap.getHeight();
Matrix matrix = new Matrix();
//按照比例選擇縮放參照
if (scaleBitmap < scaleView) {
//比例小於視框時,所有按照圖片高度和視框高度的比例進行縮放
matrix.postScale(scaleHeight, scaleHeight);
}else {
//比例大於視框時,所有按照圖片寬度和視框寬度的比例進行縮放
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();
複製代碼
這裏要注意一個問題就是,Java中進行除法運算並得到帶小數點的結果,須要將算式中的一個值轉爲float才能夠取得。
在最後將bitmap畫入畫布時,也要記得計算一下位置,居中顯示纔算完整實現效果。
在設定好縮放值inSampleSize 後,經過BitmapFactory.decodeFile或者decode其餘形式,生成縮放後的Bitmap位圖。若是已經有Bitmap圖了,能夠轉成File地址來實現。
而縮放值inSampleSize 能夠直接設定具體倍數,好比2就是2分之一倍,或者經過計算原圖寬高和設定的想達到的寬高獲得比例。
其中很實用的一點是,在獲取圖片的寬高的時候,能夠將inJustDecodeBounds設成true,此時bitmap不會加載到內存,而只是獲取到圖片的height和width,節省內存提升效率。
示例:
//使用BitmapFactory.Options的inSampleSize參數來縮放
public static Drawable resizeImage2(String path,
int width,int height)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//不加載bitmap到內存中
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));
}
複製代碼
首先要得到原bitmap,建立一個Matrix對象,包含想要達到的寬和高,最後在原Bitmap的基礎上生成新圖片。效率比較低。
示例:
//使用Bitmap加Matrix來縮放
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);
}
複製代碼
Android自帶的處理方法,會結合第一種和第二種方法和一些其餘算法對圖片進行加工,效率會比第二種高一點,使用也比較方便,一行代碼就能夠了:
imView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap,200,100));
複製代碼
最後在三種圖片的處理方式中都發現了一個問題,也是之前我對圖片處理的一個知識盲區:圖片不只在拉大的時候會模糊,在縮小的時候一樣也可能模糊。一張照片,壓縮10倍以後,其分辨率已經不足以看清細節,鋸齒很是嚴重。因此這三種圖片的壓縮,是會下降顯示效果的,若是須要尺寸減少畫質不變,應該須要其餘的算法來解決。