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

Anyone can build their own AI robot from scratch

From driverless cars to software engineering, fro...

Aston Martin recalls 1,658 vehicles worldwide, Chinese dealers to take the blame

According to Reuters, Andy Palmer, CEO of British...

WeChat’s new killer feature—“Nearby Businesses”

When the WeChat Nearby People app first appeared,...

Common content misunderstandings of low-follow Douyin sales accounts

Recently, many friends have been asking questions...

Is your phone battery life too short? Pay attention to your charging habits

[[438944]] The battery life of a new mobile phone...

Birds are experts in eating spicy food! Why are they not afraid of spicy food?

There are many interesting phenomena hidden in th...

Content, community, and brand are three in one, curing traffic anxiety

Starting from the content mechanism of WeChat, th...

Umeng: 5 tips to increase user activity through in-app communities

To what extent can the community influence the us...

Advanced checklist for private domain operators

What is a private domain operator ? As the name s...

New traffic diversion methods in 2020 and 6 implementation steps!

Behind every search action and every click is a l...