Android 怎么把一张图片变为黑白?
Android 怎么实现抖音上很火的黑金效果?
这篇文章就会给大家分享怎么利用 RenderScript 实现黑白、黑金效果。
一、什么是 RenderScript ?
RenderScript 是 Android 自带一个高效的计算框架,能够自动利用 CPU、GPU、DSP 来做并行计算,能在处理图片、数学模型计算等场景提供高效的计算能力。 语法类似 C/C++, 但它是在运行时编译,是跨平台的。性能比 Java 好,比 Native 略差。
二、如何使用 RenderScript ?
使用时分两个步骤: (1) 编写 .rs 脚本文件; (2) 在Java中使用 RenderScript;
(1) 编写 .rs 文件
这里我们用一个很简单的 将图片置灰 为例实现 Gray.rs 文件;
#pragma version(1)
#pragma rs java_package_name(me.moolv.demo.rs)
void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
// a 是透明度,这里不修改透明度。
out->a = in->a;
// 快,但并不是真正意义的去色
out->r = out->g = out->b = (in->r + in->g + in->b) / 3;
// 慢,但是是真正的去色
// out->r = out->g = out->b = (in->r * 299 + in->g * 587 + in->b * 114 + 500) / 1000;
}
void init() {
}
第1行声明 RenderScript 的版本; 第2行 java_package_name 生命该脚本所在的Java包的包名;
root 函数: root 函数是这个脚本的入口函数,对于图片来说,root函数负责对每一个像素做处理。 参数 in
是输入像素点的指针; out
是输出像素点的指针。
init 函数: init 函数是可选的,用于做初始化的工作。
(2) 在 Java 代码中使用
在 Java 代码中 import:
import me.moolv.demo.rs.ScriptC_Gray;
这里的类名是 ScriptC_
加上 .rs 的文件名。包名就是在 rs 文件生声明的包名。
下面是具体使用:
/**
* 将 bitmap 去色后返回一张新的 Bitmap。
*/
public static Bitmap gray(@NonNull Context context, @NonNull Bitmap bitmap) {
// 创建输出 bitamp
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap outBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
// 创建 RenderScript 对象
RenderScript rs = RenderScript.create(context);
// 创建输入、输出 Allocation
Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
// 创建我们在上面定义的 script
ScriptC_Gray script = new ScriptC_Gray(rs);
// 对每一个像素执行 root 方法
script.forEach_root(allIn, allOut);
// 将执行结果复制到输出 bitmap 上
allOut.copyTo(outBitmap);
// 释放资源
rs.destroy();
return outBitmap;
}
原图和效果:
![0bb2381c47a95bac704b3f2c54c13a0d.png](https://i-blog.csdnimg.cn/blog_migrate/3e98aad5896b9ccce44a723a9f48ae7d.jpeg)
![94f3df618c14ec00fb25a786e28c659b.png](https://i-blog.csdnimg.cn/blog_migrate/e1b8cde64168df1ec84487639e216384.jpeg)
三、多个 kernal 函数
除了 root 函数,我们还可以在 .rs 中定义其他的 kernal 函数,例如:
/**
* 黑金色转换
*/
uchar4 __attribute__((kernel)) blackGold(uchar4 in, uint32_t x, uint32_t y) {
uchar4 out = in;
if ((in.r < in.b) && (in.g < in.b)) {
out.r = out.g = out.b = (in.r*299 + in.g*587 + in.b*114 + 500) / 1000;
}
return out;
}
其中函数返回值必须是 uchar4
, 并且用 __attribute__((kernel))
标记该函数是个 kernal 函数。
在 Java 代码中这样调用就可以了:
script.forEach_blackGold(allIn, allOut);
效果:
![8f2a5013d4986f2e62736384c211c71c.png](https://i-blog.csdnimg.cn/blog_migrate/23a17605e5f703313c7596a53a9169d3.jpeg)
还可以在 .rs 文件中定义自己的结构体,这里就不举例啦。