0%

Android开发:高斯模糊blur效果

代码来自:http://blog.csdn.net/huli870715/article/details/39378349 原文对三种方法做了测试,这里直接上最优代码。个人感觉效果仍然不是那么好,在ZTE Grand S II(骁龙800+2G RAM)上运行大概需要十几ms,第一次启动会更长。 布局:

Controller的代码:

@ViewById
ImageView image;
@ViewById
TextView text;

@AfterViews
public void afterViews()
{
    applyBlur();
}
private void applyBlur() {
    image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            image.getViewTreeObserver().removeOnPreDrawListener(this);
            image.buildDrawingCache();
            Bitmap bmp = image.getDrawingCache();
            blur2(bmp, text);
            return true;
        }
    });
}

@Override
public void setTopBar() {

}

private void blur2(Bitmap bkg, View view) {
    long startMs = System.currentTimeMillis();
    float radius = 2;
    float scaleFactor = 20;
    Bitmap overlay = Bitmap.createBitmap((int)(view.getMeasuredWidth()/scaleFactor), (int)(view.getMeasuredHeight()/scaleFactor), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(overlay);
    canvas.translate(-view.getLeft()/scaleFactor, -view.getTop()/scaleFactor);
    canvas.scale(1 / scaleFactor, 1 / scaleFactor);
    Paint paint = new Paint();
    paint.setFlags(Paint.FILTER\_BITMAP\_FLAG);
    canvas.drawBitmap(bkg, 0, 0, paint);
    overlay = ImageUtil.fastblur(getActivity(), overlay, (int) radius);
    view.setBackground(new BitmapDrawable(getResources(), overlay));
    PToast.show("cost " + (System.currentTimeMillis() - startMs) + "ms");
}

fastblur:

/**
* Android api 17实现的虚化
* 某些机型上可能会Crash
*
* @param context
* @param sentBitmap
* @param radius 大于1小于等于25
* @return
*/
@SuppressLint(“NewApi”)
public static Bitmap fastblur(Context context, Bitmap sentBitmap, int radius) {
if (sentBitmap == null) {
return null;
}
if (Build.VERSION.SDK_INT > 16) {
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);

        final RenderScript rs = RenderScript.create(context);
        final Allocation input = Allocation.createFromBitmap(rs,
                sentBitmap, Allocation.MipmapControl.MIPMAP_NONE,
                Allocation.USAGE_SCRIPT);
        final Allocation output = Allocation.createTyped(rs,
                input.getType());
        final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs,
                Element.U8_4(rs));
        script.setRadius(radius /* e.g. 3.f */);
        script.setInput(input);
        script.forEach(output);
        output.copyTo(bitmap);
        return bitmap;
    }
    return stackblur(sentBitmap, radius);
}

/\*\*
 \* 纯Java实现的虚化,适用老版本api,外部只需调fastblur,会自动判断
 \*
 \* @param sentBitmap
 \* @param radius
 \* @return
 */
private static Bitmap stackblur(Bitmap sentBitmap,
                                int radius) {

    Bitmap bitmap = null;
    try {
        bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
    } catch (OutOfMemoryError e) {
        e.printStackTrace();
        return sentBitmap;
    }

    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);
}