I’ll put the ## in front

Recently I have been preparing for the completion of the project, considering that a fuzzy effect may be used, so I learned some gaussian blur effect implementation. The best known is FastBlur and the optimizations that come from it, and RenderScript.

Since this is something that needs to be learned now, some of the graphics and rendering issues will not be mentioned. However, in the process of use, we can feel that although different schemes can achieve the same fuzzy effect, the efficiency difference is really very big.

This article to achieve gaussian blur is based on the following article learning, first recommended. This article is about the same, but with a little more detail and some changes to the implementation logic and details in the code. But the main content is unchanged, so it is the same to choose which article to learn.

Waterborne sky – teach you one minute to achieve dynamic blur effect

## A quick talk about Renderscript

Since the implementation of the effect is based on Renderscript, it is necessary to understand it first.

According to its official documentation, this is very vague. This is all we need to know:

RenderScript is a framework for running computationally intensive tasks at high performance on Android.

Renderscript is a framework for high-performance computing on the Android platform.

Since it is high performance computing, RenderScript is very powerful for image processing, so it is a good choice for gaussian blur.

So how do you use it? Can be seen in the official document, if need using Renderscript in Java code, we must rely on android. The Renderscript or android. Support. V8. The Renderscript apis. That’s a lot easier now that you have an API.

Here is a brief description of the steps to use, which is also described in the official documentation:

  • First you need to create a Renderscript from the Context;
  • Secondly, through the created Renderscript, ScriptIntrinsic script can be almost insic. For example, there is no need for blur, that is ScriptIntrinsicBlur.
  • Then create at least one Allocation class to create and allocate memory space.
  • Then the image is some processing, such as blur processing;
  • After the processing is complete, the Allocation class is needed to fill the allocated memory space.
  • Finally, some resources can be recycled selectively.

The explanation in the document is always very rules, more difficult to understand, we combine the original blog qiushui long days code to take a look at the steps:

/** * @author Qiushui * @description * @Revision Xiarui 16.09.05 */ public class BlurBitmapUtil private static finalfloatBITMAP_SCALE = 0.4 f; /** * how to blur the image ** @param context context object * @param image to blur the image * @return*/ public static Bitmap blurBitmap(Context Context, Bitmap image,floatBlurRadius) {int width = math.round (image.getwidth () * BITMAP_SCALE); int height = Math.round(image.getHeight() * BITMAP_SCALE); / / will shrink after images as pre-rendered Bitmap inputBitmap = Bitmap. CreateScaledBitmap (image, width, height,false); Bitmap outputBitmap = bitmap.createBitMap (inputBitmap); RenderScript rs = renderscript.create (context); / / create a blur RenderScript tool object ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur. Create (rs, Element U8_4 (rs)); // Since RenderScript does not use VMS to allocate memory, we need to use Allocation class to create and allocate memory space. // When creating Allocation object, memory is empty, so we need to use copyTo() to fill in the Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap); Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap); Blurscript. setRadius(blurRadius); // Set the render blur to 25F. // Set the blurScript object's input memory blurScript.setinput (tmpIn); // Save the output data to blurScript.foreach (tmpOut); // Fill the Allocation with data tmpout.copyto (outputBitmap);returnoutputBitmap; }}Copy the code

The above is to deal with the Gaussian blur code, which is written in detail, and has been zooming the picture. This is a tool class, so you can Copy it directly.

Of course, the original blogger has wrapped the code into wheels, and you can also reference Gradle directly in your project, but I think the source code should be taken a look at.

## Simple blur

Now that you have a general idea, let’s look at how to achieve gaussian blur.

First, you can directly reference the original blogger’s encapsulated wheel in your project:

compile 'com. Qiushui: blurredview: 0.8.1'
Copy the code

If you don’t want to reference it, you must add the following code to build.gradle in the current Module:

defaultConfig {
    renderscriptTargetApi 19
    renderscriptSupportModeEnabled true
}
Copy the code

Once it’s built, it’s ready to use. If the build fails, all you need to do is set minSdkVersion to 19 for whatever reason. But knowing from StackOverflow that this is a Bug, don’t bother.

In order to get a Gaussian blur image, you need three things:

  • Context: Context object
  • Bitmap: Images that need to be blurred
  • BlurRadius: BlurRadius

Here are a few things to note:

For now, this solution only works with PNG images, and the image size should be small, although the code has already scaled the image, but still can be stuck.

Now just set the image and blur level:

/** * initialize View */ @suppressWarnings ("deprecation")
private void initView() { basicImage = (ImageView) findViewById(R.id.iv_basic_pic); / / to get the initial figure Bitmap initBitmap = BitmapUtil. DrawableToBitmap (getResources (). GetDrawable (R.r aw. PIC)); / / processing get blur image Bitmap blurBitmap = BlurBitmapUtil. BlurBitmap (this, initBitmap, 20 f); basicImage.setImageBitmap(blurBitmap); }Copy the code

Take a look at the operation diagram:

As you can see, the picture has achieved fuzzy effect, and also quite fast, generally by BlurBitmapUtil. BlurBitmap () can get a blurred effect diagram.

## Custom blur control

The original blogger’s wheel encapsulated a custom BlurredView that I didn’t think was necessary at first. It was later discovered that the reason for the customization was the need to achieve dynamic blur effects.

So why not set the blur level manually? His explanation:

“Using the above code to render in real time would cause the interface to lag badly.”

I tried it myself, and it was a little bit stuck. His solution for dynamic blurring is as follows:

“Blur the image to the maximum extent possible, then place the original image on top of the blurred image, changing the opacity (Alpha) of the original image to achieve a dynamic blur effect.”

This scheme is really clever to achieve dynamic effects, but note that to use this method, you must have two identical images. If you write directly in code, you need two controls, if there are many images, obviously not desirable. So there’s a custom BlurredView in the wheel.

However, this BlurredView doesn’t encapsulate very well, and I deleted some of the content for reasons I’ll discuss later. Let’s look at the core code.

First, the custom BlurredView inherits from RelativeLayout, which, as you can see in the layout file, has two ImageViews stacked on top of each other.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <ImageView
        android:id="@+id/blurredview_blurred_img". /> <ImageView android:id="@+id/blurredview_origin_img". /> </FrameLayout>Copy the code

Some attributes are also defined:

<resources>
    <declare-styleable name="BlurredView">
        <attr name="src" format="reference"/>
        <attr name="disableBlurred" format="boolean"/>
    </declare-styleable>
</resources>
Copy the code

One is to set the image, and the other is to set whether blur is disabled. Finally, there is the BlurredView class, which has the following code, with a lot of cuts and only the core code posted:

/** * @author Qiushui * @description public Class BlurredView extends */ RelativeLayout {/ * = = = = = = = = = = global related = = = = = = = = = = * / private Context mContext; Private static final int ALPHA_MAX_VALUE = 255; // Maximum transparency private static finalfloatBLUR_RADIUS = 25f; / / maximum fuzzy degree (from 0.0 to 25.0) / * = = = = = = = = = = image related = = = = = = = = = = * / private ImageView mOriginImg; // ImageView private ImageView mBlurredImg; ImageView private Bitmap mBlurredBitmap; Private Bitmap mOriginBitmap; / / the original Bitmap / * = = = = = = = = = = attribute related = = = = = = = = = = * / private Boolean isDisableBlurred; // Disable blur effects... /** * Add code to the blurredBitmap ** @param blurredBitmap */ public voidsetBlurredImg(Bitmap blurredBitmap) {
        if(null ! = blurredBitmap) { mOriginBitmap = blurredBitmap; mBlurredBitmap = BlurBitmapUtil.blurBitmap(mContext, blurredBitmap, BLUR_RADIUS);setImageView(); }}... /** * fill ImageView */ private voidsetImageView() { mBlurredImg.setImageBitmap(mBlurredBitmap); mOriginImg.setImageBitmap(mOriginBitmap); } /** * set ambiguity ** @param level Ambiguity between 0 and 100. */ @suppressWarnings ("deprecation")
    public void setBlurredLevel(int level) {// Throw an exception beyond the BlurredLevel rangeif (level < 0 || level > 100) {
            throw new IllegalStateException("No validate level, the value must be 0~100"); } // Disable fuzzy direct returnif (isDisableBlurred) {
            return; } // Set the transparency moriginim.setalpha ((int) (ALPHA_MAX_VALUE - level * 2.55)); }... }Copy the code

As you can see from the code, the core is the following three methods:

  • SetBlurredImg (Bitmap blurredBitmap) : Set up the image and make two copies
  • SetImageView () : set the corresponding image for the two imageViews, internal call;
  • SetBlurredLevel (int Level) : Sets the transparency level;

The idea is to first select an image, one as the original image, one as the blurred image. Set the two images separately to the two ImageViews in the custom BlurredView, and finally process the opacity of the blurred image.

Ok, now to write a custom blur effect, first the layout, very simple:

 <com.blurdemo.view.BlurredView
        android:id="@+id/bv_custom_blur"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:src="@raw/pic"
        app:disableBlurred="false" />
Copy the code

As you can see, with the image set and the blur set on, all we need to do in our Activity is set the transparency:

private void initView() { customBView = (BlurredView) findViewById(R.id.bv_custom_blur); / / set up the fuzzy degree of customBView. SetBlurredLevel (100); }Copy the code

The effect picture is the same as the above one, so I won’t repeat it here. As you can see, the code is a lot simpler, but just because it’s convenient and simple is not where custom Views come in, it’s where dynamic blur comes in.

## Dynamic blur

Let’s take a look at what motion blur is:

As you can see, the background blur changes as we touch the screen. If you want to set the blur directly, it will be very slow, so as the original blogger said, you can do it with two images.

The general idea is that the top image is blurred, the bottom image is not processed, and then change the opacity of the blurred image by gesture.

So the code above is almost the same, just override the onTouchEvent method:

/** * initializes View */ private voidinitView() { customBView = (BlurredView) findViewById(R.id.bv_dynamic_blur); // Set the initial ambiguity to initLevel = 100; customBView.setBlurredLevel(initLevel); Override public Boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:
            downY = ev.getY();
            break;

        case MotionEvent.ACTION_MOVE:
            floatmoveY = ev.getY(); // Finger slide distancefloatoffsetY = moveY - downY; Int screenY = getWindowManager().getDefaultDisplay().getheight () * 10; MovePercent = offsetY/screenY; currentLevel = initLevel + (int) (movePercent * 100);if (currentLevel < 0) {
                currentLevel = 0;
            }
            if(currentLevel > 100) { currentLevel = 100; } / / set the fuzzy degree of customBView. SetBlurredLevel (currentLevel); // Change the initial blur level initLevel = currentLevel;break;
        case MotionEvent.ACTION_UP:
            break;
    }
    return super.onTouchEvent(ev);
}
Copy the code

As you can see from the code, the transparency level is calculated by the percentage of finger sliding distance to the screen. The code should not be difficult and easy to understand. Of course, the original blogger blog is changed through the progress bar, but also can, I will not repeat.

## combine with RecylcerView

Let’s take a look at a rendering, which is also modeled after the original blogger, but there are slight differences.

In the original custom BlurredView, there were several pieces of code that changed the location of the background image, because it was expected that the background image could be moved when it was pulled up and down, but the effect was not very good from the experience, and there was a problem with white space during the pull up process.

The original blogger suggested a solution: manually adding a height to the background image, but this wasn’t the best solution, so I removed this feature until I found a better way to do it.

Now how do you do that? The first layout is a custom BlurredView at the bottom, with a RecylcerView at the top. The RecylcerView has two types: the header layout and the list at the bottom.

Again, the focus is on the implementation of the dynamic blur. In the above dynamic blur, we override the onTouchEvent method, but this happens to be RecylcerView, and we can dynamically change the transparency based on its scroll listener, which is onScrollListener, The core methods are as follows:

/ / RecyclerView rolling listening mainRView. SetOnScrollListener (new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); MScrollerY += dy; // Control the blur degree according to the rolling distanceif (Math.abs(mScrollerY) > 1000) {
                mAlpha = 100;
            } else{ mAlpha = Math.abs(mScrollerY) / 10; } / / set the transparency grade recyclerBView setBlurredLevel (mAlpha); }});Copy the code

The code is very simple, that is, the transparency is calculated and dynamically changed in the onScrolled method. It is easy to implement as long as you master the principle.

# # to summarize

As can be seen from all the previous dynamic diagrams, it still runs relatively fast, but I see from Android Monitor that GPU rendering takes a long time at the beginning of each blur, so it may still be poor in terms of performance.

Of course, it could have something to do with the simulator, because real testing is fast. And it seems to be a bit faster than FastBlur, so when you have time to test the performance of a few gaussian blur implementations to compare.

At this point, this method of implementing Gaussian blur has been completely covered, thanks to the original blogger such an excellent article, again attached link:

Waterborne sky – teach you one minute to achieve dynamic blur effect

### Additional resources

RenderScript – Android Developers

Introduction to Android RenderScript (1)

Gaussian blur effect implementation scheme and performance comparison – lcyFox

### project source code

BlurDemo – IamXiaRui – Github


Personal blog: www.iamxiarui.com

The original link: http://www.iamxiarui.com/?p=854