Lesson 154. Drawing. PorterDuff.Mode, PorterDuffXfermode

Lesson 154. Drawing. PorterDuff.Mode, PorterDuffXfermode


In this lesson:

– parse PorterDuff modes using PorterDuffXfermode

This lesson will be about colors in the chart again. PorterDuff modes allow us to get different results when applying one image to another. That is, the values ​​of color and transparency of both images are taken and, according to a certain algorithm, the final values ​​are calculated.

For example, I took the picture from here.

Here are the main PorterDuff modes. Let’s create an example that will show us similar results.

Let’s create a project:

Project name: P1541_PorterDuff
Build Target: Android 4.4
Application name: PorterDuff
Package name: ru.startandroid.develop.p1541porterduff
Create Activity: MainActivity

MainActivity.java:

package ru.startandroid.develop.p1541porterduff;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new DrawView(this));
  }

  class DrawView extends View {

    Paint paintSrc;
    Paint paintDst;
    Paint paintBorder;

    Path pathSrc;
    Path pathDst;

    Bitmap bitmapSrc;
    Bitmap bitmapDst;

    // PorterDuff режим
    PorterDuff.Mode mode = PorterDuff.Mode.SRC;
    
    int colorDst = Color.BLUE;
    int colorSrc = Color.YELLOW;

    public DrawView(Context context) {
      super(context);

      // необходимо для корректной работы
      if (android.os.Build.VERSION.SDK_INT >= 11) {
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
      }

      // DST фигура 
      pathDst = new Path();
      pathDst.moveTo(0, 0);
      pathDst.lineTo(500, 0);
      pathDst.lineTo(500, 500);
      pathDst.close();

      // создание DST bitmap
      bitmapDst = createBitmap(pathDst, colorDst);
      
      // кисть для вывода DST bitmap
      paintDst = new Paint();

      // SRC фигура 
      pathSrc = new Path();
      pathSrc.moveTo(0, 0);
      pathSrc.lineTo(500, 0);
      pathSrc.lineTo(0, 500);
      pathSrc.close();

      // создание SRC bitmap      
      bitmapSrc = createBitmap(pathSrc, colorSrc);

      // кисть для вывода SRC bitmap      
      paintSrc = new Paint();
      paintSrc.setXfermode(new PorterDuffXfermode(mode));

      // кисть для рамки
      paintBorder = new Paint();
      paintBorder.setStyle(Paint.Style.STROKE);
      paintBorder.setStrokeWidth(3);
      paintBorder.setColor(Color.BLACK);
    }

    private Bitmap createBitmap(Path path, int color) {
      // создание bitmap и канвы для него
      Bitmap bitmap = Bitmap.createBitmap(500, 500,
          Bitmap.Config.ARGB_8888);
      Canvas bitmapCanvas = new Canvas(bitmap);

      // создание кисти нужного цвета
      Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
      paint.setStyle(Paint.Style.FILL_AND_STROKE);
      paint.setColor(color);

      // рисование фигуры на канве bitmap
      bitmapCanvas.drawPath(path, paint);
      
      return bitmap;
    }

    @Override
    protected void onDraw(Canvas canvas) {
      canvas.translate(390, 80);
      
      // DST bitmap
      canvas.drawBitmap(bitmapDst, 0, 0, paintDst);

      // SRC bitmap
      canvas.drawBitmap(bitmapSrc, 0, 0, paintSrc);
      
      // рамка
      canvas.drawRect(0, 0, 500, 500, paintBorder);

    }
  }
}

We will have two pictures. One with blue triangle (DST), the other with yellow (SRC). In the constructor DrawView we create the pathDst triangle, and using it and the blue color we create bitmapDst. Similarly, we create the pathSrc triangle, and with it we create bitmapSrc in yellow.

We will use paintDst brush to draw a bitmapDst picture, and paintSrc to bitmapSrc. And for the paintSrc brush, we call the setXfermode method, in which we pass an object with mode = PorterDuff.Mode.SRC mode to PorterDuffXfermode. Next, we will change the value of the mode variable and look at the result.

The paintBorder brush will simply draw a black frame.

In the method createBitmap create a Bitmap 500×500 in size, create a personal canvas for him and draw the path obtained with the specified color.

In the method onDraw draw bitmapDst, then bitmapSrc. And for clarity, we draw a black frame.

That is, we draw a bitmapDst (DST) image, and a bitmapSrc (SRC) over it. To draw bitmapSrc, we use a paintSrc brush with PorterDuff mode, so it will not be just an overlay of one image to another, but certain algorithms will be used to get the result.

run the program

In SRC mode the result will be:

only the SRC image is displayed, ie bitmapSrc

Now we will change the code of the mode variable and get the following results:

DST

only the DST image is displayed, ie bitmapDst

CLEAR

Nothing is displayed

SRC_OVER

The SRC is displayed above the DST

DST_OVER

DST is displayed above the SRC

SRC_IN

the part of the SRC that intersects with the DST is displayed

DST_IN

displays the portion of the DST that intersects the SRC

SRC_OUT

a portion of the SRC that does not intersect with the DST is displayed

DST_OUT

a portion of the DST that does not intersect with the SRC is displayed

SRC_ATOP

DST is displayed, and a portion of the SRC intersecting DST over it

DST_ATOP

the SRC is displayed and the portion of the DST that intersects the SRC

XOR

SRC + DST is displayed without crossing them

ADD

For this mode, we change colors so that a clearer example comes out:

    int colorDst = Color.RED;
    int colorSrc = Color.GREEN;

Adding colors. Red + green when added gave yellow.

We have considered the modes in the simplest cases when alpha = 1. But if we change the value of alpha, the result will be different. Note the list of modes. Calculations formulas are shown on the right for each mode. These are two comma-separated formulas. It calculates two values: the transparency value and the color value. The formulas use the following parameters:

Yes – alpha DST
Dc – DST color
With – alpha src
Sc – SRC color

That is, using the color and transparency values ​​of the SRC and DST image points, the system calculates the color and transparency values ​​of the resulting image points.

Consider one example and manually calculate these values ​​to make the mechanism clear. Take DST_OUT mode as an example. For him formulas will be as follows: [Da * (1 – Sa), Dc * (1 – Sa)].

For past examples, we used yellow and blue. Let’s change them a bit by adding transparency:

    int colorDst = Color.argb(170, 0, 0, 255);
    int colorSrc = Color.argb(85, 255, 255, 0);

For blue (DST) we set alpha level 170 and for yellow (SRC) – 85.

Mode set DST_OUT:

   PorterDuff.Mode mode = PorterDuff.Mode.DST_OUT;

Run the program, see the picture

We see differences from DST_OUT, which we had earlier. This is because of transparency.

The system applies the calculation formulas pixel-wide. That is, for each pixel, it takes the values ​​Da, Dc, Sa, Sc and uses the PorterDuff mode formula to get the overlay result. We have the same color images and consist of a set of identical pixels, SRC – in yellow, DST – in blue. Therefore, we do not need to count pixels, we can divide all the images into 4 regions, which will differ in the set of values ​​of Da, Dc, Sa, Sc.

Areas will be as follows:

1) SRC area without intersection with DST

2) the intersection region of the SRC with DST

3) DST area without intersection with SRC

4) area beyond SRC and DST

I have shown these areas in the picture

Let’s determine the color and alpha values ​​for these areas.

I will recall the SRC and DST images for clarity

SRC

DST

We use the values ​​colorDst (170, 0, 0, 255) and colorSrc (85, 255, 255, 0).

Da = 170, Dc = (0,0,255) – parameter values ​​for DST

Sa = 80, Sc = (255,255,0) – parameter values ​​for SRC

I will make a small indentation. In formulas we will bring the values ​​in the range from 0 to 255 to the range from 0 to 1. That is, for example, 170 would be 170/255, ie 2/3. And 85 will be 85/255, that is 1/3. Zero remains zero. Well, 255 will be equal to 1.

That is, we get

Yes = 2/3, Dc = (0,0,1)

Sa = 1/3, Sc = (1,1,0)

So, we define the parameters for the areas:

1) Yes = 0, Dc = (0,0,0), Sa = 1/3, Sc = (1,1,0)

Only SRC is in this area. And DST is here by zeros.

2) Yes = 2/3, Dc = (0,0,1), Sa = 1/3, Sc = (1,1,0)

In this area, both images are present

3) Yes = 2/3, Dc = (0,0,1), Sa = 0, Sc = (0,0,0)

Only DST is in this area. And SRC – by zeros.

4) Yes = 0, Dc = (0,0,0), Sa = 0, Sc = (0,0,0)

In this area, both images are missing.

Now we take formulas

Ta = Yes * (1 – Sa)

Tc = Dc * (1 – Sa)

and we begin to consider for each zone Ta (final alpha value) and Tc (final color value)

1)

Yes = 0, Dc = (0,0,0), Sa = 1/3, Sc = (1,1,0)

Ta = Yes * (1 – Sa) = 0 * (1 – 1/3) = 0 * 2/3 = 0

Tc = Dc * (1 – Sa) = (0,0,0) * (1 – 1/3) = (0,0,0) * 2/3 = (0,0,0)

That is, both alpha and color are zero. The total ARGB will be (0,0,0,0)

2)

Yes = 2/3, Dc = (0,0,1), Sa = 1/3, Sc = (1,1,0)

Ta = Yes * (1 – Sa) = 2/3 * (1 – 1/3) = 2/3 * 2/3 = 4/9

Tc = Dc * (1 – Sa) = (0,0,1) * (1 – 1/3) = (0,0,1) * 2/3 = (0,0,2 / 3)

Returning to the range 0-255, we get

4/9 = 4/9 * 255 = 113

(0,0,2 / 3) = (0,0,170)

The total ARGB will be (113,0,0,170)

3)

Yes = 2/3, Dc = (0,0,1), Sa = 0, Sc = (0,0,0)

Ta = Yes * (1 – Sa) = 2/3 * (1 – 0) = 2/3

Tc = Dc * (1 – Sa) = (0,0,1) * (1 – 0) = (0,0,1)

The total ARGB will be (170,0,0,255)

4)

Yes = 0, Dc = (0,0,0), Sa = 0, Sc = (0,0,0)

Ta = Yes * (1 – Sa) = 0 * (1 – 0) = 0

Tc = Dc * (1 – Sa) = (0,0,0) * (1 – 0) = (0,0,0)

The total ARGB will be (0,0,0,0)

That is, we got this picture

Try drawing simple shapes near the edge of the canvas with the resulting color values ​​to make sure everything is correct and the colors in the image match the values ​​we calculated.

We have a few more unexplored PorterDuff modes, which we will cover in the next lesson.

In the next lesson:

– we use PorterDuffColorFilter




Discuss in the forum [2 replies]

Leave a Comment