通过渲染器Shader实现图像变换效果
在上一篇文章中,一起学习了通过设定画笔风格来实现图形变换,没读过的朋友可以点击下面链接:
http://www.cnblogs.com/fuly550871915/p/4886455.html
是不是觉得自己学到的知识更多了呢?那么再多学一点总没坏处。在本篇文章中,将会一起学习通过给画笔设定Shader属性,实现图形变换。并带领读者一起实现两个实际例子,图片渲染器和线性渲染器。有没有发现我们的画笔特别强大呢??确实,我们曾经给它设置过颜色矩阵属性,设置过xfermode风格属性,现在又来设定Shader属性。好了,废话不多说了,进入本章的主要内容吧。
一、基础知识
渲染效果大家都应该见到过,比如下面的这张图片。
上面是一张中规中矩的线性渲染的图片,从蓝色渲染到红色。但是在android中,有一个很奇葩的渲染方法,叫图片渲染。什么是图片渲染呢??没法说清楚,到下面的实战项目中大家看到效果就明白了。其他的渲染,比如线性渐变,矩形渐变等都是大家熟知的了。
对于给画笔设定图片渲染,首先要实例化一个图片渲染对象,然后再设定给画笔。示例代码如下:
//初始化图片渲染器
mBitmapShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
//将画笔绑定图片渲染器
paint.setShader(mBitmapShader);
其中bmp是一个Bitmap图片,而渲染的模式有Shader.TileMode.REPEAT,Shader.TileMode.CLAMP,Shader.TileMode.MIRROR。分别是重复模式,拉伸边缘像素模式,镜像模式。这几种模式你现在无法理解,到实战项目中,我们会演示效果,到时候你就明白了。上面的代码是x方向和y方向都设定为重复渲染模式。
对于给画笔设定普通的渲染器,比如说线性渲染,一句代码搞定,如下:
//方法new LinearGradient(x0, y0, x1, y1, color0, color1, tile)
//设置线性渲染器,(x0,y0)是起点坐标,(x1,y1)是终点坐标
//从color0渲染到color1,当然这里的color也可以改为透明度
//最后的tile表示选择一种渲染模式
paint.setShader(new LinearGradient(0, 0, 300, 300, Color.BLUE, Color.RED, Shader.TileMode.CLAMP));
注释中说的很清楚了,至于渲染模式,上面也有解释。
好了,然我们快进入实战,看看这些方法到底是怎么用的吧。
二、图片渲染实战
这里我们需要一张图片资源,读者可以替换为自己的图片,建议图片选的小一点尽量。这样效果看起来方便一些。在上一篇文章的代码基础上我们接着往下写。首先新建MyShaderView继承自view。代码中的注释很详细,在代码中用画笔绑定了图片渲染器然后画了一个圆出来。如下:
package com.fuly.image; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
/**
* 利用渲染器shader变换图像
* @author fuly1314
*
*/
public class MyShaderView extends View{ private Bitmap bmp;
private Paint paint = new Paint();
private BitmapShader mBitmapShader;//图片渲染器 public MyShaderView(Context context) {
super(context);
}
public MyShaderView(Context context, AttributeSet attrs) {
super(context, attrs); }
public MyShaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} protected void onDraw(Canvas canvas) { super.onDraw(canvas); bmp = BitmapFactory.decodeResource(getResources(), R.drawable.hudie2);
//初始化图片渲染器
mBitmapShader = new BitmapShader(bmp, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
//将画笔绑定图片渲染器
paint.setShader(mBitmapShader); canvas.drawCircle(150, 150, 300, paint); } }
然后新建布局imageshader.xml把这个view装进去。如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"> <com.fuly.image.MyShaderView
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/> </LinearLayout>
接着新建活动ShaderActivity显示这个布局,此时别忘记给这个活动注册。如下:
package com.fuly.image; import android.app.Activity;
import android.os.Bundle; public class ShaderActivity extends Activity{ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.imageshader); } }
最后给MainActivity中的按钮添加监听事件,如下:
package com.fuly.image; import android.os.Bundle;
import android.view.View;
import android.app.Activity;
import android.content.Intent; public class MainActivity extends Activity { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} //下面是按钮事件
public void btnMatrix(View v){
Intent intent = new Intent(this,MatrixActivity.class);
startActivity(intent);
}
public void btnXFermode(View v){
Intent intent = new Intent(this,XFermodeActivity.class);
startActivity(intent);
}
public void btnShader(View v){
Intent intent = new Intent(this,ShaderActivity.class);
startActivity(intent);
} }
好了,快运行程序看看效果。如下:
注意在图片渲染中,我们使用了REPEAT模式。从效果来看其实就是用我们的这张小蝴蝶的图片来填充我们画的圆,如果发现图片太小,填充不完怎么办,那就不断重复画这个图片直到填充完为止。这下你明白什么是REPEAT模式了吧。下面我们将MyShaderView的第42行,即实例化图片渲染的代码改变一下,变成MIRROR模式,如下:
//初始化图片渲染器
mBitmapShader = new BitmapShader(bmp, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
只改这一个地方,然后重新运行程序,效果图如下:
有没有发现跟REPEAT模式有什么不同?也就是说在填充的时候,发现图片不够大,那就画它的镜像(即在镜子里的图像,也就是倒影)来填充,如此反复,直到填充完为止。这既是MIRROR模式的效果了。那么CLAMP模式又是什么样的呢?我们仍然修改第42行代码,如下:
//初始化图片渲染器
mBitmapShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
为了让显示效果更好一点,我们替换为另外一张图片,此时要修改相应的获取bmp的代码。这个即修改第40的代码即可。我就不贴出来了。然后运行程序,效果如下:
上图中,左侧是效果图,右侧就是我所使用的那张原图。可以看到,CLAMP模式的意思其实当发现原来图片不够填充的时候,就拉伸原图片边缘的像素直到填充满为止。
好了。经过那上面的三轮实验,相信你不经对着三种模式有所了解,而且对图片渲染也很熟悉了。那么下面就让我们来实现常规的渲染,比如线性渐变。
三、线性渐变实战
在这里简单起见,我就简单的单纯的只实现一个线性渐变的效果吧。目的是为让大家看看,普通的渲染是怎么绑定画笔的。目前来说,掌握这个就达到这篇文章的目的了。首先老规矩,新建LinearShaderView继承自view,在这里的代码中,将为画笔绑定一个线性渐变的渲染,并用它画出一个矩形。代码如下:
package com.fuly.image; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
/**
* 利用线性渲染器shader变换图像
* @author fuly1314
*
*/
public class LinearShaderView extends View{ private Paint paint = new Paint(); public LinearShaderView(Context context) {
super(context);
}
public LinearShaderView(Context context, AttributeSet attrs) {
super(context, attrs); }
public LinearShaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} protected void onDraw(Canvas canvas) { super.onDraw(canvas);
//方法new LinearGradient(x0, y0, x1, y1, color0, color1, tile)
//设置线性渲染器,(x0,y0)是起点坐标,(x1,y1)是终点坐标
//从color0渲染到color1,当然这里的color也可以改为透明度
//最后的tile表示选择一种渲染模式
paint.setShader(new LinearGradient(0, 0, 300, 300, Color.BLUE, Color.RED,
Shader.TileMode.CLAMP));
//初始化图片渲染器 canvas.drawRect(0, 0, 300, 300, paint); } }
新建布局imagelinearshader.xml,将这个布局加进去,代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"> <com.fuly.image.LinearShaderView android:layout_width="wrap_content"
android:layout_height="wrap_content"/> </LinearLayout>
然后该新建活动了LinearShaderActivity用来显示我们的布局,代码如下:
package com.fuly.image; import android.app.Activity;
import android.os.Bundle; public class LinearShaderActivity extends Activity{ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.imagelinearshader); } }
最后呢,就是MainActivity中的按钮事件了,如下:
package com.fuly.image; import android.os.Bundle;
import android.view.View;
import android.app.Activity;
import android.content.Intent; public class MainActivity extends Activity { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} //下面是按钮事件
public void btnMatrix(View v){
Intent intent = new Intent(this,MatrixActivity.class);
startActivity(intent);
}
public void btnXFermode(View v){
Intent intent = new Intent(this,XFermodeActivity.class);
startActivity(intent);
}
public void btnShader(View v){
Intent intent = new Intent(this,ShaderActivity.class);
startActivity(intent);
}
public void btnLShader(View v){
Intent intent = new Intent(this,LinearShaderActivity.class);
startActivity(intent);
} }
然后运行程序,效果如下:
好了,至此,你有没有学会怎么给画笔绑定普通的渲染呢?上面实现的效果比较简单,其实利用线性渐变结合xfermode风格可以实现常见的水面倒影效果,这个有兴趣可以自己百度下相关案例。
不知道你有没有发现,不知不觉间我们已经实现了4个按钮的效果了。还有最后一个按钮“像素块实验”没有实现了,下一篇文章中,我们就来看看这个效果吧。然后这个图形变换基础系列文章就完结了。
通过渲染器Shader实现图像变换效果的更多相关文章
- Android渲染器Shader:LinearGradient(一)
Android渲染器Shader:LinearGradient(一) LinearGradient是Android的线性渲染器.我写5个LinearGradient渲染器渲染后的View表现结果 ...
- Android渲染器Shader:环状放射渐变渲染器RadialGradient(三)
Android渲染器Shader:环状放射渐变渲染器RadialGradient(三) Android RadialGradient渲染器提供一种环状.发散.放射形状的渐变渲染器. 写一个例子: ...
- Android渲染器Shader:梯度渐变扫描渲染器SweepGradient(二)
Android渲染器Shader:梯度渐变扫描渲染器SweepGradient(二) 附录文章1介绍了线性渐变渲染器. Android的SweepGradient梯度渐变扫描,重点是在构造Swe ...
- 关于 android的 渲染器 Shader
因为公司在 自定义的画图上面比较苛刻(各种要求= =),最后又是改来改去的.反正是 Shader起到很大作用,特此记录一下下.在achartengine的基础上没有能满足他们= = androd 提供 ...
- 渲染器 Shader BitmapShader
渲染模式: tileX tileY:The tiling mode for x/y to draw the bitmap in. 在位图上 X/Y 方向 瓦工/花砖/瓷砖 模式 CLAMP :如 ...
- 基于OpenGL编写一个简易的2D渲染框架-09 重构渲染器-Shader
Shader 只是进行一些简单的封装,主要功能: 1.编译着色程序 2.绑定 Uniform 数据 3.根据着色程序的顶点属性传递顶点数据到 GPU 着色程序的编译 GLuint Shader::cr ...
- Android Shader渲染器:BitmapShader图片渲染
public class BitmapShader extends Shader BitmapShader, Shader家族的 专门处理图片渲染的 构造方法: public BitmapShade ...
- CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL
CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL +BIT祝威+悄悄在此留下版了个权的信息说: 开始 本文用step by step的方式,讲述如何使 ...
- Unity3D着色器Shader编程入门(一)
自学Unity3D也有大半年了,对Shader一直不敢入坑,最近看了些资料,以及通过自己的实践,对Shader还是有一点了解了,分享下仅作入门参考. 因Shader是对图像图像渲染的,学习前可以去了解 ...
随机推荐
- Hibernate 一对一映射(惟一外键)
- Ajax介绍及爬取哔哩哔哩番剧索引追番人数排行
Ajax,是利用JavaScript在保证页面不被刷新,页面链接不改变的情况下与服务器交换数据并更新部分网页的技术.简单的说,Ajax使得网页无需刷新即可更新其内容.举个例子,我们用浏览器打开新浪微博 ...
- 实现easyui的combogrid模糊查询框
这里用的方法是一个不可编辑的combogrid控件,覆盖上一个可输入的Input控件. 思路: 1.初始时取到后台查询出的列表,存储到全局变量 2.当输入框输入内容时,循环匹配列表,重新绑定到comb ...
- 如何高效的算出2x8的值
原文出自:https://blog.csdn.net/seesun2012 位移算法,如何高效的算出2*8的值,为什么8<<1,4<<2,2<<3,1<< ...
- NodeJs接口token认证express框架passport实现方式Bearer认证
1.生成一个简单的express项目(命令:express passport-test),项目结构如下: 2.添加项目依赖: npm install passport --save npm insta ...
- form表单在发送到服务器时候编码方式
enctype(编码方式):规定了form表单在发送到服务器时候编码方式.有如下的三个值可选: 1.application/x-www-form-urlencoded.默认的编码方式.但是在用文本的传 ...
- Spring课程 Spring入门篇 6-2 ProxyFactoryBean及相关内容(上)
1 解析 1.1 类的方式实现各种通知需要实现的接口 1.2 创建Spring aop代理的优点及方法 1.3 代理控制切入点和通知的顺序的代码实现(具体完全实现,见代码2.1) 1.4 代理方式选择 ...
- Redis(MySQL和redis怎么分工合作的?)
新手: redis也是服务器,主要部署在服务器上缓解服务器的压力,对于访问量交大的数据可以先缓存到redis,用户访问时直接访问redis,不用再直接访问数据库,缓解数据库的压力.mysql主要存储数 ...
- RegExp.prototype.exec()使用技巧
RegExp.prototype.exec() exec() 方法在一个指定字符串中执行一个搜索匹配.返回一个结果数组或 null. 如果你只是为了判断是否匹配(true或 false),可以使用 R ...
- thinkphp5设置404页面不跳转
thinkphp5设置404页面的步骤: 1. 首先关闭调试模式,即配置application/config文件,使'app_debug' => false 2. 添加自定义404页面跳转地址, ...