Android快速实现动态模糊效果

写在前面

现在,越来越多的App里面使用了模糊效果,这种模糊效果称之为高斯模糊。大家都知道,在Android平台上进行模糊渲染是一个相当耗CPU也相当耗时的操作,一旦处理不好,卡顿是在所难免的。一般来说,考虑到效率,渲染一张图片最好的方法是使用OpenGL,其次是使用C++/C,使用Java代码是效率是最低,速度也是最慢的。但是Android推出RenderScript之后,我们就有了选择,测试表明,使用RederScript的渲染效率和使用C++/C不相上下,但是使用RenderScript却比使用JNI简单得多!同时,Android团队提供了RenderScript的支持库,使得在低版本的Android平台上也能使用。

不过在使用RenderScript之前,对于模糊一张图片,需要注意的是,我们应该尽量不要使用原尺寸分辨率的图片,最好将图片缩小比例,这小渲染的效率要高一些,速度也更快一些。

什么是RenderScript

RenderScript是一种低级的高性能编程语言,用于3D渲染和处理密集型计算(3D播放等和关于CPU密集型的计算)。一直以来Android 在绘图性能的表现一直差强人意,引入NDK之后才有所改善,而在Honeycomb 中发布了RenderScript 这一杀手级在Framework 后,大大的增加了Android本地语言的执行能力和计算能力。现在网上介绍RenderScript的文章非常少,附上一篇博客,大家可以能更好理解这门语言。

关于Android RenderScript 的详细说明和一些实用文档

如果需要详细了解,可以查看官方文档RenderScript

动态模糊的实现

使用之前,先要在Module build.gradle里面作下面的定义:

MainActivity.java

package com.jackie.blurimage;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private ImageView mBlurImage, mOriginImage;
    private SeekBar mSeekBar;
    private TextView mSeekProgress;

    private int mAlpha;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initData();
        initEvent();
    }

    private void initView() {
        mBlurImage = (ImageView) findViewById(R.id.blur_image);
        mOriginImage = (ImageView) findViewById(R.id.origin_image);
        mSeekBar = (SeekBar) findViewById(R.id.seek_bar);
        mSeekProgress = (TextView) findViewById(R.id.seek_progress);
    }

    private void initData() {
        // 获取图片
        Bitmap originBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blur);
        Bitmap blurBitmap = BlurUtils.blur(this, originBitmap);

        // 填充模糊后的图像和原图
        mBlurImage.setImageBitmap(blurBitmap);
        mOriginImage.setImageBitmap(originBitmap);
    }

    private void initEvent() {
        mSeekBar.setMax(100);

        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                mAlpha = progress;

                mOriginImage.setAlpha((int) (255 - mAlpha * 2.55));
                mSeekProgress.setText(String.valueOf(mAlpha));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_weight="1"
        android:layout_height="0dp">

        <ImageView
            android:id="@+id/blur_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/blur"/>

        <ImageView
            android:id="@+id/origin_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"/>
    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="vertical">

        <SeekBar
            android:id="@+id/seek_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginTop="@dimen/activity_vertical_margin"/>

        <TextView
            android:id="@+id/seek_progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="0"
            android:textSize="24sp"/>
    </LinearLayout>
</LinearLayout>

从上面的代码可以看出,在FrameLayout上放了两张图片,然后动态更改图片的透明度来达到动态模糊效果。
BlurUtils.java

package com.jackie.blurimage;

import android.content.Context;
import android.graphics.Bitmap;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;

/**
 * Created by Jackie on 2017/1/21.
 * 高斯模糊工具类
 */

public class BlurUtils {
    /**
     * 图片缩放比例
     */
    private static final float SCALE_DEGREE = 0.4f;
    /**
     * 最大模糊度(在0.0到25.0之间)
     */
    private static final float BLUR_RADIUS = 25f;

    /**
     * 模糊图片
     * @param context   上下文
     * @param bitmap    需要模糊的图片
     * @return          模糊处理后的图片
     */
    public static Bitmap blur(Context context,Bitmap bitmap) {
        //计算图片缩小的长宽
        int width = Math.round(bitmap.getWidth() * SCALE_DEGREE);
        int height = Math.round(bitmap.getHeight() * SCALE_DEGREE);

        //将缩小后的图片作为预渲染的图片
        Bitmap inputBitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);
        //创建一张渲染后的输入图片
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);

        //创建RenderScript内核对象
        RenderScript renderScript = RenderScript.create(context);
        //创建一个模糊效果的RenderScript的工具对象
        ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));

        /**
         * 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间。
         * 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去。
         */
        Allocation inputAllocation = Allocation.createFromBitmap(renderScript, inputBitmap);
        Allocation outputAllocation = Allocation.createFromBitmap(renderScript, outputBitmap);

        //设置渲染的模糊程度,25f是最大模糊度
        scriptIntrinsicBlur.setRadius(BLUR_RADIUS);
        //设置ScriptIntrinsicBlur对象的输入内存
        scriptIntrinsicBlur.setInput(inputAllocation);
        //将ScriptIntrinsicBlur输出数据保存到输出内存中
        scriptIntrinsicBlur.forEach(outputAllocation);

        //将数据填充到Allocation中
        outputAllocation.copyTo(outputBitmap);

        return outputBitmap;
    }
}

效果图如下,妹纸一枚!

时间: 2024-10-06 15:10:05

Android快速实现动态模糊效果的相关文章

android快速开发框架

一.依赖注入DI通过依赖注入减少View.服务.资源简化初始化,事件绑定等重复繁琐工作1. AndroidAnnotations(Code Diet) android快速开发框架项目地址:https://github.com/excilys/androidannotations文档介绍:https://github.com/excilys/androidannotations/wiki官方网站:http://androidannotations.org/特点:(1)依赖注入:包括view,ext

Android 快速开发框架CommonLibsForAndroid(有Demo)

这个项目所包含的功能,全部是从实际项目中提取,开发这个类库的初衷也只是为了方便自己开发Android项目.由于时间所限,目前大量的内容还没整理到这个开源项目中,doc和demo也有所欠缺,我将尽快完善.而其中大量不合理的内容,也将逐步改进. 欢迎大家提各种意见,当然更欢迎fork和pull request. https://github.com/cymcsg/CommonLibsForAndroid CommonLibsForAndroid Using CommonLibs is a fast

Android基础篇之Android快速入门--你必须要知道的基础

Android快速入门 1. 搭建开发环境 >解压压缩文件,得到:①Android SDK   (类似于JDK)② Eclipse  ③ADT >配置两个path环境变量:D:\adt-bundle-windows-x86\sdk\platform-tools:D:\adt-bundle-windows-x86\sdk\tools >配置基本的Eclipse的设置: 调整字体大小,字符集,配置android sdk的位置 >创建模拟器: 2. 创建第一个Android项目: Hel

Android快速开发之appBase——(6).HttpReq和APICloudSDK

Android快速开发之appBase--(6).HttpReq和APICloudSDK HttpReq和APICloudSDK都是网络请求组件,都是基于xUtils的HttpUtils重新封装的.接下来讲一下使用方法. 1.HttpReq 看以看到有这么几个方法 GET:GET方式请求 POST:普通的POST表单提交 POST:将数据以流的形式传递 /** * POST请求,用InputStream的方式传递请求参数 * * @param api * 接口地址 * @param reques

Android快速调试方法

Android快速调试方法 前言:目前市面上OTT网络机顶盒几乎全部使用Android系统,公司目前是多个人使用一个编译服务器,编译一次Android系统花费时间较长,调试Android某一部分功能时候就不得不编译整个Android系统来调试,严重降低了工作开发效率,巧合之下看到公司大牛写的Android调试方法,放与网络与大家参考学习. 公司网络机顶盒(OTT)盒子使用Amlogic提供的芯片,下面就以amlogic Android系统为例. 1 Uboot快速调试方法 1.1 编译 #! /

Android 快速开发系列 打造万能的ListView GridView 适配器

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38902805 ,本文出自[张鸿洋的博客] 1.概述 相信做Android开发的写得最多的就是ListView,GridView的适配器吧,记得以前开发一同事开发项目,一个项目下来基本就一直在写ListView的Adapter都快吐了~~~对于Adapter一般都继承BaseAdapter复写几个方法,getView里面使用ViewHolder模式,其实大部分的代码基本都是类似的

看大师讲解Android快速开发框架EasyAndroid

前几天做了小应用,感觉小有成就,名字叫"长见识了",是一款趣味答题类的游戏,题目各种火爆各种经典,下载地址,看似一个简单的答题小游戏却是五脏俱全,从开发流程上都进行了严格的规范,大家有空可以下载玩玩~ 在这个应用中,用到了我以前集成的一个快速开发框架-EasyAndroid,这个框架我以前在做项目的时候总结,整理出来的,对于快速开发Android应用非常实用. 其实,Android应用的开发并不难,我们拿到一款Android应用后,百分之九十以上无外乎有这么几个功能: 1,IOC Mo

android快速上手(三)常用控件使用

完成了android的第一个程序HelloWorld,下面就开始控件的学习,下面是一些常见的控件. (一)TextView 简单的文本描述 (二)EditText 编辑框,输入文字信息 (三)Button 按钮,点击后会触发点击事件,可以对事件进行处理 (四)ImageView 图片控件,可以加载图片显示 (五)ListView 列表,需要跟适配器Adapter结合,适配器提供数据 (六)Toast 闪现提示语,常用于普通的提示文本,只显示一小段时间自动消失 (七)ScrollView 一般用于

Android 6.0 - 动态权限管理的解决方案(转)

转自:http://www.cnblogs.com/dubo-/p/6018262.html Android 6.0 - 动态权限管理的解决方案 转载请标注 Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样, 一方面让用户更加容易的控制自己的隐私, 一方面需要重新适配应用权限. 时代总是不断发展, 程序总是以人为本, 让我们为应用添加动态权限管理吧! 这里提供了一个非常不错的解决方案, 提供源码, 项目可以直