這是一篇比較簡單的處理圖片的應用文,我們先看一下具體的場景:
這裡實現了上傳圖片的功能,圖片限制在紅色框框內且比例為4/3,標準的照片比例。但是如果使用者上傳了其他比例的圖片,為了照顧觀感肯定是要對圖片進行一個等比壓縮處理,最後的效果和ImageView中ScareType的FitCenter效果是一樣的,也就是保持圖片的比例,並且最大化的顯示在時框中。
那麼對於自定義View如何實現這一效果呢?首先分析一下圖片是如何被處理的。
三種情況:
-
比例小於視框
也就是圖片比較“高”,例如上圖左邊,是一張16比9的照片,9/16 < 3/4。
顯示高度 = 視框高度
-
比例等於視框
也就是4比3的圖片,可以完美的貼合視框不留空白
顯示寬高 = 視框寬高
-
比例大於視框
也就是圖片比較“寬”,例如上圖右邊,比例為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畫入畫布時,也要記得計算一下位置,居中顯示才算完整實現效果。
然後簡單介紹一下Android中縮放影象生成縮圖的三種方式:
1、BitmapFactory和 BitmapFactory.Options
在設定好縮放值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));
}
複製程式碼
2、使用Bitmap加Matrix來縮放
首先要獲得原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);
}
複製程式碼
3、Android自帶的ThumbnailUtils
Android自帶的處理方法,會結合第一種和第二種方法和一些其他演算法對圖片進行加工,效率會比第二種高一點,使用也比較方便,一行程式碼就可以了:
imView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap,200,100));
複製程式碼
關於圖片壓縮
最後在三種圖片的處理方式中都發現了一個問題,也是以前我對圖片處理的一個知識盲區:圖片不僅在拉大的時候會模糊,在縮小的時候同樣也可能模糊。一張照片,壓縮10倍之後,其解析度已經不足以看清細節,鋸齒非常嚴重。所以這三種圖片的壓縮,是會降低顯示效果的,如果需要尺寸減小畫質不變,應該需要其他的演算法來解決。