Merge "Add ColorSpace information on Bitmap"
diff --git a/api/current.txt b/api/current.txt
index 9d61da7..32d5bd3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12212,6 +12212,7 @@
method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
method public final int getAllocationByteCount();
method public final int getByteCount();
+ method public final android.graphics.ColorSpace getColorSpace();
method public final android.graphics.Bitmap.Config getConfig();
method public int getDensity();
method public int getGenerationId();
@@ -12594,6 +12595,7 @@
method public java.lang.String getName();
method public boolean isSrgb();
method public abstract boolean isWideGamut();
+ method public static android.graphics.ColorSpace match(float[], android.graphics.ColorSpace.Rgb.TransferParameters);
method public float[] toXyz(float, float, float);
method public abstract float[] toXyz(float[]);
field public static final float[] ILLUMINANT_A;
@@ -12678,6 +12680,10 @@
public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], android.graphics.ColorSpace.Rgb.TransferParameters);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], float[], android.graphics.ColorSpace.Rgb.TransferParameters);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], double);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], float[], double);
method public float[] fromLinear(float, float, float);
method public float[] fromLinear(float[]);
method public float[] fromXyz(float[]);
@@ -12689,6 +12695,7 @@
method public java.util.function.DoubleUnaryOperator getOetf();
method public float[] getPrimaries(float[]);
method public float[] getPrimaries();
+ method public android.graphics.ColorSpace.Rgb.TransferParameters getTransferParameters();
method public float[] getTransform(float[]);
method public float[] getTransform();
method public float[] getWhitePoint(float[]);
@@ -12699,6 +12706,18 @@
method public float[] toXyz(float[]);
}
+ public static class ColorSpace.Rgb.TransferParameters {
+ ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double);
+ ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double, double, double);
+ field public final double a;
+ field public final double b;
+ field public final double c;
+ field public final double d;
+ field public final double e;
+ field public final double f;
+ field public final double g;
+ }
+
public class ComposePathEffect extends android.graphics.PathEffect {
ctor public ComposePathEffect(android.graphics.PathEffect, android.graphics.PathEffect);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 87846c0..5784853 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12929,6 +12929,7 @@
method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
method public final int getAllocationByteCount();
method public final int getByteCount();
+ method public final android.graphics.ColorSpace getColorSpace();
method public final android.graphics.Bitmap.Config getConfig();
method public int getDensity();
method public int getGenerationId();
@@ -13311,6 +13312,7 @@
method public java.lang.String getName();
method public boolean isSrgb();
method public abstract boolean isWideGamut();
+ method public static android.graphics.ColorSpace match(float[], android.graphics.ColorSpace.Rgb.TransferParameters);
method public float[] toXyz(float, float, float);
method public abstract float[] toXyz(float[]);
field public static final float[] ILLUMINANT_A;
@@ -13395,6 +13397,10 @@
public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], android.graphics.ColorSpace.Rgb.TransferParameters);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], float[], android.graphics.ColorSpace.Rgb.TransferParameters);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], double);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], float[], double);
method public float[] fromLinear(float, float, float);
method public float[] fromLinear(float[]);
method public float[] fromXyz(float[]);
@@ -13406,6 +13412,7 @@
method public java.util.function.DoubleUnaryOperator getOetf();
method public float[] getPrimaries(float[]);
method public float[] getPrimaries();
+ method public android.graphics.ColorSpace.Rgb.TransferParameters getTransferParameters();
method public float[] getTransform(float[]);
method public float[] getTransform();
method public float[] getWhitePoint(float[]);
@@ -13416,6 +13423,18 @@
method public float[] toXyz(float[]);
}
+ public static class ColorSpace.Rgb.TransferParameters {
+ ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double);
+ ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double, double, double);
+ field public final double a;
+ field public final double b;
+ field public final double c;
+ field public final double d;
+ field public final double e;
+ field public final double f;
+ field public final double g;
+ }
+
public class ComposePathEffect extends android.graphics.PathEffect {
ctor public ComposePathEffect(android.graphics.PathEffect, android.graphics.PathEffect);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index cce6024..32312f2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -12250,6 +12250,7 @@
method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
method public final int getAllocationByteCount();
method public final int getByteCount();
+ method public final android.graphics.ColorSpace getColorSpace();
method public final android.graphics.Bitmap.Config getConfig();
method public int getDensity();
method public int getGenerationId();
@@ -12632,6 +12633,7 @@
method public java.lang.String getName();
method public boolean isSrgb();
method public abstract boolean isWideGamut();
+ method public static android.graphics.ColorSpace match(float[], android.graphics.ColorSpace.Rgb.TransferParameters);
method public float[] toXyz(float, float, float);
method public abstract float[] toXyz(float[]);
field public static final float[] ILLUMINANT_A;
@@ -12716,6 +12718,10 @@
public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], android.graphics.ColorSpace.Rgb.TransferParameters);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], float[], android.graphics.ColorSpace.Rgb.TransferParameters);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], double);
+ ctor public ColorSpace.Rgb(java.lang.String, float[], float[], double);
method public float[] fromLinear(float, float, float);
method public float[] fromLinear(float[]);
method public float[] fromXyz(float[]);
@@ -12727,6 +12733,7 @@
method public java.util.function.DoubleUnaryOperator getOetf();
method public float[] getPrimaries(float[]);
method public float[] getPrimaries();
+ method public android.graphics.ColorSpace.Rgb.TransferParameters getTransferParameters();
method public float[] getTransform(float[]);
method public float[] getTransform();
method public float[] getWhitePoint(float[]);
@@ -12737,6 +12744,18 @@
method public float[] toXyz(float[]);
}
+ public static class ColorSpace.Rgb.TransferParameters {
+ ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double);
+ ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double, double, double);
+ field public final double a;
+ field public final double b;
+ field public final double c;
+ field public final double d;
+ field public final double e;
+ field public final double f;
+ field public final double g;
+ }
+
public class ComposePathEffect extends android.graphics.PathEffect {
ctor public ComposePathEffect(android.graphics.PathEffect, android.graphics.PathEffect);
}
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index a196540..2766689 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -9,6 +9,7 @@
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkHalf.h"
+#include "SkMatrix44.h"
#include "SkPM4f.h"
#include "SkPM4fPriv.h"
#include "GraphicsJNI.h"
@@ -1168,6 +1169,61 @@
///////////////////////////////////////////////////////////////////////////////
+static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
+ LocalScopedBitmap bitmapHolder(bitmapHandle);
+ if (!bitmapHolder.valid()) return JNI_TRUE;
+
+ SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
+ return colorSpace == nullptr ||
+ colorSpace == SkColorSpace::MakeSRGB().get() ||
+ colorSpace == SkColorSpace::MakeRGB(
+ SkColorSpace::kSRGB_RenderTargetGamma,
+ SkColorSpace::kSRGB_Gamut,
+ SkColorSpace::kNonLinearBlending_ColorSpaceFlag).get();
+}
+
+static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle,
+ jfloatArray xyzArray, jfloatArray paramsArray) {
+
+ LocalScopedBitmap bitmapHolder(bitmapHandle);
+ if (!bitmapHolder.valid()) return JNI_FALSE;
+
+ SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
+ if (colorSpace == nullptr) return JNI_FALSE;
+
+ SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+ if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;
+
+ jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
+ xyz[0] = xyzMatrix.getFloat(0, 0);
+ xyz[1] = xyzMatrix.getFloat(1, 0);
+ xyz[2] = xyzMatrix.getFloat(2, 0);
+ xyz[3] = xyzMatrix.getFloat(0, 1);
+ xyz[4] = xyzMatrix.getFloat(1, 1);
+ xyz[5] = xyzMatrix.getFloat(2, 1);
+ xyz[6] = xyzMatrix.getFloat(0, 2);
+ xyz[7] = xyzMatrix.getFloat(1, 2);
+ xyz[8] = xyzMatrix.getFloat(2, 2);
+ env->ReleaseFloatArrayElements(xyzArray, xyz, 0);
+
+ SkColorSpaceTransferFn transferParams;
+ if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;
+
+ jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
+ params[0] = transferParams.fA;
+ params[1] = transferParams.fB;
+ params[2] = transferParams.fC;
+ params[3] = transferParams.fD;
+ params[4] = transferParams.fE;
+ params[5] = transferParams.fF;
+ params[6] = transferParams.fG;
+ env->ReleaseFloatArrayElements(paramsArray, params, 0);
+
+ return JNI_TRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
jint x, jint y) {
SkBitmap bitmap;
@@ -1459,7 +1515,9 @@
{ "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
(void*) Bitmap_createHardwareBitmap },
{ "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
- (void*) Bitmap_createGraphicBufferHandle }
+ (void*) Bitmap_createGraphicBufferHandle },
+ { "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace },
+ { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB },
};
int register_android_graphics_Bitmap(JNIEnv* env)
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index ba7f05d..9cd9d3d 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -19,12 +19,12 @@
import android.annotation.CheckResult;
import android.annotation.ColorInt;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Trace;
import android.util.DisplayMetrics;
import android.util.Log;
-
import libcore.util.NativeAllocationRegistry;
import java.io.OutputStream;
@@ -73,6 +73,8 @@
private int mHeight;
private boolean mRecycled;
+ private ColorSpace mColorSpace;
+
/** @hide */
public int mDensity = getDefaultDensity();
@@ -1435,6 +1437,47 @@
}
/**
+ * Returns the color space associated with this bitmap. If the color
+ * space is unknown, this method returns null.
+ */
+ @Nullable
+ public final ColorSpace getColorSpace() {
+ // A reconfigure can change the configuration and rgba16f is
+ // always linear scRGB at this time
+ if (getConfig() == Config.RGBA_F16) {
+ // Reset the color space for potential future reconfigurations
+ mColorSpace = null;
+ return ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
+ }
+
+ // Cache the color space retrieval since it can be fairly expensive
+ if (mColorSpace == null) {
+ if (nativeIsSRGB(mNativePtr)) {
+ mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
+ } else {
+ float[] xyz = new float[9];
+ float[] params = new float[7];
+
+ boolean hasColorSpace = nativeGetColorSpace(mNativePtr, xyz, params);
+ if (hasColorSpace) {
+ ColorSpace.Rgb.TransferParameters parameters =
+ new ColorSpace.Rgb.TransferParameters(
+ params[0], params[1], params[2],
+ params[3], params[4], params[5], params[6]);
+ ColorSpace cs = ColorSpace.match(xyz, parameters);
+ if (cs != null) {
+ mColorSpace = cs;
+ } else {
+ mColorSpace = new ColorSpace.Rgb("Unknown", xyz, parameters);
+ }
+ }
+ }
+ }
+
+ return mColorSpace;
+ }
+
+ /**
* Fills the bitmap's pixels with the specified {@link Color}.
*
* @throws IllegalStateException if the bitmap is not mutable.
@@ -1816,4 +1859,6 @@
private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
+ private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
+ private static native boolean nativeIsSRGB(long nativePtr);
}
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index b1a433c..908ec50 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -20,8 +20,8 @@
import android.annotation.ColorInt;
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.Size;
import android.annotation.Nullable;
+import android.annotation.Size;
import android.util.Pair;
import java.util.ArrayList;
@@ -263,18 +263,18 @@
* <tr><td>Name</td><td colspan="4">sRGB IEC61966-2.1</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(\begin{equation}
- * C_{sRGB} = \begin{cases} 12.92 \times C_{linear} & C_{linear} \le 0.0031308 \\
- * 1.055 \times C_{linear}^{\frac{1}{2.4}} - 0.055 & C_{linear} \gt 0.0031308 \end{cases}
+ * C_{sRGB} = \begin{cases} 12.92 \times C_{linear} & C_{linear} \lt 0.0031308 \\
+ * 1.055 \times C_{linear}^{\frac{1}{2.4}} - 0.055 & C_{linear} \ge 0.0031308 \end{cases}
* \end{equation}\)
* </td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
- * C_{linear} = \begin{cases}\frac{C_{sRGB}}{12.92} & C_{sRGB} \le 0.04045 \\
- * \left( \frac{C_{sRGB} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \gt 0.04045 \end{cases}
+ * C_{linear} = \begin{cases}\frac{C_{sRGB}}{12.92} & C_{sRGB} \lt 0.04045 \\
+ * \left( \frac{C_{sRGB} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.04045 \end{cases}
* \end{equation}\)
* </td>
* </tr>
@@ -298,11 +298,11 @@
* <tr><td>Name</td><td colspan="4">sRGB IEC61966-2.1 (Linear)</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(C_{sRGB} = C_{linear}\)</td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(C_{linear} = C_{sRGB}\)</td>
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
@@ -325,22 +325,22 @@
* <tr><td>Name</td><td colspan="4">scRGB-nl IEC 61966-2-2:2003</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(\begin{equation}
* C_{scRGB} = \begin{cases} sign(C_{linear}) 12.92 \times \left| C_{linear} \right| &
- * \left| C_{linear} \right| \le 0.0031308 \\
+ * \left| C_{linear} \right| \lt 0.0031308 \\
* sign(C_{linear}) 1.055 \times \left| C_{linear} \right| ^{\frac{1}{2.4}} - 0.055 &
- * \left| C_{linear} \right| \gt 0.0031308 \end{cases}
+ * \left| C_{linear} \right| \ge 0.0031308 \end{cases}
* \end{equation}\)
* </td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
* C_{linear} = \begin{cases}sign(C_{scRGB}) \frac{\left| C_{scRGB} \right|}{12.92} &
- * \left| C_{scRGB} \right| \le 0.04045 \\
+ * \left| C_{scRGB} \right| \lt 0.04045 \\
* sign(C_{scRGB}) \left( \frac{\left| C_{scRGB} \right| + 0.055}{1.055} \right) ^{2.4} &
- * \left| C_{scRGB} \right| \gt 0.04045 \end{cases}
+ * \left| C_{scRGB} \right| \ge 0.04045 \end{cases}
* \end{equation}\)
* </td>
* </tr>
@@ -364,11 +364,11 @@
* <tr><td>Name</td><td colspan="4">scRGB IEC 61966-2-2:2003</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(C_{scRGB} = C_{linear}\)</td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(C_{linear} = C_{scRGB}\)</td>
* </tr>
* <tr><td>Range</td><td colspan="4">\([-0.5..7.499[\)</td></tr>
@@ -391,7 +391,7 @@
* <tr><td>Name</td><td colspan="4">Rec. ITU-R BT.709-5</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(\begin{equation}
* C_{BT709} = \begin{cases} 4.5 \times C_{linear} & C_{linear} \lt 0.018 \\
* 1.099 \times C_{linear}^{\frac{1}{2.2}} - 0.099 & C_{linear} \ge 0.018 \end{cases}
@@ -399,7 +399,7 @@
* </td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
* C_{linear} = \begin{cases}\frac{C_{BT709}}{4.5} & C_{BT709} \lt 0.081 \\
* \left( \frac{C_{BT709} + 0.099}{1.099} \right) ^{2.2} & C_{BT709} \ge 0.081 \end{cases}
@@ -426,7 +426,7 @@
* <tr><td>Name</td><td colspan="4">Rec. ITU-R BT.2020-1</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(\begin{equation}
* C_{BT2020} = \begin{cases} 4.5 \times C_{linear} & C_{linear} \lt 0.0181 \\
* 1.0993 \times C_{linear}^{\frac{1}{2.2}} - 0.0993 & C_{linear} \ge 0.0181 \end{cases}
@@ -434,7 +434,7 @@
* </td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
* C_{linear} = \begin{cases}\frac{C_{BT2020}}{4.5} & C_{BT2020} \lt 0.08145 \\
* \left( \frac{C_{BT2020} + 0.0993}{1.0993} \right) ^{2.2} & C_{BT2020} \ge 0.08145 \end{cases}
@@ -461,11 +461,11 @@
* <tr><td>Name</td><td colspan="4">SMPTE RP 431-2-2007 DCI (P3)</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">N/A</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(C_{P3} = C_{linear}^{\frac{1}{2.6}}\)</td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(C_{linear} = C_{P3}^{2.6}\)</td>
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
@@ -488,18 +488,18 @@
* <tr><td>Name</td><td colspan="4">Display P3</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(\begin{equation}
- * C_{sRGB} = \begin{cases} 12.92 \times C_{linear} & C_{linear} \le 0.0031308 \\
- * 1.055 \times C_{linear}^{\frac{1}{2.4}} - 0.055 & C_{linear} \gt 0.0031308 \end{cases}
+ * C_{sRGB} = \begin{cases} 12.92 \times C_{linear} & C_{linear} \lt 0.0031308 \\
+ * 1.055 \times C_{linear}^{\frac{1}{2.4}} - 0.055 & C_{linear} \ge 0.0031308 \end{cases}
* \end{equation}\)
* </td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
- * C_{linear} = \begin{cases}\frac{C_{sRGB}}{12.92} & C_{sRGB} \le 0.04045 \\
- * \left( \frac{C_{sRGB} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \gt 0.04045 \end{cases}
+ * C_{linear} = \begin{cases}\frac{C_{sRGB}}{12.92} & C_{sRGB} \lt 0.04045 \\
+ * \left( \frac{C_{sRGB} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.04045 \end{cases}
* \end{equation}\)
* </td>
* </tr>
@@ -523,7 +523,7 @@
* <tr><td>Name</td><td colspan="4">NTSC (1953)</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">C</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(\begin{equation}
* C_{BT709} = \begin{cases} 4.5 \times C_{linear} & C_{linear} \lt 0.018 \\
* 1.099 \times C_{linear}^{\frac{1}{2.2}} - 0.099 & C_{linear} \ge 0.018 \end{cases}
@@ -531,7 +531,7 @@
* </td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
* C_{linear} = \begin{cases}\frac{C_{BT709}}{4.5} & C_{BT709} \lt 0.081 \\
* \left( \frac{C_{BT709} + 0.099}{1.099} \right) ^{2.2} & C_{BT709} \ge 0.081 \end{cases}
@@ -558,7 +558,7 @@
* <tr><td>Name</td><td colspan="4">SMPTE-C RGB</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(\begin{equation}
* C_{BT709} = \begin{cases} 4.5 \times C_{linear} & C_{linear} \lt 0.018 \\
* 1.099 \times C_{linear}^{\frac{1}{2.2}} - 0.099 & C_{linear} \ge 0.018 \end{cases}
@@ -566,7 +566,7 @@
* </td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
* C_{linear} = \begin{cases}\frac{C_{BT709}}{4.5} & C_{BT709} \lt 0.081 \\
* \left( \frac{C_{BT709} + 0.099}{1.099} \right) ^{2.2} & C_{BT709} \ge 0.081 \end{cases}
@@ -593,11 +593,11 @@
* <tr><td>Name</td><td colspan="4">Adobe RGB (1998)</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(C_{RGB} = C_{linear}^{\frac{1}{2.2}}\)</td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(C_{linear} = C_{RGB}^{2.2}\)</td>
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
@@ -620,7 +620,7 @@
* <tr><td>Name</td><td colspan="4">ROMM RGB ISO 22028-2:2013</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D50</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(\begin{equation}
* C_{ROMM} = \begin{cases} 16 \times C_{linear} & C_{linear} \lt 0.001953 \\
* C_{linear}^{\frac{1}{1.8}} & C_{linear} \ge 0.001953 \end{cases}
@@ -628,7 +628,7 @@
* </td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
* C_{linear} = \begin{cases}\frac{C_{ROMM}}{16} & C_{ROMM} \lt 0.031248 \\
* C_{ROMM}^{1.8} & C_{ROMM} \ge 0.031248 \end{cases}
@@ -655,11 +655,11 @@
* <tr><td>Name</td><td colspan="4">SMPTE ST 2065-1:2012 ACES</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D60</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(C_{ACES} = C_{linear}\)</td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(C_{linear} = C_{ACES}\)</td>
* </tr>
* <tr><td>Range</td><td colspan="4">\([-65504.0, 65504.0]\)</td></tr>
@@ -682,11 +682,11 @@
* <tr><td>Name</td><td colspan="4">Academy S-2014-004 ACEScg</td></tr>
* <tr><td>CIE standard illuminant</td><td colspan="4">D60</td></tr>
* <tr>
- * <td>Opto-electronic transfer function</td>
+ * <td>Opto-electronic transfer function (OETF)</td>
* <td colspan="4">\(C_{ACEScg} = C_{linear}\)</td>
* </tr>
* <tr>
- * <td>Electro-optical transfer function</td>
+ * <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(C_{linear} = C_{ACEScg}\)</td>
* </tr>
* <tr><td>Range</td><td colspan="4">\([-65504.0, 65504.0]\)</td></tr>
@@ -1379,6 +1379,37 @@
}
/**
+ * <p>Returns a {@link Named} instance of {@link ColorSpace} that matches
+ * the specified RGB to CIE XYZ transform and transfer functions. If no
+ * instance can be found, this method returns null.</p>
+ *
+ * <p>The color transform matrix is assumed to target the CIE XYZ space
+ * a {@link #ILLUMINANT_D50 D50} standard illuminant.</p>
+ *
+ * @param toXYZD50 3x3 column-major transform matrix from RGB to the profile
+ * connection space CIE XYZ as an array of 9 floats, cannot be null
+ * @param function Parameters for the transfer functions
+ * @return A non-null {@link ColorSpace} if a match is found, null otherwise
+ */
+ @Nullable
+ public static ColorSpace match(
+ @NonNull @Size(9) float[] toXYZD50,
+ @NonNull Rgb.TransferParameters function) {
+
+ for (ColorSpace colorSpace : sNamedColorSpaces) {
+ if (colorSpace.getModel() == Model.RGB) {
+ ColorSpace.Rgb rgb = (ColorSpace.Rgb) adapt(colorSpace, ILLUMINANT_D50_XYZ);
+ if (compare(toXYZD50, rgb.mTransform) &&
+ compare(function, rgb.mTransferParameters)) {
+ return colorSpace;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
* <p>Creates a new {@link Renderer} that can be used to visualize and
* debug color spaces. See the documentation of {@link Renderer} for
* more information.</p>
@@ -1397,17 +1428,14 @@
"sRGB IEC61966-2.1",
SRGB_PRIMARIES,
ILLUMINANT_D65,
- x -> rcpResponse(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
- x -> response(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
- 0.0f, 1.0f,
+ new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
Named.SRGB.ordinal()
);
sNamedColorSpaces[Named.LINEAR_SRGB.ordinal()] = new ColorSpace.Rgb(
"sRGB IEC61966-2.1 (Linear)",
SRGB_PRIMARIES,
ILLUMINANT_D65,
- DoubleUnaryOperator.identity(),
- DoubleUnaryOperator.identity(),
+ 1.0,
0.0f, 1.0f,
Named.LINEAR_SRGB.ordinal()
);
@@ -1415,17 +1443,16 @@
"scRGB-nl IEC 61966-2-2:2003",
SRGB_PRIMARIES,
ILLUMINANT_D65,
- x -> absRcpResponse(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
- x -> absResponse(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
+ x -> absRcpResponse(x, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
+ x -> absResponse(x, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
-0.799f, 2.399f,
Named.EXTENDED_SRGB.ordinal()
);
sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
- "scRGB- IEC 61966-2-2:2003",
+ "scRGB IEC 61966-2-2:2003",
SRGB_PRIMARIES,
ILLUMINANT_D65,
- DoubleUnaryOperator.identity(),
- DoubleUnaryOperator.identity(),
+ 1.0,
-0.5f, 7.499f,
Named.LINEAR_EXTENDED_SRGB.ordinal()
);
@@ -1433,26 +1460,21 @@
"Rec. ITU-R BT.709-5",
new float[] { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f },
ILLUMINANT_D65,
- x -> rcpResponse(x, 1 / 0.45, 1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081),
- x -> response(x, 1 / 0.45, 1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081),
- 0.0f, 1.0f,
+ new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45),
Named.BT709.ordinal()
);
sNamedColorSpaces[Named.BT2020.ordinal()] = new ColorSpace.Rgb(
"Rec. ITU-R BT.2020-1",
new float[] { 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f },
ILLUMINANT_D65,
- x -> rcpResponse(x, 1 / 0.45, 1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145),
- x -> response(x, 1 / 0.45, 1 / 1.0993, 0.099 / 1.0993, 1 / 4.5, 0.08145),
- 0.0f, 1.0f,
+ new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45),
Named.BT2020.ordinal()
);
sNamedColorSpaces[Named.DCI_P3.ordinal()] = new ColorSpace.Rgb(
"SMPTE RP 431-2-2007 DCI (P3)",
new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
new float[] { 0.314f, 0.351f },
- x -> Math.pow(x < 0.0f ? 0.0f : x, 1 / 2.6),
- x -> Math.pow(x < 0.0f ? 0.0f : x, 2.6),
+ 2.6,
0.0f, 1.0f,
Named.DCI_P3.ordinal()
);
@@ -1460,35 +1482,28 @@
"Display P3",
new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
ILLUMINANT_D65,
- x -> rcpResponse(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
- x -> response(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
- 0.0f, 1.0f,
+ new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
Named.DISPLAY_P3.ordinal()
);
sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb(
"NTSC (1953)",
NTSC_1953_PRIMARIES,
ILLUMINANT_C,
- x -> rcpResponse(x, 1 / 0.45, 1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081),
- x -> response(x, 1 / 0.45, 1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081),
- 0.0f, 1.0f,
+ new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45),
Named.NTSC_1953.ordinal()
);
sNamedColorSpaces[Named.SMPTE_C.ordinal()] = new ColorSpace.Rgb(
"SMPTE-C RGB",
new float[] { 0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f },
ILLUMINANT_D65,
- x -> rcpResponse(x, 1 / 0.45, 1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081),
- x -> response(x, 1 / 0.45, 1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081),
- 0.0f, 1.0f,
+ new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45),
Named.SMPTE_C.ordinal()
);
sNamedColorSpaces[Named.ADOBE_RGB.ordinal()] = new ColorSpace.Rgb(
"Adobe RGB (1998)",
new float[] { 0.64f, 0.33f, 0.21f, 0.71f, 0.15f, 0.06f },
ILLUMINANT_D65,
- x -> Math.pow(x < 0.0f ? 0.0f : x, 1 / 2.2),
- x -> Math.pow(x < 0.0f ? 0.0f : x, 2.2),
+ 2.2,
0.0f, 1.0f,
Named.ADOBE_RGB.ordinal()
);
@@ -1496,17 +1511,14 @@
"ROMM RGB ISO 22028-2:2013",
new float[] { 0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f },
ILLUMINANT_D50,
- x -> rcpResponse(x, 1.8, 1.0, 0.0, 1 / 16.0, 0.031248),
- x -> response(x, 1.8, 1.0, 0.0, 1 / 16.0, 0.031248),
- 0.0f, 1.0f,
+ new Rgb.TransferParameters(1.0, 0.0, 1 / 16.0, 0.031248, 1.8),
Named.PRO_PHOTO_RGB.ordinal()
);
sNamedColorSpaces[Named.ACES.ordinal()] = new ColorSpace.Rgb(
"SMPTE ST 2065-1:2012 ACES",
new float[] { 0.73470f, 0.26530f, 0.0f, 1.0f, 0.00010f, -0.0770f },
ILLUMINANT_D60,
- DoubleUnaryOperator.identity(),
- DoubleUnaryOperator.identity(),
+ 1.0,
-65504.0f, 65504.0f,
Named.ACES.ordinal()
);
@@ -1514,8 +1526,7 @@
"Academy S-2014-004 ACEScg",
new float[] { 0.713f, 0.293f, 0.165f, 0.830f, 0.128f, 0.044f },
ILLUMINANT_D60,
- DoubleUnaryOperator.identity(),
- DoubleUnaryOperator.identity(),
+ 1.0,
-65504.0f, 65504.0f,
Named.ACESCG.ordinal()
);
@@ -1530,27 +1541,61 @@
}
// Reciprocal piecewise gamma response
- private static double rcpResponse(double x, double g,double a, double b, double c, double d) {
+ private static double rcpResponse(double x, double a, double b, double c, double d, double g) {
return x >= d * c ? (Math.pow(x, 1.0 / g) - b) / a : x / c;
}
// Piecewise gamma response
- private static double response(double x, double g, double a, double b, double c, double d) {
+ private static double response(double x, double a, double b, double c, double d, double g) {
return x >= d ? Math.pow(a * x + b, g) : c * x;
}
+ // Reciprocal piecewise gamma response
+ private static double rcpResponse(double x, double a, double b, double c, double d,
+ double e, double f, double g) {
+ return x >= d * c ? (Math.pow(x - e, 1.0 / g) - b) / a : (x - f) / c;
+ }
+
+ // Piecewise gamma response
+ private static double response(double x, double a, double b, double c, double d,
+ double e, double f, double g) {
+ return x >= d ? Math.pow(a * x + b, g) + e : c * x + f;
+ }
+
// Reciprocal piecewise gamma response, encoded as sign(x).f(abs(x)) for color
// spaces that allow negative values
@SuppressWarnings("SameParameterValue")
- private static double absRcpResponse(double x, double g, double a, double b, double c, double d) {
- return Math.copySign(rcpResponse(x < 0.0 ? -x : x, g, a, b, c, d), x);
+ private static double absRcpResponse(double x, double a, double b, double c, double d, double g) {
+ return Math.copySign(rcpResponse(x < 0.0 ? -x : x, a, b, c, d, g), x);
}
// Piecewise gamma response, encoded as sign(x).f(abs(x)) for color spaces that
// allow negative values
@SuppressWarnings("SameParameterValue")
- private static double absResponse(double x, double g, double a, double b, double c, double d) {
- return Math.copySign(response(x < 0.0 ? -x : x, g, a, b, c, d), x);
+ private static double absResponse(double x, double a, double b, double c, double d, double g) {
+ return Math.copySign(response(x < 0.0 ? -x : x, a, b, c, d, g), x);
+ }
+
+ /**
+ * Compares two sets of parametric transfer functions parameters with a precision of 1e-3.
+ *
+ * @param a The first set of parameters to compare
+ * @param b The second set of parameters to compare
+ * @return True if the two sets are equal, false otherwise
+ */
+ private static boolean compare(
+ @Nullable Rgb.TransferParameters a,
+ @Nullable Rgb.TransferParameters b) {
+ //noinspection SimplifiableIfStatement
+ if (a == null && b == null) return true;
+ return a != null && b != null &&
+ Math.abs(a.a - b.a) < 1e-3 &&
+ Math.abs(a.b - b.b) < 1e-3 &&
+ Math.abs(a.c - b.c) < 1e-3 &&
+ Math.abs(a.d - b.d) < 1e-3 &&
+ Math.abs(a.e - b.e) < 1e-3 &&
+ Math.abs(a.f - b.f) < 1e-3 &&
+ Math.abs(a.g - b.g) < 1e-3;
}
/**
@@ -1710,7 +1755,7 @@
* <p>Computes the chromatic adaptation transform from the specified
* source white point to the specified destination white point.</p>
*
- * <p>The transform is computed using the von Kris method, described
+ * <p>The transform is computed using the von Kries method, described
* in more details in the documentation of {@link Adaptation}. The
* {@link Adaptation} enum provides different matrices that can be
* used to perform the adaptation.</p>
@@ -1925,6 +1970,11 @@
*
* $$RGB_{out} = OETF(f(EOTF(RGB_{in})))$$
*
+ * <p>If the transfer functions of the color space can be expressed as an
+ * ICC parametric curve as defined in ICC.1:2004-10, the numeric parameters
+ * can be retrieved by calling {@link #getTransferParameters()}. This can
+ * be useful to match color spaces for instance.</p>
+ *
* <p class="note">Some RGB color spaces, such as {@link Named#ACES} and
* {@link Named#LINEAR_EXTENDED_SRGB scRGB}, are said to be linear because
* their transfer functions are the identity function: \(f(x) = x\).
@@ -1967,14 +2017,175 @@
*/
@AnyThread
public static class Rgb extends ColorSpace {
+ /**
+ * {@usesMathJax}
+ *
+ * <p>Defines the parameters for the ICC parametric curve type 4, as
+ * defined in ICC.1:2004-10, section 10.15.</p>
+ *
+ * <p>The EOTF is of the form:</p>
+ *
+ * \(\begin{equation}
+ * Y = \begin{cases}c X + f & X \lt d \\
+ * \left( a X + b \right) ^{g} + e & X \ge d \end{cases}
+ * \end{equation}\)
+ *
+ * <p>The corresponding OETF is simply the inverse function.</p>
+ *
+ * <p>The parameters defined by this class form a valid transfer
+ * function only if all the following conditions are met:</p>
+ * <ul>
+ * <li>No parameter is a {@link Double#isNaN(double) Not-a-Number}</li>
+ * <li>\(d\) is in the range \([0..1]\)</li>
+ * <li>The function is not constant</li>
+ * <li>The function is positive and increasing</li>
+ * </ul>
+ */
+ public static class TransferParameters {
+ /** Variable \(a\) in the equation of the EOTF described above. */
+ public final double a;
+ /** Variable \(b\) in the equation of the EOTF described above. */
+ public final double b;
+ /** Variable \(c\) in the equation of the EOTF described above. */
+ public final double c;
+ /** Variable \(d\) in the equation of the EOTF described above. */
+ public final double d;
+ /** Variable \(e\) in the equation of the EOTF described above. */
+ public final double e;
+ /** Variable \(f\) in the equation of the EOTF described above. */
+ public final double f;
+ /** Variable \(g\) in the equation of the EOTF described above. */
+ public final double g;
+
+ /**
+ * <p>Defines the parameters for the ICC parametric curve type 3, as
+ * defined in ICC.1:2004-10, section 10.15.</p>
+ *
+ * <p>The EOTF is of the form:</p>
+ *
+ * \(\begin{equation}
+ * Y = \begin{cases}c X & X \lt d \\
+ * \left( a X + b \right) ^{g} & X \ge d \end{cases}
+ * \end{equation}\)
+ *
+ * <p>This constructor is equivalent to setting \(e\) and \(f\) to 0.</p>
+ *
+ * @param a The value of \(a\) in the equation of the EOTF described above
+ * @param b The value of \(b\) in the equation of the EOTF described above
+ * @param c The value of \(c\) in the equation of the EOTF described above
+ * @param d The value of \(d\) in the equation of the EOTF described above
+ * @param g The value of \(g\) in the equation of the EOTF described above
+ *
+ * @throws IllegalArgumentException If the parameters form an invalid transfer function
+ */
+ public TransferParameters(double a, double b, double c, double d, double g) {
+ this(a, b, c, d, 0.0, 0.0, g);
+ }
+
+ /**
+ * <p>Defines the parameters for the ICC parametric curve type 4, as
+ * defined in ICC.1:2004-10, section 10.15.</p>
+ *
+ * @param a The value of \(a\) in the equation of the EOTF described above
+ * @param b The value of \(b\) in the equation of the EOTF described above
+ * @param c The value of \(c\) in the equation of the EOTF described above
+ * @param d The value of \(d\) in the equation of the EOTF described above
+ * @param e The value of \(e\) in the equation of the EOTF described above
+ * @param f The value of \(f\) in the equation of the EOTF described above
+ * @param g The value of \(g\) in the equation of the EOTF described above
+ *
+ * @throws IllegalArgumentException If the parameters form an invalid transfer function
+ */
+ public TransferParameters(double a, double b, double c, double d, double e,
+ double f, double g) {
+
+ if (Double.isNaN(a) || Double.isNaN(b) || Double.isNaN(c) ||
+ Double.isNaN(d) || Double.isNaN(e) || Double.isNaN(f) ||
+ Double.isNaN(g)) {
+ throw new IllegalArgumentException("Parameters cannot be NaN");
+ }
+
+ if (!(d >= 0.0 && d <= 1.0 + Math.ulp(1.0))) {
+ throw new IllegalArgumentException("Parameter d must be in the range [0..1]");
+ }
+
+ if (d == 0.0 && (a == 0.0 || g == 0.0)) {
+ throw new IllegalArgumentException(
+ "Parameter a or g is zero, the transfer function is constant");
+ }
+
+ if (d >= 1.0 && c == 0.0) {
+ throw new IllegalArgumentException(
+ "Parameter c is zero, the transfer function is constant");
+ }
+
+ if ((a == 0.0 || g == 0.0) && c == 0.0) {
+ throw new IllegalArgumentException("Parameter a or g is zero," +
+ " and c is zero, the transfer function is constant");
+ }
+
+ if (c < 0.0) {
+ throw new IllegalArgumentException("The transfer function must be increasing");
+ }
+
+ if (a < 0.0 || g < 0.0) {
+ throw new IllegalArgumentException("The transfer function must be " +
+ "positive or increasing");
+ }
+
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ this.e = e;
+ this.f = f;
+ this.g = g;
+ }
+
+ @SuppressWarnings("SimplifiableIfStatement")
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TransferParameters that = (TransferParameters) o;
+
+ if (Double.compare(that.a, a) != 0) return false;
+ if (Double.compare(that.b, b) != 0) return false;
+ if (Double.compare(that.c, c) != 0) return false;
+ if (Double.compare(that.d, d) != 0) return false;
+ if (Double.compare(that.e, e) != 0) return false;
+ if (Double.compare(that.f, f) != 0) return false;
+ return Double.compare(that.g, g) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ int result;
+ long temp;
+ temp = Double.doubleToLongBits(a);
+ result = (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(b);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(c);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(d);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(e);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(f);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(g);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+ }
+
@NonNull private final float[] mWhitePoint;
@NonNull private final float[] mPrimaries;
@NonNull private final float[] mTransform;
@NonNull private final float[] mInverseTransform;
- @NonNull private final boolean mIsWideGamut;
- @NonNull private final boolean mIsSrgb;
-
@NonNull private final DoubleUnaryOperator mOetf;
@NonNull private final DoubleUnaryOperator mEotf;
@NonNull private final DoubleUnaryOperator mClampedOetf;
@@ -1983,6 +2194,11 @@
private final float mMin;
private final float mMax;
+ private final boolean mIsWideGamut;
+ private final boolean mIsSrgb;
+
+ @Nullable private TransferParameters mTransferParameters;
+
/**
* <p>Creates a new RGB color space using a 3x3 column-major transform matrix.
* The transform matrix must convert from the RGB space to the profile connection
@@ -2010,7 +2226,7 @@
@NonNull @Size(9) float[] toXYZ,
@NonNull DoubleUnaryOperator oetf,
@NonNull DoubleUnaryOperator eotf) {
- this(name, computePrimaries(toXYZ, eotf), computeWhitePoint(toXYZ, eotf),
+ this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ),
oetf, eotf, 0.0f, 1.0f, MIN_ID);
}
@@ -2065,6 +2281,251 @@
}
/**
+ * <p>Creates a new RGB color space using a 3x3 column-major transform matrix.
+ * The transform matrix must convert from the RGB space to the profile connection
+ * space CIE XYZ.</p>
+ *
+ * <p class="note">The range of the color space is imposed to be \([0..1]\).</p>
+ *
+ * @param name Name of the color space, cannot be null, its length must be >= 1
+ * @param toXYZ 3x3 column-major transform matrix from RGB to the profile
+ * connection space CIE XYZ as an array of 9 floats, cannot be null
+ * @param function Parameters for the transfer functions
+ *
+ * @throws IllegalArgumentException If any of the following conditions is met:
+ * <ul>
+ * <li>The name is null or has a length of 0.</li>
+ * <li>Gamma is negative.</li>
+ * </ul>
+ *
+ * @see #get(Named)
+ */
+ public Rgb(
+ @NonNull @Size(min = 1) String name,
+ @NonNull @Size(9) float[] toXYZ,
+ @NonNull TransferParameters function) {
+ this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ), function, MIN_ID);
+ }
+
+ /**
+ * <p>Creates a new RGB color space using a specified set of primaries
+ * and a specified white point.</p>
+ *
+ * <p>The primaries and white point can be specified in the CIE xyY space
+ * or in CIE XYZ. The length of the arrays depends on the chosen space:</p>
+ *
+ * <table summary="Parameters length">
+ * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr>
+ * <tr><td>xyY</td><td>6</td><td>2</td></tr>
+ * <tr><td>XYZ</td><td>9</td><td>3</td></tr>
+ * </table>
+ *
+ * <p>When the primaries and/or white point are specified in xyY, the Y component
+ * does not need to be specified and is assumed to be 1.0. Only the xy components
+ * are required.</p>
+ *
+ * @param name Name of the color space, cannot be null, its length must be >= 1
+ * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats
+ * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats
+ * @param function Parameters for the transfer functions
+ *
+ * @throws IllegalArgumentException If any of the following conditions is met:
+ * <ul>
+ * <li>The name is null or has a length of 0.</li>
+ * <li>The primaries array is null or has a length that is neither 6 or 9.</li>
+ * <li>The white point array is null or has a length that is neither 2 or 3.</li>
+ * <li>The transfer parameters are invalid.</li>
+ * </ul>
+ *
+ * @see #get(Named)
+ */
+ public Rgb(
+ @NonNull @Size(min = 1) String name,
+ @NonNull @Size(min = 6, max = 9) float[] primaries,
+ @NonNull @Size(min = 2, max = 3) float[] whitePoint,
+ @NonNull TransferParameters function) {
+ this(name, primaries, whitePoint, function, MIN_ID);
+ }
+
+ /**
+ * <p>Creates a new RGB color space using a specified set of primaries
+ * and a specified white point.</p>
+ *
+ * <p>The primaries and white point can be specified in the CIE xyY space
+ * or in CIE XYZ. The length of the arrays depends on the chosen space:</p>
+ *
+ * <table summary="Parameters length">
+ * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr>
+ * <tr><td>xyY</td><td>6</td><td>2</td></tr>
+ * <tr><td>XYZ</td><td>9</td><td>3</td></tr>
+ * </table>
+ *
+ * <p>When the primaries and/or white point are specified in xyY, the Y component
+ * does not need to be specified and is assumed to be 1.0. Only the xy components
+ * are required.</p>
+ *
+ * @param name Name of the color space, cannot be null, its length must be >= 1
+ * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats
+ * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats
+ * @param function Parameters for the transfer functions
+ * @param id ID of this color space as an integer between {@link #MIN_ID} and {@link #MAX_ID}
+ *
+ * @throws IllegalArgumentException If any of the following conditions is met:
+ * <ul>
+ * <li>The name is null or has a length of 0.</li>
+ * <li>The primaries array is null or has a length that is neither 6 or 9.</li>
+ * <li>The white point array is null or has a length that is neither 2 or 3.</li>
+ * <li>The ID is not between {@link #MIN_ID} and {@link #MAX_ID}.</li>
+ * <li>The transfer parameters are invalid.</li>
+ * </ul>
+ *
+ * @see #get(Named)
+ */
+ private Rgb(
+ @NonNull @Size(min = 1) String name,
+ @NonNull @Size(min = 6, max = 9) float[] primaries,
+ @NonNull @Size(min = 2, max = 3) float[] whitePoint,
+ @NonNull TransferParameters function,
+ @IntRange(from = MIN_ID, to = MAX_ID) int id) {
+ this(name, primaries, whitePoint,
+ function.e == 0.0 && function.f == 0.0 ?
+ x -> rcpResponse(x, function.a, function.b,
+ function.c, function.d, function.g) :
+ x -> rcpResponse(x, function.a, function.b, function.c,
+ function.d, function.e, function.f, function.g),
+ function.e == 0.0 && function.f == 0.0 ?
+ x -> response(x, function.a, function.b,
+ function.c, function.d, function.g) :
+ x -> response(x, function.a, function.b, function.c,
+ function.d, function.e, function.f, function.g),
+ 0.0f, 1.0f, id);
+ mTransferParameters = function;
+ }
+
+ /**
+ * <p>Creates a new RGB color space using a 3x3 column-major transform matrix.
+ * The transform matrix must convert from the RGB space to the profile connection
+ * space CIE XYZ.</p>
+ *
+ * <p class="note">The range of the color space is imposed to be \([0..1]\).</p>
+ *
+ * @param name Name of the color space, cannot be null, its length must be >= 1
+ * @param toXYZ 3x3 column-major transform matrix from RGB to the profile
+ * connection space CIE XYZ as an array of 9 floats, cannot be null
+ * @param gamma Gamma to use as the transfer function
+ *
+ * @throws IllegalArgumentException If any of the following conditions is met:
+ * <ul>
+ * <li>The name is null or has a length of 0.</li>
+ * <li>Gamma is negative.</li>
+ * </ul>
+ *
+ * @see #get(Named)
+ */
+ public Rgb(
+ @NonNull @Size(min = 1) String name,
+ @NonNull @Size(9) float[] toXYZ,
+ double gamma) {
+ this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ), gamma, 0.0f, 1.0f, MIN_ID);
+ }
+
+ /**
+ * <p>Creates a new RGB color space using a specified set of primaries
+ * and a specified white point.</p>
+ *
+ * <p>The primaries and white point can be specified in the CIE xyY space
+ * or in CIE XYZ. The length of the arrays depends on the chosen space:</p>
+ *
+ * <table summary="Parameters length">
+ * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr>
+ * <tr><td>xyY</td><td>6</td><td>2</td></tr>
+ * <tr><td>XYZ</td><td>9</td><td>3</td></tr>
+ * </table>
+ *
+ * <p>When the primaries and/or white point are specified in xyY, the Y component
+ * does not need to be specified and is assumed to be 1.0. Only the xy components
+ * are required.</p>
+ *
+ * @param name Name of the color space, cannot be null, its length must be >= 1
+ * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats
+ * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats
+ * @param gamma Gamma to use as the transfer function
+ *
+ * @throws IllegalArgumentException If any of the following conditions is met:
+ * <ul>
+ * <li>The name is null or has a length of 0.</li>
+ * <li>The primaries array is null or has a length that is neither 6 or 9.</li>
+ * <li>The white point array is null or has a length that is neither 2 or 3.</li>
+ * <li>Gamma is negative.</li>
+ * </ul>
+ *
+ * @see #get(Named)
+ */
+ public Rgb(
+ @NonNull @Size(min = 1) String name,
+ @NonNull @Size(min = 6, max = 9) float[] primaries,
+ @NonNull @Size(min = 2, max = 3) float[] whitePoint,
+ double gamma) {
+ this(name, primaries, whitePoint, gamma, 0.0f, 1.0f, MIN_ID);
+ }
+
+ /**
+ * <p>Creates a new RGB color space using a specified set of primaries
+ * and a specified white point.</p>
+ *
+ * <p>The primaries and white point can be specified in the CIE xyY space
+ * or in CIE XYZ. The length of the arrays depends on the chosen space:</p>
+ *
+ * <table summary="Parameters length">
+ * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr>
+ * <tr><td>xyY</td><td>6</td><td>2</td></tr>
+ * <tr><td>XYZ</td><td>9</td><td>3</td></tr>
+ * </table>
+ *
+ * <p>When the primaries and/or white point are specified in xyY, the Y component
+ * does not need to be specified and is assumed to be 1.0. Only the xy components
+ * are required.</p>
+ *
+ * @param name Name of the color space, cannot be null, its length must be >= 1
+ * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats
+ * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats
+ * @param gamma Gamma to use as the transfer function
+ * @param min The minimum valid value in this color space's RGB range
+ * @param max The maximum valid value in this color space's RGB range
+ * @param id ID of this color space as an integer between {@link #MIN_ID} and {@link #MAX_ID}
+ *
+ * @throws IllegalArgumentException If any of the following conditions is met:
+ * <ul>
+ * <li>The name is null or has a length of 0.</li>
+ * <li>The primaries array is null or has a length that is neither 6 or 9.</li>
+ * <li>The white point array is null or has a length that is neither 2 or 3.</li>
+ * <li>The minimum valid value is >= the maximum valid value.</li>
+ * <li>The ID is not between {@link #MIN_ID} and {@link #MAX_ID}.</li>
+ * <li>Gamma is negative.</li>
+ * </ul>
+ *
+ * @see #get(Named)
+ */
+ private Rgb(
+ @NonNull @Size(min = 1) String name,
+ @NonNull @Size(min = 6, max = 9) float[] primaries,
+ @NonNull @Size(min = 2, max = 3) float[] whitePoint,
+ double gamma,
+ float min,
+ float max,
+ @IntRange(from = MIN_ID, to = MAX_ID) int id) {
+ this(name, primaries, whitePoint,
+ gamma == 1.0 ? DoubleUnaryOperator.identity() :
+ x -> Math.pow(x < 0.0 ? 0.0 : x, 1 / gamma),
+ gamma == 1.0 ? DoubleUnaryOperator.identity() :
+ x -> Math.pow(x < 0.0 ? 0.0 : x, gamma),
+ min, max, id);
+ mTransferParameters = gamma == 1.0 ?
+ new TransferParameters(0.0, 0.0, 1.0, 1.0 + Math.ulp(1.0), gamma) :
+ new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
+ }
+
+ /**
* <p>Creates a new RGB color space using a specified set of primaries
* and a specified white point.</p>
*
@@ -2183,6 +2644,8 @@
mIsWideGamut = colorSpace.mIsWideGamut;
mIsSrgb = colorSpace.mIsSrgb;
+
+ mTransferParameters = colorSpace.mTransferParameters;
}
/**
@@ -2360,6 +2823,7 @@
* @return A transfer function that converts from linear space to "gamma space"
*
* @see #getEotf()
+ * @see #getTransferParameters()
*/
@NonNull
public DoubleUnaryOperator getOetf() {
@@ -2383,12 +2847,31 @@
* @return A transfer function that converts from "gamma space" to linear space
*
* @see #getOetf()
+ * @see #getTransferParameters()
*/
@NonNull
public DoubleUnaryOperator getEotf() {
return mClampedEotf;
}
+ /**
+ * <p>Returns the parameters used by the {@link #getEotf() electro-optical}
+ * and {@link #getOetf() opto-electronic} transfer functions. If the transfer
+ * functions do not match the ICC parametric curves defined in ICC.1:2004-10
+ * (section 10.15), this method returns null.</p>
+ *
+ * <p>See {@link TransferParameters} for a full description of the transfer
+ * functions.</p>
+ *
+ * @return An instance of {@link TransferParameters} or null if this color
+ * space's transfer functions do not match the equation defined in
+ * {@link TransferParameters}
+ */
+ @Nullable
+ public TransferParameters getTransferParameters() {
+ return mTransferParameters;
+ }
+
@Override
public boolean isSrgb() {
return mIsSrgb;
@@ -2544,6 +3027,11 @@
if (Float.compare(rgb.mMax, mMax) != 0) return false;
if (!Arrays.equals(mWhitePoint, rgb.mWhitePoint)) return false;
if (!Arrays.equals(mPrimaries, rgb.mPrimaries)) return false;
+ if (mTransferParameters != null) {
+ return mTransferParameters.equals(rgb.mTransferParameters);
+ } else if (rgb.mTransferParameters == null) {
+ return true;
+ }
//noinspection SimplifiableIfStatement
if (!mOetf.equals(rgb.mOetf)) return false;
return mEotf.equals(rgb.mEotf);
@@ -2554,10 +3042,14 @@
int result = super.hashCode();
result = 31 * result + Arrays.hashCode(mWhitePoint);
result = 31 * result + Arrays.hashCode(mPrimaries);
- result = 31 * result + mOetf.hashCode();
- result = 31 * result + mEotf.hashCode();
result = 31 * result + (mMin != +0.0f ? Float.floatToIntBits(mMin) : 0);
result = 31 * result + (mMax != +0.0f ? Float.floatToIntBits(mMax) : 0);
+ result = 31 * result +
+ (mTransferParameters != null ? mTransferParameters.hashCode() : 0);
+ if (mTransferParameters == null) {
+ result = 31 * result + mOetf.hashCode();
+ result = 31 * result + mEotf.hashCode();
+ }
return result;
}
@@ -2746,18 +3238,15 @@
* range of the color space is [0..1].
*
* @param toXYZ The color space's 3x3 transform matrix to XYZ
- * @param EOTF The color space's electro-optical transfer function
* @return A new array of 6 floats containing the color space's
* primaries in CIE xyY
*/
@NonNull
@Size(6)
- private static float[] computePrimaries(@NonNull @Size(9) float[] toXYZ,
- DoubleUnaryOperator EOTF) {
- float one = (float) EOTF.applyAsDouble(1.0);
- float[] r = mul3x3Float3(toXYZ, new float[] { one, 0.0f, 0.0f });
- float[] g = mul3x3Float3(toXYZ, new float[] { 0.0f, one, 0.0f });
- float[] b = mul3x3Float3(toXYZ, new float[] { 0.0f, 0.0f, one });
+ private static float[] computePrimaries(@NonNull @Size(9) float[] toXYZ) {
+ float[] r = mul3x3Float3(toXYZ, new float[] { 1.0f, 0.0f, 0.0f });
+ float[] g = mul3x3Float3(toXYZ, new float[] { 0.0f, 1.0f, 0.0f });
+ float[] b = mul3x3Float3(toXYZ, new float[] { 0.0f, 0.0f, 1.0f });
float rSum = r[0] + r[1] + r[2];
float gSum = g[0] + g[1] + g[2];
@@ -2776,16 +3265,13 @@
* range of the color space is [0..1].
*
* @param toXYZ The color space's 3x3 transform matrix to XYZ
- * @param EOTF The color space's electro-optical transfer function
* @return A new array of 2 floats containing the color space's
* white point in CIE xyY
*/
@NonNull
@Size(2)
- private static float[] computeWhitePoint(@NonNull @Size(9) float[] toXYZ,
- @NonNull DoubleUnaryOperator EOTF) {
- float one = (float) EOTF.applyAsDouble(1.0);
- float[] w = mul3x3Float3(toXYZ, new float[] { one, one, one });
+ private static float[] computeWhitePoint(@NonNull @Size(9) float[] toXYZ) {
+ float[] w = mul3x3Float3(toXYZ, new float[] { 1.0f, 1.0f, 1.0f });
float sum = w[0] + w[1] + w[2];
return new float[] { w[0] / sum, w[1] / sum };
}
@@ -2988,6 +3474,7 @@
* Computes an extra transform to apply in XYZ space depending on the
* selected rendering intent.
*/
+ @Nullable
private static float[] computeTransform(@NonNull ColorSpace source,
@NonNull ColorSpace destination, @NonNull RenderIntent intent) {
if (intent != RenderIntent.ABSOLUTE) return null;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 7c2e78c..19063e3 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -133,7 +133,7 @@
* this function returns GL_SRGB8_ALPHA8, otherwise it returns GL_RGBA
*/
constexpr GLint rgbaInternalFormat(bool needSRGB = true) const {
- return extensions().hasSRGB() && needSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA;
+ return extensions().hasLinearBlending() && needSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA;
}
/**
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 00238a2..1e71cb0 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -20,6 +20,8 @@
#include "Properties.h"
#include "utils/StringUtils.h"
+#include <cutils/compiler.h>
+
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -28,14 +30,6 @@
namespace android {
namespace uirenderer {
-// Debug
-#if DEBUG_EXTENSIONS
- #define EXT_LOGD(...) ALOGD(__VA_ARGS__)
-#else
- #define EXT_LOGD(...)
-#endif
-
-
Extensions::Extensions() {
const char* version = (const char*) glGetString(GL_VERSION);
@@ -66,17 +60,18 @@
mHas4BitStencil = extensions.has("GL_OES_stencil4");
mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage");
-#ifdef ANDROID_ENABLE_LINEAR_BLENDING
mHasSRGB = mVersionMajor >= 3 || extensions.has("GL_EXT_sRGB");
mHasSRGBWriteControl = extensions.has("GL_EXT_sRGB_write_control");
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
// If linear blending is enabled, the device must have (ES3.0 or EXT_sRGB)
// and EXT_sRGB_write_control
LOG_ALWAYS_FATAL_IF(!mHasSRGB, "Linear blending requires ES 3.0 or EXT_sRGB");
LOG_ALWAYS_FATAL_IF(!mHasSRGBWriteControl, "Linear blending requires EXT_sRGB_write_control");
+
+ mHasLinearBlending = true;
#else
- mHasSRGB = false;
- mHasSRGBWriteControl = false;
+ mHasLinearBlending = false;
#endif
}
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 2c38507..0ecfdb1 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -17,11 +17,6 @@
#ifndef ANDROID_HWUI_EXTENSIONS_H
#define ANDROID_HWUI_EXTENSIONS_H
-#include <cutils/compiler.h>
-
-#include <string>
-#include <unordered_set>
-
namespace android {
namespace uirenderer {
@@ -45,6 +40,7 @@
inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
inline bool hasSRGB() const { return mHasSRGB; }
inline bool hasSRGBWriteControl() const { return hasSRGB() && mHasSRGBWriteControl; }
+ inline bool hasLinearBlending() const { return hasSRGB() && mHasLinearBlending; }
inline int getMajorGlVersion() const { return mVersionMajor; }
inline int getMinorGlVersion() const { return mVersionMinor; }
@@ -59,6 +55,7 @@
bool mHasUnpackSubImage;
bool mHasSRGB;
bool mHasSRGBWriteControl;
+ bool mHasLinearBlending;
int mVersionMajor;
int mVersionMinor;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 71bee93..18bfcc2 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -68,7 +68,7 @@
, mMaxSize(Properties::gradientCacheSize)
, mUseFloatTexture(extensions.hasFloatTextures())
, mHasNpot(extensions.hasNPot())
- , mHasSRGB(extensions.hasSRGB()) {
+ , mHasLinearBlending(extensions.hasLinearBlending()) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
mCache.setOnEntryRemovedListener(this);
@@ -263,7 +263,7 @@
if (mUseFloatTexture) {
texture->upload(GL_RGBA16F, width, height, GL_RGBA, GL_FLOAT, pixels);
} else {
- GLint internalFormat = mHasSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA;
+ GLint internalFormat = mHasLinearBlending ? GL_SRGB8_ALPHA8 : GL_RGBA;
texture->upload(internalFormat, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
}
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 5e35435..f299a40 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -170,7 +170,7 @@
GLint mMaxTextureSize;
bool mUseFloatTexture;
bool mHasNpot;
- bool mHasSRGB;
+ bool mHasLinearBlending;
mutable Mutex mLock;
}; // class GradientCache
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index ca05648..40ab778 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -418,7 +418,7 @@
ProgramCache::ProgramCache(Extensions& extensions)
: mHasES3(extensions.getMajorGlVersion() >= 3)
- , mHasSRGB(extensions.hasSRGB()) {
+ , mHasLinearBlending(extensions.hasLinearBlending()) {
}
ProgramCache::~ProgramCache() {
@@ -642,11 +642,11 @@
}
if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) &&
!description.hasAlpha8Texture)) {
- shader.append(gFS_OETF[description.hasLinearTexture && !mHasSRGB]);
+ shader.append(gFS_OETF[description.hasLinearTexture && !mHasLinearBlending]);
}
if (description.hasGradient) {
shader.append(gFS_Gradient_Functions);
- shader.append(gFS_Gradient_Preamble[mHasSRGB]);
+ shader.append(gFS_Gradient_Preamble[mHasLinearBlending]);
}
// Begin the shader
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index c2f715d..cedd854b 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -59,7 +59,7 @@
std::map<programid, std::unique_ptr<Program>> mCache;
const bool mHasES3;
- const bool mHasSRGB;
+ const bool mHasLinearBlending;
}; // class ProgramCache
}; // namespace uirenderer
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 0dbd767..cfc2744 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -241,21 +241,23 @@
}
}
-SkBitmap Texture::uploadToN32(const SkBitmap& bitmap, bool hasSRGB, sk_sp<SkColorSpace> sRGB) {
+SkBitmap Texture::uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
+ sk_sp<SkColorSpace> sRGB) {
SkBitmap rgbaBitmap;
rgbaBitmap.allocPixels(SkImageInfo::MakeN32(bitmap.width(), bitmap.height(),
- bitmap.info().alphaType(), hasSRGB ? sRGB : nullptr));
+ bitmap.info().alphaType(), hasLinearBlending ? sRGB : nullptr));
rgbaBitmap.eraseColor(0);
SkCanvas canvas(rgbaBitmap);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
return rgbaBitmap;
}
-bool Texture::hasUnsupportedColorType(const SkImageInfo& info, bool hasSRGB, SkColorSpace* sRGB) {
+bool Texture::hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending,
+ SkColorSpace* sRGB) {
bool needSRGB = info.colorSpace() == sRGB;
return info.colorType() == kARGB_4444_SkColorType
|| info.colorType() == kIndex_8_SkColorType
- || (info.colorType() == kRGB_565_SkColorType && hasSRGB && needSRGB);
+ || (info.colorType() == kRGB_565_SkColorType && hasLinearBlending && needSRGB);
}
@@ -295,11 +297,11 @@
mCaches.textureState().bindTexture(mTarget, mId);
// TODO: Handle sRGB gray bitmaps
- bool hasSRGB = mCaches.extensions().hasSRGB();
- if (CC_UNLIKELY(hasUnsupportedColorType(bitmap.info(), hasSRGB, sRGB.get()))) {
+ bool hasLinearBlending = mCaches.extensions().hasLinearBlending();
+ if (CC_UNLIKELY(hasUnsupportedColorType(bitmap.info(), hasLinearBlending, sRGB.get()))) {
SkBitmap skBitmap;
bitmap.getSkBitmap(&skBitmap);
- SkBitmap rgbaBitmap = uploadToN32(skBitmap, hasSRGB, std::move(sRGB));
+ SkBitmap rgbaBitmap = uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
uploadToTexture(needsAlloc, internalFormat, format, type, rgbaBitmap.rowBytesAsPixels(),
rgbaBitmap.bytesPerPixel(), rgbaBitmap.width(),
rgbaBitmap.height(), rgbaBitmap.getPixels());
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index ce9d4dc..e7fbf20 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -40,8 +40,10 @@
*/
class Texture : public GpuMemoryTracker {
public:
- static SkBitmap uploadToN32(const SkBitmap& bitmap, bool hasSRGB, sk_sp<SkColorSpace> sRGB);
- static bool hasUnsupportedColorType(const SkImageInfo& info, bool hasSRGB, SkColorSpace* sRGB);
+ static SkBitmap uploadToN32(const SkBitmap& bitmap,
+ bool hasLinearBlending, sk_sp<SkColorSpace> sRGB);
+ static bool hasUnsupportedColorType(const SkImageInfo& info,
+ bool hasLinearBlending, SkColorSpace* sRGB);
static void colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType,
bool needSRGB, GLint* outInternalFormat, GLint* outFormat, GLint* outType);
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index a55b061..db4ff39 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -19,6 +19,8 @@
#include <SkBitmap.h>
+#include <cutils/compiler.h>
+
#include <utils/LruCache.h>
#include <utils/Mutex.h>
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index f9730c9..49b69eb 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -234,7 +234,7 @@
sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
bool needSRGB = skBitmap.info().colorSpace() == sRGB.get();
- bool hasSRGB = caches.extensions().hasSRGB();
+ bool hasLinearBlending = caches.extensions().hasLinearBlending();
GLint format, type, internalFormat;
uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
needSRGB, &internalFormat, &format, &type);
@@ -252,8 +252,8 @@
SkBitmap bitmap;
if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(),
- hasSRGB, sRGB.get()))) {
- bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasSRGB, std::move(sRGB));
+ hasLinearBlending, sRGB.get()))) {
+ bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
} else {
bitmap = skBitmap;
}
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 7dfc2ee..8bce990 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -174,13 +174,15 @@
meshState().disableTexCoordsVertexArray();
debugOverdraw(false, false);
// TODO: We need a way to know whether the functor is sRGB aware (b/32072673)
- if (mCaches->extensions().hasSRGBWriteControl()) {
+ if (mCaches->extensions().hasLinearBlending() &&
+ mCaches->extensions().hasSRGBWriteControl()) {
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
}
}
void RenderState::resumeFromFunctorInvoke() {
- if (mCaches->extensions().hasSRGBWriteControl()) {
+ if (mCaches->extensions().hasLinearBlending() &&
+ mCaches->extensions().hasSRGBWriteControl()) {
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
}
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 0950eb8..4a27ca2f 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -121,4 +121,4 @@
} /* namespace uirenderer */
} /* namespace android */
-#endif /* TEST_UTILS_H */
+#endif /* COLOR_H */