Android Canvas更改形状和文本相交的颜色 [英] Android Canvas change color of intersection of shapes and texts

查看:80
本文介绍了Android Canvas更改形状和文本相交的颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Canvas更改形状和文本的交集颜色. 我有2种形状和1种带有不同颜料的文本.

I'm trying to change color of intersection of shapes and text using Canvas. i have 2 shapes and 1 text with different paints.

这没有任何PorterDuffXfermode,并且PorterDuffColorFilter模式已添加到任何绘画中.我希望形状的交集是特定的颜色,例如白色,而文本则是红色或白色,如下图所示.

This is without any PorterDuffXfermode, and PorterDuffColorFilter mode added to any paint. I want intersection of shapes to be particular color, for example white, and text red or white like the images below.

在我的示例中,文本位于底部,中间的圆圈和上方的矩形,但是它并不重要,我只是想弄清楚它是如何工作的,以及应该如何将交集设置为特定的颜色.

In my example, text is at the bottom, circle middle and rectangle above but it's insignificant, i'm just trying to figure out how it works and how should intersection can be set to particular color.

如您在此图像中所见背景为黑色,圆圈为白色,文本为黑色.当圆圈重叠时,圆圈的交点变为黑色,文本的重叠部分变为白色.

As you can see in this image background is black, circles are white and text is black. When circles overlap intersection of circles turns to black and overlapping section of text turns to white.

我可以做到

canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));

如果圆形和矩形均为白色,背景为黑色.当我将背景色更改为任何其他颜色时,文本不可见,形状为黑色.

if circle and rectangle are both white and background is black. When i change background color to any other color, text is not visible, shapes are black.

我还想知道如何获得类似于此图像的类似结果可以将圆形,矩形和文本的重叠部分设置为特定颜色吗?

I also wonder how can i get similar results like in this image Can overlapping sections for circle, rectangle and text can be set to specific color?

推荐答案

Android Canvas更改形状和文本的交集颜色

Android Canvas change color of intersection of shapes and texts

和:

"如果圆形和矩形均为白色,背景为黑色. 当我将背景颜色更改为任何其他颜色时,文本不可见,形状为黑色."

"If circle and rectangle are both white and background is black. When I change background color to any other color, text is not visible, shapes are black."

PorterDuff

  • (1)是的,我们可以使用 PorterDuff.Mode (Mode.ADD):

    PorterDuff

    • (1) Yes we can with PorterDuff.Mode (Mode.ADD):

      PorterDuff.Mode模式= Mode.ADD;

      PorterDuff.Mode mode = Mode.ADD;

      (2)Canvas的背景必须为transparentcompositing才能正常工作. 如果您需要任何其他背景颜色,那么我们需要在单独 Canvas上进行合成. 然后,将图形复制到原始的Canvas.

      (2) The Canvas background must be transparent for the compositing to work. If you need any other background color then we need to do the compositing on a separate Canvas. Then we copy the drawing to the original Canvas.

      我还想知道如何获得类似的结果,例如图像"

      这是代码输出(PorterDuff决定混合颜色; O():

      Here is the code output (PorterDuff decides the blend color ;O( ):

      (Q1 :)可以将圆形,矩形和文本的重叠部分设置为 具体的颜色?"

      (Q1:) "Can overlapping sections for circle, rectangle and text can be set to specific color?"

      • (A1 :)是的,可以(很费力)完成.差不多完成了,但是很有信心.这是几乎完成的图像(我必须在此答案中使用几乎所有内容,必须是一种更简单的方法...):
        • (A1:) Yes it can be done (with much effort). Almost finished but confident it can. here are the almost finished images (I had to use almost all of the stuff in this answer, there must be an easier way...):
        • @Override
          protected void onDraw(Canvas canvas) 
          {
              super.onDraw(canvas);
          
              Paint paint          = new Paint();
              Paint paintClear     = new Paint();
              TextPaint textPaint  = new TextPaint();
              int width            = getWidth();
              int height           = getHeight();
              int x                = 100;
              int y                = 100;
              int radius           = 100;
          
              PorterDuff.Mode mode        = Mode.ADD;      // mode Mode.ADD
          
              paintClear.setStyle(Style.FILL); 
              paint.setStyle(Style.FILL); 
              textPaint.setAntiAlias(true); 
              textPaint.setTextSize(100 * getResources().getDisplayMetrics().density);
              textPaint.setColor(Color.GREEN);    
              textPaint.setStrokeWidth(3);     
          
              // ** clear canvas backgound to white**
              paintClear.setColor(Color.WHITE);
              canvas.drawPaint(paintClear); 
              //canvas.save();
          
              Bitmap compositeBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
              Canvas compositeCanvas = new Canvas(compositeBitmap);
              paintClear.setColor(Color.TRANSPARENT);
              compositeCanvas.drawPaint(paintClear); 
          
              // ** draw destination circle in red **
              paint.setColor(Color.RED);
              compositeCanvas.drawCircle(x+100, y+100, radius, paint);
          
              // ** set Xfermode **
              paint.setXfermode(new PorterDuffXfermode(mode));
              textPaint.setXfermode(new PorterDuffXfermode(mode));
          
              // ** draw source circle in blue **
              paint.setColor(Color.BLUE);
              compositeCanvas.drawCircle(x-0, y-0, radius, paint);
          
              // ** draw text in Green **
              compositeCanvas.save();
              compositeCanvas.rotate(-45, x, y+150);
              compositeCanvas.drawText("- 65,6", x, y+150, textPaint);
              compositeCanvas.restore();
          
              //copy compositeCanvas to canvas
              canvas.drawBitmap(compositeBitmap, 0, 0, null);
              //canvas.restore();
          }//onDraw
          

          路口测试

          使用 RectF 包含并相交:

          public Rect  mBound = new Rect(0  , 0  , 10 , 10);
          public RectF a1     = new Rect(0f , 0f , 10f, 10f);
          public RectF b1     = new Rect(5f , 5f , 20f, 20f);
          public RectF c1     = new Rect(30f, 30f, 40f, 40f);
          
          int boolean hit       = false;
          int boolean intersect = false;
          hit = hitTest(20,15); // returns false
          hit = hitTest(5,5);   // returns true 
          intersect = intersectsTest(a1,b1);// returns true
          intersect = intersectsTest(a1,c1);// returns false
          
          public boolean hitTest(int x, int y) 
          {
              return mBound.contains(x, y); 
          }//
          // Returns true if the two specified rectangles intersect
          public boolean intersectsTest(RectF a, RectF b) 
          {
              return intersects ( a, b);
          }//
          

          注释

          您表示想了解有关彩色绘画的更多信息,这是我喜欢的一些东西.

          Notes

          You indicated you wanted to know more about color drawing, here are some things I toyed with.

          具有setColorFilterColorMatrixColorFilter的实验:

          textPaint.setColorFilter(new ColorMatrixColorFilter(getColorMatrix5()));//custom 5
          
          //custom 5
          private ColorMatrix getColorMatrix5() 
          {
              ColorMatrix colorMatrix = new ColorMatrix();
              colorMatrix.setSaturation(0);//make it greyscale
              ColorMatrix blueMatrix = new ColorMatrix(new float[] {
                  0, 0, 0, 0, 0, // red
                  0, 0, 0, 0, 0, // green
                  1, 1, 1, 1, 1, // blue
                  1, 1, 1, 1, 1  // alpha
              });
              // Convert, then scale and clamp
              colorMatrix.postConcat(blueMatrix);
              return colorMatrix;
          }//getColorMatrix1
          

          自定义PorterDuff

          听起来您需要Custom PorterDuff.这是一些代码,可让您大致了解如何编写代码(Android使用以C++编写的库).

          Customise PorterDuff

          It sounds like you need a Custom PorterDuff. Here's some code to give you an idea of how to write one (Android uses a library written in C++).

          public class MyPorterDuffMode
          {
          
              public Bitmap applyOverlayMode(Bitmap srcBmp, Bitmap destBmp)
              {
                  int width          = srcBmp.getWidth();
                  int height         = srcBmp.getHeight();
                  int srcPixels[]    = new int[width * height];
                  int destPixels[]   = new int[width * height];
                  int resultPixels[] = new int[width * height];
                  int aS   = 0, rS = 0, gS = 0, bS = 0;
                  int rgbS = 0;
                  int aD   = 0, rD = 0, gD = 0, bD = 0;
                  int rgbD = 0;
          
                  try
                  {
                      srcBmp.getPixels(srcPixels, 0, width, 0, 0, width, height);
                      destBmp.getPixels(destPixels, 0, width, 0, 0, width, height);
                      srcBmp.recycle();
                      destBmp.recycle();
                  }
                  catch(IllegalArgumentException e)
                  {
                  }
                  catch(ArrayIndexOutOfBoundsException e)
                  {
                  }
          
                  for(int y = 0; y < height; y++)
                  {
                      for(int x = 0; x < width; x++)
                      {
                          rgbS = srcPixels[y*width + x];
                          aS = (rgbS >> 24) & 0xff;
                          rS = (rgbS >> 16) & 0xff;
                          gS = (rgbS >>  8) & 0xff;
                          bS = (rgbS      ) & 0xff;
          
                          rgbD = destPixels[y*width + x];
                          aD = ((rgbD >> 24) & 0xff);
                          rD = (rgbD >> 16) & 0xff;
                          gD = (rgbD >>  8) & 0xff;
                          bD = (rgbD      )  & 0xff;
          
                          //overlay-mode
                          rS = overlay_byte(rD, rS, aS, aD);
                          gS = overlay_byte(gD, gS, aS, aD);
                          bS = overlay_byte(bD, bS, aS, aD);
                          aS = aS + aD - Math.round((aS * aD)/255f);
          
                          resultPixels[y*width + x] = ((int)aS << 24) | ((int)rS << 16) | ((int)gS << 8) | (int)bS;
                      }
                  }
                  return Bitmap.createBitmap(resultPixels, width, height, srcBmp.getConfig());
              }
          
              // kOverlay_Mode
              int overlay_byte(int sc, int dc, int sa, int da) 
              {
                  int tmp = sc * (255 - da) + dc * (255 - sa);
                  int rc;
                  if (2 * dc <= da) 
                  {
                      rc = 2 * sc * dc;
                  } 
                  else 
                  {
                      rc = sa * da - 2 * (da - dc) * (sa - sc);
                  }
                  return clamp_div255round(rc + tmp);
              }
          
              int clamp_div255round(int prod) 
              {
                  if (prod <= 0) 
                  {
                      return 0;
                  } 
                  else if (prod >= 255*255) 
                  {
                      return 255;
                  } 
                  else 
                  {
                      return Math.round((float)prod/255);
                  }
              }
          
          }//class MyPorterDuffMode
          

          代码参考

          请参见 PorterDuff ColorFilter ColorMatrix PorterDuffColorFilter Canvas

          See PorterDuff, PorterDuff.Mode,PorterDuffXfermode, ColorFilter,ColorMatrix, ColorMatrixColorFilter, PorterDuffColorFilter, Canvas, Color.

          这篇关于Android Canvas更改形状和文本相交的颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆