Animation / Bitmap / Canvas / RenderScript

Blurring Images – Part 6

In the previous article we looked at frame rates, and explored how we can measure them by adding some simple benchmarking logging. In this article we’ll look at implementing our dynamic blurring so that we can animate things, and optimising things to improve our framerate.

The first thing that we’ll do is to simply add our RenderScript blur method to our onPreDraw() method to see how our existing implementation performs:

This gets called every time we draw. So how does it look?

That’s not looking great, so what about the frame rate?

Less than 5 frames per second is pretty poor, and explains why it looks so bad. Hang on though – if we look at the local frames compared to the frames value, there’s a big discrepancy. Our custom TextView is only being drawn 32 times in 6.5 seconds to achieve that poor frame rate, yet our onPreDraw() method is being called 224 times. It is in our onPreDraw() method that we are actually performing the blur.

Hopefully it should be pretty obvious from this that it would be far more efficient to perform the blur operation in the onDraw() method of our custom control rather than our onPreDraw() method.

While we’re moving this code across, let’s also consider some other optimisations. We saw previously that setting up and tearing down our RenderScript context was a little heavy, so why not re-use the context for the duration of the animation? Also, the size of the Allocation that we created to hold the bitmap being blurred within the RenderScript memory space will not change unless the dimensions of the control change, so we can reuse this to prevent unnecessary object creation.

So our custom TextView now looks like this:

We must initialise the blur operation by calling initBlur() and passing in a reference to the ImageView holding the background image that we wish to blur. This obtains a reference to the background image, sets up the RenderScript context and calls resize() to initialise Bitmap, Allocation, and ScriptIntrinsicBlur objects required to perform the actual blur. Any time the size of the custom view changes, resize will be called again to re-create these objects to the appropriate size.

The onDraw() method performs the blur operation, and simply draws the resultant bitmap before the rest of the view is drawn.

When we are finished animating we should call cleanupBlur() to tidy up, and deallocate the objects used for animating the individual frames.

Our MainActivity code just needs to change to call initBlur() when we start animating, invalidate() (to force onDraw()) in onPreDraw(), and cleanupBlur() when we stop animating:

If we run this the animation seems to be much smoother than before:

But what about the all important frame rate:

Over 50 fps is more than ten times better than we had before, and is a perfectly respectable frame rate.

Before we get carried away with this, there are a couple of quite major caveats:

  1. This is running on very high specification hardware (at the time of writing!). We will definitely not achieve this kind of frame rate across all devices.
  2. The custom TextView is relatively small, and therefore the number of pixels in the bitmap that we are blurring in each frame is also relatively small. As the size of the TextView increases, number of pixels that must be blurred will increase exponentially, which will reduce our frame rate.

At this point it would appear that we have very much achieved what we set out to in blurring a part of an image, and managing to achieve a highly respectable frame rate when performing this blur on a frame by frame basis as part of an animation. However, there is an alternative approach that we can use to achieve this high frame rate, and in the concluding article in this series we’ll take a look at it.

The source code for this article is available here.

© 2014, Mark Allison. All rights reserved.

Copyright © 2014 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.