Android 圖片處理之固定視框中的等比例壓縮

蘆葦科技App技術團隊發表於2019-01-25

這是一篇比較簡單的處理圖片的應用文,我們先看一下具體的場景:

Android 圖片處理之固定視框中的等比例壓縮

這裡實現了上傳圖片的功能,圖片限制在紅色框框內且比例為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倍之後,其解析度已經不足以看清細節,鋸齒非常嚴重。所以這三種圖片的壓縮,是會降低顯示效果的,如果需要尺寸減小畫質不變,應該需要其他的演算法來解決。

相關文章