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.