Skip to content
This repository has been archived by the owner on Oct 20, 2022. It is now read-only.

Latest commit

 

History

History

blur_an_image_with_renderscript

id title subtitle brief article recipe api sdk
3BF2B1FB-B4D3-4986-9630-7DC7B19E55D7
Blur an Image with Renderscript
Apply a Gaussian Blur with Renderscript
This recipe shows how to apply a Gaussian blur an image using the class Android.Renderscripts.ScriptIntrinsicBlur, which is first available in Android 4.2.2 (API level 17).

This recipe shows one way to blur an image using an API that was introduced in Android 4.2.2 (API level 17) - Android.Renderscripts.ScriptIntrinsicBlur. This class will apply a Gaussian blur. ScriptIntrinsicBlur is a pre-implemented graphics filter that runs at the native level for maximum performance. Because this class uses Renderscript, it can spread out the workload over all the CPU cores on the device for maximum performance.

The recipe Blur an Image with Managed Code is a example of how to apply a blur effect on all Android API levels.

This application will display a picture and a SeekBar. The value of the SeekBar will determine how much the image should be blurred. You can see this application running in the following screenshots:

Requirements

This recipe will only work with Android 4.2.2 (API level 17) or higher.

Recipe

The UI for this recipe is contained in the following XML layout file:

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:layout_width="fill_parent"
                  android:layout_height="fill_parent">
        <SeekBar
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:id="@+id/seekBar1"
                android:max="25" />
        <ImageView
                android:src="@drawable/dog_and_monkeys"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:id="@+id/originalImageView" />
    </LinearLayout>

This is a very simple UI that has an ImageView and a SeekBar. We inflate this layout and wire up an event handler to the SeekBar in OnCreate method of our activity, as shown in the following code:

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);

    SetContentView (Resource.Layout.Main);
    _imageView = FindViewById<ImageView> (Resource.Id.originalImageView);

    _seekbar = FindViewById<SeekBar> (Resource.Id.seekBar1);
    _seekbar.StopTrackingTouch += BlurImageHandler;
}

When the user stops sliding their finger along the SeekBar, the StopTrackingTouch event will be fired and the BlurImageHandler method invoked. The contents of this handler maybe seen in the following snippet:

private void BlurImageHandler (object sender, SeekBar.StopTrackingTouchEventArgs e)
{
    int radius = e.SeekBar.Progress;
    if (radius == 0) {
        // We don't want to blur, so just load the un-altered image.
        _imageView.SetImageResource (Resource.Drawable.dog_and_monkeys);
    } else {
        DisplayBlurredImage (radius);
    }
}

If the SeekBar has a value greater than zero, then we will need to apply a blur filter. If the value of the SeekBar is zero, then no blur needs to be applied. The code inside DisplayBlurredImage can be seen below:

private void DisplayBlurredImage (int radius)
{
    _seekbar.StopTrackingTouch -= BlurImageHandler;
    _seekbar.Enabled = false;

    ShowIndeterminateProgressDialog ();

    Task.Factory.StartNew (() => {
        Bitmap bmp = CreateBlurredImage (radius);
        return bmp;
    })
    .ContinueWith (task => {
        Bitmap bmp = task.Result;
        _imageView.SetImageBitmap (bmp);
        _seekbar.StopTrackingTouch += BlurImageHandler;
        _seekbar.Enabled = true;
        DismissIndeterminateProgressDialog ();
    }, TaskScheduler.FromCurrentSynchronizationContext ());
}

Let's take a quick moment to understand DisplayBlurredImage. The first thing we do is to disable the SeekBar and display an indeterminate progress dialog. To keep our application responsive and to prevent an ANR (Application Not Responding) message from Android, the actual filtering will be performed in a separate thread. This example will invoke the method CreateBlurredImage via the Task Parallel Library. The Task that we created to do this work has a continuation that will update the UI with the blurred image and dismiss the progress dialog. This continuation is scheduled to run in the UI thread of our application.

The final piece of code we need to examine will perform the actual blurring of the image. The code for this is contained in the method CreateBlurredImage. This code has comments inline to help explain the relevant parts of code:

private Bitmap CreateBlurredImage (int radius)
{
    // Load a clean bitmap and work from that.
    Bitmap originalBitmap = BitmapFactory.DecodeResource (Resources, Resource.Drawable.dog_and_monkeys);

    // Create another bitmap that will hold the results of the filter.
    Bitmap blurredBitmap;
    blurredBitmap = Bitmap.CreateBitmap (originalBitmap);

    // Create the Renderscript instance that will do the work.
    RenderScript rs = RenderScript.Create (this);

    // Allocate memory for Renderscript to work with
    Allocation input = Allocation.CreateFromBitmap (rs, originalBitmap, Allocation.MipmapControl.MipmapFull, AllocationUsage.Script);
    Allocation output = Allocation.CreateTyped (rs, input.Type);

    // Load up an instance of the specific script that we want to use.
    ScriptIntrinsicBlur script = ScriptIntrinsicBlur.Create (rs, Element.U8_4 (rs));
    script.SetInput (input);

    // Set the blur radius
    script.SetRadius (radius);

    // Start the ScriptIntrinisicBlur
    script.ForEach (output);

    // Copy the output to the blurred bitmap
    output.CopyTo (blurredBitmap);

    return blurredBitmap;
}

Summary

This recipe showed one way to apply a Gaussian blur to an image using Android.Renderscripts.ScriptIntrinsicBlur. To keep the UI responsive, the filter was applied in a background thread using the Task Parallel Library.