1. 程式人生 > >Android中縮放圖片的方法

Android中縮放圖片的方法

簡介

在Android專案中常常需要調整原始圖片的尺寸大小以適應儲存、傳輸和圖片處理等需求。在Android API中提供了一些縮放圖片的方法,在專案中發現,使用Android API中的Canvas、BitmapFactory和ThumbnailUtils等類的相關方法縮放圖片,鋸齒感明顯,影象質量不高;另外還有一些第三方的開源庫專門用於在Android平臺縮放圖片;在FFmpeg中也提供了縮放圖片和視訊的方法,可以編譯FFmpeg在Android平臺呼叫相關方法。本文將總結在專案中使用上述方法的操作和實現的效果。

使用Canvas

首先建立一個Canvas物件,使用Canvas的drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)方法,根據Rect dst指定bitmap繪製在canvas上的位置,從而改變bitmap的大小。需要注意的是,使用這種方法時,為了得到更好效果的輸出,要新增抗鋸齒處理。

/**
     * 使用Canvas
     * @param bitmap 原始的Bitmap
     * @param rect Bitmap被縮放放置的Rect
     * @return 縮放後的Bitmap
     */
    public static Bitmap scaleCanvas(Bitmap bitmap, Rect rect) {
        Bitmap newBitmap = Bitmap.createBitmap(rect.width(), rect.height(), Bitmap.Config.ARGB_8888);//建立和目標相同大小的空Bitmap
Canvas canvas = new Canvas(newBitmap); Paint paint = new Paint(); Bitmap temp = bitmap; //針對繪製bitmap新增抗鋸齒 PaintFlagsDrawFilter pfd= new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG); paint.setFilterBitmap(true); //對Bitmap進行濾波處理 paint.setAntiAlias(true
);//設定抗鋸齒 canvas.setDrawFilter(pfd); canvas.drawBitmap(temp, null, rect, paint); return newBitmap; }

在我們的專案中,需要將一個尺寸較大的圖片縮小後合併到另外一個圖片上,那麼使用這種方法縮小原始圖片和原始圖片的對比如下。

![原始圖片](https://img-blog.csdn.net/20180620171543160?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1R1R2VMZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 原圖 ![縮小後的圖片](https://img-blog.csdn.net/20180620171729581?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1R1R2VMZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 使用Canvas縮小

使用Matrix

Bitmap實際上就是由畫素點組成的矩陣,在Android中的Matrix主要用於對影象縮放、平移和旋轉處理操作,Matrix物件呼叫postScale(float sx, float sy)方法設定縮放,在Bitmap的createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)方法中將Matrix物件傳入,即可根據Matrix規則生成新的Bitmap。

    /**
     * 使用Matrix
     * @param bitmap 原始的Bitmap
     * @param width 目標寬度
     * @param height 目標高度
     * @return 縮放後的Bitmap
     */
    public static Bitmap scaleMatrix(Bitmap bitmap, int width, int height){
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        float scaleW = width/w;
        float scaleH = height/h;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleW, scaleH); // 長和寬放大縮小的比例
        return Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
    }

使用ThumbnailUtils

ThumbnailUtils是Android API提供的獲取縮圖的工具類,所以可以很容易地獲得縮放後的Bitmap,使用該類中extractThumbnail(Bitmap source, int width, int height)方法返回獲得縮放的Bitmap,該方法的引數中,source指輸入待縮放的原始Bitmap,width和height分別指目標寬度和高度。
canvas
Matrix
ThumbnailUtils
上面分別是使用Canvas、Matrix和ThumbnailUtils得到的縮小後的圖片。

上述方法存在的問題

使用上述方法得到的縮放圖片的質量並不太好,失真比較嚴重。例如在我們的專案中,是將一個較大尺寸的圖片縮小後貼到一個較小尺寸的圖片上,合併後的圖片只要稍微放大就會看到明顯的鋸齒感,與原始圖片存在著明顯的差異。
在Android中使用的影象縮放的演算法都是比較簡單高效的,所以輸出的質量就不太好。比如使用Matrix縮小圖片採用的是雙線性取樣(Bilinear Resampling)的演算法,產生的圖片斜率不太準確、細節會出現退化。對於同樣的圖片,使用Matrix方法縮小尺寸,和使用Photoshop縮小到相同的尺寸,可以明顯分辨出差別。所以,使用Android中採用的縮放圖片的演算法處理效果不好,失真也更嚴重。

使用第三方庫

有一些開源的Android平臺的第三方庫可以用來調整圖片的尺寸,它們採用一些演算法可以產生不同質量的縮放圖。比如ComPressHelperCompressorLuban等壓縮圖片的Android庫,也提供了縮放圖片的方法,具體的使用方法可以參考連結頁面。在實際使用中,發現其輸出質量並不比使用Android API的高。使用CompressHelper縮小圖片尺寸和原始圖片的對比如下。

原始圖片
原圖
CompressHelper
使用CompressHelper縮小

使用FFmpeg

FFmpeg的libswscale類庫提供了將輸入的圖片縮放到指定的大小,使用scale過濾器指定縮放後的寬高大小,也可以只設置寬和高中的一個,另一個置為-1,保持輸出的寬高比。使用-sws_flags方法可以指定縮放所採用的演算法,下面是一個指定縮放寬高和縮放演算法的命令示例:ffmpeg -i test.tif -vf scale=504:376 -sws_flags bilinear out.bmp
之前的博文已經介紹過編譯在Android以命令呼叫FFmpeg的動態庫,可以通過指令呼叫具體的FFmpeg的處理操作。指定輸入、輸出路徑、目標的寬高和採用的縮放演算法,生成縮放圖片命令的函式如下。

/**
 * FFmpeg縮放圖片
 * @param input 輸入路徑
 * @param output 輸出路徑
 * @param width 目標寬度
 * @param height 目標高度
 * @param algorithm 縮放演算法
 * @return FFmpeg縮放命令
 */
public static String[] scaleImage(String input, String output, int width, int height, String algorithm) {
   final int count = 8;
   String[] commands = new String[count];
   int index = 0;
   commands[index++] = "ffmpeg";
   commands[index++] = "-i";
   commands[index++] = input;
   commands[index++] = "-vf";
   commands[index++] = "scale="+width+":"+height;
   commands[index++] = "-sws_flags";
   commands[index++] = algorithm;
   commands[index++] = output;
   return commands;
}

FFmpeg中提供的各種縮放演算法,採用其中bicubic、spline、sinc等許多演算法產生的縮放後的圖片質量要明顯好於使用Android API生成的縮放圖片。

原始圖片
原圖
ffmpeg
呼叫FFmpeg使用bicubic演算法縮小
下面是使用Android API和使用FFmpeg產生的縮放圖,肉眼可以明顯分辨出二者的質量差別。
Matrix –使用Matrix
ffmpeg –使用FFmpeg

總結

在Android專案中需要縮放圖片的尺寸,一般使用Android API中提供的方法就可以滿足需求,而且這些方法呼叫簡單,處理效率高。如果僅僅縮放圖片,並不提倡使用CompressHelper等第三方庫,這些庫主要側重於圖片壓縮效率,縮放圖片的效果並不比Android API好。如果需要得到更高質量的縮放圖片,則應該使用其它的縮放演算法處理,FFmpeg中不光提供了簡單的縮放圖片的方法,還提供了十幾種縮放演算法選項,另外,根據具體的圖片特徵選擇合適的演算法,可以更好地提高縮放圖片的質量。

參考