PorterDuff.java revision c7dacca00828e586ce4496d83a25a4d60a6fb60f
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.graphics;
18
19/**
20 * <p>This class contains the list of alpha compositing and blending modes
21 * that can be passed to {@link PorterDuffXfermode}, a specialized implementation
22 * of {@link Paint}'s {@link Paint#setXfermode(Xfermode) transfer mode}.
23 * All the available modes can be found in the {@link Mode} enum.</p>
24 */
25public class PorterDuff {
26    /**
27     * {@usesMathJax}
28     *
29     * <h3>Porter-Duff</h3>
30     *
31     * <p>The name of the parent class is an homage to the work of Thomas Porter and
32     * Tom Duff, presented in their seminal 1984 paper titled "Compositing Digital Images".
33     * In this paper, the authors describe 12 compositing operators that govern how to
34     * compute the color resulting of the composition of a source (the graphics object
35     * to render) with a destination (the content of the render target).</p>
36     *
37     * <p>"Compositing Digital Images" was published in <em>Computer Graphics</em>
38     * Volume 18, Number 3 dated July 1984.</p>
39     *
40     * <p>Because the work of Porter and Duff focuses solely on the effects of the alpha
41     * channel of the source and destination, the 12 operators described in the original
42     * paper are called alpha compositing modes here.</p>
43     *
44     * <p>For convenience, this class also provides several blending modes, which similarly
45     * define the result of compositing a source and a destination but without being
46     * constrained to the alpha channel. These blending modes are not defined by Porter
47     * and Duff but have been included in this class for convenience purposes.</p>
48     *
49     * <h3>Diagrams</h3>
50     *
51     * <p>All the example diagrams presented below use the same source and destination
52     * images:</p>
53     *
54     * <table summary="Source and Destination" style="background-color: transparent;">
55     *     <tr>
56     *         <td style="border: none; text-align: center;">
57     *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC.png" />
58     *             <figcaption>Source image</figcaption>
59     *         </td>
60     *         <td style="border: none; text-align: center;">
61     *             <img src="{@docRoot}reference/android/images/graphics/composite_DST.png" />
62     *             <figcaption>Destination image</figcaption>
63     *         </td>
64     *     </tr>
65     * </table>
66     *
67     * <p>The order of drawing operations used to generate each diagram is shown in the
68     * following code snippet:</p>
69     *
70     * <pre class="prettyprint">
71     * Paint paint = new Paint();
72     * canvas.drawBitmap(destinationImage, 0, 0, paint);
73     *
74     * PorterDuff.Mode mode = // choose a mode
75     * paint.setXfermode(new PorterDuffXfermode(mode));
76     *
77     * canvas.drawBitmap(sourceImage, 0, 0, paint);
78     * </pre>
79
80     *
81     * <h3>Alpha compositing modes</h3>
82     *
83     * <table summary="Alpha compositing modes" style="background-color: transparent;">
84     *     <tr>
85     *         <td style="border: none; text-align: center;">
86     *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC.png" />
87     *             <figcaption>{@link #SRC Source}</figcaption>
88     *         </td>
89     *         <td style="border: none; text-align: center;">
90     *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC_OVER.png" />
91     *             <figcaption>{@link #SRC_OVER Source Over}</figcaption>
92     *         </td>
93     *         <td style="border: none; text-align: center;">
94     *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC_IN.png" />
95     *             <figcaption>{@link #SRC_IN Source In}</figcaption>
96     *         </td>
97     *         <td style="border: none; text-align: center;">
98     *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC_ATOP.png" />
99     *             <figcaption>{@link #SRC_ATOP Source Atop}</figcaption>
100     *         </td>
101     *     </tr>
102     *     <tr>
103     *         <td style="border: none; text-align: center;">
104     *             <img src="{@docRoot}reference/android/images/graphics/composite_DST.png" />
105     *             <figcaption>{@link #DST Destination}</figcaption>
106     *         </td>
107     *         <td style="border: none; text-align: center;">
108     *             <img src="{@docRoot}reference/android/images/graphics/composite_DST_OVER.png" />
109     *             <figcaption>{@link #DST_OVER Destination Over}</figcaption>
110     *         </td>
111     *         <td style="border: none; text-align: center;">
112     *             <img src="{@docRoot}reference/android/images/graphics/composite_DST_IN.png" />
113     *             <figcaption>{@link #DST_IN Destination In}</figcaption>
114     *         </td>
115     *         <td style="border: none; text-align: center;">
116     *             <img src="{@docRoot}reference/android/images/graphics/composite_DST_ATOP.png" />
117     *             <figcaption>{@link #DST_ATOP Destination Atop}</figcaption>
118     *         </td>
119     *     </tr>
120     *     <tr>
121     *         <td style="border: none; text-align: center;">
122     *             <img src="{@docRoot}reference/android/images/graphics/composite_CLEAR.png" />
123     *             <figcaption>{@link #CLEAR Clear}</figcaption>
124     *         </td>
125     *         <td style="border: none; text-align: center;">
126     *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC_OUT.png" />
127     *             <figcaption>{@link #SRC_OUT Source Out}</figcaption>
128     *         </td>
129     *         <td style="border: none; text-align: center;">
130     *             <img src="{@docRoot}reference/android/images/graphics/composite_DST_OUT.png" />
131     *             <figcaption>{@link #DST_OUT Destination Out}</figcaption>
132     *         </td>
133     *         <td style="border: none; text-align: center;">
134     *             <img src="{@docRoot}reference/android/images/graphics/composite_XOR.png" />
135     *             <figcaption>{@link #XOR Exclusive Or}</figcaption>
136     *         </td>
137     *     </tr>
138     * </table>
139     *
140     * <h3>Blending modes</h3>
141     *
142     * <table summary="Blending modes" style="background-color: transparent;">
143     *     <tr>
144     *         <td style="border: none; text-align: center;">
145     *             <img src="{@docRoot}reference/android/images/graphics/composite_DARKEN.png" />
146     *             <figcaption>{@link #DARKEN Darken}</figcaption>
147     *         </td>
148     *         <td style="border: none; text-align: center;">
149     *             <img src="{@docRoot}reference/android/images/graphics/composite_LIGHTEN.png" />
150     *             <figcaption>{@link #LIGHTEN Lighten}</figcaption>
151     *         </td>
152     *         <td style="border: none; text-align: center;">
153     *             <img src="{@docRoot}reference/android/images/graphics/composite_MULTIPLY.png" />
154     *             <figcaption>{@link #MULTIPLY Multiply}</figcaption>
155     *         </td>
156     *     </tr>
157     *     <tr>
158     *         <td style="border: none; text-align: center;">
159     *             <img src="{@docRoot}reference/android/images/graphics/composite_SCREEN.png" />
160     *             <figcaption>{@link #SCREEN Screen}</figcaption>
161     *         </td>
162     *         <td style="border: none; text-align: center;">
163     *             <img src="{@docRoot}reference/android/images/graphics/composite_OVERLAY.png" />
164     *             <figcaption>{@link #OVERLAY Overlay}</figcaption>
165     *         </td>
166     *     </tr>
167     * </table>
168     *
169     * <h3>Compositing equations</h3>
170     *
171     * <p>The documentation of each individual alpha compositing or blending mode below
172     * provides the exact equation used to compute alpha and color value of the result
173     * of the composition of a source and destination.</p>
174     *
175     * <p>The result (or output) alpha value is noted \(\alpha_{out}\). The result (or output)
176     * color value is noted \(C_{out}\).</p>
177     */
178    public enum Mode {
179        // these value must match their native equivalents. See SkXfermode.h
180        /**
181         * <p>
182         *     <img src="{@docRoot}reference/android/images/graphics/composite_CLEAR.png" />
183         *     <figcaption>Destination pixels covered by the source are cleared to 0.</figcaption>
184         * </p>
185         * <p>\(\alpha_{out} = 0\)</p>
186         * <p>\(C_{out} = 0\)</p>
187         */
188        CLEAR       (0),
189        /**
190         * <p>
191         *     <img src="{@docRoot}reference/android/images/graphics/composite_SRC.png" />
192         *     <figcaption>The source pixels replace the destination pixels.</figcaption>
193         * </p>
194         * <p>\(\alpha_{out} = \alpha_{src}\)</p>
195         * <p>\(C_{out} = C_{src}\)</p>
196         */
197        SRC         (1),
198        /**
199         * <p>
200         *     <img src="{@docRoot}reference/android/images/graphics/composite_DST.png" />
201         *     <figcaption>The source pixels are discarded, leaving the destination intact.</figcaption>
202         * </p>
203         * <p>\(\alpha_{out} = \alpha_{dst}\)</p>
204         * <p>\(C_{out} = C_{dst}\)</p>
205         */
206        DST         (2),
207        /**
208         * <p>
209         *     <img src="{@docRoot}reference/android/images/graphics/composite_SRC_OVER.png" />
210         *     <figcaption>The source pixels are drawn over the destination pixels.</figcaption>
211         * </p>
212         * <p>\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)</p>
213         * <p>\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
214         */
215        SRC_OVER    (3),
216        /**
217         * <p>
218         *     <img src="{@docRoot}reference/android/images/graphics/composite_DST_OVER.png" />
219         *     <figcaption>The source pixels are drawn behind the destination pixels.</figcaption>
220         * </p>
221         * <p>\(\alpha_{out} = \alpha_{dst} + (1 - \alpha_{dst}) * \alpha_{src}\)</p>
222         * <p>\(C_{out} = C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p>
223         */
224        DST_OVER    (4),
225        /**
226         * <p>
227         *     <img src="{@docRoot}reference/android/images/graphics/composite_SRC_IN.png" />
228         *     <figcaption>Keeps the source pixels that cover the destination pixels,
229         *     discards the remaining source and destination pixels.</figcaption>
230         * </p>
231         * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
232         * <p>\(C_{out} = C_{src} * \alpha_{dst}\)</p>
233         */
234        SRC_IN      (5),
235        /**
236         * <p>
237         *     <img src="{@docRoot}reference/android/images/graphics/composite_DST_IN.png" />
238         *     <figcaption>Keeps the destination pixels that cover source pixels,
239         *     discards the remaining source and destination pixels.</figcaption>
240         * </p>
241         * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
242         * <p>\(C_{out} = C_{dst} * \alpha_{src}\)</p>
243         */
244        DST_IN      (6),
245        /**
246         * <p>
247         *     <img src="{@docRoot}reference/android/images/graphics/composite_SRC_OUT.png" />
248         *     <figcaption>Keeps the source pixels that do not cover destination pixels.
249         *     Discards source pixels that cover destination pixels. Discards all
250         *     destination pixels.</figcaption>
251         * </p>
252         * <p>\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src}\)</p>
253         * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src}\)</p>
254         */
255        SRC_OUT     (7),
256        /**
257         * <p>
258         *     <img src="{@docRoot}reference/android/images/graphics/composite_DST_OUT.png" />
259         *     <figcaption>Keeps the destination pixels that are not covered by source pixels.
260         *     Discards destination pixels that are covered by source pixels. Discards all
261         *     source pixels.</figcaption>
262         * </p>
263         * <p>\(\alpha_{out} = (1 - \alpha_{src}) * \alpha_{dst}\)</p>
264         * <p>\(C_{out} = (1 - \alpha_{src}) * C_{dst}\)</p>
265         */
266        DST_OUT     (8),
267        /**
268         * <p>
269         *     <img src="{@docRoot}reference/android/images/graphics/composite_SRC_ATOP.png" />
270         *     <figcaption>Discards the source pixels that do not cover destination pixels.
271         *     Draws remaining source pixels over destination pixels.</figcaption>
272         * </p>
273         * <p>\(\alpha_{out} = \alpha_{dst}\)</p>
274         * <p>\(C_{out} = \alpha_{dst} * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
275         */
276        SRC_ATOP    (9),
277        /**
278         * <p>
279         *     <img src="{@docRoot}reference/android/images/graphics/composite_DST_ATOP.png" />
280         *     <figcaption>Discards the destination pixels that are not covered by source pixels.
281         *     Draws remaining destination pixels over source pixels.</figcaption>
282         * </p>
283         * <p>\(\alpha_{out} = \alpha_{src}\)</p>
284         * <p>\(C_{out} = \alpha_{src} * C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p>
285         */
286        DST_ATOP    (10),
287        /**
288         * <p>
289         *     <img src="{@docRoot}reference/android/images/graphics/composite_XOR.png" />
290         *     <figcaption>Discards the source and destination pixels where source pixels
291         *     cover destination pixels. Draws remaining source pixels.</figcaption>
292         * </p>
293         * <p>\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)</p>
294         * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
295         */
296        XOR         (11),
297        /**
298         * <p>
299         *     <img src="{@docRoot}reference/android/images/graphics/composite_DARKEN.png" />
300         *     <figcaption>Retains the smallest component of the source and
301         *     destination pixels.</figcaption>
302         * </p>
303         * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
304         * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + min(C_{src}, C_{dst})\)</p>
305         */
306        DARKEN      (16),
307        /**
308         * <p>
309         *     <img src="{@docRoot}reference/android/images/graphics/composite_LIGHTEN.png" />
310         *     <figcaption>Retains the largest component of the source and
311         *     destination pixel.</figcaption>
312         * </p>
313         * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
314         * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + max(C_{src}, C_{dst})\)</p>
315         */
316        LIGHTEN     (17),
317        /**
318         * <p>
319         *     <img src="{@docRoot}reference/android/images/graphics/composite_MULTIPLY.png" />
320         *     <figcaption>Multiplies the source and destination pixels.</figcaption>
321         * </p>
322         * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
323         * <p>\(C_{out} = C_{src} * C_{dst}\)</p>
324         */
325        MULTIPLY    (13),
326        /**
327         * <p>
328         *     <img src="{@docRoot}reference/android/images/graphics/composite_SCREEN.png" />
329         *     <figcaption>Adds the source and destination pixels, then subtracts the
330         *     source pixels multiplied by the destination.</figcaption>
331         * </p>
332         * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
333         * <p>\(C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst}\)</p>
334         */
335        SCREEN      (14),
336        /**
337         * <p>
338         *     <img src="{@docRoot}reference/android/images/graphics/composite_ADD.png" />
339         *     <figcaption>Adds the source pixels to the destination pixels and saturates
340         *     the result.</figcaption>
341         * </p>
342         * <p>\(\alpha_{out} = max(0, min(\alpha_{src} + \alpha_{dst}, 1))\)</p>
343         * <p>\(C_{out} = max(0, min(C_{src} + C_{dst}, 1))\)</p>
344         */
345        ADD         (12),
346        /**
347         * <p>
348         *     <img src="{@docRoot}reference/android/images/graphics/composite_OVERLAY.png" />
349         *     <figcaption>Multiplies or screens the source and destination depending on the
350         *     destination color.</figcaption>
351         * </p>
352         * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
353         * <p>\(\begin{equation}
354         * C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\
355         * \alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) & otherwise \end{cases}
356         * \end{equation}\)</p>
357         */
358        OVERLAY     (15);
359
360        Mode(int nativeInt) {
361            this.nativeInt = nativeInt;
362        }
363
364        /**
365         * @hide
366         */
367        public final int nativeInt;
368    }
369
370    /**
371     * @hide
372     */
373    public static int modeToInt(Mode mode) {
374        return mode.nativeInt;
375    }
376
377    /**
378     * @hide
379     */
380    public static Mode intToMode(int val) {
381        switch (val) {
382            default:
383            case  0: return Mode.CLEAR;
384            case  1: return Mode.SRC;
385            case  2: return Mode.DST;
386            case  3: return Mode.SRC_OVER;
387            case  4: return Mode.DST_OVER;
388            case  5: return Mode.SRC_IN;
389            case  6: return Mode.DST_IN;
390            case  7: return Mode.SRC_OUT;
391            case  8: return Mode.DST_OUT;
392            case  9: return Mode.SRC_ATOP;
393            case 10: return Mode.DST_ATOP;
394            case 11: return Mode.XOR;
395            case 16: return Mode.DARKEN;
396            case 17: return Mode.LIGHTEN;
397            case 13: return Mode.MULTIPLY;
398            case 14: return Mode.SCREEN;
399            case 12: return Mode.ADD;
400            case 15: return Mode.OVERLAY;
401        }
402    }
403}
404