Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > Android毛玻璃效果

Android中毛玻璃效果的两种实现代码

作者:adam.li

这篇文章主要介绍了Android中毛玻璃效果的两种实现代码,第一种是使用JAVA算法FastBlur实现,第二种是使用Android自带类RenderScript 实现,本文通过实例代码介绍的非常详细,需要的朋友参考下吧

Android中毛玻璃效果主要有两种实现方式。
1.使用JAVA算法FastBlur实现
方法1 先将图片缩小,然后放大图片,再设置为控件背景以达到更模糊的效果,同时也提升模糊算法的处理效率。
2.使用Android自带类RenderScript 实现
方法2 模糊半径只能设置1-25。

对比下来同样的模糊半径 ,方法1 的模糊效果更好,且方法1 的模糊半径可以设置范围更大。示例代码如下:
1.activity中调用

private void testImageBlur() {
        Log.i(TAG, "testImageBlur() 11");
        Bitmap bitmapOrigin1 = getTestImage();
        //1.显示原图
        mImageOrigin.setImageBitmap(bitmapOrigin1);
        Log.i(TAG, "testImageBlur() 22 bitmapOrigin1.isRecycled:" + bitmapOrigin1.isRecycled());
        final float RADIUS = 20;
        Bitmap bitmapOrigin2 = getTestImage();
        Bitmap bitmapFastBlur = BitmapUtil.blurFastBlur(this, bitmapOrigin2, 20);
        //2.显示使用FastBlur处理后 高斯模糊图片
        mImageFastBlurResult.setImageBitmap(bitmapFastBlur);
        Bitmap bitmapOrigin3 = getTestImage();
        Bitmap bitmapRenderScriptBlur = BitmapUtil.blurRenderScript(this, bitmapOrigin3, 25);
        //3.显示 RenderScript 处理后的高斯模糊图片
        mImageRenderScriptResult.setImageBitmap(bitmapRenderScriptBlur);
        Log.i(TAG, "testImageBlur() 33 bitmapOrigin3.isRecycled:" + bitmapOrigin3.isRecycled()
                + " bitmapOrigin1.isRecycled():" + bitmapOrigin1.isRecycled());
    }

2.BitmapUtil.java 类

public class BitmapUtil {
    private static final String TAG = "BitmapUtil";
    public static BitmapDrawable getConfirmDialogBg(Context context) {
        return getScreenBlurBg(context, 30.0f, 1676, 160, 834, 1094);
    }
    /**
     * 使用 获取全屏高斯模糊的图片 BitmapDrawable
     *
     * @param activity
     * @return
     */
    public static BitmapDrawable getScreenBlurBg(Activity activity) {
        WeakReference<Bitmap> screenBitmap = new WeakReference(FastBlurUtil.takeScreenShot(activity));
        Log.i(TAG, "getScreenBlurBg 00 screenBitmap:" + screenBitmap);
        if (null == screenBitmap) {
            return null;
        }
        Log.i(TAG, "getScreenBlurBg 11 screenBitmap:" + screenBitmap);
        long startMs = System.currentTimeMillis();
        float radius = 10.0F;
        Bitmap bitmapSmall = small(screenBitmap.get());
        Bitmap bitmapBlur = FastBlurUtil.fastBlur(bitmapSmall, radius);
        WeakReference<Bitmap> overlay = new WeakReference(FastBlurUtil.getDimBitmap(bitmapBlur, 0.2F));
        Log.i(TAG, "getScreenBlurBg 22 =====blur time:" + (System.currentTimeMillis() - startMs));
        try {
            if (screenBitmap.get() != null && !screenBitmap.get().isRecycled()) {
                screenBitmap.get().recycle();
            }
            if (null != bitmapSmall && !bitmapSmall.isRecycled()) {
                bitmapSmall.recycle();
            }
            if (null != bitmapBlur && !bitmapBlur.isRecycled()) {
                bitmapBlur.recycle();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        BitmapDrawable rst = new BitmapDrawable(activity.getResources(), overlay.get());
        return rst;
    }
    /**
     * 获取屏幕指定区域高斯模糊的图片 BitmapDrawable
     *
     * @param context
     * @param blurRadius 模糊半径
     * @param xOffset    指定区域的左上角顶点X坐标偏移
     * @param yOffset    指定区域的左上角顶点Y坐标偏移
     * @param width      指定区域的宽度
     * @param height     指定区域的高度
     * @return
     */
    public static BitmapDrawable getScreenBlurBg(Context context, float blurRadius, int xOffset, int yOffset, int width, int height) {
        Bitmap screenBitmap = FastBlurUtil.screenshot(context);
        if (null == screenBitmap) {
            return null;
        }
        Bitmap b1 = crop(screenBitmap, xOffset, yOffset, width, height);
        Bitmap overlay = FastBlurUtil.fastBlur(bitmapMergeWithColor(b1), blurRadius);
//        Bitmap overlay = FastBlurUtility.getDimBitmap(FastBlurUtility.fastBlur(small(bitmapMerge(b1, b2)), radius), 0.2F);
        BitmapDrawable rst = new BitmapDrawable(context.getResources(), getRoundedCornerBitmap(overlay));
        return rst;
    }
    /**
     * 在给定的bitmap中剪裁指定区域
     *
     * @param source
     * @param xOffset 指定区域的左上角顶点X坐标偏移
     * @param yOffset 指定区域的左上角顶点Y坐标偏移
     * @param width   指定区域的宽度
     * @param height  指定区域的高度
     * @return
     */
    public static Bitmap crop(Bitmap source, int xOffset, int yOffset, int width, int height) {
        return Bitmap.createBitmap(source, xOffset, yOffset, width, height);
    }
    /**
     * 缩小bitmap,可以使用此方法先将图片缩小,再设置为控件背景以达到更模糊的效果
     *
     * @param bitmap
     * @return
     */
    private static Bitmap small(Bitmap bitmap) {
        Matrix matrix = new Matrix();
        matrix.postScale(0.25F, 0.25F);
        Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizeBmp;
    }
    /**
     * 图片圆角化
     *
     * @param bitmap
     * @return
     */
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
        final float roundPx = 24f;
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                .getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        final int color = 0xFFFFFFFF;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }
    /**
     * 将bitmap与指定颜色混合
     *
     * @param b1
     * @return
     */
    private static Bitmap bitmapMergeWithColor(Bitmap b1) {
        if (!b1.isMutable()) {
            b1 = b1.copy(Bitmap.Config.ARGB_8888, true);
        }
        Canvas canvas = new Canvas(b1);
        canvas.drawARGB(79, 255, 255, 255);
        canvas.save();
        canvas.restore();
        return b1;
    }
    /**
     * 使用 fastBlur 接口实现高斯模糊效果
     *
     * @param context
     * @param orginBitmap 需要做模糊效果的原始 bitmap
     * @param radius      模糊半径
     * @return 模糊后的bitmap
     */
    public static Bitmap blurFastBlur(Context context, Bitmap orginBitmap, float radius) {
        Log.i(TAG, "getScreenBlurBg 00 orginBitmap:" + orginBitmap);
        if (null == orginBitmap) {
            return null;
        }
        Log.i(TAG, "getScreenBlurBg 11 orginBitmap:" + orginBitmap);
        long startMs = System.currentTimeMillis();
        //先将图片缩小,再设置为控件背景以达到更模糊的效果,同时也提升模糊算法的处理效率
        Bitmap bitmapSmall = small(orginBitmap);
        Bitmap bitmapBlur = FastBlurUtil.fastBlur(bitmapSmall, radius);
        WeakReference<Bitmap> overlay = new WeakReference(FastBlurUtil.getDimBitmap(bitmapBlur, 0.2F));
        //WeakReference<Bitmap> overlay = new WeakReference(bitmapBlur);
        Log.i(TAG, "getScreenBlurBg 22 =====blur time:" + (System.currentTimeMillis() - startMs));
        try {
            if (orginBitmap != null && !orginBitmap.isRecycled()) {
                orginBitmap.recycle();
            }
            if (null != bitmapSmall && !bitmapSmall.isRecycled()) {
                bitmapSmall.recycle();
            }
            if (null != bitmapBlur && !bitmapBlur.isRecycled()) {
                bitmapBlur.recycle();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return overlay.get();
    }
    /**
     * 使用Android自带 RenderScript 接口实现高斯模糊效果
     *
     * @param context
     * @param smallBitmap 需要做模糊效果的bitmap
     * @param radius      模糊半径
     * @return 模糊后的bitmap
     */
    public static Bitmap blurRenderScript(Context context, Bitmap smallBitmap, float radius) {
        // Create a new bitmap that is a copy of the original bitmap
        Bitmap bitmap = smallBitmap.copy(Bitmap.Config.ARGB_8888, true);
        // Initialize RenderScript
        RenderScript rs = RenderScript.create(context);
        // Create an empty allocation that will hold the original bitmap
        Allocation input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
        // Create an empty allocation that will hold the blurred bitmap
        Allocation output = Allocation.createTyped(rs, input.getType());
        // Load the script in the Allocation
        ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        script.setInput(input);
        // Set the blur radius
        //float radius = 20f; // 20 works well for me
        // Start the Script Intrinsic Blur
        script.setRadius(radius);
        script.forEach(output);
        // Copy the script result into the blurred bitmap
        output.copyTo(bitmap);
        // Recycle the original bitmap
        smallBitmap.recycle();
        // After all of this, we can return the now-blurred bitmap
        return bitmap;
    }
}

3.FastBlurUtil.java 类

public class FastBlurUtil {
    public FastBlurUtil() {
    }
    public static Bitmap getBlurBackgroundDrawer(Context context) {
        Bitmap bmp = screenshot(context);
        return startBlurBackground(bmp);
    }
    public static Bitmap screenshot(Context context) {
        int[] dim = new int[]{ScreenUtils.getScreenWidth(context), ScreenUtils.getScreenHeight(context)};
        String surfaceClassName = "";
        if (VERSION.SDK_INT <= 17) {
            surfaceClassName = "android.view.Surface";
        } else {
            surfaceClassName = "android.view.SurfaceControl";
        }
        try {
            Class<?> c = Class.forName(surfaceClassName);
            Method method = c.getMethod("screenshot", Rect.class, Integer.TYPE, Integer.TYPE, Integer.TYPE);
            method.setAccessible(true);
            Bitmap bitmap = (Bitmap)method.invoke((Object)null, new Rect(0, 0, dim[0], dim[1]), dim[0], dim[1], 0);
            if(null == bitmap){
                return null;
            }
            bitmap = bitmap.copy(Config.ARGB_8888, true);
            return bitmap;
        } catch (NoSuchMethodException | InvocationTargetException | ClassNotFoundException | IllegalAccessException var6) {
            var6.printStackTrace();
            return null;
        }
    }
    public static Bitmap takeScreenShot(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap b1 = view.getDrawingCache();
        int width = activity.getResources().getDisplayMetrics().widthPixels;
        int height = activity.getResources().getDisplayMetrics().heightPixels + getNavigationBarOffset(activity);
        Bitmap bmp = Bitmap.createBitmap(b1, 0, 0, width, height);
        view.destroyDrawingCache();
        return bmp;
    }
    @RequiresApi(
            api = 26
    )
    private static Bitmap startBlurBackground(Bitmap bkg) {
        long startMs = System.currentTimeMillis();
        float radius = 10.0F;
        Bitmap overlay = getDimBitmap(fastBlur(small(bkg), radius), 0.2F);
        Log.i("FastBlurUtility", "=====blur time:" + (System.currentTimeMillis() - startMs));
        return overlay;
    }
    private static Bitmap big(Bitmap bitmap) {
        Matrix matrix = new Matrix();
        matrix.postScale(4.0F, 4.0F);
        Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizeBmp;
    }
    private static Bitmap small(Bitmap bitmap) {
        Matrix matrix = new Matrix();
        matrix.postScale(0.25F, 0.25F);
        Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizeBmp;
    }
    private static int getStatusBarHeight(Activity activity) {
        int result = 0;
        int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = activity.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }
    private static int getNavigationBarOffset(Activity activity) {
        int result = 0;
        Resources resources = activity.getResources();
        if (VERSION.SDK_INT >= 21) {
            int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
            if (resourceId > 0) {
                result = resources.getDimensionPixelSize(resourceId);
            }
        }
        return result;
    }
    /**
     * 每个像素设置模糊效果
     * @param bitmap 原图
     * @param radiusf 模糊半径
     * @return 模糊处理后的效果图
     */
    public static Bitmap fastBlur(Bitmap bitmap, float radiusf) {
        if (bitmap == null) {
            return null;
        } else {
            int radius = (int)radiusf;
            if (radius < 1) {
                return null;
            } else {
                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[] vmin = new int[Math.max(w, h)];
                int divsum = div + 1 >> 1;
                divsum *= divsum;
                int[] dv = new int[256 * divsum];
                int i;
                for(i = 0; i < 256 * divsum; ++i) {
                    dv[i] = i / divsum;
                }
                int yi = 0;
                int yw = 0;
                int[][] stack = new int[div][3];
                int r1 = radius + 1;
                int rsum;
                int gsum;
                int bsum;
                int x;
                int y;
                int p;
                int stackpointer;
                int stackstart;
                int[] sir;
                int rbs;
                int routsum;
                int goutsum;
                int boutsum;
                int rinsum;
                int ginsum;
                int binsum;
                for(y = 0; y < h; ++y) {
                    bsum = 0;
                    gsum = 0;
                    rsum = 0;
                    boutsum = 0;
                    goutsum = 0;
                    routsum = 0;
                    binsum = 0;
                    ginsum = 0;
                    rinsum = 0;
                    for(i = -radius; i <= radius; ++i) {
                        p = pix[yi + Math.min(wm, Math.max(i, 0))];
                        sir = stack[i + radius];
                        sir[0] = (p & 16711680) >> 16;
                        sir[1] = (p & '\uff00') >> 8;
                        sir[2] = p & 255;
                        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 & 16711680) >> 16;
                        sir[1] = (p & '\uff00') >> 8;
                        sir[2] = p & 255;
                        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) {
                    bsum = 0;
                    gsum = 0;
                    rsum = 0;
                    boutsum = 0;
                    goutsum = 0;
                    routsum = 0;
                    binsum = 0;
                    ginsum = 0;
                    rinsum = 0;
                    int 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) {
                        pix[yi] = -16777216 & 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;
            }
        }
    }
    @RequiresApi(
            api = 26
    )
    public static Bitmap getDimBitmap(Bitmap background, float dimAmount) {
        if (background == null) {
            return null;
        } else {
            int bgWidth = background.getWidth();
            int bgHeight = background.getHeight();
            Bitmap newbmp = Bitmap.createBitmap(bgWidth, bgHeight, Config.ARGB_8888);
            Canvas cv = new Canvas(newbmp);
            cv.drawBitmap(background, 0.0F, 0.0F, (Paint)null);
            cv.drawColor(Color.argb(dimAmount, 0.0F, 0.0F, 0.0F));
            cv.save();
            cv.restore();
            return newbmp;
        }
    }
}

到此这篇关于Android中毛玻璃效果的两种实现的文章就介绍到这了,更多相关Android毛玻璃效果内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文