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