当前位置:   article > 正文

图像混合利器—Xfermode应用_nt.setxfermode(new porterduffxfermode(porterduff.m

nt.setxfermode(new porterduffxfermode(porterduff.mode.cle

现在来搞一下Xfermode的知识点,先拿出Xfermode的代码研究一下:

  1. private static final Xfermode[] sModes = {
  2. /** [0, 0] */
  3. new PorterDuffXfermode(PorterDuff.Mode.CLEAR),//在该区域里什么都不显示
  4. /** [Sa, Sc] */
  5. new PorterDuffXfermode(PorterDuff.Mode.SRC),//在该区域里只显示原图
  6. /** [Da, Dc] */
  7. new PorterDuffXfermode(PorterDuff.Mode.DST),//在该区域里只显示目标图
  8. /** [Da, Sc * Da + (1 - Sa) * Dc] */
  9. new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),//在该区域显示目标图并且相交部分显示原图
  10. /** [Sa, Sa * Dc + Sc * (1 - Da)] */
  11. new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),//在该区域显示原图并且相交部分显示目标图
  12. /** [Sa * Da, Sc * Da] */
  13. new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),//在该区域只显示相交区域且显示相交部分的原图
  14. /** [Sa * Da, Sa * Dc] */
  15. new PorterDuffXfermode(PorterDuff.Mode.DST_IN),//在该区域只显示相交区域且显示相交部分的目标图
  16. /** [Sa * Da, Sc * Dc] */
  17. new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),//在该区域只显示相交区域且显示两种的叠加颜色
  18. /** [Sa * (1 - Da), Sc * (1 - Da)] */
  19. new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),//在该区域显示非相交部分的原图
  20. /** [Da * (1 - Sa), Dc * (1 - Sa)] */
  21. new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),//在该区域显示非相交部分的目标图
  22. /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
  23. new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),//在该区域全部显示且原图在目标图的上方
  24. /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
  25. new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),//在该区域全部显示且目标图在原图的上方
  26. /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
  27. new PorterDuffXfermode(PorterDuff.Mode.XOR),//在该区域全部显示并且相交部分显示透明
  28. /** [Sa + Da - Sa*Da,Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
  29. new PorterDuffXfermode(PorterDuff.Mode.DARKEN),//在该区域全部显示且相交部分的颜色变深
  30. /** [Sa + Da - Sa*Da,Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
  31. new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),//在该区域全部显示且相交部分的颜色变亮
  32. /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
  33. new PorterDuffXfermode(PorterDuff.Mode.SCREEN),//在该区域全部显示且相交部分滤掉原图的颜色
  34. /** Saturate(S + D) */
  35. new PorterDuffXfermode(PorterDuff.Mode.ADD),//在该区域全部显示且相交部分饱和度相加
  36. new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)//在该区域全部显示且相交部分为叠加的颜色
  37. };

解释:

         1、Sa代表源alpha值,Da代表目标alpha值,Sc代表源色值,Dc代表目标色值

         2、设置Xfermode的为源图

so 列举几个进行分析:

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的情况下则显示透明

具体代码如下:

  1. // 创建一个圆形图片,m
  2. static Bitmap makeDst(int w, int h) {
  3. Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  4. Canvas c = new Canvas(bm);
  5. Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
  6. p.setColor(0xFFFFCC44);
  7. c.drawOval(new RectF(0, 0, 2*w/3, 2*h/3), p);
  8. return bm;
  9. }
  10. // 创建一个矩形Bitmap,命名为原图片
  11. static Bitmap makeSrc(int w, int h) {
  12. Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  13. Canvas c = new Canvas(bm);
  14. Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
  15. p.setColor(0xFF66AAFF);
  16. c.drawRect(w/3, h/3, w * 19 / 20, h * 19 / 20, p);
  17. return bm;
  18. }
  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. canvas.drawColor(Color.GRAY);
  4. Paint paint = new Paint();
  5. canvas.drawBitmap(mSrcB, screenW / 8 - W / 4, screenH / 12, paint);
  6. canvas.drawBitmap(mDstB, screenW / 2, screenH / 12+H/3, paint);
  7. //创建一个图层,在图层上演示图形混合后的效果
  8. int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.MATRIX_SAVE_FLAG |
  9. Canvas.CLIP_SAVE_FLAG |
  10. Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
  11. Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
  12. Canvas.CLIP_TO_LAYER_SAVE_FLAG);
  13. canvas.drawBitmap(mDstB, screenW / 4, screenH / 3, paint);//圆形
  14. //设置Paint的Xfermode
  15. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
  16. canvas.drawBitmap(mSrcB, screenW / 4, screenH / 3, paint);//矩形
  17. paint.setXfermode(null);
  18. //还原画布
  19. canvas.restoreToCount(sc);
  20. }
  21. }

Xfermode应用:

一、实现波动文字

  1. // 存为新图层
  2. int saveLayerCount = canvas.saveLayer(0, 0, width, height, paint,
  3. Canvas.ALL_SAVE_FLAG);
  4. canvas.drawBitmap(dest, bitSrc, bitDest, paint);
  5. paint.setXfermode(mode);//设置SRC_IN模式,显示相交部分并且相交部分为原图
  6. canvas.drawRect(dynamicRectF, paint);
  7. paint.setXfermode(null);
  8. canvas.restoreToCount(saveLayerCount);</span>
然后通过改变dynamicRecF的位置来实现动画效果
  1. currentTop = currentTop - 1;
  2. try {
  3. Thread.sleep((int) (Math.random() * 100));
  4. } catch (InterruptedException e) {
  5. e.printStackTrace();
  6. }
  7. if (dynamicRectF.top <= height / 2) {
  8. currentTop = height / 2 + dest.getHeight();
  9. }
  10. dynamicRectF.top = currentTop;
  11. dynamicRectF.bottom = currentTop + dest.getHeight();
  12. postInvalidate();//更新</span>

二、实现圆形头像

步骤:

                *先将一个圆生成一个图片

  1. private Bitmap getCircleBit() {
  2. Bitmap blank = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
  3. Canvas canvas = new Canvas(blank);
  4. Paint paint = new Paint();
  5. paint.setStyle(Paint.Style.FILL);
  6. paint.setColor(Color.RED);
  7. paint.setAntiAlias(true);
  8. radius = Math.min(getWidth() / 2, getHeight() / 2);
  9. canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, paint);
  10. return blank;
  11. }</span>
                  *得到ImageView的图片并进行缩放
  1. Drawable drawable = getDrawable();
  2. //开始对图片进行缩放
  3. //1得到图片的宽高
  4. int dW = drawable.getIntrinsicWidth();
  5. int dH = drawable.getIntrinsicHeight();
  6. System.out.println("dW:" + dW + " dH:" + dH);
  7. float scale = 1.0f;//3得到缩放比例
  8. //2判断 图片在圆内 圆在图片内
  9. if (dW <= (2 * radius) || dH <= (2 * radius)) {
  10. //图片在圆内
  11. scale = Math.max((2 * radius * 1.0f) / dW, (2 * radius * 1.0f) / dH);
  12. } else {
  13. //圆在图片内
  14. scale = Math.max((2 * radius * 1.0f) / dW, (2 * radius * 1.0f) / dH);
  15. }
  16. drawable.setBounds(0, 0, dW, dH);
  17. ivBitmap = scaleDrawable(drawable, scale);
  18. circlePaint = new Paint();
  19. circlePaint.setAntiAlias(true);
  20. circlePaint.setFilterBitmap(false);
  21. mode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
  22. }
  23. private Bitmap scaleDrawable(Drawable drawable, float scale) {
  24. Bitmap blank = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
  25. Canvas canvas = new Canvas(blank);
  26. drawable.draw(canvas);
  27. Matrix matrix = new Matrix();
  28. matrix.setScale(scale, scale);//根据传递过来的值进行缩放
  29. Bitmap newBitmap = Bitmap.createBitmap(blank, 0, 0,drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), matrix, false);
  30. //注意第四个参数和第五个参数要为原始图片的大小
  31. return newBitmap;
  32. }</span>
                 *在onDraw方法里面进行显示
  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. //super.onDraw(canvas);//屏蔽掉父类的onDraw方法
  4. Bitmap blank = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
  5. Canvas drawCanvas = new Canvas(blank);
  6. drawCanvas.drawBitmap(ivBitmap, 0, 0, circlePaint);
  7. circlePaint.setXfermode(mode);
  8. drawCanvas.drawBitmap(CircleBit, 0, 0, circlePaint);
  9. circlePaint.setXfermode(null);
  10. canvas.drawBitmap(blank, 0, 0, null);
  11. }</span>

三、实现撕美女衣服的功能

实现这种功能有两种思路:1、使用Bitmap.setPixel(x,y,Color.TRANSPARENT)  2、使用Xfermode来实现

1、使用Bitmap.setPixel(x,y,Color.TRANSPARENT)来实现

  1. Bitmap up_bit = BitmapFactory.decodeResource(getResources(), R.drawable.g7_up);
  2. Bitmap bottom_bit = BitmapFactory.decodeResource(getResources(), R.drawable.g7_back);
  3. bottom.setImageBitmap(bottom_bit);
  4. blank = Bitmap.createBitmap(up_bit.getWidth(), up_bit.getHeight(), Bitmap.Config.ARGB_8888);//创建一个具有透明度的空白图片
  5. Canvas canvas = new Canvas(blank);//将空白的图片加入画布中
  6. canvas.drawBitmap(up_bit, 0, 0, null);//画布画出图片
  7. top.setImageBitmap(blank);
  8. top.setOnTouchListener(this);//为顶部的控件设置触摸事件
  9. }
  10. @Override
  11. public boolean onTouch(View v, MotionEvent event) {
  12. switch (event.getAction()) {
  13. case MotionEvent.ACTION_DOWN:
  14. case MotionEvent.ACTION_MOVE:
  15. //以触摸点作为中心点,边长为40的矩形区域设置透明
  16. for (float i = event.getX() - 20; i < event.getX() + 20; i++) {
  17. for (float j = event.getY() - 20; j < event.getY() + 20; j++) {
  18. if (i >= 0 && i <= blank.getWidth() && j >= 0 && j <= blank.getHeight()) {
  19. blank.setPixel((int) i, (int) j, Color.TRANSPARENT);//为图片的点设置透明
  20. }
  21. }
  22. }
  23. top.setImageBitmap(blank);//每次对图片进行了设置都需要将设置后的图片存入ImageView控件中
  24. break;
  25. }
  26. return true;
  27. }
2、使用Xfermode来实现:
  1. try {
  2. g7_up = R.drawable.class.getDeclaredField("g7_up").getInt(this);//利用反射得到resId,这样的好处
  3. /**
  4. * 可以通过for循环遍历
  5. * for(int i = 0 ; i < 100 ; i++){
  6. * list.add(R.drawable.class.getDeclaredField(String.format("g%02d_up",i).getInt(this));
  7. * }
  8. */
  9. g7_back = R.drawable.class.getDeclaredField("g7_back").getInt(this);
  10. } catch (IllegalAccessException e) {
  11. e.printStackTrace();
  12. } catch (NoSuchFieldException e) {
  13. e.printStackTrace();
  14. }
  15. Bitmap top_bit = BitmapFactory.decodeResource(getResources(), g7_up);
  16. Bitmap bottom_bit = BitmapFactory.decodeResource(getResources(), g7_back);
  17. bottom.setImageBitmap(bottom_bit);
  18. paint = new Paint();
  19. paint.setAlpha(0);
  20. paint.setStyle(Paint.Style.FILL);
  21. paint.setAntiAlias(true);//用来防止边缘的锯齿
  22. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
  23. //CLEAR /** [0, 0] */ Sa=0时,相交部分透明 可以
  24. //SRC /** [Sa, Sc] */ Sa=0时,相交部分透明 可以
  25. //SRC_IN /** [Sa * Da, Sc * Da] */ Sa=0时,相交部分透明 可以
  26. //SRC_OUT /** [Sa * (1 - Da), Sc * (1 - Da)] */Sa=0时,相交部分透明 可以
  27. //DST_IN /** [Sa * Da, Sa * Dc] */ Sa=0时,相交部分透明 可以
  28. //DST_OUT /** [Da * (1 - Sa), Dc * (1 - Sa)] */Sa=0时,相交部分不透明 不可以
  29. blank = Bitmap.createBitmap(top_bit.getWidth(), top_bit.getHeight(), Bitmap.Config.ARGB_4444);
  30. canvas = new Canvas(blank);
  31. canvas.drawBitmap(top_bit, 0, 0, null);
  32. top.setImageBitmap(blank);
  33. top.setOnTouchListener(this);
  34. }
  35. @Override
  36. public boolean onTouch(View v, MotionEvent event) {
  37. switch (event.getAction()) {
  38. case MotionEvent.ACTION_DOWN:
  39. case MotionEvent.ACTION_MOVE:
  40. canvas.drawCircle(event.getX(), event.getY(), 20, paint);
  41. top.setImageBitmap(blank);//将改变之后的图片传入控件中
  42. break;
  43. }
  44. return true;
  45. }

四、实现图片倒影的效果

实现步骤:

             *得到倒影图像

  1. Matrix m = new Matrix();
  2. m.setScale(1, -1);//将图片倒过来
  3. Bitmap reflectBitmap = Bitmap.createBitmap(srcBitmap, 0, height / 2, srcBitmap.getWidth(), height / 2, m, false);
           *创建空白画布画出源图和倒影图

  1. Bitmap finalBitmap = Bitmap.createBitmap(width, height + height + gapHeight, Bitmap.Config.ARGB_8888);
  2. Canvas canvas = new Canvas(finalBitmap);
  3. canvas.drawBitmap(srcBitmap, 0, 0, null);//添加原图
  4. canvas.drawRect(0, height, width, height + gapHeight, new Paint());//在图片和倒影之间添加一个空白的矩形
  5. canvas.drawBitmap(reflectBitmap, 0, height + gapHeight, null);//添加倒影
        *为倒影添加遮罩层渐变的效果

  1. Paint paint = new Paint();
  2. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//DST_IN /** [Sa * Da, Sa * Dc] */ 可以看出显示的目标图受原图透明度的影响
  3. LinearGradient lg = new LinearGradient(0, height, 0, height + height / 2, Color.parseColor("#83FFFFFF"), Color.parseColor("#22FFFFFF"), Shader.TileMode.CLAMP);
  4. paint.setShader(lg);//为矩形设置渐变
  5. canvas.drawRect(0, height + gapHeight, width, height + gapHeight + height / 2, paint);
        * 将图片添加到ImageView中

  1. BitmapDrawable bd = new BitmapDrawable(getResources(), finalBitmap);
  2. bd.setAntiAlias(true);
  3. RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) iv.getLayoutParams();
  4. params.width = 300;
  5. params.height = 400;
  6. iv.setLayoutParams(params);
  7. iv.setImageBitmap(bd.getBitmap());

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/332644
推荐阅读
  

闽ICP备14008679号