通过jni调用C函数实现Android毛玻璃效果

之前项目中,有个需求是对Activtiy背景进行虚化,实现毛玻璃效果。实现的大体思路:

  1. 对手机屏幕进行截屏处理,获得截屏图片的bitmap;
  2. 对bitmap进行相应的config处理和缩放像素处理;
  3. 通过高斯模糊算法对处理后的bitmap进行虚化;
  4. 将虚化后的bitmap作为背景图展示。

虽然实现了,但由于效果不佳或是影响性能,最终选择放弃。最近闲的没事,准备将这件事给完成。
因为之前对bitmap的算法处理是通过java代码实现的,如果想提高性能或是减少处理时间,达到秒开的效果,必须设置虚化的程度低,但这样效果并不好看,但只是一味追求效果,由于java代码运行比较慢,在处理时间上必定会有延迟,总之就是有性能没效果,有效果没性能的矛盾,体验十分不佳,网上也给出过方案是通过c的方式实现,今天就来完成,随便回顾一遍jni的流程,长时间不碰全忘...

配置NDK,生成.so动态库

  1. build.gradle文件下,添加ndk配置:
android {
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 25
        ...
        ndk {
            moduleName "blur_lib"   // 动态库名称
            abiFilters "armeabi", "armeabi-v7a", "x86" // 相应的架构平台
            ldLibs "log" //log输出
            ldLibs "jnigraphics" //graphic相关jni
        }
    }
   ...
}

项目的gradle.properties添加支持NDKandroid.useDeprecatedNdk=true
local.properties添加ndk-bundle路径
ndk.dir=C\:\\Users\\Administrator\\AppData\\Local\\Android\\Sdk\\ndk-bundle

  1. 创建NativeHelper类如下:
public class NativeHelper {
    static {
        System.loadLibrary("blur_lib");
    }
    // 参数r为对bitmap虚化的程度范围
    static native void blurBitmap(Object bitmap, int r);
}

在Terminal中cd到java目录下生成.h头文件,方便得到c中的类名,输入命令行:
javah -jni com.pecoo.blurjnidemo.NativeHelper

  1. main下创建一个jni folder,里面创建.c/c++和.h头文件,高斯算法代码粘进来,并在.h头文件进行相应的方法申明。
  2. 再创建一个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"   // 在第一步中创建的.h头文件,下面可以调用里面的方法

// 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是不是这两种格式,因为算法中只有对这两种图片会做处理
      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) {
          // 调用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);
      }
      // 对应上面的AndroidBitmap_lockPixels()
      AndroidBitmap_unlockPixels(env, bitmapIn);
  }
#ifdef __cplusplus
}
#endif
#endif

5.生成.so动态库:Build->Rebuild Project完成后,会在build文件下生成相应平台的.so。复制到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

虚化图片,实现效果:

对于截屏,获取到截屏的bitmap步骤这儿就忽略了,直接拿张资源图片进行处理,显示在界面上

// 获得bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blur_img);
// 获得图片的宽高
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// 设置想要的大小
Display display = getWindowManager().getDefaultDisplay();
int newWidth = display.getWidth();
int newHeight = display.getHeight();
// 计算缩放比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Log.d(TAG, "scaleWidth:" + scaleWidth);
Log.d(TAG, "scaleHeight:" + scaleHeight);
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
// matrix.postScale(scaleWidth, scaleHeight);
// 实现模糊效果之前,这里可对bitmap进行更大缩放,减少像素点还可提高性能
float scaleFactor = 10;
float scale = 1f / scaleFactor;
matrix.postScale(scale, scale);
// 得到新的图片
Bitmap newbm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix,true);
bitmap.recycle();

子线程中调用处理bitmap的本地函数

    private void blur(final Bitmap bitmap, final int radius) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                super.run();
                // blurNatively()主要是检查图片是否为ARGB8888和RGB565,如果是则调用 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地址发一下,仅供参考。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容