Loading core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -14951,6 +14951,8 @@ package android.graphics { enum_constant public static final android.graphics.ColorSpace.Named ACESCG; enum_constant public static final android.graphics.ColorSpace.Named ADOBE_RGB; enum_constant public static final android.graphics.ColorSpace.Named BT2020; enum_constant public static final android.graphics.ColorSpace.Named BT2020_HLG; enum_constant public static final android.graphics.ColorSpace.Named BT2020_PQ; enum_constant public static final android.graphics.ColorSpace.Named BT709; enum_constant public static final android.graphics.ColorSpace.Named CIE_LAB; enum_constant public static final android.graphics.ColorSpace.Named CIE_XYZ; core/java/android/hardware/DataSpace.java +1 −3 Original line number Diff line number Diff line Loading @@ -521,9 +521,7 @@ public final class DataSpace { public static final int DATASPACE_BT2020_HLG = 168165376; /** * ITU-R Recommendation 2020 (BT.2020) * * Ultra High-definition television. * Perceptual Quantizer encoding. * * <p>Composed of the following -</p> * <pre> Loading graphics/java/android/graphics/BitmapFactory.java +13 −3 Original line number Diff line number Diff line Loading @@ -161,11 +161,17 @@ public class BitmapFactory { * be thrown by the decode methods when setting a non-RGB color space * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p> * * <p class="note">The specified color space's transfer function must be * <p class="note"> * Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, * the specified color space's transfer function must be * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An * <code>IllegalArgumentException</code> will be thrown by the decode methods * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the * specified color space returns null.</p> * specified color space returns null. * * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, * non ICC parametric curve transfer function is allowed. * E.g., {@link ColorSpace.Named#BT2020_HLG BT2020_HLG}.</p> * * <p>After decode, the bitmap's color space is stored in * {@link #outColorSpace}.</p> Loading Loading @@ -458,7 +464,11 @@ public class BitmapFactory { throw new IllegalArgumentException("The destination color space must use the " + "RGB color model"); } if (((ColorSpace.Rgb) opts.inPreferredColorSpace).getTransferParameters() == null) { if (!opts.inPreferredColorSpace.equals(ColorSpace.get(ColorSpace.Named.BT2020_HLG)) && !opts.inPreferredColorSpace.equals( ColorSpace.get(ColorSpace.Named.BT2020_PQ)) && ((ColorSpace.Rgb) opts.inPreferredColorSpace) .getTransferParameters() == null) { throw new IllegalArgumentException("The destination color space must use an " + "ICC parametric transfer function"); } Loading graphics/java/android/graphics/ColorSpace.java +188 −59 Original line number Diff line number Diff line Loading @@ -199,6 +199,8 @@ public abstract class ColorSpace { private static final float[] SRGB_PRIMARIES = { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }; private static final float[] NTSC_1953_PRIMARIES = { 0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f }; private static final float[] BT2020_PRIMARIES = { 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f }; /** * A gray color space does not have meaningful primaries, so we use this arbitrary set. */ Loading @@ -208,6 +210,12 @@ public abstract class ColorSpace { private static final Rgb.TransferParameters SRGB_TRANSFER_PARAMETERS = new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4); private static final Rgb.TransferParameters BT2020_HLG_TRANSFER_PARAMETERS = new Rgb.TransferParameters(2.0f, 2.0f, 1 / 0.17883277f, 0.28466892f, 0.5599107f, 0.0f, -3.0f, true); private static final Rgb.TransferParameters BT2020_PQ_TRANSFER_PARAMETERS = new Rgb.TransferParameters(107 / 128.0f, 1.0f, 32 / 2523.0f, 2413 / 128.0f, -2392 / 128.0f, 8192 / 1305.0f, -2.0f, true); // See static initialization block next to #get(Named) private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length]; Loading Loading @@ -703,7 +711,29 @@ public abstract class ColorSpace { * <tr><td>Range</td><td colspan="4">\(L: [0.0, 100.0], a: [-128, 128], b: [-128, 128]\)</td></tr> * </table> */ CIE_LAB CIE_LAB, /** * <p>{@link ColorSpace.Rgb RGB} color space BT.2100 standardized as * Hybrid Log Gamma encoding.</p> * <table summary="Color space definition"> * <tr><th>Property</th><th colspan="4">Value</th></tr> * <tr><td>Name</td><td colspan="4">Hybrid Log Gamma encoding</td></tr> * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> * </table> */ BT2020_HLG, /** * <p>{@link ColorSpace.Rgb RGB} color space BT.2100 standardized as * Perceptual Quantizer encoding.</p> * <table summary="Color space definition"> * <tr><th>Property</th><th colspan="4">Value</th></tr> * <tr><td>Name</td><td colspan="4">Perceptual Quantizer encoding</td></tr> * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> * </table> */ BT2020_PQ // Update the initialization block next to #get(Named) when adding new values } Loading Loading @@ -1534,7 +1564,7 @@ public abstract class ColorSpace { sDataToColorSpaces.put(DataSpace.DATASPACE_BT709, 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 }, BT2020_PRIMARIES, ILLUMINANT_D65, null, new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45), Loading Loading @@ -1616,6 +1646,70 @@ public abstract class ColorSpace { "Generic L*a*b*", Named.CIE_LAB.ordinal() ); sNamedColorSpaces[Named.BT2020_HLG.ordinal()] = new ColorSpace.Rgb( "Hybrid Log Gamma encoding", BT2020_PRIMARIES, ILLUMINANT_D65, null, x -> transferHLGOETF(x), x -> transferHLGEOTF(x), 0.0f, 1.0f, BT2020_HLG_TRANSFER_PARAMETERS, Named.BT2020_HLG.ordinal() ); sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020_HLG, Named.BT2020_HLG.ordinal()); sNamedColorSpaces[Named.BT2020_PQ.ordinal()] = new ColorSpace.Rgb( "Perceptual Quantizer encoding", BT2020_PRIMARIES, ILLUMINANT_D65, null, x -> transferST2048OETF(x), x -> transferST2048EOTF(x), 0.0f, 1.0f, BT2020_PQ_TRANSFER_PARAMETERS, Named.BT2020_PQ.ordinal() ); sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020_PQ, Named.BT2020_PQ.ordinal()); } private static double transferHLGOETF(double x) { double a = 0.17883277; double b = 0.28466892; double c = 0.55991073; double r = 0.5; return x > 1.0 ? a * Math.log(x - b) + c : r * Math.sqrt(x); } private static double transferHLGEOTF(double x) { double a = 0.17883277; double b = 0.28466892; double c = 0.55991073; double r = 0.5; return x <= 0.5 ? (x * x) / (r * r) : Math.exp((x - c) / a + b); } private static double transferST2048OETF(double x) { double m1 = (2610.0 / 4096.0) / 4.0; double m2 = (2523.0 / 4096.0) * 128.0; double c1 = (3424.0 / 4096.0); double c2 = (2413.0 / 4096.0) * 32.0; double c3 = (2392.0 / 4096.0) * 32.0; double tmp = Math.pow(x, m1); tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); return Math.pow(tmp, m2); } private static double transferST2048EOTF(double x) { double m1 = (2610.0 / 4096.0) / 4.0; double m2 = (2523.0 / 4096.0) * 128.0; double c1 = (3424.0 / 4096.0); double c2 = (2413.0 / 4096.0) * 32.0; double c3 = (2392.0 / 4096.0) * 32.0; double tmp = Math.pow(Math.min(Math.max(x, 0.0), 1.0), 1.0 / m2); tmp = Math.max(tmp - c1, 0.0) / (c2 - c3 * tmp); return Math.pow(tmp, 1.0 / m1); } // Reciprocal piecewise gamma response Loading Loading @@ -2197,6 +2291,58 @@ public abstract class ColorSpace { /** Variable \(g\) in the equation of the EOTF described above. */ public final double g; private TransferParameters(double a, double b, double c, double d, double e, double f, double g, boolean nonCurveTransferParameters) { // nonCurveTransferParameters correspondes to a "special" transfer function if (!nonCurveTransferParameters) { 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"); } // Next representable float after 1.0 // We use doubles here but the representation inside our native code // is often floats if (!(d >= 0.0 && d <= 1.0f + Math.ulp(1.0f))) { throw new IllegalArgumentException( "Parameter d must be in the range [0..1], " + "was " + d); } 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; } /** * <p>Defines the parameters for the ICC parametric curve type 3, as * defined in ICC.1:2004-10, section 10.15.</p> Loading @@ -2219,7 +2365,7 @@ public abstract class ColorSpace { * @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); this(a, b, c, d, 0.0, 0.0, g, false); } /** Loading @@ -2238,51 +2384,7 @@ public abstract class ColorSpace { */ 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"); } // Next representable float after 1.0 // We use doubles here but the representation inside our native code is often floats if (!(d >= 0.0 && d <= 1.0f + Math.ulp(1.0f))) { throw new IllegalArgumentException("Parameter d must be in the range [0..1], " + "was " + d); } 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; this(a, b, c, d, e, f, g, false); } @SuppressWarnings("SimplifiableIfStatement") Loading Loading @@ -2357,6 +2459,36 @@ public abstract class ColorSpace { private static native long nativeCreate(float a, float b, float c, float d, float e, float f, float g, float[] xyz); private static DoubleUnaryOperator generateOETF(TransferParameters function) { boolean isNonCurveTransferParameters = function.equals(BT2020_HLG_TRANSFER_PARAMETERS) || function.equals(BT2020_PQ_TRANSFER_PARAMETERS); if (isNonCurveTransferParameters) { return function.f == 0.0 && function.g < 0.0 ? x -> transferHLGOETF(x) : x -> transferST2048OETF(x); } else { return 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); } } private static DoubleUnaryOperator generateEOTF(TransferParameters function) { boolean isNonCurveTransferParameters = function.equals(BT2020_HLG_TRANSFER_PARAMETERS) || function.equals(BT2020_PQ_TRANSFER_PARAMETERS); if (isNonCurveTransferParameters) { return function.f == 0.0 && function.g < 0.0 ? x -> transferHLGEOTF(x) : x -> transferST2048EOTF(x); } else { return 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); } } /** * <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 Loading Loading @@ -2553,16 +2685,8 @@ public abstract class ColorSpace { @NonNull TransferParameters function, @IntRange(from = MIN_ID, to = MAX_ID) int id) { this(name, primaries, whitePoint, transform, 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), generateOETF(function), generateEOTF(function), 0.0f, 1.0f, function, id); } Loading Loading @@ -3063,8 +3187,13 @@ public abstract class ColorSpace { */ @Nullable public TransferParameters getTransferParameters() { if (mTransferParameters != null && !mTransferParameters.equals(BT2020_PQ_TRANSFER_PARAMETERS) && !mTransferParameters.equals(BT2020_HLG_TRANSFER_PARAMETERS)) { return mTransferParameters; } return null; } @Override public boolean isSrgb() { Loading libs/hwui/jni/Graphics.cpp +18 −10 Original line number Diff line number Diff line Loading @@ -576,14 +576,22 @@ jobject GraphicsJNI::getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace, LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix)); skcms_TransferFunction transferParams; // We can only handle numerical transfer functions at the moment LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams)); decodeColorSpace->transferFn(&transferParams); auto res = skcms_TransferFunction_getType(&transferParams); LOG_ALWAYS_FATAL_IF(res == skcms_TFType_HLGinvish || res == skcms_TFType_Invalid); jobject params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID, jobject params; if (res == skcms_TFType_PQish || res == skcms_TFType_HLGish) { params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID, transferParams.a, transferParams.b, transferParams.c, transferParams.d, transferParams.e, transferParams.f, transferParams.g); transferParams.g, true); } else { params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID, transferParams.a, transferParams.b, transferParams.c, transferParams.d, transferParams.e, transferParams.f, transferParams.g, false); } jfloatArray xyzArray = env->NewFloatArray(9); jfloat xyz[9] = { Loading Loading @@ -808,8 +816,8 @@ int register_android_graphics_Graphics(JNIEnv* env) gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters")); gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class, "<init>", "(DDDDDDD)V"); gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class, "<init>", "(DDDDDDDZ)V"); gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics"); gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class); Loading Loading
core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -14951,6 +14951,8 @@ package android.graphics { enum_constant public static final android.graphics.ColorSpace.Named ACESCG; enum_constant public static final android.graphics.ColorSpace.Named ADOBE_RGB; enum_constant public static final android.graphics.ColorSpace.Named BT2020; enum_constant public static final android.graphics.ColorSpace.Named BT2020_HLG; enum_constant public static final android.graphics.ColorSpace.Named BT2020_PQ; enum_constant public static final android.graphics.ColorSpace.Named BT709; enum_constant public static final android.graphics.ColorSpace.Named CIE_LAB; enum_constant public static final android.graphics.ColorSpace.Named CIE_XYZ;
core/java/android/hardware/DataSpace.java +1 −3 Original line number Diff line number Diff line Loading @@ -521,9 +521,7 @@ public final class DataSpace { public static final int DATASPACE_BT2020_HLG = 168165376; /** * ITU-R Recommendation 2020 (BT.2020) * * Ultra High-definition television. * Perceptual Quantizer encoding. * * <p>Composed of the following -</p> * <pre> Loading
graphics/java/android/graphics/BitmapFactory.java +13 −3 Original line number Diff line number Diff line Loading @@ -161,11 +161,17 @@ public class BitmapFactory { * be thrown by the decode methods when setting a non-RGB color space * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p> * * <p class="note">The specified color space's transfer function must be * <p class="note"> * Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, * the specified color space's transfer function must be * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An * <code>IllegalArgumentException</code> will be thrown by the decode methods * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the * specified color space returns null.</p> * specified color space returns null. * * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, * non ICC parametric curve transfer function is allowed. * E.g., {@link ColorSpace.Named#BT2020_HLG BT2020_HLG}.</p> * * <p>After decode, the bitmap's color space is stored in * {@link #outColorSpace}.</p> Loading Loading @@ -458,7 +464,11 @@ public class BitmapFactory { throw new IllegalArgumentException("The destination color space must use the " + "RGB color model"); } if (((ColorSpace.Rgb) opts.inPreferredColorSpace).getTransferParameters() == null) { if (!opts.inPreferredColorSpace.equals(ColorSpace.get(ColorSpace.Named.BT2020_HLG)) && !opts.inPreferredColorSpace.equals( ColorSpace.get(ColorSpace.Named.BT2020_PQ)) && ((ColorSpace.Rgb) opts.inPreferredColorSpace) .getTransferParameters() == null) { throw new IllegalArgumentException("The destination color space must use an " + "ICC parametric transfer function"); } Loading
graphics/java/android/graphics/ColorSpace.java +188 −59 Original line number Diff line number Diff line Loading @@ -199,6 +199,8 @@ public abstract class ColorSpace { private static final float[] SRGB_PRIMARIES = { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }; private static final float[] NTSC_1953_PRIMARIES = { 0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f }; private static final float[] BT2020_PRIMARIES = { 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f }; /** * A gray color space does not have meaningful primaries, so we use this arbitrary set. */ Loading @@ -208,6 +210,12 @@ public abstract class ColorSpace { private static final Rgb.TransferParameters SRGB_TRANSFER_PARAMETERS = new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4); private static final Rgb.TransferParameters BT2020_HLG_TRANSFER_PARAMETERS = new Rgb.TransferParameters(2.0f, 2.0f, 1 / 0.17883277f, 0.28466892f, 0.5599107f, 0.0f, -3.0f, true); private static final Rgb.TransferParameters BT2020_PQ_TRANSFER_PARAMETERS = new Rgb.TransferParameters(107 / 128.0f, 1.0f, 32 / 2523.0f, 2413 / 128.0f, -2392 / 128.0f, 8192 / 1305.0f, -2.0f, true); // See static initialization block next to #get(Named) private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length]; Loading Loading @@ -703,7 +711,29 @@ public abstract class ColorSpace { * <tr><td>Range</td><td colspan="4">\(L: [0.0, 100.0], a: [-128, 128], b: [-128, 128]\)</td></tr> * </table> */ CIE_LAB CIE_LAB, /** * <p>{@link ColorSpace.Rgb RGB} color space BT.2100 standardized as * Hybrid Log Gamma encoding.</p> * <table summary="Color space definition"> * <tr><th>Property</th><th colspan="4">Value</th></tr> * <tr><td>Name</td><td colspan="4">Hybrid Log Gamma encoding</td></tr> * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> * </table> */ BT2020_HLG, /** * <p>{@link ColorSpace.Rgb RGB} color space BT.2100 standardized as * Perceptual Quantizer encoding.</p> * <table summary="Color space definition"> * <tr><th>Property</th><th colspan="4">Value</th></tr> * <tr><td>Name</td><td colspan="4">Perceptual Quantizer encoding</td></tr> * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> * </table> */ BT2020_PQ // Update the initialization block next to #get(Named) when adding new values } Loading Loading @@ -1534,7 +1564,7 @@ public abstract class ColorSpace { sDataToColorSpaces.put(DataSpace.DATASPACE_BT709, 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 }, BT2020_PRIMARIES, ILLUMINANT_D65, null, new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45), Loading Loading @@ -1616,6 +1646,70 @@ public abstract class ColorSpace { "Generic L*a*b*", Named.CIE_LAB.ordinal() ); sNamedColorSpaces[Named.BT2020_HLG.ordinal()] = new ColorSpace.Rgb( "Hybrid Log Gamma encoding", BT2020_PRIMARIES, ILLUMINANT_D65, null, x -> transferHLGOETF(x), x -> transferHLGEOTF(x), 0.0f, 1.0f, BT2020_HLG_TRANSFER_PARAMETERS, Named.BT2020_HLG.ordinal() ); sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020_HLG, Named.BT2020_HLG.ordinal()); sNamedColorSpaces[Named.BT2020_PQ.ordinal()] = new ColorSpace.Rgb( "Perceptual Quantizer encoding", BT2020_PRIMARIES, ILLUMINANT_D65, null, x -> transferST2048OETF(x), x -> transferST2048EOTF(x), 0.0f, 1.0f, BT2020_PQ_TRANSFER_PARAMETERS, Named.BT2020_PQ.ordinal() ); sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020_PQ, Named.BT2020_PQ.ordinal()); } private static double transferHLGOETF(double x) { double a = 0.17883277; double b = 0.28466892; double c = 0.55991073; double r = 0.5; return x > 1.0 ? a * Math.log(x - b) + c : r * Math.sqrt(x); } private static double transferHLGEOTF(double x) { double a = 0.17883277; double b = 0.28466892; double c = 0.55991073; double r = 0.5; return x <= 0.5 ? (x * x) / (r * r) : Math.exp((x - c) / a + b); } private static double transferST2048OETF(double x) { double m1 = (2610.0 / 4096.0) / 4.0; double m2 = (2523.0 / 4096.0) * 128.0; double c1 = (3424.0 / 4096.0); double c2 = (2413.0 / 4096.0) * 32.0; double c3 = (2392.0 / 4096.0) * 32.0; double tmp = Math.pow(x, m1); tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); return Math.pow(tmp, m2); } private static double transferST2048EOTF(double x) { double m1 = (2610.0 / 4096.0) / 4.0; double m2 = (2523.0 / 4096.0) * 128.0; double c1 = (3424.0 / 4096.0); double c2 = (2413.0 / 4096.0) * 32.0; double c3 = (2392.0 / 4096.0) * 32.0; double tmp = Math.pow(Math.min(Math.max(x, 0.0), 1.0), 1.0 / m2); tmp = Math.max(tmp - c1, 0.0) / (c2 - c3 * tmp); return Math.pow(tmp, 1.0 / m1); } // Reciprocal piecewise gamma response Loading Loading @@ -2197,6 +2291,58 @@ public abstract class ColorSpace { /** Variable \(g\) in the equation of the EOTF described above. */ public final double g; private TransferParameters(double a, double b, double c, double d, double e, double f, double g, boolean nonCurveTransferParameters) { // nonCurveTransferParameters correspondes to a "special" transfer function if (!nonCurveTransferParameters) { 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"); } // Next representable float after 1.0 // We use doubles here but the representation inside our native code // is often floats if (!(d >= 0.0 && d <= 1.0f + Math.ulp(1.0f))) { throw new IllegalArgumentException( "Parameter d must be in the range [0..1], " + "was " + d); } 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; } /** * <p>Defines the parameters for the ICC parametric curve type 3, as * defined in ICC.1:2004-10, section 10.15.</p> Loading @@ -2219,7 +2365,7 @@ public abstract class ColorSpace { * @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); this(a, b, c, d, 0.0, 0.0, g, false); } /** Loading @@ -2238,51 +2384,7 @@ public abstract class ColorSpace { */ 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"); } // Next representable float after 1.0 // We use doubles here but the representation inside our native code is often floats if (!(d >= 0.0 && d <= 1.0f + Math.ulp(1.0f))) { throw new IllegalArgumentException("Parameter d must be in the range [0..1], " + "was " + d); } 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; this(a, b, c, d, e, f, g, false); } @SuppressWarnings("SimplifiableIfStatement") Loading Loading @@ -2357,6 +2459,36 @@ public abstract class ColorSpace { private static native long nativeCreate(float a, float b, float c, float d, float e, float f, float g, float[] xyz); private static DoubleUnaryOperator generateOETF(TransferParameters function) { boolean isNonCurveTransferParameters = function.equals(BT2020_HLG_TRANSFER_PARAMETERS) || function.equals(BT2020_PQ_TRANSFER_PARAMETERS); if (isNonCurveTransferParameters) { return function.f == 0.0 && function.g < 0.0 ? x -> transferHLGOETF(x) : x -> transferST2048OETF(x); } else { return 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); } } private static DoubleUnaryOperator generateEOTF(TransferParameters function) { boolean isNonCurveTransferParameters = function.equals(BT2020_HLG_TRANSFER_PARAMETERS) || function.equals(BT2020_PQ_TRANSFER_PARAMETERS); if (isNonCurveTransferParameters) { return function.f == 0.0 && function.g < 0.0 ? x -> transferHLGEOTF(x) : x -> transferST2048EOTF(x); } else { return 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); } } /** * <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 Loading Loading @@ -2553,16 +2685,8 @@ public abstract class ColorSpace { @NonNull TransferParameters function, @IntRange(from = MIN_ID, to = MAX_ID) int id) { this(name, primaries, whitePoint, transform, 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), generateOETF(function), generateEOTF(function), 0.0f, 1.0f, function, id); } Loading Loading @@ -3063,8 +3187,13 @@ public abstract class ColorSpace { */ @Nullable public TransferParameters getTransferParameters() { if (mTransferParameters != null && !mTransferParameters.equals(BT2020_PQ_TRANSFER_PARAMETERS) && !mTransferParameters.equals(BT2020_HLG_TRANSFER_PARAMETERS)) { return mTransferParameters; } return null; } @Override public boolean isSrgb() { Loading
libs/hwui/jni/Graphics.cpp +18 −10 Original line number Diff line number Diff line Loading @@ -576,14 +576,22 @@ jobject GraphicsJNI::getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace, LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix)); skcms_TransferFunction transferParams; // We can only handle numerical transfer functions at the moment LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams)); decodeColorSpace->transferFn(&transferParams); auto res = skcms_TransferFunction_getType(&transferParams); LOG_ALWAYS_FATAL_IF(res == skcms_TFType_HLGinvish || res == skcms_TFType_Invalid); jobject params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID, jobject params; if (res == skcms_TFType_PQish || res == skcms_TFType_HLGish) { params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID, transferParams.a, transferParams.b, transferParams.c, transferParams.d, transferParams.e, transferParams.f, transferParams.g); transferParams.g, true); } else { params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID, transferParams.a, transferParams.b, transferParams.c, transferParams.d, transferParams.e, transferParams.f, transferParams.g, false); } jfloatArray xyzArray = env->NewFloatArray(9); jfloat xyz[9] = { Loading Loading @@ -808,8 +816,8 @@ int register_android_graphics_Graphics(JNIEnv* env) gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters")); gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class, "<init>", "(DDDDDDD)V"); gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class, "<init>", "(DDDDDDDZ)V"); gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics"); gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class); Loading