StackBlur 是一个快速高斯模糊算法,原作者是由 Mario Klingemann 开发的 Javascript 版本。Victor Laskin 实现了一个 C++多线程版本,Android 上我们基于 Victor Laskin 的版本进行 JNI 移植。
这个算法应用非常广泛 iOS 上 Camera+ 也是用的这套算法,还有 CUDA 版本等…

移植

这里我们可以直接借用 android-stackblur 的代码,注意这个版本并不支持带透明度的图片,且不要使用多线程来处理图片。

CMakeLists

Android Studio 2.2 以上的版本支持使用 CMake 来编译 JNI 了,具体操作可以参考官方文档

https://developer.android.com/studio/projects/add-native-code.html

流程没什么难点,官网上有的就不再赘述,对于没有接触过CMake的人来说,编写 CMakeLists 文件是很懵逼的事情,想要完整学完 CMake,学习曲线还是蛮陡峭的,下面就是移植后的 CMakeLists 文件。以后自己编写其他的 CMakeLists 参照例子依葫芦画瓢即可。

CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

add_library( StackBlur

SHARED

src/main/cpp/StackBlur.c )

# 从ndk中寻找库,StackBlur.c 使用了这些库所以需要找出来。
# 下面的代码的含义是找到 log 库,命名为 log-lib
find_library( log-lib
log )

find_library( m-lib
m )

find_library( jnigraphics-lib
jnigraphics )

target_link_libraries( StackBlur
${log-lib}
${m-lib}
${jnigraphics-lib} )

集成 glide

glide 是一个优秀的图片加载库,具有强大的可扩展性,对于图片的处理 Gilde 使用 Transformation 进行图片的转换功能,我们就只需要实现一个模糊功能的 Transformation 即可。

GlideStackBlur.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class GlideStackBlur extends BitmapTransformation {

private TintColorGenerator mTintColorGenerator;

public GlideStackBlur(Context context) {
super(context);
}

public GlideStackBlur(Context context, TintColorGenerator tintColorGenerator) {
super(context);
mTintColorGenerator = tintColorGenerator;
}

@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
if (toTransform != null) {
long startTime = System.currentTimeMillis();

BlurUtils blurManager = new BlurUtils(toTransform);
Bitmap blur = blurManager.process(40);

final Bitmap result = Bitmap.createBitmap(blur.getWidth(), blur.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);

canvas.drawBitmap(blur, 0, 0, paint);

blurManager.recycle();

if (BuildConfig.DEBUG) {
Log.d("GlideStackBlur", outWidth + "," + outHeight + " Time: " + (System.currentTimeMillis() - startTime));
}

return result;
}

return null;
}

@Override
public String getId() {
String id = "cn.gavinliu.android.lib.glide.stackblur.GlideStackBlur";
if (mTintColorGenerator != null) {
id += mTintColorGenerator.getId();
}
return id;
}
}
1
2
3
Glide.with(this).load(url)
.transform(new GlideStackBlur(this))
.into(imageView);

扩展染色功能

使用 ColorFilter 功能可以在图片上在叠加一个颜色。

1
2
3
4
5
6
7
...
if (mTintColorGenerator != null) {
int color = mTintColorGenerator.generate(toTransform);
PorterDuffColorFilter colorFilter = new PorterDuffColorFilter((color), PorterDuff.Mode.SRC_OVER);
paint.setColorFilter(colorFilter);
}
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Glide.with(this).load(url)
.transform(new GlideStackBlur(this, new TintColorGenerator() {
@Override
public int generate(Bitmap bitmap) {
// You can generate dynamic color
return 0x803F51B5;
}

@Override
public String getId() {
return ".TintColorGenerator";
}
}))
.into(imageView);

源码

https://github.com/gavinliu/glide-stackblur