Android and Renderscript intrinsics

Intrinsics are renderscripts shipped with the platform, designed for some common image processing tasks. I will use an example from a real application where we wanted a few different things to happen when the user clicked an item in a gridview, triggering a details view to be shown. First we wanted to create the illusion that the grid was moving away from us and the details towards us. This was pretty straight forward, using a ObjectAnimator to animate the scaleY and scaleX of the background. We also animated the x,y position of the background so that it moved slightly upwards on the screen, again to create that feeling of it moving away from us. And most importantly we added a strong blur to the background for the same reason. The blur was added using a renderscript intrinsic, ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); that you can find in the android.renderscript package in the ScriptIntrinsicBlur class.

The background (the gridview in our case) was first rendered to a bitmap via a canvas. Rendering to a bitmap could be done for each frame, or before the animation is started. Since rendering a view + its children in android is generally slow (100+ms for the gridview in this example) this was done before starting the animation. To speed up the rendering additionally the gridview was rendered at a reduced resolution (since we will blur it its ok to have it at reduced resolution).

Config config = Bitmap.Config.ARGB_8888;
final Bitmap inputBitmap = Bitmap.createBitmap((int) (root.getWidth() * BACKGROUND_SCALE_DOWN_FACTOR),
    (int) (root.getHeight() * BACKGROUND_SCALE_DOWN_FACTOR), config);
Canvas canvas = new Canvas(inputBitmap);
Matrix matrix = new Matrix();
matrix.setScale(BACKGROUND_SCALE_DOWN_FACTOR, BACKGROUND_SCALE_DOWN_FACTOR);
canvas.drawColor(0xff000000);
canvas.setMatrix(matrix);
draw(canvas);

After the draw(canvas) call have been made the inputBitmap will now look just like the girdview and we can use that as a starting point for blurring and animating the background.

rs = RenderScript.create(context);
blurInputAllocation = Allocation.createFromBitmap(rs, inputBitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
blurOutputAllocation = Allocation.createTyped(rs, blurInputAllocation.getType());
blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

The first line creates a render script context needed for the creation of allocations and the intrinsic. The input and output allocations are bitmaps used as input and output for the script. Next step is to setup a script to use on the allocations we just created, this is can be done by calling the create method on the ScriptIntrinsicBlur class.  The second param, Element.U8_4(rs), sent to the create method tells the script what format the input and output data has. U8_4 tells us that each element on the allocations consists of 4 Unsigned 8 bit fields, and this just happen to match the bitmap format used for the creating of the allocations.

Next step is to run the script.

blurInputAllocation.copyFrom(inputBitmap);
blurScript.setInput(blurInputAllocation);
blurScript.setRadius(blurStrength);
blurScript.forEach(blurOutputAllocation);
blurOutputAllocation.copyTo(outputBitmap);

First we copy the pixels from the inputBitmap to the blurInputAllocation and the we need to tell the script to use the blurInputAllocation as input. After this we need to tell the script how much we want it to blur the input. Then we tell the script the forEach element in the input allocation, do whatever the script does and put the result in the corresponding element in the output allocation. And last we copy the data in the output allocation the the outputBitmap that we can now use to set as background for the current view (this could be view hovering above the gridview).

For a full listing of the code have a look at github. (my apologies for the project being in eclipse format and not studio/gradle)

This Post Has 2 Comments

  1. can you please tell me how do i blur a fragment if a layoutDrawer is pulled

  2. Hi Noddy, if the LayoutDrawer is visible or not should not affect the blur effect described above. But its a limitation of this blur that you can not interact with the LayoutDrawer or any other component from the blurred view once it is blurred.
    If you are having problems with the LayoutDrawer not blurring that might be due to it not living in the same ViewGroup as the rest of the Activity/Fragment. If that’s the case I’m not sure on how to fix it.

Leave a Reply

Close Menu