Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -15974,6 +15974,7 @@ package android.graphics { enum_constant public static final android.graphics.ColorSpace.Named LINEAR_EXTENDED_SRGB; enum_constant public static final android.graphics.ColorSpace.Named LINEAR_SRGB; enum_constant public static final android.graphics.ColorSpace.Named NTSC_1953; enum_constant @FlaggedApi("com.android.graphics.flags.ok_lab_colorspace") public static final android.graphics.ColorSpace.Named OK_LAB; enum_constant public static final android.graphics.ColorSpace.Named PRO_PHOTO_RGB; enum_constant public static final android.graphics.ColorSpace.Named SMPTE_C; enum_constant public static final android.graphics.ColorSpace.Named SRGB; graphics/java/android/framework_graphics.aconfig +9 −0 Original line number Diff line number Diff line Loading @@ -24,3 +24,12 @@ flag { description: "Return null when decode from URI fails in Icon.loadDrawable()" bug: "335878768" } flag { name: "ok_lab_colorspace" is_exported: true is_fixed_read_only: true namespace: "core_graphics" description: "Add OkLab ColorSpace support" bug: "344038816" } graphics/java/android/graphics/ColorSpace.java +179 −47 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.graphics; import android.annotation.AnyThread; import android.annotation.FlaggedApi; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -27,9 +28,13 @@ import android.hardware.DataSpace; import android.hardware.DataSpace.ColorDataSpace; import android.util.SparseIntArray; import com.android.graphics.flags.Flags; import libcore.util.NativeAllocationRegistry; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.function.DoubleUnaryOperator; /** Loading Loading @@ -230,7 +235,9 @@ public abstract class ColorSpace { -2392 / 128.0, 8192 / 1305.0, Rgb.TransferParameters.TYPE_PQish); // See static initialization block next to #get(Named) private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length]; private static final HashMap<Integer, ColorSpace> sNamedColorSpaceMap = new HashMap<>(); private static final SparseIntArray sDataToColorSpaces = new SparseIntArray(); @NonNull private final String mName; Loading Loading @@ -745,7 +752,23 @@ public abstract class ColorSpace { * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> * </table> */ BT2020_PQ BT2020_PQ, /** * <p>{@link ColorSpace.Lab Lab} color space OkLab standardized as * OkLab</p> * <table summary="Color space definition"> * <tr><th>Property</th><th colspan="4">Value</th></tr> * <tr><td>Name</td><td colspan="4">Oklab</td></tr> * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> * <tr> * <td>Range</td> * <td colspan="4">\(L: `[0.0, 1.0]`, a: `[-2, 2]`, b: `[-2, 2]`\)</td> * </tr> * </table> */ @FlaggedApi(Flags.FLAG_OK_LAB_COLORSPACE) OK_LAB // Update the initialization block next to #get(Named) when adding new values } Loading Loading @@ -1428,11 +1451,11 @@ public abstract class ColorSpace { */ @NonNull static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) { if (index < 0 || index >= sNamedColorSpaces.length) { throw new IllegalArgumentException("Invalid ID, must be in the range [0.." + sNamedColorSpaces.length + ")"); ColorSpace colorspace = sNamedColorSpaceMap.get(index); if (colorspace == null) { throw new IllegalArgumentException("Invalid ID: " + index); } return sNamedColorSpaces[index]; return colorspace; } /** Loading Loading @@ -1485,12 +1508,20 @@ public abstract class ColorSpace { * * <p>This method is thread-safe.</p> * * Note that in the Android W release and later, this can return the SRGB ColorSpace if * the {@link ColorSpace.Named} parameter is not enabled in the corresponding release. * * @param name The name of the color space to get an instance of * @return A non-null {@link ColorSpace} instance * @return A non-null {@link ColorSpace} instance. If the ColorSpace is not supported * then the SRGB ColorSpace is returned. */ @NonNull public static ColorSpace get(@NonNull Named name) { return sNamedColorSpaces[name.ordinal()]; ColorSpace colorSpace = sNamedColorSpaceMap.get(name.ordinal()); if (colorSpace == null) { return sNamedColorSpaceMap.get(Named.SRGB.ordinal()); } return colorSpace; } /** Loading @@ -1511,7 +1542,8 @@ public abstract class ColorSpace { @NonNull @Size(9) float[] toXYZD50, @NonNull Rgb.TransferParameters function) { for (ColorSpace colorSpace : sNamedColorSpaces) { Collection<ColorSpace> colorspaces = sNamedColorSpaceMap.values(); for (ColorSpace colorSpace : colorspaces) { if (colorSpace.getModel() == Model.RGB) { ColorSpace.Rgb rgb = (ColorSpace.Rgb) adapt(colorSpace, ILLUMINANT_D50_XYZ); if (compare(toXYZD50, rgb.mTransform) && Loading @@ -1525,25 +1557,25 @@ public abstract class ColorSpace { } static { sNamedColorSpaces[Named.SRGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.SRGB.ordinal(), new ColorSpace.Rgb( "sRGB IEC61966-2.1", SRGB_PRIMARIES, ILLUMINANT_D65, null, SRGB_TRANSFER_PARAMETERS, Named.SRGB.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_SRGB, Named.SRGB.ordinal()); sNamedColorSpaces[Named.LINEAR_SRGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.LINEAR_SRGB.ordinal(), new ColorSpace.Rgb( "sRGB IEC61966-2.1 (Linear)", SRGB_PRIMARIES, ILLUMINANT_D65, 1.0, 0.0f, 1.0f, Named.LINEAR_SRGB.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_SRGB_LINEAR, Named.LINEAR_SRGB.ordinal()); sNamedColorSpaces[Named.EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.EXTENDED_SRGB.ordinal(), new ColorSpace.Rgb( "scRGB-nl IEC 61966-2-2:2003", SRGB_PRIMARIES, ILLUMINANT_D65, Loading @@ -1553,112 +1585,113 @@ public abstract class ColorSpace { -0.799f, 2.399f, SRGB_TRANSFER_PARAMETERS, Named.EXTENDED_SRGB.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_SCRGB, Named.EXTENDED_SRGB.ordinal()); sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.LINEAR_EXTENDED_SRGB.ordinal(), new ColorSpace.Rgb( "scRGB IEC 61966-2-2:2003", SRGB_PRIMARIES, ILLUMINANT_D65, 1.0, -0.5f, 7.499f, Named.LINEAR_EXTENDED_SRGB.ordinal() ); )); sDataToColorSpaces.put( DataSpace.DATASPACE_SCRGB_LINEAR, Named.LINEAR_EXTENDED_SRGB.ordinal()); sNamedColorSpaces[Named.BT709.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.BT709.ordinal(), new ColorSpace.Rgb( "Rec. ITU-R BT.709-5", SRGB_PRIMARIES, ILLUMINANT_D65, null, SMPTE_170M_TRANSFER_PARAMETERS, Named.BT709.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_BT709, Named.BT709.ordinal()); sNamedColorSpaces[Named.BT2020.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.BT2020.ordinal(), new ColorSpace.Rgb( "Rec. ITU-R BT.2020-1", BT2020_PRIMARIES, ILLUMINANT_D65, null, new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45), Named.BT2020.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020, Named.BT2020.ordinal()); sNamedColorSpaces[Named.DCI_P3.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.DCI_P3.ordinal(), new ColorSpace.Rgb( "SMPTE RP 431-2-2007 DCI (P3)", DCI_P3_PRIMARIES, new float[] { 0.314f, 0.351f }, 2.6, 0.0f, 1.0f, Named.DCI_P3.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_DCI_P3, Named.DCI_P3.ordinal()); sNamedColorSpaces[Named.DISPLAY_P3.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.DISPLAY_P3.ordinal(), new ColorSpace.Rgb( "Display P3", DCI_P3_PRIMARIES, ILLUMINANT_D65, null, SRGB_TRANSFER_PARAMETERS, Named.DISPLAY_P3.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_DISPLAY_P3, Named.DISPLAY_P3.ordinal()); sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.NTSC_1953.ordinal(), new ColorSpace.Rgb( "NTSC (1953)", NTSC_1953_PRIMARIES, ILLUMINANT_C, null, SMPTE_170M_TRANSFER_PARAMETERS, Named.NTSC_1953.ordinal() ); sNamedColorSpaces[Named.SMPTE_C.ordinal()] = new ColorSpace.Rgb( )); sNamedColorSpaceMap.put(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, null, SMPTE_170M_TRANSFER_PARAMETERS, Named.SMPTE_C.ordinal() ); sNamedColorSpaces[Named.ADOBE_RGB.ordinal()] = new ColorSpace.Rgb( )); sNamedColorSpaceMap.put(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, 2.2, 0.0f, 1.0f, Named.ADOBE_RGB.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_ADOBE_RGB, Named.ADOBE_RGB.ordinal()); sNamedColorSpaces[Named.PRO_PHOTO_RGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.PRO_PHOTO_RGB.ordinal(), new ColorSpace.Rgb( "ROMM RGB ISO 22028-2:2013", new float[] { 0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f }, ILLUMINANT_D50, null, 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( )); sNamedColorSpaceMap.put(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, 1.0, -65504.0f, 65504.0f, Named.ACES.ordinal() ); sNamedColorSpaces[Named.ACESCG.ordinal()] = new ColorSpace.Rgb( )); sNamedColorSpaceMap.put(Named.ACESCG.ordinal(), new ColorSpace.Rgb( "Academy S-2014-004 ACEScg", new float[] { 0.713f, 0.293f, 0.165f, 0.830f, 0.128f, 0.044f }, ILLUMINANT_D60, 1.0, -65504.0f, 65504.0f, Named.ACESCG.ordinal() ); sNamedColorSpaces[Named.CIE_XYZ.ordinal()] = new Xyz( )); sNamedColorSpaceMap.put(Named.CIE_XYZ.ordinal(), new Xyz( "Generic XYZ", Named.CIE_XYZ.ordinal() ); sNamedColorSpaces[Named.CIE_LAB.ordinal()] = new ColorSpace.Lab( )); sNamedColorSpaceMap.put(Named.CIE_LAB.ordinal(), new ColorSpace.Lab( "Generic L*a*b*", Named.CIE_LAB.ordinal() ); sNamedColorSpaces[Named.BT2020_HLG.ordinal()] = new ColorSpace.Rgb( )); sNamedColorSpaceMap.put(Named.BT2020_HLG.ordinal(), new ColorSpace.Rgb( "Hybrid Log Gamma encoding", BT2020_PRIMARIES, ILLUMINANT_D65, Loading @@ -1668,9 +1701,9 @@ public abstract class ColorSpace { 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( sNamedColorSpaceMap.put(Named.BT2020_PQ.ordinal(), new ColorSpace.Rgb( "Perceptual Quantizer encoding", BT2020_PRIMARIES, ILLUMINANT_D65, Loading @@ -1680,8 +1713,14 @@ public abstract class ColorSpace { 0.0f, 1.0f, BT2020_PQ_TRANSFER_PARAMETERS, Named.BT2020_PQ.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020_PQ, Named.BT2020_PQ.ordinal()); if (Flags.okLabColorspace()) { sNamedColorSpaceMap.put(Named.OK_LAB.ordinal(), new ColorSpace.OkLab( "Oklab", Named.OK_LAB.ordinal() )); } } private static double transferHLGOETF(Rgb.TransferParameters params, double x) { Loading Loading @@ -2142,10 +2181,103 @@ public abstract class ColorSpace { return v; } } private static float clamp(float x, float min, float max) { return x < min ? min : x > max ? max : x; } /** * Implementation of the Oklab color space. Oklab uses a D65 white point. */ @AnyThread private static final class OkLab extends ColorSpace { private OkLab(@NonNull String name, @IntRange(from = MIN_ID, to = MAX_ID) int id) { super(name, Model.LAB, id); } @Override public boolean isWideGamut() { return true; } @Override public float getMinValue(@IntRange(from = 0, to = 3) int component) { return component == 0 ? 0.0f : -0.5f; } @Override public float getMaxValue(@IntRange(from = 0, to = 3) int component) { return component == 0 ? 1.0f : 0.5f; } @Override public float[] toXyz(@NonNull @Size(min = 3) float[] v) { v[0] = clamp(v[0], 0.0f, 1.0f); v[1] = clamp(v[1], -0.5f, 0.5f); v[2] = clamp(v[2], -0.5f, 0.5f); mul3x3Float3(INVERSE_M2, v); v[0] = v[0] * v[0] * v[0]; v[1] = v[1] * v[1] * v[1]; v[2] = v[2] * v[2] * v[2]; mul3x3Float3(INVERSE_M1, v); return v; } @Override public float[] fromXyz(@NonNull @Size(min = 3) float[] v) { mul3x3Float3(M1, v); v[0] = (float) Math.cbrt(v[0]); v[1] = (float) Math.cbrt(v[1]); v[2] = (float) Math.cbrt(v[2]); mul3x3Float3(M2, v); return v; } /** * Temp array used as input to compute M1 below */ private static final float[] M1TMP = { 0.8189330101f, 0.0329845436f, 0.0482003018f, 0.3618667424f, 0.9293118715f, 0.2643662691f, -0.1288597137f, 0.0361456387f, 0.6338517070f }; /** * This is the matrix applied before the nonlinear transform for (D50) XYZ-to-Oklab. * This combines the D50-to-D65 white point transform with the normal transform matrix * because this is always done together in [fromXyz]. */ private static final float[] M1 = mul3x3( M1TMP, chromaticAdaptation(Adaptation.BRADFORD, ILLUMINANT_D50, ILLUMINANT_D65) ); /** * Matrix applied after the nonlinear transform. */ private static final float[] M2 = { 0.2104542553f, 1.9779984951f, 0.0259040371f, 0.7936177850f, -2.4285922050f, 0.7827717662f, -0.0040720468f, 0.4505937099f, -0.8086757660f }; /** * The inverse of the [M1] matrix, transforming back to XYZ (D50) */ private static final float[] INVERSE_M1 = inverse3x3(M1); /** * The inverse of the [M2] matrix, doing the first linear transform in the * Oklab-to-XYZ before doing the nonlinear transform. */ private static final float[] INVERSE_M2 = inverse3x3(M2); } /** Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -15974,6 +15974,7 @@ package android.graphics { enum_constant public static final android.graphics.ColorSpace.Named LINEAR_EXTENDED_SRGB; enum_constant public static final android.graphics.ColorSpace.Named LINEAR_SRGB; enum_constant public static final android.graphics.ColorSpace.Named NTSC_1953; enum_constant @FlaggedApi("com.android.graphics.flags.ok_lab_colorspace") public static final android.graphics.ColorSpace.Named OK_LAB; enum_constant public static final android.graphics.ColorSpace.Named PRO_PHOTO_RGB; enum_constant public static final android.graphics.ColorSpace.Named SMPTE_C; enum_constant public static final android.graphics.ColorSpace.Named SRGB;
graphics/java/android/framework_graphics.aconfig +9 −0 Original line number Diff line number Diff line Loading @@ -24,3 +24,12 @@ flag { description: "Return null when decode from URI fails in Icon.loadDrawable()" bug: "335878768" } flag { name: "ok_lab_colorspace" is_exported: true is_fixed_read_only: true namespace: "core_graphics" description: "Add OkLab ColorSpace support" bug: "344038816" }
graphics/java/android/graphics/ColorSpace.java +179 −47 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.graphics; import android.annotation.AnyThread; import android.annotation.FlaggedApi; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -27,9 +28,13 @@ import android.hardware.DataSpace; import android.hardware.DataSpace.ColorDataSpace; import android.util.SparseIntArray; import com.android.graphics.flags.Flags; import libcore.util.NativeAllocationRegistry; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.function.DoubleUnaryOperator; /** Loading Loading @@ -230,7 +235,9 @@ public abstract class ColorSpace { -2392 / 128.0, 8192 / 1305.0, Rgb.TransferParameters.TYPE_PQish); // See static initialization block next to #get(Named) private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length]; private static final HashMap<Integer, ColorSpace> sNamedColorSpaceMap = new HashMap<>(); private static final SparseIntArray sDataToColorSpaces = new SparseIntArray(); @NonNull private final String mName; Loading Loading @@ -745,7 +752,23 @@ public abstract class ColorSpace { * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> * </table> */ BT2020_PQ BT2020_PQ, /** * <p>{@link ColorSpace.Lab Lab} color space OkLab standardized as * OkLab</p> * <table summary="Color space definition"> * <tr><th>Property</th><th colspan="4">Value</th></tr> * <tr><td>Name</td><td colspan="4">Oklab</td></tr> * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> * <tr> * <td>Range</td> * <td colspan="4">\(L: `[0.0, 1.0]`, a: `[-2, 2]`, b: `[-2, 2]`\)</td> * </tr> * </table> */ @FlaggedApi(Flags.FLAG_OK_LAB_COLORSPACE) OK_LAB // Update the initialization block next to #get(Named) when adding new values } Loading Loading @@ -1428,11 +1451,11 @@ public abstract class ColorSpace { */ @NonNull static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) { if (index < 0 || index >= sNamedColorSpaces.length) { throw new IllegalArgumentException("Invalid ID, must be in the range [0.." + sNamedColorSpaces.length + ")"); ColorSpace colorspace = sNamedColorSpaceMap.get(index); if (colorspace == null) { throw new IllegalArgumentException("Invalid ID: " + index); } return sNamedColorSpaces[index]; return colorspace; } /** Loading Loading @@ -1485,12 +1508,20 @@ public abstract class ColorSpace { * * <p>This method is thread-safe.</p> * * Note that in the Android W release and later, this can return the SRGB ColorSpace if * the {@link ColorSpace.Named} parameter is not enabled in the corresponding release. * * @param name The name of the color space to get an instance of * @return A non-null {@link ColorSpace} instance * @return A non-null {@link ColorSpace} instance. If the ColorSpace is not supported * then the SRGB ColorSpace is returned. */ @NonNull public static ColorSpace get(@NonNull Named name) { return sNamedColorSpaces[name.ordinal()]; ColorSpace colorSpace = sNamedColorSpaceMap.get(name.ordinal()); if (colorSpace == null) { return sNamedColorSpaceMap.get(Named.SRGB.ordinal()); } return colorSpace; } /** Loading @@ -1511,7 +1542,8 @@ public abstract class ColorSpace { @NonNull @Size(9) float[] toXYZD50, @NonNull Rgb.TransferParameters function) { for (ColorSpace colorSpace : sNamedColorSpaces) { Collection<ColorSpace> colorspaces = sNamedColorSpaceMap.values(); for (ColorSpace colorSpace : colorspaces) { if (colorSpace.getModel() == Model.RGB) { ColorSpace.Rgb rgb = (ColorSpace.Rgb) adapt(colorSpace, ILLUMINANT_D50_XYZ); if (compare(toXYZD50, rgb.mTransform) && Loading @@ -1525,25 +1557,25 @@ public abstract class ColorSpace { } static { sNamedColorSpaces[Named.SRGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.SRGB.ordinal(), new ColorSpace.Rgb( "sRGB IEC61966-2.1", SRGB_PRIMARIES, ILLUMINANT_D65, null, SRGB_TRANSFER_PARAMETERS, Named.SRGB.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_SRGB, Named.SRGB.ordinal()); sNamedColorSpaces[Named.LINEAR_SRGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.LINEAR_SRGB.ordinal(), new ColorSpace.Rgb( "sRGB IEC61966-2.1 (Linear)", SRGB_PRIMARIES, ILLUMINANT_D65, 1.0, 0.0f, 1.0f, Named.LINEAR_SRGB.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_SRGB_LINEAR, Named.LINEAR_SRGB.ordinal()); sNamedColorSpaces[Named.EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.EXTENDED_SRGB.ordinal(), new ColorSpace.Rgb( "scRGB-nl IEC 61966-2-2:2003", SRGB_PRIMARIES, ILLUMINANT_D65, Loading @@ -1553,112 +1585,113 @@ public abstract class ColorSpace { -0.799f, 2.399f, SRGB_TRANSFER_PARAMETERS, Named.EXTENDED_SRGB.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_SCRGB, Named.EXTENDED_SRGB.ordinal()); sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.LINEAR_EXTENDED_SRGB.ordinal(), new ColorSpace.Rgb( "scRGB IEC 61966-2-2:2003", SRGB_PRIMARIES, ILLUMINANT_D65, 1.0, -0.5f, 7.499f, Named.LINEAR_EXTENDED_SRGB.ordinal() ); )); sDataToColorSpaces.put( DataSpace.DATASPACE_SCRGB_LINEAR, Named.LINEAR_EXTENDED_SRGB.ordinal()); sNamedColorSpaces[Named.BT709.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.BT709.ordinal(), new ColorSpace.Rgb( "Rec. ITU-R BT.709-5", SRGB_PRIMARIES, ILLUMINANT_D65, null, SMPTE_170M_TRANSFER_PARAMETERS, Named.BT709.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_BT709, Named.BT709.ordinal()); sNamedColorSpaces[Named.BT2020.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.BT2020.ordinal(), new ColorSpace.Rgb( "Rec. ITU-R BT.2020-1", BT2020_PRIMARIES, ILLUMINANT_D65, null, new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45), Named.BT2020.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020, Named.BT2020.ordinal()); sNamedColorSpaces[Named.DCI_P3.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.DCI_P3.ordinal(), new ColorSpace.Rgb( "SMPTE RP 431-2-2007 DCI (P3)", DCI_P3_PRIMARIES, new float[] { 0.314f, 0.351f }, 2.6, 0.0f, 1.0f, Named.DCI_P3.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_DCI_P3, Named.DCI_P3.ordinal()); sNamedColorSpaces[Named.DISPLAY_P3.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.DISPLAY_P3.ordinal(), new ColorSpace.Rgb( "Display P3", DCI_P3_PRIMARIES, ILLUMINANT_D65, null, SRGB_TRANSFER_PARAMETERS, Named.DISPLAY_P3.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_DISPLAY_P3, Named.DISPLAY_P3.ordinal()); sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.NTSC_1953.ordinal(), new ColorSpace.Rgb( "NTSC (1953)", NTSC_1953_PRIMARIES, ILLUMINANT_C, null, SMPTE_170M_TRANSFER_PARAMETERS, Named.NTSC_1953.ordinal() ); sNamedColorSpaces[Named.SMPTE_C.ordinal()] = new ColorSpace.Rgb( )); sNamedColorSpaceMap.put(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, null, SMPTE_170M_TRANSFER_PARAMETERS, Named.SMPTE_C.ordinal() ); sNamedColorSpaces[Named.ADOBE_RGB.ordinal()] = new ColorSpace.Rgb( )); sNamedColorSpaceMap.put(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, 2.2, 0.0f, 1.0f, Named.ADOBE_RGB.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_ADOBE_RGB, Named.ADOBE_RGB.ordinal()); sNamedColorSpaces[Named.PRO_PHOTO_RGB.ordinal()] = new ColorSpace.Rgb( sNamedColorSpaceMap.put(Named.PRO_PHOTO_RGB.ordinal(), new ColorSpace.Rgb( "ROMM RGB ISO 22028-2:2013", new float[] { 0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f }, ILLUMINANT_D50, null, 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( )); sNamedColorSpaceMap.put(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, 1.0, -65504.0f, 65504.0f, Named.ACES.ordinal() ); sNamedColorSpaces[Named.ACESCG.ordinal()] = new ColorSpace.Rgb( )); sNamedColorSpaceMap.put(Named.ACESCG.ordinal(), new ColorSpace.Rgb( "Academy S-2014-004 ACEScg", new float[] { 0.713f, 0.293f, 0.165f, 0.830f, 0.128f, 0.044f }, ILLUMINANT_D60, 1.0, -65504.0f, 65504.0f, Named.ACESCG.ordinal() ); sNamedColorSpaces[Named.CIE_XYZ.ordinal()] = new Xyz( )); sNamedColorSpaceMap.put(Named.CIE_XYZ.ordinal(), new Xyz( "Generic XYZ", Named.CIE_XYZ.ordinal() ); sNamedColorSpaces[Named.CIE_LAB.ordinal()] = new ColorSpace.Lab( )); sNamedColorSpaceMap.put(Named.CIE_LAB.ordinal(), new ColorSpace.Lab( "Generic L*a*b*", Named.CIE_LAB.ordinal() ); sNamedColorSpaces[Named.BT2020_HLG.ordinal()] = new ColorSpace.Rgb( )); sNamedColorSpaceMap.put(Named.BT2020_HLG.ordinal(), new ColorSpace.Rgb( "Hybrid Log Gamma encoding", BT2020_PRIMARIES, ILLUMINANT_D65, Loading @@ -1668,9 +1701,9 @@ public abstract class ColorSpace { 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( sNamedColorSpaceMap.put(Named.BT2020_PQ.ordinal(), new ColorSpace.Rgb( "Perceptual Quantizer encoding", BT2020_PRIMARIES, ILLUMINANT_D65, Loading @@ -1680,8 +1713,14 @@ public abstract class ColorSpace { 0.0f, 1.0f, BT2020_PQ_TRANSFER_PARAMETERS, Named.BT2020_PQ.ordinal() ); )); sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020_PQ, Named.BT2020_PQ.ordinal()); if (Flags.okLabColorspace()) { sNamedColorSpaceMap.put(Named.OK_LAB.ordinal(), new ColorSpace.OkLab( "Oklab", Named.OK_LAB.ordinal() )); } } private static double transferHLGOETF(Rgb.TransferParameters params, double x) { Loading Loading @@ -2142,10 +2181,103 @@ public abstract class ColorSpace { return v; } } private static float clamp(float x, float min, float max) { return x < min ? min : x > max ? max : x; } /** * Implementation of the Oklab color space. Oklab uses a D65 white point. */ @AnyThread private static final class OkLab extends ColorSpace { private OkLab(@NonNull String name, @IntRange(from = MIN_ID, to = MAX_ID) int id) { super(name, Model.LAB, id); } @Override public boolean isWideGamut() { return true; } @Override public float getMinValue(@IntRange(from = 0, to = 3) int component) { return component == 0 ? 0.0f : -0.5f; } @Override public float getMaxValue(@IntRange(from = 0, to = 3) int component) { return component == 0 ? 1.0f : 0.5f; } @Override public float[] toXyz(@NonNull @Size(min = 3) float[] v) { v[0] = clamp(v[0], 0.0f, 1.0f); v[1] = clamp(v[1], -0.5f, 0.5f); v[2] = clamp(v[2], -0.5f, 0.5f); mul3x3Float3(INVERSE_M2, v); v[0] = v[0] * v[0] * v[0]; v[1] = v[1] * v[1] * v[1]; v[2] = v[2] * v[2] * v[2]; mul3x3Float3(INVERSE_M1, v); return v; } @Override public float[] fromXyz(@NonNull @Size(min = 3) float[] v) { mul3x3Float3(M1, v); v[0] = (float) Math.cbrt(v[0]); v[1] = (float) Math.cbrt(v[1]); v[2] = (float) Math.cbrt(v[2]); mul3x3Float3(M2, v); return v; } /** * Temp array used as input to compute M1 below */ private static final float[] M1TMP = { 0.8189330101f, 0.0329845436f, 0.0482003018f, 0.3618667424f, 0.9293118715f, 0.2643662691f, -0.1288597137f, 0.0361456387f, 0.6338517070f }; /** * This is the matrix applied before the nonlinear transform for (D50) XYZ-to-Oklab. * This combines the D50-to-D65 white point transform with the normal transform matrix * because this is always done together in [fromXyz]. */ private static final float[] M1 = mul3x3( M1TMP, chromaticAdaptation(Adaptation.BRADFORD, ILLUMINANT_D50, ILLUMINANT_D65) ); /** * Matrix applied after the nonlinear transform. */ private static final float[] M2 = { 0.2104542553f, 1.9779984951f, 0.0259040371f, 0.7936177850f, -2.4285922050f, 0.7827717662f, -0.0040720468f, 0.4505937099f, -0.8086757660f }; /** * The inverse of the [M1] matrix, transforming back to XYZ (D50) */ private static final float[] INVERSE_M1 = inverse3x3(M1); /** * The inverse of the [M2] matrix, doing the first linear transform in the * Oklab-to-XYZ before doing the nonlinear transform. */ private static final float[] INVERSE_M2 = inverse3x3(M2); } /** Loading