Using RenderScript to achieve Gaussian blur (frosted glass/frosted) effect

Using RenderScript to achieve Gaussian blur (frosted glass/frosted) effect

Preface

When browsing Instagram, I accidentally discovered that the design of Instagram's dialog box is very interesting, as shown below:

The background of its dialog is actually frosted glass, which is really beautiful in my opinion. Well, both the dialog box and Dilraba Dilmurat are beautiful😂. Seeing such a good effect, of course I have to start to do something and achieve a similar effect by myself. The final effect is as follows:

The dialog box background is blurred and the blur degree is manually adjusted.

Comparison of implementation methods

When I first wanted to achieve the frosted glass effect, I was confused and didn't know how to start. Fortunately, there is Google. After searching, I found that there are 4 common ways to achieve it, which are:

  • RenderScript
  • Java Algorithms
  • NDK Algorithms
  • openGL

For such a computationally intensive task of processing an entire image, openGL has the best performance, and Java is definitely the worst. The performance of RenderScript and NDK is comparable, but you know, I can't do anything about NDK and openGL. After comprehensive consideration, RenderScript should be the most suitable.

But that doesn’t mean RenderScript is completely problem-free:

  1. The larger the blur radius, the higher the performance requirement. The blur radius cannot exceed 25, so it is not possible to obtain images with very high blur.
  2. ScriptIntrinsicBlur was introduced in API 17. If you need to implement it on devices below Android 4.2, you need to introduce RenderScript Support Library. Of course, the size of the installation package will increase accordingly.

RenderScript Implementation

First, add the following code to the build.gradle file in the app directory:

  1. defaultConfig {
  2. applicationId "io.github.marktony.gaussianblur"  
  3. minSdkVersion 19
  4. targetSdkVersion 25
  5. versionCode 1
  6. versionName "1.0"  
  7. renderscriptTargetApi 19
  8. renderscriptSupportModeEnabled true  
  9. }

RenderScriptIntrinsics provides some operation classes that can help us quickly implement various image processing operations. For example, ScriptIntrinsicBlur can achieve Gaussian blur effects simply and efficiently.

  1. package io.github.marktony.gaussianblur;
  2.  
  3. import android.content.Context;
  4. import android.graphics.Bitmap;
  5. import android.support.annotation.IntRange;
  6. import android.support.annotation.NonNull;
  7. import android.support.v8.renderscript.Allocation;
  8. import android.support.v8.renderscript.Element;
  9. import android.support.v8.renderscript.RenderScript;
  10. import android.support.v8.renderscript.ScriptIntrinsicBlur;
  11.  
  12. public class RenderScriptGaussianBlur {
  13.  
  14. private RenderScript renderScript;
  15.  
  16. public RenderScriptGaussianBlur(@NonNull Context context) {
  17. this.renderScript = RenderScript.create (context);
  18. }
  19.  
  20. public Bitmap gaussianBlur(@IntRange( from = 1, to = 25) int radius, Bitmap original) {
  21. Allocation input = Allocation.createFromBitmap(renderScript, original);
  22. Allocation output = Allocation.createTyped(renderScript, input.getType());
  23. ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur. create (renderScript, Element.U8_4(renderScript));
  24. scriptIntrinsicBlur.setRadius(radius);
  25. scriptIntrinsicBlur.setInput(input);
  26. scriptIntrinsicBlur.forEach( output );
  27. output .copyTo(original);
  28. return original;
  29. }
  30.  
  31. }

Then you can use RenderScriptGaussianBlur directly and happily achieve different degrees of blur depending on the value of the SeekBar.

  1. package io.github.marktony.gaussianblur;
  2.  
  3. import android.content.DialogInterface;
  4. import android.graphics.Bitmap;
  5. import android.graphics.BitmapFactory;
  6. import android.support.v7.app.AlertDialog;
  7. import android.support.v7.app.AppCompatActivity;
  8. import android.os.Bundle;
  9. import android.util.Log;
  10. import android. view . View ;
  11. import android.view.Window ;
  12. import android.view.WindowManager ;
  13. import android.widget.FrameLayout;
  14. import android.widget.ImageView;
  15. import android.widget.LinearLayout;
  16. import android.widget.SeekBar;
  17. import android.widget.TextView;
  18.  
  19. public class MainActivity extends AppCompatActivity {
  20.  
  21. private ImageView imageView;
  22. private ImageView container;
  23. private LinearLayout layout;
  24. private TextView textViewProgress;
  25. private RenderScriptGaussianBlur blur;
  26.  
  27. @Override
  28. protected void onCreate(Bundle savedInstanceState) {
  29. super.onCreate(savedInstanceState);
  30. setContentView(R.layout.activity_main);
  31.  
  32. imageView = (ImageView) findViewById(R.id.imageView);
  33. container = (ImageView) findViewById(R.id.container);
  34.  
  35. container.setVisibility( View .GONE);
  36.  
  37. layout = (LinearLayout) findViewById(R.id.layout);
  38.  
  39. layout.setVisibility( View .VISIBLE);
  40.  
  41. SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
  42. textViewProgress = (TextView) findViewById(R.id.textViewProgress);
  43. TextView textViewDialog = (TextView) findViewById(R.id.textViewDialog);
  44. blur = new RenderScriptGaussianBlur(MainActivity.this);
  45.  
  46. seekBar.setMax(25);
  47. seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
  48. @Override
  49. public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
  50. textViewProgress.setText(String.valueOf(progress));
  51. }
  52.  
  53. @Override
  54. public void onStartTrackingTouch(SeekBar seekBar) {
  55.  
  56. }
  57.  
  58. @Override
  59. public void onStopTrackingTouch(SeekBar seekBar) {
  60. int radius = seekBar.getProgress();
  61. if (radius < 1) {
  62. radius = 1;
  63. }
  64. Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
  65. imageView.setImageBitmap(blur.gaussianBlur(radius, bitmap));
  66. }
  67. });
  68.  
  69. textViewDialog.setOnClickListener(new View .OnClickListener() {
  70. @Override
  71. public void onClick( View v) {
  72.  
  73. container.setVisibility( View .VISIBLE);
  74.  
  75. layout.setDrawingCacheEnabled( true );
  76. layout.setDrawingCacheQuality( View .DRAWING_CACHE_QUALITY_LOW);
  77.  
  78. Bitmap bitmap = layout.getDrawingCache();
  79.  
  80. container.setImageBitmap(blur.gaussianBlur(25, bitmap));
  81.  
  82. layout.setVisibility( View .INVISIBLE);
  83.  
  84. AlertDialog dialog = new AlertDialog.Builder(MainActivity.this) .create ();
  85. dialog.setTitle( "Title" );
  86. dialog.setMessage( "Message" );
  87. dialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK" , new DialogInterface.OnClickListener() {
  88. @Override
  89. public void onClick(DialogInterface dialog, int which) {
  90. dialog.dismiss();
  91. }
  92. });
  93. dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel" , new DialogInterface.OnClickListener() {
  94. @Override
  95. public void onClick(DialogInterface dialog, int which) {
  96.  
  97. }
  98. });
  99. dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
  100. @Override
  101. public void onCancel(DialogInterface dialog) {
  102.  
  103. }
  104. });
  105.  
  106. dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
  107. @Override
  108. public void onCancel(DialogInterface dialog) {
  109. container.setVisibility( View .GONE);
  110. layout.setVisibility( View .VISIBLE);
  111. }
  112. });
  113.  
  114. dialog.show();
  115. }
  116. });
  117.  
  118. }
  119. }

I have done some operations on the visibility of the view in the code, which is relatively simple and I believe you can understand it. One difference from the implementation of the dialog in Instagram is that I did not capture the bitmap of the entire page, but only the content under the actionbar. If you must achieve the same effect, just adjust the layout of the page. I won't go into details here.

Simple isn’t it?

wheel

In addition to RenderScript, there are some excellent wheels:

  • 500px-android-blur
  • Blurry
  • android-stackblur
  • FastBlur: Java Algorithm Implementation

BlurTestAndroid makes statistics and comparisons on the implementation methods, algorithms adopted and time consumed by different libraries. You can also download its demo app and test it yourself.

Example code is here: GaussianBlur

<<:  Thoughts and experience in Android development software architecture

>>:  See the strong insertion of AspectJ in Android

Recommend

Why do early products need seed users?

When it comes to the concept of seed users , I be...

Online traffic generation skills for training institutions!

Some time ago, I enrolled my daughter in a full-p...

How to operate products well in social overseas expansion?

Problem Overview Part 1 Rethinking Social Network...

VIP membership growth system of the three major mainstream video platforms!

In recent years, influenced by policies and marke...

Is there any hope for Windows 10 phones on the brink of collapse?

Although this option may seem like nonsense, it i...

How to choose H5 multi-channel App promotion?

Nowadays, there are more and more channels for Ap...

A guide to continuous traffic monetization in online education!

As an observer of the education and training indu...

Brand marketing promotion, how to make H5?

How to make H5? Based on my thoughts and ideas fr...

Marketing promotion routines, have you ever been tricked?

Discount promotions, limited-time discounts, savi...