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