1. 程式人生 > >IOS的專利?Android也能流暢實現毛玻璃效果效果

IOS的專利?Android也能流暢實現毛玻璃效果效果

高斯模糊例圖

背景介紹

上圖就是我們在IOS裝置上經常能夠見到的毛玻璃(高斯模糊)效果。不得不說,這種效果在適合的場景下使用,能夠獲得絕佳的美感。但是鑑於Android裝置效能和相容性問題,我們通常很難在Android裝置上見到這種效果。
但這並不是IOS的專利效果,Android也能輕鬆流暢的實現。本篇文章將會詳細的講解如何實現。

Android中的高斯模糊

我為什麼選擇RenderScript實現高斯模糊

目前Android裝置上實現高斯模糊效果的方式通常有:
1. 雲端處理,移動客戶端直接從網路獲取處理好的圖片。這種方式侷限性很大。
2. FastBlur等開源庫。這種方式相容性不錯,但是效率極低。
3. c實現。不懂c的理解困難。
4. OpenGL實現。效果很好,但電量和記憶體消耗比較高。
5. RenderScript實現。效果略弱於第4種,但是使用方便,速度很快,效能消耗在可接受範圍內,加上Google的相容性解決方案,可以說是能夠作為優先考慮的方式。

RenderScript

RenderScript主要在android中的對圖形進行處理,RenderScript採用C99語法進行編寫,主要優勢在於效能較高。在Api11的時候被加入到Android中。同時,Google提供了android.support.v8.renderscript相容包,能夠實現更低版本的相容。

RenderScript提供了一個用於實現高斯模糊的封裝類ScriptIntrinsicBlur ,這貨在Api17才被收編Android所以在不使用相容包的情況下只能相容到4.2的裝置。但是,我們有相容包啊向下相容不是夢。

準備階段

引入相容包

方法很簡單,只需在build.gradle中加入:

 defaultConfig {
        。
        。
        。
        //就是這麼簡單
        renderscriptTargetApi 19
        renderscriptSupportModeEnabled true
    }

你以為這樣就好了?nonono。
由於一些坑人的廠商會深度定製Android系統,所以一些必要的依賴檔案會被它們直接去掉!!這導致一些型號的裝置上呼叫RenderScriptd的部分方法時會報錯。所以我們得加上這些可能丟失的檔案
其實也簡單,開啟android_sdk/build-tools/選擇19以上版本/renderscript/lib/packaged

我們可以看見3個包含.os檔案的資料夾。

OS檔案

直接複製這三個檔案加到專案工程的jniLibs 包下。什麼?找不見jniLibs包?自己建一個嘍。

jniLibs資料夾

注意,這時候,我們很可能遇到一個奔潰,找不到.os檔案。莫慌莫慌…
在build.gradle的android{}中加入:

sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

沒完沒了!最後一步只針對使用的混淆的同學,需要在混淆中加入:

-keep class android.support.v8.renderscript.** { *; }

實現高斯模糊

終於可以開始寫程式碼了。先來看看效果。下圖高斯模糊半徑逐漸增大的效果,請忽略渣渣錄屏效果

效果圖

  • 將ScriptIntrinsicBlur封裝成工具類。咱們程式碼裡接著款
import android.support.v8.renderscript.*;  //這句很重要啊,v8包的,不然不能向下相容啊。

public class RenderScriptGaussianBlur {
  private RenderScript rs;

  public RenderScriptGaussianBlur(Context context) {
    // 建立RenderScript核心物件
    this.rs = RenderScript.create(context);
  }


  /**
   * 將圖片高斯模糊化
   * @param radius 模糊半徑,由於效能限制,這個值的取值區間為(0,25f]
   * @param bitmapOriginal 源Bitmap
   */
  public Bitmap blur(float radius, Bitmap bitmapOriginal) {
    Bitmap bmp = Bitmap.createBitmap(bitmapOriginal);
    // 由於RenderScript並沒有使用VM來分配記憶體,所以需要使用Allocation類來建立和分配記憶體空間。
    final Allocation input = Allocation.createFromBitmap(rs, bmp);
    //Type: “一個Type描述了一個Allocation或者並行操作的Element和dimensions ”
    Type type = input.getType();
    final Allocation output = Allocation.createTyped(rs, type);
    //建立一個模糊效果的RenderScript的工具物件
    //第二個引數Element相當於一種畫素處理的演算法,高斯模糊的話用這個就好
    final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
    //設定渲染的模糊程度, 25f是最大模糊度
    script.setRadius(radius);
    // 設定blurScript物件的輸入記憶體
    script.setInput(input);
    // 將輸出資料儲存到輸出剛剛建立的輸出記憶體中
    script.forEach(output);
    // 將資料填充到bitmap中
    output.copyTo(bmp);

    //銷燬它們釋放記憶體
    input.destroy();
    output.destroy();
    script.destroy();
    type.destroy();
    return bmp;
  }

  public void destory(){
    this.rs.destroy();
  }
}

挺簡單的幾句,現在我們看看如何使用。
- 降低需要進行高斯模糊的圖片質量
雖然說使用RenderScript能夠高效的進行圖片的高斯模糊,但是對於較大的圖片還是顯的力不從心。畢竟是要對每一個畫素點都要進行處理。況且一般來說,高斯模糊後圖片都比較模糊,我為何要用高清圖?��
降低圖片質量的程式碼相信大家都倒背如流了,這裡就不再重複放碼了。

  • 圖片的高斯模糊化一定要非同步進行
//處理化一個RenderScriptGaussianBlur,記得在Activity的onDestory()中呼叫destroy()釋放記憶體
blurRender = new RenderScriptGaussianBlur(this);

//這段程式碼的效果就是每點選一次按鈕,高斯模糊半徑blurRadius就+1,
//然後在RxJava的Schedulers.computation()執行緒中進行Bitmap的高斯模糊化,
//接著在onNext()中將處理後獲得的圖片設定顯示。
//也就是上圖的效果
btn2.setOnClickListener(v -> {
      if (mBitmap != null && blurRadius <= 25) {
        Disposable d = Observable.create(new ObservableOnSubscribe<Bitmap>() {
          @Override
          public void subscribe(ObservableEmitter<Bitmap> e) throws Exception {
            LogUtils.e("當前blurRadius = " + blurRadius);
            //對圖片進行高斯模糊處理
            Bitmap bitmap = blurRender.blur(blurRadius, mBitmap);
            blurRadius++;
            if (blurRadius == 25){
              blurRadius = 1;
            }
            e.onNext(bitmap);
            e.onComplete();
          }
        })
            .subscribeOn(Schedulers.computation()) //指定運算執行緒
            .observeOn(AndroidSchedulers.mainThread()) //切換回主執行緒
            .subscribeWith(new DisposableObserver<Bitmap>() {
              @Override
              public void onNext(Bitmap bitmap) {
                iv.setImageBitmap(bitmap); //展示圖片
              }

              @Override
              public void onError(Throwable e) {}

              @Override
              public void onComplete() {}
            });
        disposable.add(d);
      }
    });

效能問題

測試機:Meizu M2 Note
系統:Android 5.1

上圖高斯模糊時的CPU及記憶體變化:

高斯模糊記憶體圖

從上圖可以看到,即使我原本在播放一個動畫時的CPU使用率大概在6% 左右。在開始高斯模糊運算後,隨著高斯模糊半徑的逐漸增大,CPU峰值最大也就在21.3%。可見這種解決方案的效率是極高的。

總結

通過本篇的介紹,相信大家已經對這種在Android裝置上實現高斯模糊效果的解決方案有所瞭解了。是不是手癢想親自動手試一試呢?
當然啦,如果產品說要個高斯模糊的效果,還是那句話:IOS專利!Android做不了!��

參考文獻

  1. Google Api文件
  2. Google Blog-RenderScript in the Android Support Library
  3. Android : Simple and fast image processing with RenderScript
  4. Android RenderScript 簡單高效實現圖片的高斯模糊效果;

如果覺得這篇文章不錯,點贊走一走,關注走一走啊。