首页 > 其他分享 >Android中毛玻璃效果的两种实现

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

时间:2024-08-05 09:39:49浏览次数:14  
标签:sir return 效果 int bitmap new Android Bitmap 毛玻璃

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

 

标签:sir,return,效果,int,bitmap,new,Android,Bitmap,毛玻璃
From: https://www.cnblogs.com/adamli/p/18342622

相关文章

  • Android activity主题设置
    主题配置<stylename="MainThemeCamera"parent="Theme.AppCompat.DayNight.NoActionBar"><itemname="android:windowBackground">@color/black</item><itemname="android:windowTranslucentStatu......
  • Android mvvm使用流程
    Androidmvvm使用流程一.几种常见架构模式对比1.MVC(Model-View-Controller)MVC模式的优点在于模块化、可扩展性和可维护性,但缺点是控制器和视图之间的耦合度较高。2.MVP(Model-View-Presenter)模式Presenter同时持有Model和View对象,缺点是V层与P层还是有一定的耦合度3.MVVM(Model-View......
  • 自定义导航栏兼容ios和android
    <template>  <view class="content">    <!--距离顶部的距离刚好留出状态栏即可即statusBarHeight-->    <view class="topNav" :style="{height:navHeight+'px',paddingTop:statusBarHeight+'px'}">      <......
  • 如何对视频应用风格化效果?
    我被要求使用python将上传的视频转换为动画。期望:我得到的样本随着时间的推移我在项目上的工作还没有实现它。相反,我得到的是这样的:任何解决方案将不胜感激,谢谢这是我正在使用的代码:importsysimportcv2importtensorflowastfimportnumpyasnpf......
  • Android ImageProxy 到 byteArray 并通过套接字发送
    我正在尝试将ImageProxy转换为byteArray,以通过套接字将其发送到python服务器。我正在使用Camerax,这是我的图像分析:mageAnalysisimageAnalysis=newImageAnalysis.Builder().setTargetResolution(newSize(720,640))......
  • GitHub页面(实现贪吃蛇效果等)美化主页详细大全!
    1.引言        ......
  • 【转载】在Android中使用Rust:Rust与Android的结合
    声明:处于学习目的转载本文,若文章侵犯原作者权益,联系本人立即删除,联系方式:[email protected]文章转载于:https://developer.baidu.com/article/detail.html?id=3011246 简介:本文将介绍如何在Android平台上使用Rust编程语言,以及Rust与Android的结合所带来的优势和挑战。我们将探......
  • Android Studio开发学习(七、蓝牙模块java)
    引言    上篇我们已经介绍了蓝牙模块相关布局,所以,今天我们来学习一下功能实现,如何打开关闭蓝牙。(这里DataActivity为蓝牙列表点击设备名连接后跳转界面函数,这里暂时没有设置,只是默认空白界面)先来介绍一下蓝牙相关概念        蓝牙是一种无线技术标准,用于短......
  • Android最全8万字Fragment面试题及参考答案(持续更新)
    目录什么是Fragment?Fragment和Activity之间的关系是什么?为什么要使用Fragment而不是直接使用多个Activity?Fragment是如何被添加到Activity中的?如何从Activity中移除一个Fragment?Fragment可以嵌套吗?如何实现?如何获取当前Activity中的Fragment?如何通过FragmentManager......
  • Android开发 - Fragment 类详解
    Fragment是什么Fragment是Android开发中的一种模块化组件,一个抽象类,允许开发者将一个Activity分解成多个独立的、可重用的部分。每个Fragment都有自己的生命周期和用户界面,可以独立管理自己的UI和行为,它们可以动态地添加、移除或替换,从而提高应用程序的灵活性和可维护......