在上一篇文章中,学习了通过设置矩阵来达到图片变形的效果。没读过的朋友可以点击下面的链接:

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了。剩下的就需要你自己去探索了。回头看一看,我们的项目中还有三个按钮没有实现效果。所以保存这一节的代码,快快进入下一节吧,利用渲染器实现图片变换。

 

posted on 2015-10-16 21:44  fuly  阅读(908)  评论(0编辑  收藏  举报