Basic tutorial for Android -- 8.3.5 painting API -- Xfermode and PorterDuff (2)
This section introduces:
In the previous section, we learned about Xfermode's two dead (outdated) sons:AvoidXfermode,PixelXorXfermode,
Although it is a bit useful, it is eventually eliminated. In this section, we will learn the three sons who are still healthy in Xfermode:Porterduduxfermode;
First sacrifice the official API documentation: porterduduxfermode! The document contains very little content. We can see its constructor:
There is only one parameter:PorterDuff. ModeMode, while Android provides us with 16 image mixing modes, which is simple.
The two layers are displayed in different modes and can be combined into different results! The following figure shows the results of the 16 mixed sorting modes:
Here are two layers: The first graph isDestination chart (DST)The following figure isSource image (SRC)!
Of course, in the document, we found that the available modes are not 16, but 18, and newADDAndOVERLAYTwo modes!
Well, let's just say that the Code is the most practical. In this section, we will write down the code to verify the 18 modes!
PS: The name of PorterDuff is actually a combination of two people: Tomas Proter and Tom Duff.
It was the first person who proposed the concept of graphical mixing on SIGGRAPH. He was interested in Baidu ~
Write an example to verify the figure above:
Let's write an example to verify the above figure. We can modify different modes to compare and analyze the results!
Code Implementation:
Step 1: Let's write a tool class to get the screen width first!ScreenUtil. java:
/*** Created by Jay on 0023. */public class ScreenUtil {/*** obtain the screen width and height. After sdk17, ** @ param context */public static int [] getScreenHW (Context context) is not recommended) {WindowManager manager = (WindowManager) context. getSystemService (Context. WINDOW_SERVICE); Display display = manager. getdefadisplay display (); int width = display. getWidth (); int height = display. getHeight (); int [] HW = new int [] {width, height}; return HW;}/*** get the screen width and height, we recommend that you use ** @ param context */public static int [] getScreenHW2 (Context context) {WindowManager manager = (WindowManager) context. getSystemService (Context. WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics (); manager. getdefadisplay display (). getMetrics (dm); int width = dm. widthPixels; int height = dm. heightPixels; int [] HW = new int [] {width, height}; return HW ;} /*** get the screen width ** @ param context * @ return */public static int getScreenW (Context context) {return getScreenHW2 (context) [0];} /*** obtain the screen height ** @ param context * @ return */public static int getScreenH (Context context) {return getScreenHW2 (context) [1];}
Step 2: compile our custom View class and test it here!XfermodeView. java:
/*** Created by Jay on 0023. */public class XfermodeView extends View {private porterduxfermode pdXfermode; // defines the porterduxfermode variable // defines the MODE constant. You can directly change it here to test private static PorterDuff. mode PD_MODE = PorterDuff. mode. ADD; private int screenW, screenH; // screen width and height private int width = 200; // the width and height of the image to be drawn. private int height = 200; private Bitmap srcBitmap, dstBitmap; // Bitmap of the Upper-layer SRC and Bitmap of the lower-layer Dst public XfermodeView (Context context) {this (context, null);} public XfermodeView (Context context, AttributeSet attrs) {super (context, attrs); screenW = ScreenUtil. getScreenW (context); screenH = ScreenUtil. getScreenH (context); // create a porterduxfermode object pdXfermode = new porterduxfermode (PD_MODE); // instantiate two Bitmap srcBitmap = makeSrc (width, height); dstBitmap = makeDst (width, width, height);} public XfermodeView (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr );} // define a method to draw a circular Bitmap private 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 (0xFF26AAD1); c. drawOval (new RectF (0, 0, w * 3/4, h * 3/4), p); return bm ;} // define a Bitmap Method for drawing a rectangle. private 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 (0xFFFFCE43); c. drawRect (w/3, h/3, w * 19/20, h * 19/20, p); return bm ;}@ Override protected void onDraw (Canvas canvas) {Paint paint = new Paint (); paint. setFilterBitmap (false); paint. setStyle (Paint. style. FILL); canvas. drawBitmap (srcBitmap, (screenW/3-width)/2, (screenH/2-height)/2, paint); canvas. drawBitmap (dstBitmap, (screenW/3-width)/2 + screenW/3, (screenH/2-height)/2, paint); // create a layer, demonstrate the effect of image mixing on the layer 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 (dstBitmap, (screenW/3-width)/2 + screenW/3*2, (screenH/2-height)/2, paint ); // draw I // set the Xfermode Paint of the paint. setXfermode (pdXfermode); canvas. drawBitmap (srcBitmap, (screenW/3-width)/2 + screenW/3*2, (screenH/2-height)/2, paint); paint. setXfermode (null); // restore the canvas. restoreToCount (SC );}}
The code looks complicated, right? Otherwise, it's nothing more than getting the screen width and height, and then drawing a rectangle and a circle,
Calculate their location, set the layer (fixed writing), set the paint brush setXfermode, and then
It's just drawing on the canvas. What you don't understand may be the calculation of the drawing position. Otherwise, what do you like about the location?
Yes! Next, let's take a look at the solution. You only need to modify it.PD_MODESet the value to different modes!
Run:
1) PorterDuff. Mode. ADD:
Saturation superposition
2) PorterDuff. Mode. CLEAR:
The drawn image will not be submitted to the canvas. Well, the result... I don't know why. Normally there is nothing ..
3) PorterDuff. Mode. DARKEN:
Take all the regions of the two layers, and the color of the intersection is deepened.
4) PorterDuff. Mode. DST:
Only the alpha and color of the target image are retained, so only the target image is drawn.
5) PorterDuff. Mode. DST_ATOP:
Draw the target map at the intersection of the source and target maps, and draw the source map at the intersection
6) PorterDuff. Mode. DST_IN:
Draw the target image in the intersection of the two, and the effect will be affected by the transparency of the original image.
7) PorterDuff. Mode. DST_OUT:
Draw a target chart in different places
8) PorterDuff. Mode. DST_OVER:
The target image is drawn above
9) PorterDuff. Mode. LIGHTEN:
Take all the regions of the two layers and light the intersection color.
10) PorterDuff. Mode. MULTIPLY:
Color after overlapping the intersection of the two layers
11) PorterDuff. Mode. OVERLAY:
Overlay
12) PorterDuff. Mode. SCREEN:
Take all the regions of the two layers, and the intersection area becomes transparent.
13) PorterDuff. Mode. SRC:
Only the alpha and color of the source image are retained, so only the source image is drawn.
14) PorterDuff. Mode. SRC_ATOP:
Draw the source map at the intersection of the source and target maps, and draw the target map at the intersection
15) PorterDuff. Mode. SRC_IN:
Draw a source map where the two are located
16) PorterDuff. Mode. SRC_OUT:
Draw a source map from a non-Intersecting place
17) PorterDuff. Mode. SRC_OVER:
Draw the source image above
18) PorterDuff. Mode. XOR:
Source and target maps are drawn as they are.