androidbitmapblurrenderscript

Error when trying to blur image using RenderScript support library on android phone


I'm trying to blur my image, and display it blurred on an RelativeLayout's background with RenderScript, the app works in the emulator but my app in the phone keeps crashing with this error:

08-05 22:21:36.543: E/RenderScript_jni(11549): No GC methods 08-05 22:21:36.553: D/dalvikvm(11549): No JNI_OnLoad found in /system/lib/libRSSupport.so 0x41803ab8, skipping init 08-05 22:21:36.557: E/dalvikvm(11549): ERROR: couldn't find native method 08-05 22:21:36.557: E/dalvikvm(11549): Requested: Landroid/support/v8/renderscript/RenderScript;._nInit:()V 08-05 22:21:36.558: E/JNIHelp(11549): RegisterNatives failed for 'android/support/v8/renderscript/RenderScript', aborting 08-05 22:21:36.558: A/libc(11549): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 11549 (m.example.login)

Here is my blur code on a seperate class:

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v8.renderscript.*;

public class Blur {
    public static Bitmap blurBitmap(Context context, Bitmap src) {
        Bitmap outBitmap = src.copy(src.getConfig(), true);

        final RenderScript rs = RenderScript.create(context);
        final Allocation input = Allocation.createFromBitmap(rs, src);
        final Allocation output = Allocation.createFromBitmap(rs, outBitmap);

        final ScriptIntrinsicBlur script =
                ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        script.setRadius(25f);
        script.setInput(input);
        script.forEach(output);
        output.copyTo(outBitmap);

        rs.destroy();

        return outBitmap;
    }
}

and here is ny code in the MainActivity (I'm getting the Bitmap from the Gallery):

Uri selectedImageUri = data.getData();
Blur blur = new Blur();
imagepath = getRealPathFromURI(selectedImageUri);
Bitmap bmImg = BitmapFactory.decodeFile(imagepath);
Bitmap BlurredIMG = Blur.blurBitmap(getApplicationContext(), bmImg);
BitmapDrawable background = new BitmapDrawable(BlurredIMG);
rl.setBackgroundDrawable(background);

Solution

  • I had the same issue. After hours of researching I've found another solution. It works very fast (around 10-15ms) if pre-scale image vertically and horizontally and then apply this algorithm.
    My solution looks like this

    //here we scale bitmap and apply blur
    private Bitmap blur(Bitmap bkg) {
    
                float scaleFactor = 8;
                int radius = 2;
                int inputWidth = bkg.getWidth();
                int inputHeight = bkg.getHeight();
    
                Bitmap overlay = Bitmap.createBitmap((int)(inputWidth/scaleFactor),(int)(inputHeight/scaleFactor), Bitmap.Config.ARGB_8888);
    
                Canvas canvas = new Canvas(overlay);
    
                canvas.scale(1 / scaleFactor, 1 / scaleFactor);
                Paint paint = new Paint();
                paint.setFlags(Paint.FILTER_BITMAP_FLAG);
    
                canvas.drawBitmap(bkg, 0, 0, paint);
    
                //  bkg.recycle();
                overlay = FastBlur.doBlur(overlay, radius, true);
                return getResizedBitmap(overlay, inputWidth, inputHeight, true);
    
            }
    
    
            public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth, boolean willDelete) {
    
                int width = bm.getWidth();
    
                int height = bm.getHeight();
    
                float scaleWidth = ((float) newWidth) / width;
    
                float scaleHeight = ((float) newHeight) / height;
    
                // CREATE A MATRIX FOR THE MANIPULATION
    
                Matrix matrix = new Matrix();
    
                // RESIZE THE BIT MAP
    
                matrix.postScale(scaleWidth, scaleHeight);
    
                // RECREATE THE NEW BITMAP
    
                Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
    
                //          if(willDelete)
                //              bm.recycle();
    
                return resizedBitmap;
            }
    

    At last this is my class which wraps blur algorithm

    public class FastBlur {
        
        public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {
    
            // Stack Blur v1.0 from
            // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
            //
            // Java Author: Mario Klingemann <mario at quasimondo.com>
            // http://incubator.quasimondo.com
            // created Feburary 29, 2004
            // Android port : Yahel Bouaziz <yahel at kayenko.com>
            // http://www.kayenko.com
            // ported april 5th, 2012
    
            // This is a compromise between Gaussian Blur and Box blur
            // It creates much better looking blurs than Box Blur, but is
            // 7x faster than my Gaussian Blur implementation.
            //
            // I called it Stack Blur because this describes best how this
            // filter works internally: it creates a kind of moving stack
            // of colors whilst scanning through the image. Thereby it
            // just has to add one new block of color to the right side
            // of the stack and remove the leftmost color. The remaining
            // colors on the topmost layer of the stack are either added on
            // or reduced by one, depending on if they are on the right or
            // on the left side of the stack.
            //
            // If you are using this algorithm in your code please add
            // the following line:
            //
            // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
    
            Bitmap bitmap;
            if (canReuseInBitmap) {
                bitmap = sentBitmap;
            } else {
                bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
            }
    
            if (radius < 1) {
                return (null);
            }
    
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
    
            int[] pix = new int[w * h];
            bitmap.getPixels(pix, 0, w, 0, 0, w, h);
    
            int wm = w - 1;
            int hm = h - 1;
            int wh = w * h;
            int div = radius + radius + 1;
    
            int r[] = new int[wh];
            int g[] = new int[wh];
            int b[] = new int[wh];
            int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
            int vmin[] = new int[Math.max(w, h)];
    
            int divsum = (div + 1) >> 1;
            divsum *= divsum;
            int dv[] = new int[256 * divsum];
            for (i = 0; i < 256 * divsum; i++) {
                dv[i] = (i / divsum);
            }
    
            yw = yi = 0;
    
            int[][] stack = new int[div][3];
            int stackpointer;
            int stackstart;
            int[] sir;
            int rbs;
            int r1 = radius + 1;
            int routsum, goutsum, boutsum;
            int rinsum, ginsum, binsum;
    
            for (y = 0; y < h; y++) {
                rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
                for (i = -radius; i <= radius; i++) {
                    p = pix[yi + Math.min(wm, Math.max(i, 0))];
                    sir = stack[i + radius];
                    sir[0] = (p & 0xff0000) >> 16;
                    sir[1] = (p & 0x00ff00) >> 8;
                    sir[2] = (p & 0x0000ff);
                    rbs = r1 - Math.abs(i);
                    rsum += sir[0] * rbs;
                    gsum += sir[1] * rbs;
                    bsum += sir[2] * rbs;
                    if (i > 0) {
                        rinsum += sir[0];
                        ginsum += sir[1];
                        binsum += sir[2];
                    } else {
                        routsum += sir[0];
                        goutsum += sir[1];
                        boutsum += sir[2];
                    }
                }
                stackpointer = radius;
    
                for (x = 0; x < w; x++) {
    
                    r[yi] = dv[rsum];
                    g[yi] = dv[gsum];
                    b[yi] = dv[bsum];
    
                    rsum -= routsum;
                    gsum -= goutsum;
                    bsum -= boutsum;
    
                    stackstart = stackpointer - radius + div;
                    sir = stack[stackstart % div];
    
                    routsum -= sir[0];
                    goutsum -= sir[1];
                    boutsum -= sir[2];
    
                    if (y == 0) {
                        vmin[x] = Math.min(x + radius + 1, wm);
                    }
                    p = pix[yw + vmin[x]];
    
                    sir[0] = (p & 0xff0000) >> 16;
                    sir[1] = (p & 0x00ff00) >> 8;
                    sir[2] = (p & 0x0000ff);
    
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
    
                    rsum += rinsum;
                    gsum += ginsum;
                    bsum += binsum;
    
                    stackpointer = (stackpointer + 1) % div;
                    sir = stack[(stackpointer) % div];
    
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
    
                    rinsum -= sir[0];
                    ginsum -= sir[1];
                    binsum -= sir[2];
    
                    yi++;
                }
                yw += w;
            }
            for (x = 0; x < w; x++) {
                rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
                yp = -radius * w;
                for (i = -radius; i <= radius; i++) {
                    yi = Math.max(0, yp) + x;
    
                    sir = stack[i + radius];
    
                    sir[0] = r[yi];
                    sir[1] = g[yi];
                    sir[2] = b[yi];
    
                    rbs = r1 - Math.abs(i);
    
                    rsum += r[yi] * rbs;
                    gsum += g[yi] * rbs;
                    bsum += b[yi] * rbs;
    
                    if (i > 0) {
                        rinsum += sir[0];
                        ginsum += sir[1];
                        binsum += sir[2];
                    } else {
                        routsum += sir[0];
                        goutsum += sir[1];
                        boutsum += sir[2];
                    }
    
                    if (i < hm) {
                        yp += w;
                    }
                }
                yi = x;
                stackpointer = radius;
                for (y = 0; y < h; y++) {
                    // Preserve alpha channel: ( 0xff000000 & pix[yi] )
                    pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
    
                    rsum -= routsum;
                    gsum -= goutsum;
                    bsum -= boutsum;
    
                    stackstart = stackpointer - radius + div;
                    sir = stack[stackstart % div];
    
                    routsum -= sir[0];
                    goutsum -= sir[1];
                    boutsum -= sir[2];
    
                    if (x == 0) {
                        vmin[y] = Math.min(y + r1, hm) * w;
                    }
                    p = x + vmin[y];
    
                    sir[0] = r[p];
                    sir[1] = g[p];
                    sir[2] = b[p];
    
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
    
                    rsum += rinsum;
                    gsum += ginsum;
                    bsum += binsum;
    
                    stackpointer = (stackpointer + 1) % div;
                    sir = stack[stackpointer];
    
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
    
                    rinsum -= sir[0];
                    ginsum -= sir[1];
                    binsum -= sir[2];
    
                    yi += w;
                }
            }
    
            bitmap.setPixels(pix, 0, w, 0, 0, w, h);
    
            return (bitmap);
        }
    
    }