文章目录

  • Android Bitmap 使用 ScriptIntrinsicBlur、Toolkit 实现模糊
  • 软件修改Bitmap像素点实现模糊
  • 使用 RenderScript 模糊
  • 使用 Toolkit 模糊
  • Toolkit 和 RenderScript 效率对比
  • Bitmap缩放处理
  • 改变图片的对比度/明暗度


Android Bitmap 使用 ScriptIntrinsicBlur、Toolkit 实现模糊

软件修改Bitmap像素点实现模糊

此方法无sdk版本要求,但是效率非常非常差,没有可使用性。
具体源码可以参考后文附的完整实例

使用 RenderScript 模糊

ScriptIntrinsicBlur 要求 android sdk 版本最低 17, Android 12(API 31) 开始废弃
设备和组件制造商已停止提供硬件加速支持,预计将在未来的版本中完全取消对 RenderScript 的支持。

详细使用代码如下:

/**
 * 通过调用系统高斯模糊api的方法模糊
 *
 * @param bitmap    source bitmap
 * @param outBitmap out bitmap
 * @param radius    0 < radius <= 25
 * @param context   context
 * @return out bitmap
 */
public static Bitmap blurBitmap(Bitmap bitmap, Bitmap outBitmap, float radius, Context context) {
    //Let's create an empty bitmap with the same size of the bitmap we want to blur
    //Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);

    //Instantiate a new Renderscript
    RenderScript rs = RenderScript.create(context);

    //Create an Intrinsic Blur Script using the Renderscript
    ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

    //Create the Allocations (in/out) with the Renderscript and the in/out bitmaps
    Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
    Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);

    //Set the radius of the blur
    blurScript.setRadius(radius);

    //Perform the Renderscript
    blurScript.setInput(allIn);
    blurScript.forEach(allOut);

    //Copy the final bitmap created by the out Allocation to the outBitmap
    allOut.copyTo(outBitmap);

    //recycle the original bitmap
//   bitmap.recycle();

    //After finishing everything, we destroy the Renderscript.
    rs.destroy();

    return outBitmap;
}

使用 Toolkit 模糊

Toolkit 是 ScriptIntrinsicBlur 的替代方案之一,效率更高
Toolkit.kt 只是一个 JAVA 接口,主要实现是在JNI中
以模糊为例,其部分实现代码如下 ,参见 Blur.cpp

/**
 * Full blur of a line of U_8 data.
 *
 * @param outPtr Where to store the results
 * @param xstart The index of the section we're starting to blur.
 * @param xend  The end index of the section.
 * @param currentY The index of the line we're blurring.
 */
void BlurTask::kernelU1(void *outPtr, uint32_t xstart, uint32_t xend, uint32_t currentY) {
    float buf[4 * 2048];
    const uint32_t stride = mSizeX * mVectorSize;

    uchar *out = (uchar *)outPtr;
    uint32_t x1 = xstart;
    uint32_t x2 = xend;

    float *fout = (float *)buf;
    int y = currentY;
    if ((y > mIradius) && (y < ((int)mSizeY - mIradius -1))) {
        const uchar *pi = mIn + (y - mIradius) * stride;
        OneVFU1(fout, pi, stride, mFp, mIradius * 2 + 1, mSizeX, mUsesSimd);
    } else {
        x1 = 0;
        while(mSizeX > x1) {
            OneVU1(mSizeY, fout, x1, y, mIn, stride, mFp, mIradius);
            fout++;
            x1++;
        }
    }

    x1 = xstart;
    while ((x1 < x2) &&
           ((x1 < (uint32_t)mIradius) || (((uintptr_t)out) & 0x3))) {
        OneHU1(mSizeX, out, x1, buf, mFp, mIradius);
        out++;
        x1++;
    }

    while(x2 > x1) {
        OneHU1(mSizeX, out, x1, buf, mFp, mIradius);
        out++;
        x1++;
    }
}

只需要下载 renderscript-intrinsics-replacement-toolkit ,编译 renderscript-toolkit 模块 ,引用即可
也可直接下载已经编译好的文件 renderscript-toolkit-debug-1.0.0.aar 引用

implementation (project(":renderscript-toolkit"))   
//或者如下方式,引入下载的aar
implementation (files("libs/renderscript-toolkit-debug-1.0.0.aar"))

使用方法如下

Toolkit.blur(inputBitmap, radius, null)

Toolkit 和 RenderScript 效率对比

结果如下,可以看到 Toolkit 在部分场景已经超越 RenderScript,特别是在处理小图时

D  FastBlur 1898X3069 cost time: 1055
D  RSBlur 1898X3069 cost time: 42
D  Toolkit 1898X3069 cost time: 29

 Toolkit 是不是最终的方案呢?

如果对性能有更高的要求,还可以使用 Vulkan、RenderEffect 继续优化

本文首发地址

Bitmap缩放处理

对于模糊处理,bitmap尺寸越小,处理的越迅速。
为了达到需要的模糊效果,通常我们需要对输入 bitmap 缩放的处理,缩放代码如下:

/**
 * 比例压缩图片
 *
 * @param sourceBitmap 源bitmap
 * @param scaleFactor  大于1,将bitmap缩小
 * @return 缩小scaleFactor倍后的bitmap
 */
public static Bitmap compressBitmap(Bitmap sourceBitmap, float scaleFactor) {
    Bitmap overlay = Bitmap.createBitmap((int) (sourceBitmap.getWidth() / scaleFactor),
            (int) (sourceBitmap.getHeight() / scaleFactor), Config.ARGB_8888);
    Canvas canvas = new Canvas(overlay);
    canvas.translate(0, 0);
    canvas.scale(1 / scaleFactor, 1 / scaleFactor);
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    canvas.drawBitmap(sourceBitmap, 0, 0, paint);
    return overlay;
}

改变图片的对比度/明暗度

详细说明见代码注释,示例代码

/**
 * 改变图片对比度,达到使图片明暗变化的效果
 *
 * @param srcBitmap source bitmap
 * @param contrast  图片亮度,0:全黑;小于1,比原图暗;1.0f原图;大于1比原图亮
 * @return bitmap
 */
public static Bitmap darkBitmap(Bitmap srcBitmap, float contrast) {

    float offset = (float) 0.0; //picture RGB offset

    int imgHeight, imgWidth;
    imgHeight = srcBitmap.getHeight();
    imgWidth = srcBitmap.getWidth();

    Bitmap bmp = Bitmap.createBitmap(imgWidth, imgHeight, Config.ARGB_8888);
    ColorMatrix cMatrix = new ColorMatrix();
    cMatrix.set(new float[]{contrast, 0, 0, 0, offset,
            0, contrast, 0, 0, offset,
            0, 0, contrast, 0, offset,
            0, 0, 0, 1, 0});

    Paint paint = new Paint();
    paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));

    Canvas canvas = new Canvas(bmp);
    canvas.drawBitmap(srcBitmap, 0, 0, paint);

    return bmp;
}

以上就是基于 ScriptIntrinsicBlur 和 Toolkit 对 Bitmap 模糊实现,希望对你有所帮助。
如果你在使用过程遇到问题,可以留言讨论。
如果你觉得本文写的还不错,欢迎点赞+收藏。