Blur Dialog Fragment, a small step into the world of blur effect.

Motivations

A couple of weeks ago, we started to play with blur effect on Android. We found that blurred components enhanced pretty well any modern design app.

Like any new hotness, we wanted to use it with caution since we could be tend to apply such an effect everywhere. The use case on which we finally based our playground was the DialogFragment. For us, the goal of a Dialog is to bring emphasis on a component when no other action should be available. Thus, blurring the entire screen displayed in the background of a dialog actually make sense as it helps to bring the emphasis we are looking for : the user is even less distracted by the content under dialog than he is with only a dimming effect. Even if in pratice more and more dialogs can (and must) be replaced by better component in term of user experience, we believe that they are still relevant for some use-cases so let's see how we managed to implement the BlurDialogFragment class!

An impressive study made by Pavel Dudka

First of all, we based the blurring part on the impressive works of Pavel Dudka : Advanced blurring techniques . We were very impressed by the efficiency of the FastBlur algorithm once the source image was downscaled. To summarize the Pavel's approach, we don't need an hight-quality image since "blurring process itself is all about loosing pixels". That's why a downscale factor is applied to the source Bitmap in order to reduce the time of the blurring process. With this pre-processing and according to his benchmark, the FastBlur algorithm is 6 times faster than ScriptIntrinsicBlur from RenderScript.

Despite his results, Pavel wrote the following warning concerning the memory allocation used by the FastBlur algorithm :

WARNING! Please note that FastBlur uses hell a lot of additional memory (it is copying entire bitmap into temp buffers), so even if it works perfect for small bitmaps, I would not recommend using it for blurring entire screen since you can easily get OutOfMemoryException on low-end devices. Use your best judgement.

Unfortunately, "blurring the entire screen" was exactly what we were looking for. Therefore we decided to take Pavel's warning into account and find out by ourselves the memory trace of both blurring methods. Our goal was to provide the more efficient implementation which means finding the best ratio between execution time and memory allocation. For the whole set of metrics presented bellow, we used a Nexus 4 running a 4.4.4 stock rom.

Let's start with the FastBlur approach.

First of all, we need to capture the entire screen in order to apply our blur effect. We simply retrieve the drawing cache of the DecorView which leads to an allocation of 3072ko.

Then, we allocate a new Bitmap (on which the FastBlur will be launched) by applying a downscale factor of 8. As mentioned bellow, blurring is all about "loosing pixels", that's why in addition we use Bitmap.Config.RGB_565 to reduce by half the size of this Bitmap (only 2 bytes are used for each pixel instead of 4). The resulting allocation is equal to 192ko.

Finally, we apply the FastBlur algorithm which works with a buffer. Therefore, another memory allocation of 192ko is performed.

Fast blur 3072ko (screen capture) + 192ko (DownScaled+RGB_565) + 192ko(Buffer used by FastBlur) = 3456ko

And what's about ScriptIntrinsicBlur ?

The first step is exactly the same : 3072ko.

Then, we tryied to apply the same downscale factor as well as change the encoded format. But unfortunately, an RSIllegalArgumentException was thrown. The ScriptIntrinsicBlur seems only to work with ARGB_8888. Therefore, by keeping the Bitmap.Config.ARGB_8888, the size of the allocated Bitmap is twice bigger : 384ko.

Finally, we apply the ScriptIntrinsicBlur using RenderScript which doesn't need any additional buffer.

RenderScript 3072ko (screen capture) + 384ko (DownScaled+ARGB_8888) = 3456ko

According to our results and the Pavel's study, the FastBlur approach is 6 times faster than RenderScript for the same memory trace. In fact, despite the buffer, the FastBlur approach can be performed on a RGB_565 encoded Bitmap which reduces the memory allocation by half whereas the ScriptIntrinsicBlur can only be applied on a ARGB_8888 encoded Bitmap. Therefore, we decided to use FastBlur instead of RenderScript for our BlurDialogFragment. If we missed something, don't hesitate to give us your input by using the disqus at the end! We will really appreciate that. You can also directly contribute to our project as explained here!

Bring the magic

Once the blurring part was achieved, we simply had to encapsulate the whole behaviour into a BlurDialogFragment which process blurring effect off the UI thread. Here is a screenshot of the result:

As usual the whole project is open-source and can be found on GitHub. In addition, a sample app can be downloaded on the Google Play store. It allows you to play with the blur radius and the downscale parameters in order to obtain the wished effect. Don't hesitate to use the gradle dependency to use it in your project! Any feedback, both positive and negative, are welcome (=

References

Discuss and share ideas on this experiment

[1] http://trickyandroid.com/advanced-blurring-techniques/ [2] http://developer.android.com/reference/android/graphics/Bitmap.Config.html [3] http://grepcode.com/.../support/v8/renderscript/ScriptIntrinsicBlur.java#53 [4] https://github.com/tvbarthel/BlurDialogFragment [5] https://play.google.com/.../?id=fr.tvbarthel.lib.blurdialogfragment.sample

Please enable JavaScript to view the comments powered by Disqus.

Disqus