赞
踩
现在来搞一下Xfermode的知识点,先拿出Xfermode的代码研究一下:
- private static final Xfermode[] sModes = {
- /** [0, 0] */
- new PorterDuffXfermode(PorterDuff.Mode.CLEAR),//在该区域里什么都不显示
- /** [Sa, Sc] */
- new PorterDuffXfermode(PorterDuff.Mode.SRC),//在该区域里只显示原图
- /** [Da, Dc] */
- new PorterDuffXfermode(PorterDuff.Mode.DST),//在该区域里只显示目标图
- /** [Da, Sc * Da + (1 - Sa) * Dc] */
- new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),//在该区域显示目标图并且相交部分显示原图
- /** [Sa, Sa * Dc + Sc * (1 - Da)] */
- new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),//在该区域显示原图并且相交部分显示目标图
- /** [Sa * Da, Sc * Da] */
- new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),//在该区域只显示相交区域且显示相交部分的原图
- /** [Sa * Da, Sa * Dc] */
- new PorterDuffXfermode(PorterDuff.Mode.DST_IN),//在该区域只显示相交区域且显示相交部分的目标图
- /** [Sa * Da, Sc * Dc] */
- new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),//在该区域只显示相交区域且显示两种的叠加颜色
- /** [Sa * (1 - Da), Sc * (1 - Da)] */
- new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),//在该区域显示非相交部分的原图
- /** [Da * (1 - Sa), Dc * (1 - Sa)] */
- new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),//在该区域显示非相交部分的目标图
-
- /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
- new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),//在该区域全部显示且原图在目标图的上方
- /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
- new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),//在该区域全部显示且目标图在原图的上方
- /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
- new PorterDuffXfermode(PorterDuff.Mode.XOR),//在该区域全部显示并且相交部分显示透明
- /** [Sa + Da - Sa*Da,Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
- new PorterDuffXfermode(PorterDuff.Mode.DARKEN),//在该区域全部显示且相交部分的颜色变深
- /** [Sa + Da - Sa*Da,Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
- new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),//在该区域全部显示且相交部分的颜色变亮
- /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
- new PorterDuffXfermode(PorterDuff.Mode.SCREEN),//在该区域全部显示且相交部分滤掉原图的颜色
- /** Saturate(S + D) */
- new PorterDuffXfermode(PorterDuff.Mode.ADD),//在该区域全部显示且相交部分饱和度相加
- new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)//在该区域全部显示且相交部分为叠加的颜色
- };
解释:
1、Sa代表源alpha值,Da代表目标alpha值,Sc代表源色值,Dc代表目标色值
2、设置Xfermode的为源图
1、PorterDuff.Mode.CLEAR /** [0, 0] */
//根据公式可知,不管源图和目标图如何都将置为0,在该区域里什么都不显示
2、PorterDuff.Mode.SRC_ATOP /** [Da, Sc * Da + (1 - Sa) * Dc] */
(1)当源图不相交部分(Da,Dc都为0):[0,0]则不显示;
(2)当目标图不相交部分(Sa,Sc都为0) :[Da,Dc]则显示目标图;
(3)源图和目标图相交部分则主要显示目标图
3、PorterDuff.Mode.DST_ATOP /** [Sa, Sa * Dc + Sc * (1 - Da)] */
//有公式可知,
(1)当源图不相交部分(Da,Dc都为0):[Sa,Sc]则显示源图;
(2)当目标图不相交部分(Sa,Sc都为0) :[0,0]则不显示;
(3)源图和目标图相交部分则主要显示源图
4、PorterDuff.Mode.DST_IN /** [Sa * Da, Sa * Dc] */
//在该区域只显示相交区域且显示相交部分的目标图
5、PorterDuff.Mode.XOR /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
//有公式可知,
(1)当源图不相交部分(Da,Dc都为0):[Sa,Sc]则显示源图;
(2)当目标图不相交部分(Sa,Sc都为0) :[Da,Dc]则显示目标图;
(3)源图和目标图相交部分如果Da和Sa都不为0的情况下则显示透明
具体代码如下:- // 创建一个圆形图片,m
- static Bitmap makeDst(int w, int h) {
- Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(bm);
- Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
-
- p.setColor(0xFFFFCC44);
- c.drawOval(new RectF(0, 0, 2*w/3, 2*h/3), p);
- return bm;
- }
-
- // 创建一个矩形Bitmap,命名为原图片
- static Bitmap makeSrc(int w, int h) {
- Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(bm);
- Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
- p.setColor(0xFF66AAFF);
- c.drawRect(w/3, h/3, w * 19 / 20, h * 19 / 20, p);
- return bm;
- }
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.drawColor(Color.GRAY);
- Paint paint = new Paint();
- canvas.drawBitmap(mSrcB, screenW / 8 - W / 4, screenH / 12, paint);
- canvas.drawBitmap(mDstB, screenW / 2, screenH / 12+H/3, paint);
- //创建一个图层,在图层上演示图形混合后的效果
- int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.MATRIX_SAVE_FLAG |
- Canvas.CLIP_SAVE_FLAG |
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
- Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
- Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- canvas.drawBitmap(mDstB, screenW / 4, screenH / 3, paint);//圆形
- //设置Paint的Xfermode
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
- canvas.drawBitmap(mSrcB, screenW / 4, screenH / 3, paint);//矩形
- paint.setXfermode(null);
- //还原画布
- canvas.restoreToCount(sc);
- }
- }
Xfermode应用:
一、实现波动文字
- // 存为新图层
- int saveLayerCount = canvas.saveLayer(0, 0, width, height, paint,
- Canvas.ALL_SAVE_FLAG);
- canvas.drawBitmap(dest, bitSrc, bitDest, paint);
- paint.setXfermode(mode);//设置SRC_IN模式,显示相交部分并且相交部分为原图
- canvas.drawRect(dynamicRectF, paint);
- paint.setXfermode(null);
- canvas.restoreToCount(saveLayerCount);</span>
然后通过改变dynamicRecF的位置来实现动画效果
- currentTop = currentTop - 1;
- try {
- Thread.sleep((int) (Math.random() * 100));
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- if (dynamicRectF.top <= height / 2) {
- currentTop = height / 2 + dest.getHeight();
- }
- dynamicRectF.top = currentTop;
- dynamicRectF.bottom = currentTop + dest.getHeight();
- postInvalidate();//更新</span>
二、实现圆形头像
步骤:
*先将一个圆生成一个图片
- private Bitmap getCircleBit() {
- Bitmap blank = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(blank);
- Paint paint = new Paint();
- paint.setStyle(Paint.Style.FILL);
- paint.setColor(Color.RED);
- paint.setAntiAlias(true);
- radius = Math.min(getWidth() / 2, getHeight() / 2);
- canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, paint);
- return blank;
- }</span>
*得到ImageView的图片并进行缩放
- Drawable drawable = getDrawable();
- //开始对图片进行缩放
- //1得到图片的宽高
- int dW = drawable.getIntrinsicWidth();
- int dH = drawable.getIntrinsicHeight();
- System.out.println("dW:" + dW + " dH:" + dH);
- float scale = 1.0f;//3得到缩放比例
- //2判断 图片在圆内 圆在图片内
- if (dW <= (2 * radius) || dH <= (2 * radius)) {
- //图片在圆内
- scale = Math.max((2 * radius * 1.0f) / dW, (2 * radius * 1.0f) / dH);
- } else {
- //圆在图片内
- scale = Math.max((2 * radius * 1.0f) / dW, (2 * radius * 1.0f) / dH);
- }
- drawable.setBounds(0, 0, dW, dH);
- ivBitmap = scaleDrawable(drawable, scale);
- circlePaint = new Paint();
- circlePaint.setAntiAlias(true);
- circlePaint.setFilterBitmap(false);
- mode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
- }
-
- private Bitmap scaleDrawable(Drawable drawable, float scale) {
- Bitmap blank = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(blank);
- drawable.draw(canvas);
- Matrix matrix = new Matrix();
- matrix.setScale(scale, scale);//根据传递过来的值进行缩放
- Bitmap newBitmap = Bitmap.createBitmap(blank, 0, 0,drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), matrix, false);
- //注意第四个参数和第五个参数要为原始图片的大小
- return newBitmap;
- }</span>
*在onDraw方法里面进行显示
- @Override
- protected void onDraw(Canvas canvas) {
- //super.onDraw(canvas);//屏蔽掉父类的onDraw方法
- Bitmap blank = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
- Canvas drawCanvas = new Canvas(blank);
- drawCanvas.drawBitmap(ivBitmap, 0, 0, circlePaint);
- circlePaint.setXfermode(mode);
- drawCanvas.drawBitmap(CircleBit, 0, 0, circlePaint);
- circlePaint.setXfermode(null);
- canvas.drawBitmap(blank, 0, 0, null);
- }</span>
三、实现撕美女衣服的功能
实现这种功能有两种思路:1、使用Bitmap.setPixel(x,y,Color.TRANSPARENT) 2、使用Xfermode来实现
1、使用Bitmap.setPixel(x,y,Color.TRANSPARENT)来实现
- Bitmap up_bit = BitmapFactory.decodeResource(getResources(), R.drawable.g7_up);
- Bitmap bottom_bit = BitmapFactory.decodeResource(getResources(), R.drawable.g7_back);
- bottom.setImageBitmap(bottom_bit);
- blank = Bitmap.createBitmap(up_bit.getWidth(), up_bit.getHeight(), Bitmap.Config.ARGB_8888);//创建一个具有透明度的空白图片
- Canvas canvas = new Canvas(blank);//将空白的图片加入画布中
- canvas.drawBitmap(up_bit, 0, 0, null);//画布画出图片
- top.setImageBitmap(blank);
- top.setOnTouchListener(this);//为顶部的控件设置触摸事件
- }
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- //以触摸点作为中心点,边长为40的矩形区域设置透明
- for (float i = event.getX() - 20; i < event.getX() + 20; i++) {
- for (float j = event.getY() - 20; j < event.getY() + 20; j++) {
- if (i >= 0 && i <= blank.getWidth() && j >= 0 && j <= blank.getHeight()) {
- blank.setPixel((int) i, (int) j, Color.TRANSPARENT);//为图片的点设置透明
- }
- }
- }
- top.setImageBitmap(blank);//每次对图片进行了设置都需要将设置后的图片存入ImageView控件中
- break;
- }
- return true;
- }
2、使用Xfermode来实现:
- try {
- g7_up = R.drawable.class.getDeclaredField("g7_up").getInt(this);//利用反射得到resId,这样的好处
- /**
- * 可以通过for循环遍历
- * for(int i = 0 ; i < 100 ; i++){
- * list.add(R.drawable.class.getDeclaredField(String.format("g%02d_up",i).getInt(this));
- * }
- */
- g7_back = R.drawable.class.getDeclaredField("g7_back").getInt(this);
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- Bitmap top_bit = BitmapFactory.decodeResource(getResources(), g7_up);
- Bitmap bottom_bit = BitmapFactory.decodeResource(getResources(), g7_back);
- bottom.setImageBitmap(bottom_bit);
-
- paint = new Paint();
- paint.setAlpha(0);
- paint.setStyle(Paint.Style.FILL);
- paint.setAntiAlias(true);//用来防止边缘的锯齿
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
- //CLEAR /** [0, 0] */ Sa=0时,相交部分透明 可以
- //SRC /** [Sa, Sc] */ Sa=0时,相交部分透明 可以
- //SRC_IN /** [Sa * Da, Sc * Da] */ Sa=0时,相交部分透明 可以
- //SRC_OUT /** [Sa * (1 - Da), Sc * (1 - Da)] */Sa=0时,相交部分透明 可以
- //DST_IN /** [Sa * Da, Sa * Dc] */ Sa=0时,相交部分透明 可以
- //DST_OUT /** [Da * (1 - Sa), Dc * (1 - Sa)] */Sa=0时,相交部分不透明 不可以
- blank = Bitmap.createBitmap(top_bit.getWidth(), top_bit.getHeight(), Bitmap.Config.ARGB_4444);
- canvas = new Canvas(blank);
- canvas.drawBitmap(top_bit, 0, 0, null);
- top.setImageBitmap(blank);
- top.setOnTouchListener(this);
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- canvas.drawCircle(event.getX(), event.getY(), 20, paint);
- top.setImageBitmap(blank);//将改变之后的图片传入控件中
- break;
- }
- return true;
- }
四、实现图片倒影的效果
实现步骤:
*得到倒影图像
- Matrix m = new Matrix();
- m.setScale(1, -1);//将图片倒过来
- Bitmap reflectBitmap = Bitmap.createBitmap(srcBitmap, 0, height / 2, srcBitmap.getWidth(), height / 2, m, false);
*创建空白画布画出源图和倒影图
- Bitmap finalBitmap = Bitmap.createBitmap(width, height + height + gapHeight, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(finalBitmap);
- canvas.drawBitmap(srcBitmap, 0, 0, null);//添加原图
- canvas.drawRect(0, height, width, height + gapHeight, new Paint());//在图片和倒影之间添加一个空白的矩形
- canvas.drawBitmap(reflectBitmap, 0, height + gapHeight, null);//添加倒影
*为倒影添加遮罩层渐变的效果
- Paint paint = new Paint();
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//DST_IN /** [Sa * Da, Sa * Dc] */ 可以看出显示的目标图受原图透明度的影响
- LinearGradient lg = new LinearGradient(0, height, 0, height + height / 2, Color.parseColor("#83FFFFFF"), Color.parseColor("#22FFFFFF"), Shader.TileMode.CLAMP);
- paint.setShader(lg);//为矩形设置渐变
- canvas.drawRect(0, height + gapHeight, width, height + gapHeight + height / 2, paint);
* 将图片添加到ImageView中
- BitmapDrawable bd = new BitmapDrawable(getResources(), finalBitmap);
- bd.setAntiAlias(true);
- RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) iv.getLayoutParams();
- params.width = 300;
- params.height = 400;
- iv.setLayoutParams(params);
- iv.setImageBitmap(bd.getBitmap());
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。