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

這是一篇比較簡(jiǎn)單的處理圖片的應(yīng)用文,我們先看一下具體的場(chǎng)景:

image

這里實(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)解決。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一直以來(lái)Bitmap都是開發(fā)中很棘手的問題,這個(gè)問題就是傳說中的OOM(java.lang.OutofMemory...
    M悇芐冋憶閱讀 5,057評(píng)論 0 11
  • 目錄介紹 01.如何計(jì)算Bitmap占用內(nèi)存1.1 如何計(jì)算占用內(nèi)存1.2 上面方法計(jì)算內(nèi)存對(duì)嗎1.3 一個(gè)像素占...
    楊充211閱讀 4,435評(píng)論 1 9
  • 圖片壓縮就是為了避免我們內(nèi)存溢出,所有要對(duì)一系列進(jìn)行壓縮二次采樣等 1.什么是OOM?為什么會(huì)引起OOM? out...
    lay_wn閱讀 1,041評(píng)論 0 1
  • 2021期待與你一起共事,點(diǎn)擊查看崗位[http://www.itdecent.cn/p/6f4d67fa406...
    閑庭閱讀 17,064評(píng)論 0 75
  • 摘要:對(duì)android 上圖片壓縮,其實(shí)總結(jié)起來(lái)基本可以分為兩類壓縮:尺寸壓縮和質(zhì)量壓縮, 尺寸壓縮其實(shí)也可以理解...
    男爵是只貓丶閱讀 8,985評(píng)論 2 14

友情鏈接更多精彩內(nèi)容