在上一篇文章中,学习了通过设置矩阵来达到图片变形的效果。没读过的朋友可以点击下面的链接:
http://www.cnblogs.com/fuly550871915/p/4886353.html
在这一篇文章中,快马加鞭,继续学习图片变形的方法。通过给画笔设定xFermode风格,可以达到很多常见的图像效果。那么首先先来简单了解一下xFermode风格。
一、基础知识
配合下面的一张图,来说一说什么是xFermode风格。如下:
正如图中所示,列举了一些xfermode风格。比如Clear就是一个空白风格,此时画笔移动将会画空白,相当于一个橡皮擦的效果。再比如Srcin风格,你可以把它想象成两张图叠加(图中的圆和方块),求出它们交集里位于下面的图片(即最后显示的是方块的颜色)。同理,DstIn就是求交集后位于上面的图片。xfermode风格有很多很多种,这里不一一解释了,用到的时候再细细看吧。那么如何给画笔设定xfermode风格呢?利用的是一句代码,如下:
//为画笔设置xFermode风格,只有具有alpha通道的图片才有效 paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));
其中paint是一只画笔。注意到注释中有一句话:只有具有alpha通道的图片才有效。为什么呢?其实翻看源码,可以发现SrcIn风格并不是像前面我们说的是图片相交求交集,只是它的效果看起来像这样子而已。其实它的真正原理是有严格的计算公式的。我截一张图如下:
这是源码中的说明,注释中的S和D表示不同位置的图片,android中将canvas先画的图片作为Dst,将后画的图片作为Src。注释中的a就是表示透明度alpha。因为说,这种风格只有有透明度通道的图片才有效,如果一张图片没有透明度通道,那么将不可使用。
另外需要注意的是,因为xfermode的很多特性不支持硬件加速,因为使用前,一定要禁用硬件加速,即写下下面一句代码:
1 setLayerType(LAYER_TYPE_SOFTWARE, null);//注意,一定要禁用硬件加速器
好了,你或许仍旧感到云里雾里。没关系,跟着我一起做一个实际例子,实际例子是最好的学习资料。那么我们来实现一个常见的图片效果吧。比如一张圆角的图片是如何实现的呢?如下图:
而它的实际图片为:
下面我们就来写实际的代码,来实现这样子的效果。
二、实战
在上一篇的文章中的代码基础上,继续来写今天的代码。需要一张长方形的小图片,读者可自行替换为自己的图片即可。实现上面效果的思路很简单,其实即使用canvas前后分别画一个圆角矩形和原来的图片,然后设定画笔xfermode风格来求交集即可。但是注意,要点就是先画出圆角矩形,再画出原来图片,xfermode风格设定为SrcIn。
新建类MyXFerModeView继承自view,在这个里面,我们完成圆角矩形以及原来图片的绘制,并设定好画笔风格。如下:
1 package com.fuly.image; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.Canvas; 7 import android.graphics.Paint; 8 import android.graphics.PorterDuff; 9 import android.graphics.PorterDuffXfermode; 10 import android.graphics.Rect; 11 import android.graphics.RectF; 12 import android.graphics.Xfermode; 13 import android.util.AttributeSet; 14 import android.view.View; 15 16 /** 17 * 用来实验为画笔设置xFermode风格 18 * @author fuly1314 19 * 20 */ 21 public class MyXFerModeView extends View{ 22 23 private Bitmap priBmp; 24 private Bitmap aftBmp; 25 26 public MyXFerModeView(Context context) { 27 super(context); 28 initView(); 29 30 } 31 public MyXFerModeView(Context context, AttributeSet attrs) { 32 super(context, attrs); 33 initView(); 34 35 } 36 public MyXFerModeView(Context context, AttributeSet attrs, int defStyleAttr) { 37 super(context, attrs, defStyleAttr); 38 initView(); 39 40 } 41 /** 42 * 初始化view 43 */ 44 public void initView(){ 45 46 setLayerType(LAYER_TYPE_SOFTWARE, null);//注意,一定要禁用硬件加速器 47 48 priBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test4); 49 aftBmp = Bitmap.createBitmap(priBmp.getWidth(), priBmp.getHeight(), Bitmap.Config.ARGB_8888); 50 51 Canvas canvas = new Canvas(aftBmp); 52 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿 53 //矩形,注意应该与priBmp的宽高一致 54 RectF rect = new RectF(0, 0, priBmp.getWidth(), priBmp.getHeight()); 55 //50和50分别为圆角矩形的圆角弧度(x方向和y方向) 56 canvas.drawRoundRect(rect, 50, 50, paint); 57 //为画笔设置xFermode风格,只有具有alpha通道的图片才有效 58 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 59 60 //画上图片 61 canvas.drawBitmap(priBmp, 0, 0, paint); 62 //最后别忘记取消风格 63 paint.setXfermode(null); 64 65 66 } 67 68 @Override 69 protected void onDraw(Canvas canvas) { 70 super.onDraw(canvas); 71 //然后画出新的图片,即aftBmp 72 canvas.drawBitmap(aftBmp, 5, 5, null); 73 } 74 75 }
然后新建imagemode.xml将这个view装进来,代码如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 android:gravity="center"> 7 8 <com.fuly.image.MyXFerModeView 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content"/> 11 12 </LinearLayout>
代码是不是很简单啊,继续往下写,新建活动XFermodeActivity用来将这个布局显示出来,别忘记给这个活动注册哦。代码更简单了,如下:
1 package com.fuly.image; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 6 public class XFermodeActivity extends Activity{ 7 8 9 protected void onCreate(Bundle savedInstanceState) { 10 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.imagemode); 13 14 } 15 16 }
似乎一切都完成了,不要忘记MainActivity里的按钮事件啊。代码如下:
1 package com.fuly.image; 2 3 import android.os.Bundle; 4 import android.view.View; 5 import android.app.Activity; 6 import android.content.Intent; 7 8 9 public class MainActivity extends Activity { 10 11 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_main); 15 } 16 17 //下面是按钮事件 18 public void btnMatrix(View v){ 19 Intent intent = new Intent(this,MatrixActivity.class); 20 startActivity(intent); 21 } 22 public void btnXFermode(View v){ 23 Intent intent = new Intent(this,XFermodeActivity.class); 24 startActivity(intent); 25 } 26 27 }
好了,一切都完成了。快运行程序吧。效果如下:
这样子效果就实现了。其实用xfermode风格可以实现很多常见的效果,需要你去探索。举个例子,记得QQ中我们的头像上传的时候是方形的,但是显示出来的却是圆形的。现在知道为什么了吗?xfermode完全可以实现这个效果。
好了,相信经过实际代码书写,你已经很好的熟悉了xfermode了。剩下的就需要你自己去探索了。回头看一看,我们的项目中还有三个按钮没有实现效果。所以保存这一节的代码,快快进入下一节吧,利用渲染器实现图片变换。