Skip to content Skip to sidebar Skip to footer

How To Use The Renderscript Blurring Effect Without Artifacts?

Background There are plenty of places (including here) to show how to use Renderscript to blur images, as such: @TargetApi(VERSION_CODES.JELLY_BEAN_MR1) public static Bitmap render

Solution 1:

The problem was with the algorithm I used. Thanks to this github project, I've found the issue (which is probably not using the correct type fot the allocation) and used a nicer approach:

privatestaticfinal AtomicReference<RenderScript> sRenderscript = newAtomicReference<>();


publicstatic Bitmap blur(Context context, Bitmap bitmap) {
    return blur(context, bitmap, 4, false, false);
}

publicstatic Bitmap blur(Context context, Bitmap bitmap, float radius) {
    return blur(context, bitmap, radius, false, false);
}

publicstatic Bitmap blur(Context context, Bitmap bitmapOriginal, @FloatRange(from = 0.0f, to = 25.0f)float radius, boolean overrideOriginal, boolean recycleOriginal) {
    if (bitmapOriginal == null || bitmapOriginal.isRecycled())
        returnnull;
    RenderScriptrs= sRenderscript.get();
    if (rs == null)
        if (!sRenderscript.compareAndSet(null, rs = RenderScript.create(context)) && rs != null)
            rs.destroy();
        elsers= sRenderscript.get();
    finalBitmapinputBitmap= bitmapOriginal.getConfig() == Config.ARGB_8888 ? bitmapOriginal : bitmapOriginal.copy(Config.ARGB_8888, true);
    finalBitmapoutputBitmap= overrideOriginal ? bitmapOriginal : Bitmap.createBitmap(bitmapOriginal.getWidth(), bitmapOriginal.getHeight(), Config.ARGB_8888);
    finalAllocationinput= Allocation.createFromBitmap(rs, inputBitmap);
    finalAllocationoutput= Allocation.createTyped(rs, input.getType());
    finalScriptIntrinsicBlurscript= ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
    script.setRadius(radius);
    script.setInput(input);
    script.forEach(output);
    if (recycleOriginal && !overrideOriginal)
        bitmapOriginal.recycle();
    output.copyTo(outputBitmap);
    return outputBitmap;
}

Now it all works nicely.

Solution 2:

The artifact in the original version is because the same input Allocation was used as the output Allocation for IntrinsicBlur:

    blur.setInput(overlayAlloc);
    blur.setRadius(radius);
    blur.forEach(overlayAlloc);

forEach(aOut) computes the Gaussian blur and saves the result to the output Allocation. Since the algorithm requires information about the neighbors, doing blur in place may corrupt the input data for sub-sequent calculations.

Solution 3:

I use code below. It worked!

publicstatic Bitmap blurRenderScript(Context context, Bitmap inputBitmap, int radius) {
    BitmapoutputBitmap= inputBitmap.copy(inputBitmap.getConfig(), true);
    RenderScriptrenderScript= RenderScript.create(context);
    AllocationblurInput= Allocation.createFromBitmap(renderScript, inputBitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
    AllocationblurOutput= Allocation.createFromBitmap(renderScript, outputBitmap);
    ScriptIntrinsicBlurblur= ScriptIntrinsicBlur.create(renderScript,
            Element.U8_4(renderScript));
    blur.setInput(blurInput);
    blur.setRadius(radius); // radius must be 0 < r <= 25
    blur.forEach(blurOutput);
    blurOutput.copyTo(outputBitmap);
    renderScript.destroy();

    return outputBitmap;
}

in build.Gradle

defaultConfig {
    applicationId "hello.test.app"
    minSdkVersion 16
    targetSdkVersion 22
    versionCode 1
    versionName "1.0"
    renderscriptTargetApi 18
    renderscriptSupportModeEnabled true
}

Post a Comment for "How To Use The Renderscript Blurring Effect Without Artifacts?"