Android 毛玻璃效果

一、效果图

二、实现

StackBlurManager.java

/**
 * StackBlur v1.0 for Android
 *
 * @Author: Enrique López Mañas <[email protected]>
 * http://www.neo-tech.es
 *
 * Author of the original algorithm: Mario Klingemann <mario.quasimondo.com>
 *
 * 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.
 *
 * @copyright: Enrique López Mañas
 * @license: Apache License 2.0
 */

import android.graphics.Bitmap;

import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class StackBlurManager {
    static final int EXECUTOR_THREADS = Runtime.getRuntime().availableProcessors();
    static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(EXECUTOR_THREADS);

    /**
     * Original image
     */
    private final Bitmap _image;
    /**
     * Method of blurring
     */
    private final JavaBlurProcess _blurProcess;
    /**
     * Most recent result of blurring
     */
    private Bitmap _result;

    /**
     * Constructor method (basic initialization and construction of the pixel array)
     *
     * @param image The image that will be analyed
     */
    public StackBlurManager(Bitmap image) {
        _image = image;
        _blurProcess = new JavaBlurProcess();
    }

    /**
     * Process the image on the given radius. Radius must be at least 1
     *
     * @param radius
     */
    public Bitmap process(int radius) {
        _result = _blurProcess.blur(_image, radius);
        return _result;
    }

    /**
     * Returns the blurred image as a bitmap
     *
     * @return blurred image
     */
    public Bitmap returnBlurredImage() {
        return _result;
    }

    /**
     * Save the image into the file system
     *
     * @param path The path where to save the image
     */
    public void saveIntoFile(String path) {
        try {
            FileOutputStream out = new FileOutputStream(path);
            _result.compress(Bitmap.CompressFormat.PNG, 90, out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Returns the original image as a bitmap
     *
     * @return the original bitmap image
     */
    public Bitmap getImage() {
        return this._image;
    }

    public static class JavaBlurProcess {

        private static final short[] stackblur_mul = {
                512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
                454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
                482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
                437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
                497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
                320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
                446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
                329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
                505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
                399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
                324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
                268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
                451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
                385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
                332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
                289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
        };

        private static final byte[] stackblur_shr = {
                9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
                17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
                19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
                20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
                21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
                21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
                22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
                22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
                23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
                23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
                23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
                23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
                24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
                24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
                24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
                24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
        };

        private static void blurIteration(int[] src, int w, int h, int radius, int cores, int core, int step) {
            int x, y, xp, yp, i;
            int sp;
            int stack_start;
            int stack_i;

            int src_i;
            int dst_i;

            long sum_r, sum_g, sum_b,
                    sum_in_r, sum_in_g, sum_in_b,
                    sum_out_r, sum_out_g, sum_out_b;

            int wm = w - 1;
            int hm = h - 1;
            int div = (radius * 2) + 1;
            int mul_sum = stackblur_mul[radius];
            byte shr_sum = stackblur_shr[radius];
            int[] stack = new int[div];

            if (step == 1) {
                int minY = core * h / cores;
                int maxY = (core + 1) * h / cores;

                for (y = minY; y < maxY; y++) {
                    sum_r = sum_g = sum_b =
                            sum_in_r = sum_in_g = sum_in_b =
                                    sum_out_r = sum_out_g = sum_out_b = 0;

                    src_i = w * y; // start of line (0,y)

                    for (i = 0; i <= radius; i++) {
                        stack_i = i;
                        stack[stack_i] = src[src_i];
                        sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1);
                        sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1);
                        sum_b += (src[src_i] & 0xff) * (i + 1);
                        sum_out_r += ((src[src_i] >>> 16) & 0xff);
                        sum_out_g += ((src[src_i] >>> 8) & 0xff);
                        sum_out_b += (src[src_i] & 0xff);
                    }

                    for (i = 1; i <= radius; i++) {
                        if (i <= wm) src_i += 1;
                        stack_i = i + radius;
                        stack[stack_i] = src[src_i];
                        sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i);
                        sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i);
                        sum_b += (src[src_i] & 0xff) * (radius + 1 - i);
                        sum_in_r += ((src[src_i] >>> 16) & 0xff);
                        sum_in_g += ((src[src_i] >>> 8) & 0xff);
                        sum_in_b += (src[src_i] & 0xff);
                    }

                    sp = radius;
                    xp = radius;
                    if (xp > wm) xp = wm;
                    src_i = xp + y * w; //   img.pix_ptr(xp, y);
                    dst_i = y * w; // img.pix_ptr(0, y);
                    for (x = 0; x < w; x++) {
                        src[dst_i] = (int)
                                ((src[dst_i] & 0xff000000) |
                                        ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16) |
                                        ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8) |
                                        ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
                        dst_i += 1;

                        sum_r -= sum_out_r;
                        sum_g -= sum_out_g;
                        sum_b -= sum_out_b;

                        stack_start = sp + div - radius;
                        if (stack_start >= div) stack_start -= div;
                        stack_i = stack_start;

                        sum_out_r -= ((stack[stack_i] >>> 16) & 0xff);
                        sum_out_g -= ((stack[stack_i] >>> 8) & 0xff);
                        sum_out_b -= (stack[stack_i] & 0xff);

                        if (xp < wm) {
                            src_i += 1;
                            ++xp;
                        }

                        stack[stack_i] = src[src_i];

                        sum_in_r += ((src[src_i] >>> 16) & 0xff);
                        sum_in_g += ((src[src_i] >>> 8) & 0xff);
                        sum_in_b += (src[src_i] & 0xff);
                        sum_r += sum_in_r;
                        sum_g += sum_in_g;
                        sum_b += sum_in_b;

                        ++sp;
                        if (sp >= div) sp = 0;
                        stack_i = sp;

                        sum_out_r += ((stack[stack_i] >>> 16) & 0xff);
                        sum_out_g += ((stack[stack_i] >>> 8) & 0xff);
                        sum_out_b += (stack[stack_i] & 0xff);
                        sum_in_r -= ((stack[stack_i] >>> 16) & 0xff);
                        sum_in_g -= ((stack[stack_i] >>> 8) & 0xff);
                        sum_in_b -= (stack[stack_i] & 0xff);
                    }

                }
            }

            // step 2
            else if (step == 2) {
                int minX = core * w / cores;
                int maxX = (core + 1) * w / cores;

                for (x = minX; x < maxX; x++) {
                    sum_r = sum_g = sum_b =
                            sum_in_r = sum_in_g = sum_in_b =
                                    sum_out_r = sum_out_g = sum_out_b = 0;

                    src_i = x; // x,0
                    for (i = 0; i <= radius; i++) {
                        stack_i = i;
                        stack[stack_i] = src[src_i];
                        sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1);
                        sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1);
                        sum_b += (src[src_i] & 0xff) * (i + 1);
                        sum_out_r += ((src[src_i] >>> 16) & 0xff);
                        sum_out_g += ((src[src_i] >>> 8) & 0xff);
                        sum_out_b += (src[src_i] & 0xff);
                    }
                    for (i = 1; i <= radius; i++) {
                        if (i <= hm) src_i += w; // +stride

                        stack_i = i + radius;
                        stack[stack_i] = src[src_i];
                        sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i);
                        sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i);
                        sum_b += (src[src_i] & 0xff) * (radius + 1 - i);
                        sum_in_r += ((src[src_i] >>> 16) & 0xff);
                        sum_in_g += ((src[src_i] >>> 8) & 0xff);
                        sum_in_b += (src[src_i] & 0xff);
                    }

                    sp = radius;
                    yp = radius;
                    if (yp > hm) yp = hm;
                    src_i = x + yp * w; // img.pix_ptr(x, yp);
                    dst_i = x;               // img.pix_ptr(x, 0);
                    for (y = 0; y < h; y++) {
                        src[dst_i] = (int)
                                ((src[dst_i] & 0xff000000) |
                                        ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16) |
                                        ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8) |
                                        ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
                        dst_i += w;

                        sum_r -= sum_out_r;
                        sum_g -= sum_out_g;
                        sum_b -= sum_out_b;

                        stack_start = sp + div - radius;
                        if (stack_start >= div) stack_start -= div;
                        stack_i = stack_start;

                        sum_out_r -= ((stack[stack_i] >>> 16) & 0xff);
                        sum_out_g -= ((stack[stack_i] >>> 8) & 0xff);
                        sum_out_b -= (stack[stack_i] & 0xff);

                        if (yp < hm) {
                            src_i += w; // stride
                            ++yp;
                        }

                        stack[stack_i] = src[src_i];

                        sum_in_r += ((src[src_i] >>> 16) & 0xff);
                        sum_in_g += ((src[src_i] >>> 8) & 0xff);
                        sum_in_b += (src[src_i] & 0xff);
                        sum_r += sum_in_r;
                        sum_g += sum_in_g;
                        sum_b += sum_in_b;

                        ++sp;
                        if (sp >= div) sp = 0;
                        stack_i = sp;

                        sum_out_r += ((stack[stack_i] >>> 16) & 0xff);
                        sum_out_g += ((stack[stack_i] >>> 8) & 0xff);
                        sum_out_b += (stack[stack_i] & 0xff);
                        sum_in_r -= ((stack[stack_i] >>> 16) & 0xff);
                        sum_in_g -= ((stack[stack_i] >>> 8) & 0xff);
                        sum_in_b -= (stack[stack_i] & 0xff);
                    }
                }
            }

        }

        /**
         * Process the given image, blurring by the supplied radius.
         * If radius is 0, this will return original
         *
         * @param original the bitmap to be blurred
         * @param radius   the radius in pixels to blur the image
         * @return the blurred version of the image.
         */
        public Bitmap blur(Bitmap original, float radius) {
            int w = original.getWidth();
            int h = original.getHeight();
            int[] currentPixels = new int[w * h];
            original.getPixels(currentPixels, 0, w, 0, 0, w, h);
            int cores = StackBlurManager.EXECUTOR_THREADS;

            ArrayList<BlurTask> horizontal = new ArrayList<BlurTask>(cores);
            ArrayList<BlurTask> vertical = new ArrayList<BlurTask>(cores);
            for (int i = 0; i < cores; i++) {
                horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1));
                vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2));
            }

            try {
                StackBlurManager.EXECUTOR.invokeAll(horizontal);
            } catch (InterruptedException e) {
                return null;
            }

            try {
                StackBlurManager.EXECUTOR.invokeAll(vertical);
            } catch (InterruptedException e) {
                return null;
            }

            return Bitmap.createBitmap(currentPixels, w, h, Bitmap.Config.ARGB_8888);
        }

        private static class BlurTask implements Callable<Void> {
            private final int[] _src;
            private final int _w;
            private final int _h;
            private final int _radius;
            private final int _totalCores;
            private final int _coreIndex;
            private final int _round;

            public BlurTask(int[] src, int w, int h, int radius, int totalCores, int coreIndex, int round) {
                _src = src;
                _w = w;
                _h = h;
                _radius = radius;
                _totalCores = totalCores;
                _coreIndex = coreIndex;
                _round = round;
            }

            @Override
            public Void call() throws Exception {
                blurIteration(_src, _w, _h, _radius, _totalCores, _coreIndex, _round);
                return null;
            }

        }
    }

}

2.布局文件activity_blur.xml

<ScrollView
    android:layout_height="match_parent"
    android:layout_width="match_parent"
   xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:src="@drawable/coc"
        android:scaleType="centerInside"
        android:layout_margin="15dp"/>

    <ImageView android:id="@+id/blur_image"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerInside"
        android:layout_margin="15dp"/>

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="更改毛玻璃效果"/>

</LinearLayout>
</ScrollView>

3.java代码

public class BlurActivity extends AppCompatActivity {

    private ImageView blurImage;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_blur);
        blurImage = (ImageView) findViewById(R.id.blur_image);
        button = (Button) findViewById(R.id.button);

        BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.coc);
        final StackBlurManager stackBlurManager = new StackBlurManager(bitmapDrawable.getBitmap());
        blurImage.setImageBitmap(stackBlurManager.process(100));

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                blurImage.setImageBitmap(stackBlurManager.process(new Random().nextInt(100)+1));//粗糙代码
            }
        });

    }

}

4.注意事项

<1>图片不能过大,否则会抛出异常;

<2>process(int)至少为1;

时间: 2024-08-07 08:36:37

Android 毛玻璃效果的相关文章

Android 毛玻璃效果的实现

Android 毛玻璃效果,主要找到了3中实现方案, 1.如果系统的api在16以上,可以使用系统提供的方法直接处理图片 if (Build.VERSION.SDK_INT > 16) { <span style="white-space:pre"> </span>Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); <span style="white-space:p

Android毛玻璃效果侧滑菜单

实现目标 相信大家都知道毛玻璃效果是怎样的,也可以说是高斯模糊效果.效果图如下: 这是一个透明,且会对背景进行高斯模糊的效果,看起来就像是毛玻璃一样,其实不光是侧滑菜单,只要是view,理论上都可以实现这样的效果,接下来我们就来实现这个效果. 第一步:框架搭建 我使用的android studio,所以要创建这样一个带侧滑菜单的项目非常简单,在新建项目的步骤中,执行到这一步,选择Navigation Drawer Activity就可以了: android studio会自动创建带有这种侧滑覆盖

移动端UI设计越来越流行的高斯模糊(Gaussian blur)和毛玻璃效果(磨砂效果),如何使用Android RenderScript简单实现?

高斯模糊(Gaussian blur)和毛玻璃效果(亦称磨砂效果),近两年在移动端的UI设计上越来越流行,特别是iOS手机上出现的较多,iOS系统也提供了相应的API帮助开发人员分分钟实现这两个效果.而Android系统则经历了一个漫长的探索过程,对图片的处理,从Java算法到NDK方式实现等,各种摸索层出不穷. 值得欣慰的是,Google终于在API 11中引入了 RenderScript ,一个强大的图片处理框架,帮助Android开发人员专注于图片处理算法而不是API的调度工作.使用Ren

Android高斯模糊技术,实现毛玻璃效果(转)

本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650235930&idx=1&sn=e328709c41ae208a9e41ef79d38cbeed&scene=24&srcid=09104fpQDG98JcRcUB9Ec7BN#wechat_redirect http://blog.csdn.net/grp0916/article/details/50494712 Android高

android 开发 - 对图片进行虚化(毛玻璃效果,模糊)

概述 IPAD,IPHONE上首页背景的模糊效果是不是很好看,那么在 Android中如何实现呢.我通过一种方式实现了这样的效果. 开源库名称:anroid-image-blur 一个android 下的对图片进行模糊的辅助类库 Github地址 https://github.com/vir56k/anroid-image-blur 名词解释: 虚化,模糊化,或者 毛玻璃效果 .即把一种图片变得模糊,变虚,类似在拍照时看到的虚. 在ios系统中,主系统的启动后的背景就是一个虚化的效果. 给人一种

Android Studio - 第四十七期 毛玻璃效果以及动态生成二维码以及增大点击热区

最近回看撸撸的代码,有一些自定义的view写法很不错,下面封装出来,希望能帮到大家: 1.毛玻璃效果:BitmapUtils package com.example.p030_popbgqcode.utils; import android.content.Context; import android.graphics.Bitmap; import android.renderscript.Allocation; import android.renderscript.Element; imp

毛玻璃效果简单实现

项目中需要运用到毛玻璃的效果.经过搜索查阅,踩了一些坑,找到了一条暂时可行的办法. 其中,核心的控件是使用RenderScript这个类,这个类属于jni类,在较低版本的Android系统中,是不具备它的相关方法的.所以我们只能使用support.v8里面的类.然而,support.v8并没有默认地放在新建工程中,因此我们需要自己去添加. 第一步:将D:\AndroidSdk\build-tools\23.0.1\renderscript\lib\packaged 目录下的armeabi-v7a

MIUI 6的毛玻璃效果的技术实现(实时模糊)

说说MIUI 6的毛玻璃效果的技术实现. 很久以前我们的文件夹打开和最近任务等几个地方就使用了毛玻璃效果,在技术上讲就是背景模糊.应该是比iOS 7的使用要早很多.不过那时候我们使用的是先对背景截图,再将其模糊处理,然后作为app的背景图,所以是一张静止的图片,当背景内容发生变化时模糊的图片并不会随之变化,因此比较生硬.而iOS 7的背景模糊则是实时的,当背景变化的时候,模糊内容也会实时的变化.这就把我们给比下去了.于是我们也不能闲着,既然做了,那就做好.然后我就开始做实时的背景模糊. 如果沿用

Android毛玻璃处理代码(Blur)

以下为将bitmap图像处理为毛玻璃效果的图像的工具类: public class FastBlurUtil { public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) { // Stack Blur v1.0 from // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html // // Java Auth