之前項(xiàng)目中,有個(gè)需求是對(duì)Activtiy背景進(jìn)行虛化,實(shí)現(xiàn)毛玻璃效果。實(shí)現(xiàn)的大體思路:
- 對(duì)手機(jī)屏幕進(jìn)行截屏處理,獲得截屏圖片的bitmap;
- 對(duì)bitmap進(jìn)行相應(yīng)的config處理和縮放像素處理;
- 通過高斯模糊算法對(duì)處理后的bitmap進(jìn)行虛化;
- 將虛化后的bitmap作為背景圖展示。
雖然實(shí)現(xiàn)了,但由于效果不佳或是影響性能,最終選擇放棄。最近閑的沒事,準(zhǔn)備將這件事給完成。
因?yàn)橹皩?duì)bitmap的算法處理是通過java代碼實(shí)現(xiàn)的,如果想提高性能或是減少處理時(shí)間,達(dá)到秒開的效果,必須設(shè)置虛化的程度低,但這樣效果并不好看,但只是一味追求效果,由于java代碼運(yùn)行比較慢,在處理時(shí)間上必定會(huì)有延遲,總之就是有性能沒效果,有效果沒性能的矛盾,體驗(yàn)十分不佳,網(wǎng)上也給出過方案是通過c的方式實(shí)現(xiàn),今天就來完成,隨便回顧一遍jni的流程,長時(shí)間不碰全忘...
配置NDK,生成.so動(dòng)態(tài)庫
- build.gradle文件下,添加ndk配置:
android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 25
...
ndk {
moduleName "blur_lib" // 動(dòng)態(tài)庫名稱
abiFilters "armeabi", "armeabi-v7a", "x86" // 相應(yīng)的架構(gòu)平臺(tái)
ldLibs "log" //log輸出
ldLibs "jnigraphics" //graphic相關(guān)jni
}
}
...
}
項(xiàng)目的gradle.properties添加支持NDKandroid.useDeprecatedNdk=true
local.properties添加ndk-bundle路徑
ndk.dir=C\:\\Users\\Administrator\\AppData\\Local\\Android\\Sdk\\ndk-bundle
- 創(chuàng)建NativeHelper類如下:
public class NativeHelper {
static {
System.loadLibrary("blur_lib");
}
// 參數(shù)r為對(duì)bitmap虛化的程度范圍
static native void blurBitmap(Object bitmap, int r);
}
在Terminal中cd到j(luò)ava目錄下生成.h頭文件,方便得到c中的類名,輸入命令行:
javah -jni com.pecoo.blurjnidemo.NativeHelper
- main下創(chuàng)建一個(gè)jni folder,里面創(chuàng)建.c/c++和.h頭文件,高斯算法代碼粘進(jìn)來,并在.h頭文件進(jìn)行相應(yīng)的方法申明。
- 再創(chuàng)建一個(gè)c/c++文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_pecoo_blurjnidemo_NativeHelper */
#ifndef _Included_com_pecoo_blurjnidemo_NativeHelper
#define _Included_com_pecoo_blurjnidemo_NativeHelper
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_pecoo_blurjnidemo_NativeHelper
* Method: blurBitmap
* Signature: (Ljava/lang/Object;I)V
*/
#include <android/log.h>
#include <android/bitmap.h>
#include "stackblur.h" // 在第一步中創(chuàng)建的.h頭文件,下面可以調(diào)用里面的方法
// log宏定義
#define TAG "Native_Blur_Jni"
#define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
JNIEXPORT void JNICALL Java_com_pecoo_blurjnidemo_NativeHelper_blurBitmap
(JNIEnv *env, jclass obj, jobject bitmapIn, jint r)
{
AndroidBitmapInfo infoIn;
void *pixels;
// 獲取bitmap的信息
if (AndroidBitmap_getInfo(env, bitmapIn, &infoIn) != ANDROID_BITMAP_RESULT_SUCCESS) {
LOG_D("AndroidBitmap_getInfo failed!");
return;
}
// 檢測bitmap是不是這兩種格式,因?yàn)樗惴ㄖ兄挥袑?duì)這兩種圖片會(huì)做處理
if (infoIn.format != ANDROID_BITMAP_FORMAT_RGBA_8888 &&
infoIn.format != ANDROID_BITMAP_FORMAT_RGB_565) {
LOG_D("Only support ANDROID_BITMAP_FORMAT_RGBA_8888 and ANDROID_BITMAP_FORMAT_RGB_565");
return;
}
// 鎖定圖片
if (AndroidBitmap_lockPixels(env, bitmapIn, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
LOG_D("AndroidBitmap_lockPixels failed!");
return;
}
// 得到寬高
int h = infoIn.height;
int w = infoIn.width;
if (infoIn.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
// 調(diào)用stackblur.c中的blur_ARGB_8888()或blur_RGB_565()
pixels = blur_ARGB_8888((int *) pixels, w, h, r);
} else if (infoIn.format == ANDROID_BITMAP_FORMAT_RGB_565) {
pixels = blur_RGB_565((short *) pixels, w, h, r);
}
// 對(duì)應(yīng)上面的AndroidBitmap_lockPixels()
AndroidBitmap_unlockPixels(env, bitmapIn);
}
#ifdef __cplusplus
}
#endif
#endif
5.生成.so動(dòng)態(tài)庫:Build->Rebuild Project完成后,會(huì)在build文件下生成相應(yīng)平臺(tái)的.so。復(fù)制到main下的jniLibs中
若失敗試試
D:\workspace\ndk\NDKDemo\myapplication\src\main>javah -d jni -classpath C:\Users\Administrator\AppData\Local\Android\Sdk\platforms\android-20\android.jar;..\..\build\intermediates\classes\debug com.pecoo.myapplication.NativeUtils
虛化圖片,實(shí)現(xiàn)效果:
對(duì)于截屏,獲取到截屏的bitmap步驟這兒就忽略了,直接拿張資源圖片進(jìn)行處理,顯示在界面上
// 獲得bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blur_img);
// 獲得圖片的寬高
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// 設(shè)置想要的大小
Display display = getWindowManager().getDefaultDisplay();
int newWidth = display.getWidth();
int newHeight = display.getHeight();
// 計(jì)算縮放比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Log.d(TAG, "scaleWidth:" + scaleWidth);
Log.d(TAG, "scaleHeight:" + scaleHeight);
// 取得想要縮放的matrix參數(shù)
Matrix matrix = new Matrix();
// matrix.postScale(scaleWidth, scaleHeight);
// 實(shí)現(xiàn)模糊效果之前,這里可對(duì)bitmap進(jìn)行更大縮放,減少像素點(diǎn)還可提高性能
float scaleFactor = 10;
float scale = 1f / scaleFactor;
matrix.postScale(scale, scale);
// 得到新的圖片
Bitmap newbm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix,true);
bitmap.recycle();
子線程中調(diào)用處理bitmap的本地函數(shù)
private void blur(final Bitmap bitmap, final int radius) {
Thread thread = new Thread() {
@Override
public void run() {
super.run();
// blurNatively()主要是檢查圖片是否為ARGB8888和RGB565,如果是則調(diào)用 NativeHelper中的本地方法blurBitmap()
final Bitmap ret = blurNatively(bitmap, radius,true);
runOnUiThread(new Runnable() {
@Override
public void run() {
mImageView.setBackground(new BitmapDrawable(getResources(), ret));
}
});
}
};
thread.start();
}
最后把 github地址發(fā)一下,僅供參考。