diff --git a/api/current.txt b/api/current.txt index 9b02574ef7155..5074ab299323b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -12541,6 +12541,7 @@ package android.graphics { field public int inTargetDensity; field public byte[] inTempStorage; field public deprecated boolean mCancel; + field public android.graphics.ColorSpace outColorSpace; field public android.graphics.Bitmap.Config outConfig; field public int outHeight; field public java.lang.String outMimeType; diff --git a/api/system-current.txt b/api/system-current.txt index 381ecbec13a39..9120e55fe35ae 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -13271,6 +13271,7 @@ package android.graphics { field public int inTargetDensity; field public byte[] inTempStorage; field public deprecated boolean mCancel; + field public android.graphics.ColorSpace outColorSpace; field public android.graphics.Bitmap.Config outConfig; field public int outHeight; field public java.lang.String outMimeType; diff --git a/api/test-current.txt b/api/test-current.txt index 374693573b0ba..06a1221027d08 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -12591,6 +12591,7 @@ package android.graphics { field public int inTargetDensity; field public byte[] inTempStorage; field public deprecated boolean mCancel; + field public android.graphics.ColorSpace outColorSpace; field public android.graphics.Bitmap.Config outConfig; field public int outHeight; field public java.lang.String outMimeType; diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index e64a57447e6b5..3dc1be6a26e33 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -39,6 +39,7 @@ jfieldID gOptions_widthFieldID; jfieldID gOptions_heightFieldID; jfieldID gOptions_mimeFieldID; jfieldID gOptions_outConfigFieldID; +jfieldID gOptions_outColorSpaceFieldID; jfieldID gOptions_mCancelID; jfieldID gOptions_bitmapFieldID; @@ -50,6 +51,20 @@ jmethodID gInsetStruct_constructorMethodID; jclass gBitmapConfig_class; jmethodID gBitmapConfig_nativeToConfigMethodID; +jclass gColorSpace_class; +jmethodID gColorSpace_getMethodID; +jmethodID gColorSpace_matchMethodID; + +jclass gColorSpaceRGB_class; +jmethodID gColorSpaceRGB_constructorMethodID; + +jclass gColorSpace_Named_class; +jfieldID gColorSpace_Named_sRGBFieldID; +jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID; + +jclass gTransferParameters_class; +jmethodID gTransferParameters_constructorMethodID; + using namespace android; jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format) { @@ -228,6 +243,70 @@ static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize, needsFineScale(fullSize.height(), decodedSize.height(), sampleSize); } +static jobject getColorSpace(JNIEnv* env, + sk_sp& decodeColorSpace, SkColorType decodeColorType) { + jobject colorSpace = nullptr; + + // No need to match, we know what the output color space will be + if (decodeColorType == kRGBA_F16_SkColorType) { + jobject linearExtendedSRGB = env->GetStaticObjectField( + gColorSpace_Named_class, gColorSpace_Named_LinearExtendedSRGBFieldID); + colorSpace = env->CallStaticObjectMethod(gColorSpace_class, + gColorSpace_getMethodID, linearExtendedSRGB); + } else { + // Same here, no need to match + if (decodeColorSpace->isSRGB()) { + jobject sRGB = env->GetStaticObjectField( + gColorSpace_Named_class, gColorSpace_Named_sRGBFieldID); + colorSpace = env->CallStaticObjectMethod(gColorSpace_class, + gColorSpace_getMethodID, sRGB); + } else if (decodeColorSpace.get() != nullptr) { + // Try to match against known RGB color spaces using the CIE XYZ D50 + // conversion matrix and numerical transfer function parameters + SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor); + LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix)); + + SkColorSpaceTransferFn transferParams; + // We can only handle numerical transfer functions at the moment + LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams)); + + jobject params = env->NewObject(gTransferParameters_class, + gTransferParameters_constructorMethodID, + transferParams.fA, transferParams.fB, transferParams.fC, + transferParams.fD, transferParams.fE, transferParams.fF, + transferParams.fG); + + jfloatArray xyzArray = env->NewFloatArray(9); + jfloat xyz[9] = { + xyzMatrix.getFloat(0, 0), + xyzMatrix.getFloat(1, 0), + xyzMatrix.getFloat(2, 0), + xyzMatrix.getFloat(0, 1), + xyzMatrix.getFloat(1, 1), + xyzMatrix.getFloat(2, 1), + xyzMatrix.getFloat(0, 2), + xyzMatrix.getFloat(1, 2), + xyzMatrix.getFloat(2, 2) + }; + env->SetFloatArrayRegion(xyzArray, 0, 9, xyz); + + colorSpace = env->CallStaticObjectMethod(gColorSpace_class, + gColorSpace_matchMethodID, xyzArray, params); + + if (colorSpace == nullptr) { + // We couldn't find an exact match, let's create a new color space + // instance with the 3x3 conversion matrix and transfer function + colorSpace = env->NewObject(gColorSpaceRGB_class, + gColorSpaceRGB_constructorMethodID, + env->NewStringUTF("Unknown"), xyzArray, params); + } + + env->DeleteLocalRef(xyzArray); + } + } + return colorSpace; +} + static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) { // This function takes ownership of the input stream. Since the SkAndroidCodec // will take ownership of the stream, we don't necessarily need to take ownership @@ -263,6 +342,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding env->SetIntField(options, gOptions_heightFieldID, -1); env->SetObjectField(options, gOptions_mimeFieldID, 0); env->SetObjectField(options, gOptions_outConfigFieldID, 0); + env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0); jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig); @@ -319,6 +399,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding // Set the decode colorType SkColorType decodeColorType = codec->computeOutputColorType(prefColorType); + sk_sp decodeColorSpace = codec->computeOutputColorSpace(decodeColorType); // Set the options and return if the client only wants the size. if (options != NULL) { @@ -345,6 +426,9 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding gBitmapConfig_nativeToConfigMethodID, configID); env->SetObjectField(options, gOptions_outConfigFieldID, config); + env->SetObjectField(options, gOptions_outColorSpaceFieldID, + getColorSpace(env, decodeColorSpace, decodeColorType)); + if (onlyDecodeSize) { return nullptr; } @@ -412,7 +496,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied); const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), - decodeColorType, alphaType, codec->computeOutputColorSpace(decodeColorType)); + decodeColorType, alphaType, decodeColorSpace); // For wide gamut images, we will leave the color space on the SkBitmap. Otherwise, // use the default. @@ -725,6 +809,8 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_mimeFieldID = GetFieldIDOrDie(env, options_class, "outMimeType", "Ljava/lang/String;"); gOptions_outConfigFieldID = GetFieldIDOrDie(env, options_class, "outConfig", "Landroid/graphics/Bitmap$Config;"); + gOptions_outColorSpaceFieldID = GetFieldIDOrDie(env, options_class, "outColorSpace", + "Landroid/graphics/ColorSpace;"); gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z"); jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap"); @@ -741,6 +827,29 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gBitmapConfig_nativeToConfigMethodID = GetStaticMethodIDOrDie(env, gBitmapConfig_class, "nativeToConfig", "(I)Landroid/graphics/Bitmap$Config;"); + gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace")); + gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, + "get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;"); + gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match", + "([FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/ColorSpace;"); + + gColorSpaceRGB_class = MakeGlobalRefOrDie(env, + FindClassOrDie(env, "android/graphics/ColorSpace$Rgb")); + gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class, + "", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V"); + + gColorSpace_Named_class = MakeGlobalRefOrDie(env, + FindClassOrDie(env, "android/graphics/ColorSpace$Named")); + gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env, + gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;"); + gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env, + gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;"); + + gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, + "android/graphics/ColorSpace$Rgb$TransferParameters")); + gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class, + "", "(DDDDDDD)V"); + return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory", gMethods, NELEM(gMethods)); } diff --git a/docs/html/reference/images/graphics/composite_ADD.png b/docs/html/reference/images/graphics/composite_ADD.png new file mode 100644 index 0000000000000..90932c55ac530 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_ADD.png differ diff --git a/docs/html/reference/images/graphics/composite_CLEAR.png b/docs/html/reference/images/graphics/composite_CLEAR.png new file mode 100644 index 0000000000000..7c0731d43a5f4 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_CLEAR.png differ diff --git a/docs/html/reference/images/graphics/composite_DARKEN.png b/docs/html/reference/images/graphics/composite_DARKEN.png new file mode 100644 index 0000000000000..a798b97da588d Binary files /dev/null and b/docs/html/reference/images/graphics/composite_DARKEN.png differ diff --git a/docs/html/reference/images/graphics/composite_DST.png b/docs/html/reference/images/graphics/composite_DST.png new file mode 100644 index 0000000000000..6dde48f87189b Binary files /dev/null and b/docs/html/reference/images/graphics/composite_DST.png differ diff --git a/docs/html/reference/images/graphics/composite_DST_ATOP.png b/docs/html/reference/images/graphics/composite_DST_ATOP.png new file mode 100644 index 0000000000000..c6767bd5c6310 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_DST_ATOP.png differ diff --git a/docs/html/reference/images/graphics/composite_DST_IN.png b/docs/html/reference/images/graphics/composite_DST_IN.png new file mode 100644 index 0000000000000..cf50a7b068b5e Binary files /dev/null and b/docs/html/reference/images/graphics/composite_DST_IN.png differ diff --git a/docs/html/reference/images/graphics/composite_DST_OUT.png b/docs/html/reference/images/graphics/composite_DST_OUT.png new file mode 100644 index 0000000000000..ee8a46e0c2c20 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_DST_OUT.png differ diff --git a/docs/html/reference/images/graphics/composite_DST_OVER.png b/docs/html/reference/images/graphics/composite_DST_OVER.png new file mode 100644 index 0000000000000..18389723903b5 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_DST_OVER.png differ diff --git a/docs/html/reference/images/graphics/composite_LIGHTEN.png b/docs/html/reference/images/graphics/composite_LIGHTEN.png new file mode 100644 index 0000000000000..8fc0a1054fa3c Binary files /dev/null and b/docs/html/reference/images/graphics/composite_LIGHTEN.png differ diff --git a/docs/html/reference/images/graphics/composite_MULTIPLY.png b/docs/html/reference/images/graphics/composite_MULTIPLY.png new file mode 100644 index 0000000000000..8816ab09ab5f2 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_MULTIPLY.png differ diff --git a/docs/html/reference/images/graphics/composite_OVERLAY.png b/docs/html/reference/images/graphics/composite_OVERLAY.png new file mode 100644 index 0000000000000..700a6b29fa54d Binary files /dev/null and b/docs/html/reference/images/graphics/composite_OVERLAY.png differ diff --git a/docs/html/reference/images/graphics/composite_SCREEN.png b/docs/html/reference/images/graphics/composite_SCREEN.png new file mode 100644 index 0000000000000..b698819615e7f Binary files /dev/null and b/docs/html/reference/images/graphics/composite_SCREEN.png differ diff --git a/docs/html/reference/images/graphics/composite_SRC.png b/docs/html/reference/images/graphics/composite_SRC.png new file mode 100644 index 0000000000000..2d70a54ad807e Binary files /dev/null and b/docs/html/reference/images/graphics/composite_SRC.png differ diff --git a/docs/html/reference/images/graphics/composite_SRC_ATOP.png b/docs/html/reference/images/graphics/composite_SRC_ATOP.png new file mode 100644 index 0000000000000..111869e2d2f17 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_SRC_ATOP.png differ diff --git a/docs/html/reference/images/graphics/composite_SRC_IN.png b/docs/html/reference/images/graphics/composite_SRC_IN.png new file mode 100644 index 0000000000000..1d6145b88f093 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_SRC_IN.png differ diff --git a/docs/html/reference/images/graphics/composite_SRC_OUT.png b/docs/html/reference/images/graphics/composite_SRC_OUT.png new file mode 100644 index 0000000000000..39c0c1707d158 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_SRC_OUT.png differ diff --git a/docs/html/reference/images/graphics/composite_SRC_OVER.png b/docs/html/reference/images/graphics/composite_SRC_OVER.png new file mode 100644 index 0000000000000..1489487d2df90 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_SRC_OVER.png differ diff --git a/docs/html/reference/images/graphics/composite_XOR.png b/docs/html/reference/images/graphics/composite_XOR.png new file mode 100644 index 0000000000000..6d0c5ba147624 Binary files /dev/null and b/docs/html/reference/images/graphics/composite_XOR.png differ diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index a3c6c6edb3ada..ceedc1fdb3609 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -360,6 +360,15 @@ public class BitmapFactory { */ public Bitmap.Config outConfig; + /** + * If known, the color space the decoded bitmap will have. Note that the + * output color space is not guaranteed to be the color space the bitmap + * is encoded with. If not known (when the config is + * {@link Bitmap.Config#ALPHA_8} for instance), or there is an error, + * it is set to null. + */ + public ColorSpace outColorSpace; + /** * Temp storage to use for decoding. Suggest 16K or so. */ diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 929ac22f2960a..e03dcf34a40c1 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -143,7 +143,7 @@ import java.util.function.DoubleUnaryOperator; * .render(); * *

- * + * *

DCI-P3 vs ProPhoto RGB
*

* @@ -281,7 +281,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

sRGB
*

*/ @@ -308,7 +308,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

sRGB
*

*/ @@ -347,7 +347,7 @@ public abstract class ColorSpace { * Range\([-0.799..2.399[\) * *

- * + * *

Extended sRGB (orange) vs sRGB (white)
*

*/ @@ -374,7 +374,7 @@ public abstract class ColorSpace { * Range\([-0.5..7.499[\) * *

- * + * *

Extended sRGB (orange) vs sRGB (white)
*

*/ @@ -409,7 +409,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

BT.709
*

*/ @@ -444,7 +444,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

BT.2020 (orange) vs sRGB (white)
*

*/ @@ -471,7 +471,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

DCI-P3 (orange) vs sRGB (white)
*

*/ @@ -506,7 +506,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

Display P3 (orange) vs sRGB (white)
*

*/ @@ -541,7 +541,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

NTSC 1953 (orange) vs sRGB (white)
*

*/ @@ -576,7 +576,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

SMPTE-C (orange) vs sRGB (white)
*

*/ @@ -603,7 +603,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

Adobe RGB (orange) vs sRGB (white)
*

*/ @@ -638,7 +638,7 @@ public abstract class ColorSpace { * Range\([0..1]\) * *

- * + * *

ProPhoto RGB (orange) vs sRGB (white)
*

*/ @@ -665,7 +665,7 @@ public abstract class ColorSpace { * Range\([-65504.0, 65504.0]\) * *

- * + * *

ACES (orange) vs sRGB (white)
*

*/ @@ -692,7 +692,7 @@ public abstract class ColorSpace { * Range\([-65504.0, 65504.0]\) * *

- * + * *

ACEScg (orange) vs sRGB (white)
*

*/ @@ -1931,7 +1931,7 @@ public abstract class ColorSpace { * are internally converted to xyY.

* *

- * + * *

sRGB primaries and white point
*

* @@ -1989,7 +1989,7 @@ public abstract class ColorSpace { * the range \([-65504, 65504]\).

* *

- * + * *

Extended sRGB and its large range
*

* @@ -3703,7 +3703,7 @@ public abstract class ColorSpace { * .render(); * *

- * + * *

sRGB vs DCI-P3
*

* @@ -3746,7 +3746,7 @@ public abstract class ColorSpace { * .render(); * *

- * + * *

Clipping disabled
*

* @@ -3759,7 +3759,7 @@ public abstract class ColorSpace { * .render(); * *

- * + * *

Clipping enabled
*

* @@ -3789,7 +3789,7 @@ public abstract class ColorSpace { * .render(); * *

- * + * *

CIE 1976 UCS diagram
*

* @@ -3847,7 +3847,7 @@ public abstract class ColorSpace { * .render(); * *

- * + * *

sRGB vs DCI-P3
*

* @@ -3863,7 +3863,7 @@ public abstract class ColorSpace { * .render(); * *

- * + * *

sRGB, DCI-P3, ACES and scRGB
*

* @@ -3901,7 +3901,7 @@ public abstract class ColorSpace { * .render(); * *

- * + * *

* Locating colors on the chromaticity diagram *
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index f4bf0798ad182..c4f7dc39b4bd9 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1067,19 +1067,23 @@ public class Paint { } /** - * Get the paint's xfermode object. + * Get the paint's transfer mode object. * - * @return the paint's xfermode (or null) + * @return the paint's transfer mode (or null) */ public Xfermode getXfermode() { return mXfermode; } /** - * Set or clear the xfermode object. + * Set or clear the transfer mode object. A transfer mode defines how + * source pixels (generate by a drawing command) are composited with + * the destination pixels (content of the render target). *

- * Pass null to clear any previous xfermode. + * Pass null to clear any previous transfer mode. * As a convenience, the parameter passed is also returned. + *

+ * {@link PorterDuffXfermode} is the most common transfer mode. * * @param xfermode May be null. The xfermode to be installed in the paint * @return xfermode diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java index 2bbbff309414d..d7d3049b0efa8 100644 --- a/graphics/java/android/graphics/PorterDuff.java +++ b/graphics/java/android/graphics/PorterDuff.java @@ -16,46 +16,345 @@ package android.graphics; +/** + *

This class contains the list of alpha compositing and blending modes + * that can be passed to {@link PorterDuffXfermode}, a specialized implementation + * of {@link Paint}'s {@link Paint#setXfermode(Xfermode) transfer mode}. + * All the available modes can be found in the {@link Mode} enum.

+ */ public class PorterDuff { + /** + * {@usesMathJax} + * + *

Porter-Duff

+ * + *

The name of the parent class is an homage to the work of Thomas Porter and + * Tom Duff, presented in their seminal 1984 paper titled "Compositing Digital Images". + * In this paper, the authors describe 12 compositing operators that govern how to + * compute the color resulting of the composition of a source (the graphics object + * to render) with a destination (the content of the render target).

+ * + *

"Compositing Digital Images" was published in Computer Graphics + * Volume 18, Number 3 dated July 1984.

+ * + *

Because the work of Porter and Duff focuses solely on the effects of the alpha + * channel of the source and destination, the 12 operators described in the original + * paper are called alpha compositing modes here.

+ * + *

For convenience, this class also provides several blending modes, which similarly + * define the result of compositing a source and a destination but without being + * constrained to the alpha channel. These blending modes are not defined by Porter + * and Duff but have been included in this class for convenience purposes.

+ * + *

Diagrams

+ * + *

All the example diagrams presented below use the same source and destination + * images:

+ * + * + * + * + * + * + *
+ * + *
Source image
+ *
+ * + *
Destination image
+ *
+ * + *

The order of drawing operations used to generate each diagram is shown in the + * following code snippet:

+ * + *
+     * Paint paint = new Paint();
+     * canvas.drawBitmap(destinationImage, 0, 0, paint);
+     *
+     * PorterDuff.Mode mode = // choose a mode
+     * paint.setXfermode(new PorterDuffXfermode(mode));
+     *
+     * canvas.drawBitmap(sourceImage, 0, 0, paint);
+     * 
- // these value must match their native equivalents. See SkXfermode.h + * + *

Alpha compositing modes

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * + *
{@link #SRC Source}
+ *
+ * + *
{@link #SRC_OVER Source Over}
+ *
+ * + *
{@link #SRC_IN Source In}
+ *
+ * + *
{@link #SRC_ATOP Source Atop}
+ *
+ * + *
{@link #DST Destination}
+ *
+ * + *
{@link #DST_OVER Destination Over}
+ *
+ * + *
{@link #DST_IN Destination In}
+ *
+ * + *
{@link #DST_ATOP Destination Atop}
+ *
+ * + *
{@link #CLEAR Clear}
+ *
+ * + *
{@link #SRC_OUT Source Out}
+ *
+ * + *
{@link #DST_OUT Destination Out}
+ *
+ * + *
{@link #XOR Exclusive Or}
+ *
+ * + *

Blending modes

+ * + * + * + * + * + * + * + * + * + * + * + *
+ * + *
{@link #DARKEN Darken}
+ *
+ * + *
{@link #LIGHTEN Lighten}
+ *
+ * + *
{@link #MULTIPLY Multiply}
+ *
+ * + *
{@link #SCREEN Screen}
+ *
+ * + *
{@link #OVERLAY Overlay}
+ *
+ * + *

Compositing equations

+ * + *

The documentation of each individual alpha compositing or blending mode below + * provides the exact equation used to compute alpha and color value of the result + * of the composition of a source and destination.

+ * + *

The result (or output) alpha value is noted \(\alpha_{out}\). The result (or output) + * color value is noted \(C_{out}\).

+ */ public enum Mode { - /** [0, 0] */ + // these value must match their native equivalents. See SkXfermode.h + /** + *

+ * + *

Destination pixels covered by the source are cleared to 0.
+ *

+ *

\(\alpha_{out} = 0\)

+ *

\(C_{out} = 0\)

+ */ CLEAR (0), - /** [Sa, Sc] */ + /** + *

+ * + *

The source pixels replace the destination pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{src}\)

+ *

\(C_{out} = C_{src}\)

+ */ SRC (1), - /** [Da, Dc] */ + /** + *

+ * + *

The source pixels are discarded, leaving the destination intact.
+ *

+ *

\(\alpha_{out} = \alpha_{dst}\)

+ *

\(C_{out} = C_{dst}\)

+ */ DST (2), - /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */ + /** + *

+ * + *

The source pixels are drawn over the destination pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)

+ *

\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)

+ */ SRC_OVER (3), - /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */ + /** + *

+ * + *

The source pixels are drawn behind the destination pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{dst} + (1 - \alpha_{dst}) * \alpha_{src}\)

+ *

\(C_{out} = C_{dst} + (1 - \alpha_{dst}) * C_{src}\)

+ */ DST_OVER (4), - /** [Sa * Da, Sc * Da] */ + /** + *

+ * + *

Keeps the source pixels that cover the destination pixels, + * discards the remaining source and destination pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)

+ *

\(C_{out} = C_{src} * \alpha_{dst}\)

+ */ SRC_IN (5), - /** [Sa * Da, Sa * Dc] */ + /** + *

+ * + *

Keeps the destination pixels that cover source pixels, + * discards the remaining source and destination pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)

+ *

\(C_{out} = C_{dst} * \alpha_{src}\)

+ */ DST_IN (6), - /** [Sa * (1 - Da), Sc * (1 - Da)] */ + /** + *

+ * + *

Keeps the source pixels that do not cover destination pixels. + * Discards source pixels that cover destination pixels. Discards all + * destination pixels.
+ *

+ *

\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src}\)

+ *

\(C_{out} = (1 - \alpha_{dst}) * C_{src}\)

+ */ SRC_OUT (7), - /** [Da * (1 - Sa), Dc * (1 - Sa)] */ + /** + *

+ * + *

Keeps the destination pixels that are not covered by source pixels. + * Discards destination pixels that are covered by source pixels. Discards all + * source pixels.
+ *

+ *

\(\alpha_{out} = (1 - \alpha_{src}) * \alpha_{dst}\)

+ *

\(C_{out} = (1 - \alpha_{src}) * C_{dst}\)

+ */ DST_OUT (8), - /** [Da, Sc * Da + (1 - Sa) * Dc] */ + /** + *

+ * + *

Discards the source pixels that do not cover destination pixels. + * Draws remaining source pixels over destination pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{dst}\)

+ *

\(C_{out} = \alpha_{dst} * C_{src} + (1 - \alpha_{src}) * C_{dst}\)

+ */ SRC_ATOP (9), - /** [Sa, Sa * Dc + Sc * (1 - Da)] */ + /** + *

+ * + *

Discards the destination pixels that are not covered by source pixels. + * Draws remaining destination pixels over source pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{src}\)

+ *

\(C_{out} = \alpha_{src} * C_{dst} + (1 - \alpha_{dst}) * C_{src}\)

+ */ DST_ATOP (10), - /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */ + /** + *

+ * + *

Discards the source and destination pixels where source pixels + * cover destination pixels. Draws remaining source pixels.
+ *

+ *

\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)

+ *

\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst}\)

+ */ XOR (11), - /** [Sa + Da - Sa*Da, - Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */ + /** + *

+ * + *

Retains the smallest component of the source and + * destination pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)

+ *

\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + min(C_{src}, C_{dst})\)

+ */ DARKEN (16), - /** [Sa + Da - Sa*Da, - Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */ + /** + *

+ * + *

Retains the largest component of the source and + * destination pixel.
+ *

+ *

\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)

+ *

\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + max(C_{src}, C_{dst})\)

+ */ LIGHTEN (17), - /** [Sa * Da, Sc * Dc] */ + /** + *

+ * + *

Multiplies the source and destination pixels.
+ *

+ *

\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)

+ *

\(C_{out} = C_{src} * C_{dst}\)

+ */ MULTIPLY (13), - /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */ + /** + *

+ * + *

Adds the source and destination pixels, then subtracts the + * source pixels multiplied by the destination.
+ *

+ *

\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)

+ *

\(C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst}\)

+ */ SCREEN (14), - /** Saturate(S + D) */ + /** + *

+ * + *

Adds the source pixels to the destination pixels and saturates + * the result.
+ *

+ *

\(\alpha_{out} = max(0, min(\alpha_{src} + \alpha_{dst}, 1))\)

+ *

\(C_{out} = max(0, min(C_{src} + C_{dst}, 1))\)

+ */ ADD (12), + /** + *

+ * + *

Multiplies or screens the source and destination depending on the + * destination color.
+ *

+ *

\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)

+ *

\(\begin{equation} + * C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\ + * \alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) & otherwise \end{cases} + * \end{equation}\)

+ */ OVERLAY (15); Mode(int nativeInt) { @@ -71,14 +370,14 @@ public class PorterDuff { /** * @hide */ - public static final int modeToInt(Mode mode) { + public static int modeToInt(Mode mode) { return mode.nativeInt; } /** * @hide */ - public static final Mode intToMode(int val) { + public static Mode intToMode(int val) { switch (val) { default: case 0: return Mode.CLEAR; diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java index 51044103003b2..84d953de91db9 100644 --- a/graphics/java/android/graphics/PorterDuffXfermode.java +++ b/graphics/java/android/graphics/PorterDuffXfermode.java @@ -16,6 +16,12 @@ package android.graphics; +/** + *

Specialized implementation of {@link Paint}'s + * {@link Paint#setXfermode(Xfermode) transfer mode}. Refer to the + * documentation of the {@link PorterDuff.Mode} enum for more + * information on the available alpha compositing and blending modes.

+ */ public class PorterDuffXfermode extends Xfermode { /** * Create an xfermode that uses the specified porter-duff mode.