在Android中。我们能够实现非常多非常酷的处理图片的效果。

在2014年某次会议的讲演《图像的魔力》中,我介绍了当中的一部分。

当中的一项技术是怎样模糊图像。演示样例代码是使用RenderScript实现的,由于在Android中没有内置的可使用的简单的API。在这个系列中,我们将着眼于RenderScript模糊技术和JAVA实现模糊功能。我们还将进行一些基准測试。以了解每种方案的运行情况,并探讨获取最佳性能的可行方法。

让我们先从实现一个简单的能够运行的样例開始,使用RenderScript!对于没有使用过RenderScript的开发人员来说,这是一个让人心生恐惧的设想,由于RenderScript真的是非常难,是不是?是的,的确是。只是它也有一些事情真的非常easy,而模糊图像就是当中之中的一个。
对于不熟悉RenderScript的人来说,他是在API11中引入的,而且有一个compat库,提供RenderScript给API8及以后的版本号。它本质上是一个面向图形的本地计算框架。RenderScript引擎在运行期会选择最合适的处理器(CPU或者GPU核心。多核处理器间能够分解原子操作)来运行请求的操作。

本地语法基于C99。与OpenCL, CUDA, and GLSL的API类似。

假设这听起来非常可怕,请稍等一下。由于我们正要简化整个过程。由于它是一个框架。同意我们创建自己定义的内核来实现过滤与处理,它内置了不少能够使用的内核。当中的一个同意我们模糊图像。
后面的实例代码基于API17及更高版本号开发,我已经决定不使用compat库,由于在本文写作的时候,Android Studio还不支持。

此外,我们使用的模糊核心在API17后才引入,所以有最小SDK版本号为17的需求。

让我们深入到一个简单的样例,这里有一个非常easy的RelativeLayout。包括了一个ImageView,上层还有个TextView:
  1. <?xml version="1.0" encoding="utf-8"?

    >

  2. <RelativeLayout
  3.     xmlns:android="http://schemas.android.com/apk/res/android"
  4.     android:layout_width="fill_parent"
  5.     android:layout_height="fill_parent"
  6.     android:gravity="center"
  7.     android:orientation="vertical" >
  8.      
  9.     <ImageView
  10.         android:id="@+id/image"
  11.         android:src="@drawable/broadstairs"
  12.         android:layout_width="match_parent"
  13.         android:layout_height="match_parent"
  14.         android:scaleType="matrix"
  15.         android:layout_centerInParent="true"/>
  16.     <TextView
  17.         android:id="@+id/text"
  18.         android:layout_width="wrap_content"
  19.         android:layout_height="wrap_content"
  20.         android:text="@string/hello"
  21.         android:layout_centerHorizontal="true"
  22.         android:textColor="<a href="http://www.jobbole.com/members/android/" rel="nofollow">@android</a>:color/white"
  23.         android:layout_marginTop="300dp"
  24.         android:textStyle="bold"
  25.         android:textSize="48sp"/>
  26. </RelativeLayout>

复制代码

我们想要做的效果是模糊ImageView内位于TextView显示区域的图像,有效的模糊ImageView后的区域。我们终于使用的技术是拿到位于TextView区域的图像副本进行模糊。然后再将模糊后的副本设定为TextView的背景。

我刻意的设计了这样的布局,使图像显示实际大小,并从显示屏的左上方開始。

这样让随后的位置计算简单些,而且这里讨论的是模糊技术而不是图像定位的数学算法。尝试设定ImageView的属性android:scaleType=”center”,就会发现定位出现错乱。

此处有一个方法。它有3个參数,一个位图(已在ImageView里获得),一个视图(这是我们的TextView,可是该技术适用于随意的视图类型,所以我们将在方法中进行支持),以及一个半径用来控制模糊的程度。
  1. private void blur(Bitmap bkg, View view, float radius) {
  2.     Bitmap overlay = Bitmap.createBitmap(
  3.         view.getMeasuredWidth(),
  4.         view.getMeasuredHeight(),
  5.         Bitmap.Config.ARGB_8888);  
  6.     Canvas canvas = new Canvas(overlay);
  7.     canvas.drawBitmap(bkg, -view.getLeft(),
  8.         -view.getTop(), null);   
  9.     RenderScript rs = RenderScript.create(this);  
  10.     Allocation overlayAlloc = Allocation.createFromBitmap(
  11.         rs, overlay);  
  12.     ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
  13.         rs, overlayAlloc.getElement());   
  14.     blur.setInput(overlayAlloc);  
  15.     blur.setRadius(radius);  
  16.     blur.forEach(overlayAlloc);  
  17.     overlayAlloc.copyTo(overlay);  
  18.     view.setBackground(new BitmapDrawable(
  19.         getResources(), overlay));   
  20.     rs.destroy();  
  21. }

复制代码

我们要做的第一件事是创建一个新的位图对象。用来保存想要模糊的图像区域的副本。它的大小将会是我们视图的尺寸(2-5行)。
如今我们将空的位图包装到画布中,我们能够在上面画图(7行)。
接下来的步骤我称为”缓存剪切”,我们拷贝位图中的处于视图显示区域内的那部分图像(9-10行)。
接下来我们必须做的事情是构建一个RenderScript对象上下文。在当中我们运行模糊操作(12行)。
RenderScript是一个本地环境,它在自己的内存空间内运行,所以我们不能简单的传递位图引用,我们须要在JAVA和RenderScript内存区域进行序列化。

这使用了一个分配实例来完毕,这是在RenderScript内存区域中创建和引用对象的方式,为我们的位图创建一个分配会将位图的内容拷贝的分配区域中(14-15行)。

如今我们创建一个 ScriptIntrinsicBlur实例,它创建合适的RenderScript模糊脚本,而且是脚本对象的Java接口。它让我们能够控制它。(17-18行)。

脚本的输入定义了我们须要运行模糊的位图源(20行)。
如今我们设置半径来控制模糊强度(22行)。

forEach方法运行模糊操作,參数代表了结果的输出位置。我们将它写回源分配地址以降低创建的对象数量(24行)。
如今模糊完毕了。可是我们必须把模糊后的图像拷贝回JAVA内存区域(26行)。
最后将模糊后的位图包装到BitmapDrawable内,并设置为视图的背景(28-29行)。
我们已经使用完RenderScript上下文,清理掉。这样做也将自己主动删除我们的分配(31行)。
这就是我们完整的基本模糊逻辑,但眼下还不清楚什么地方和什么时候我们须要调用此方法。不幸的是关于这个问题不能简单的进行回答,所以我们将在接下来的文章中讨论。
平时我喜欢每篇文章都公布相关工作代码,可是在本例中,我们还没达到有一个可运行的完整的端到端的演示样例的程度。

我保证在接下来的文章中进行调整。

via:
原文链接: stylingandroid 
 翻译: 伯乐在线-
fhdis
译文链接:
http://blog.jobbole.com/65353/

我们介绍了使用RenderScript使还有一个视图范围内的图片部分模糊。

可是实际上。我们并没有深入地调用这种方法来研究图像模糊行为。

原因是我们须要在性能方面进行细致考虑。这篇文章我们会进行更进一步地的探索。

调用这种方法最直白的方法是父布局的onDraw()。有经验的开发人员读到这里可能会開始摇头,我们应该保持onDraw方法的实现尽可能有效。曾经的文章中的代码包括创建对象、位图操作和切换到renderScript上下文。

当中,OnDraw会降低帧速率。你能够不相信我的做法,可是能够通过測量并证明它是有效的。

在后面的系列中,我们就会这样做。

假设布局是静态的(即我们的布局不包括不论什么动画),在布局时就不会改变待模糊的位置和范围。仅仅有在布局改变时运行该操作才有意义,但前提是布局的全部视图大小和位置依据布局变化測量和计算过。这里有一个非常实用的技巧。能够注冊一个OnGlobalLayoutListener监听函数。当布局发生改变的时候会调用onGlobalLayout()方法。

当我们收到布局已经改变的通知时,注冊的OnPreDrawListener监听函数的onPreDraw()方法会被调用每当运行onDraw方法。

我们要做的第一件事情就是取消注冊onPreDraw()方法。这样仅仅有在布局改变的时候才会被调用,而不是每次onDraw方法触发时都调用。

以下能够运行模糊方法。从这种方法的返回值非常重要,使用它能够让我们放弃onDraw操作。反复之前的布局。这对在回调函数中改动布局非常有帮助,可是这里不须要这么做。所以返回true,继续绘制。

我们的Activity代码例如以下:
  1. public class MainActivity extends Activity {
  2.     private ImageView mImage;
  3.     private TextView mText;
  4.   
  5.     private OnPreDrawListener mPreDrawListener =
  6.         new OnPreDrawListener() {
  7.   
  8.         @Override
  9.         public boolean onPreDraw() {
  10.             ViewTreeObserver observer =  mText.getViewTreeObserver();
  11.             if(observer != null) {
  12.                 observer.removeOnPreDrawListener(this);
  13.             }
  14.             Drawable drawable = mImage.getDrawable();
  15.             if (drawable != null &&
  16.                 drawable instanceof BitmapDrawable) {
  17.                 Bitmap bitmap =
  18.                     ((BitmapDrawable) drawable).getBitmap();
  19.                 if (bitmap != null) {
  20.                     blur(bitmap, mText, 25);
  21.                 }
  22.             }
  23.             return true;
  24.         }
  25.     };
  26.   
  27.     private OnGlobalLayoutListener mLayoutListener =
  28.         new OnGlobalLayoutListener() {
  29.   
  30.         @Override
  31.         public void onGlobalLayout() {
  32.             ViewTreeObserver observer =   mText.getViewTreeObserver();
  33.             if(observer != null) {
  34.                 observer.addOnPreDrawListener(
  35.                     mPreDrawListener);
  36.             }
  37.         }
  38.     };
  39.   
  40.     /**
  41.      * Called when the activity is first created.
  42.      */
  43.     @Override
  44.     public void onCreate(Bundle savedInstanceState) {
  45.         super.onCreate(savedInstanceState);
  46.         setContentView(R.layout.main);
  47.         mImage = (ImageView) findViewById(R.id.image);
  48.         mText = (TextView)findViewById(R.id.text);
  49.         if (mImage != null && mText != null) {
  50.             ViewTreeObserver observer =
  51.                 mText.getViewTreeObserver();
  52.             if (observer != null) {
  53.                 observer.addOnGlobalLayoutListener(
  54.                         mLayoutListener);
  55.             }
  56.         }
  57.     }
  58.   
  59.     private void blur(Bitmap bkg, View view, float radius) {
  60.     ....
  61.     }
  62. }

复制代码

在父布局覆盖onDraw方法的长处是。能够在布局层次上随意附加OnPreDrawListener方法。因此须要自己定义一个布局。这个布局是标准布局的子类。这样就能够覆盖onDraw方法。使用predrawlistener意味着能够非常easy在随意布局中加入。

最后,模糊图片实现例如以下:
在下一篇文章中,我会更深入地回答为什么要避免在onDraw中运行模糊操作,而且还会介绍实用的性能測量工具。

这篇文章的代码在

at=Part2" rel="nofollow">这里

via:
原文链接:
stylingandroid   翻译:
伯乐在线-
fhdis

Android模糊图像的更多相关文章

  1. Android图像处理 - 高斯模糊的原理及实现

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 由 天天P图攻城狮 发布在云+社区 作者简介:damonxia(夏正冬),天天P图Android工程师 前言 高斯模糊是图像处理中几乎每个程序员 ...

  2. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  3. 配置android sdk 环境

    1:下载adnroid sdk安装包 官方下载地址无法打开,没有vpn,使用下面这个地址下载,地址:http://www.android-studio.org/

  4. Android SwipeRefreshLayout 下拉刷新——Hi_博客 Android App 开发笔记

    以前写下拉刷新 感觉好费劲,要判断ListView是否滚到顶部,还要加载头布局,还要控制 头布局的状态,等等一大堆.感觉麻烦死了.今天学习了SwipeRefreshLayout 的用法,来分享一下,有 ...

  5. Android Studio配置 AndroidAnnotations——Hi_博客 Android App 开发笔记

    以前用Eclicps 用习惯了现在 想学学 用Android Studio 两天的钻研终于 在我电脑上装了一个Android Studio 并完成了AndroidAnnotations 的配置. An ...

  6. Android请求网络共通类——Hi_博客 Android App 开发笔记

    今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...

  7. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  8. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  9. Android Studio 多个编译环境配置 多渠道打包 APK输出配置

    看完这篇你学到什么: 熟悉gradle的构建配置 熟悉代码构建环境的目录结构,你知道的不仅仅是只有src/main 开发.生成环境等等环境可以任意切换打包 多渠道打包 APK输出文件配置 需求 一般我 ...

随机推荐

  1. oracle的批量插入sql

    insert into persons (id_p, lastname , firstName, city ) values (200,'haha' , 'deng' , 'shenzhen'), ( ...

  2. 15.并发容器之ConcurrentLinkedQueue

    1.ConcurrentLinkedQueue简介 在单线程编程中我们会经常用到一些集合类,比如ArrayList,HashMap等,但是这些类都不是线程安全的类.在面试中也经常会有一些考点,比如Ar ...

  3. 威佐夫博弈——hdu1527

    有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利. 直接说结论了,若两堆物品的初始值为(x,y),且x<y,则另z=y-x: 记w= ...

  4. linux-Centos7安装mysql5.7.19

    1.下载mysql 网址: https://dev.mysql.com/downloads/mysql/ 2.选择源码包,通用版点击下载 直接下载就可以了,不用登录 3.解压编译 先安装相关依赖包 y ...

  5. NPOI:操作总结

    1.套路 使用了NPOI一段时间,也慢慢了解了操作的流程,或者说套路: a.创建Workbook: HSSFWorkbook Workbook = new HSSFWorkbook(); b.在Wor ...

  6. 添加git 忽略文件

    在使用Git的过程中,我们喜欢有的文件比如日志,临时文件,编译的中间文件等不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这些文件的提交. Git 忽略文件提交的方法 有三种方法可以实现忽略Gi ...

  7. python命名空间的本质

    Python的命名空间是Python程序猿必须了解的内容,对Python命名空间的学习,将使我们在本质上掌握一些Python中的琐碎的规则. 接下来我将分四部分揭示Python命名空间的本质:一.命名 ...

  8. codis3.2安装配置中的一些问题

    1.参考文档与参考资料问题 安装codis集群之前,我先在网上找资料,然后又到github的项目官方地址找,不得不说,相关的资料不好找,而且找到之后有些东西说的也不是很清楚.由于codis版本迭代的问 ...

  9. L165

    New evidence of how the Norse became long-distance marinersAccording to the saga of Erik the Red, “s ...

  10. avr 烧录失败

    用Atmel studio 6.0 配置mkII烧录器 使用上位机bat程序烧录 提示错误:firmware is old... 1参考(关于FUSe setting) http://www.cnbl ...