168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy/* 268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Copyright (C) 2016 The Android Open Source Project 368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * you may not use this file except in compliance with the License. 668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * You may obtain a copy of the License at 768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Unless required by applicable law or agreed to in writing, software 1168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 1268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * See the License for the specific language governing permissions and 1468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * limitations under the License. 1568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 1668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 1768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guypackage android.graphics; 1868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 1977b161e0b14372e3eb124ed19321a9639aeb4271Romain Guyimport android.annotation.AnyThread; 2015296a2d3478f53402e2d98f49724bb791eb339dRomain Guyimport android.annotation.ColorInt; 2168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guyimport android.annotation.IntRange; 2268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guyimport android.annotation.NonNull; 23199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guyimport android.annotation.Nullable; 24efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guyimport android.annotation.Size; 25910e081216ac530432ac9d0aab10d5e5e4c73ab8Jeff Sharkeyimport android.annotation.SuppressAutoDoc; 2615296a2d3478f53402e2d98f49724bb791eb339dRomain Guyimport android.util.Pair; 2768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 2815296a2d3478f53402e2d98f49724bb791eb339dRomain Guyimport java.util.ArrayList; 2968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guyimport java.util.Arrays; 3015296a2d3478f53402e2d98f49724bb791eb339dRomain Guyimport java.util.List; 3168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guyimport java.util.function.DoubleUnaryOperator; 3268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 3368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy/** 3468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@usesMathJax} 3568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 3668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>A {@link ColorSpace} is used to identify a specific organization of colors. 3768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Each color space is characterized by a {@link Model color model} that defines 3868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * how a color value is represented (for instance the {@link Model#RGB RGB} color 3968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * model defines a color value as a triplet of numbers).</p> 4068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 4168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Each component of a color must fall within a valid range, specific to each 4268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space, defined by {@link #getMinValue(int)} and {@link #getMaxValue(int)} 4368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This range is commonly \([0..1]\). While it is recommended to use values in the 4468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * valid range, a color space always clamps input and output values when performing 4568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * operations such as converting to a different color space.</p> 4668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 4768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <h3>Using color spaces</h3> 4868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 4968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>This implementation provides a pre-defined set of common color spaces 5068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * described in the {@link Named} enum. To obtain an instance of one of the 5168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * pre-defined color spaces, simply invoke {@link #get(Named)}:</p> 5268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 5368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <pre class="prettyprint"> 5468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace sRgb = ColorSpace.get(ColorSpace.Named.SRGB); 5568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </pre> 5668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 5768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The {@link #get(Named)} method always returns the same instance for a given 5868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * name. Color spaces with an {@link Model#RGB RGB} color model can be safely 5968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * cast to {@link Rgb}. Doing so gives you access to more APIs to query various 6068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * properties of RGB color models: color gamut primaries, transfer functions, 6168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * conversions to and from linear space, etc. Please refer to {@link Rgb} for 6268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * more information.</p> 6368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 6468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The documentation of {@link Named} provides a detailed description of the 6568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * various characteristics of each available color space.</p> 6668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 6768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <h3>Color space conversions</h3> 6868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 6968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>To allow conversion between color spaces, this implementation uses the CIE 7068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * XYZ profile connection space (PCS). Color values can be converted to and from 7168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * this PCS using {@link #toXyz(float[])} and {@link #fromXyz(float[])}.</p> 7268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 7368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>For color space with a non-RGB color model, the white point of the PCS 7468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <em>must be</em> the CIE standard illuminant D50. RGB color spaces use their 7568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * native white point (D65 for {@link Named#SRGB sRGB} for instance and must 7668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * undergo {@link Adaptation chromatic adaptation} as necessary.</p> 7768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 7868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Since the white point of the PCS is not defined for RGB color space, it is 7968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * highly recommended to use the variants of the {@link #connect(ColorSpace, ColorSpace)} 8068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * method to perform conversions between color spaces. A color space can be 8168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * manually adapted to a specific white point using {@link #adapt(ColorSpace, float[])}. 8268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Please refer to the documentation of {@link Rgb RGB color spaces} for more 8368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * information. Several common CIE standard illuminants are provided in this 8468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * class as reference (see {@link #ILLUMINANT_D65} or {@link #ILLUMINANT_D50} 8568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * for instance).</p> 8668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 8768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Here is an example of how to convert from a color space to another:</p> 8868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 8968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <pre class="prettyprint"> 9068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * // Convert from DCI-P3 to Rec.2020 9168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.Connector connector = ColorSpace.connect( 9268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.get(ColorSpace.Named.DCI_P3), 9368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.get(ColorSpace.Named.BT2020)); 9468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 9568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * float[] bt2020 = connector.transform(p3r, p3g, p3b); 9668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </pre> 9768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 9868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>You can easily convert to {@link Named#SRGB sRGB} by omitting the second 9968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * parameter:</p> 10068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 10168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <pre class="prettyprint"> 10268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * // Convert from DCI-P3 to sRGB 10368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.Connector connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.DCI_P3)); 10468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 10568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * float[] sRGB = connector.transform(p3r, p3g, p3b); 10668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </pre> 10768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 10868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Conversions also work between color spaces with different color models:</p> 10968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 11068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <pre class="prettyprint"> 11168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * // Convert from CIE L*a*b* (color model Lab) to Rec.709 (color model RGB) 11268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.Connector connector = ColorSpace.connect( 11368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.get(ColorSpace.Named.CIE_LAB), 11468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.get(ColorSpace.Named.BT709)); 11568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </pre> 11668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 11768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <h3>Color spaces and multi-threading</h3> 11868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 11968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Color spaces and other related classes ({@link Connector} for instance) 12068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are immutable and stateless. They can be safely used from multiple concurrent 12168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * threads.</p> 12268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 12368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Public static methods provided by this class, such as {@link #get(Named)} 12468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * and {@link #connect(ColorSpace, ColorSpace)}, are also guaranteed to be 12568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * thread-safe.</p> 12668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 12768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #get(Named) 12868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Named 12968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Model 13068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Connector 13168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Adaptation 13268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 13377b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy@AnyThread 13468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy@SuppressWarnings("StaticInitializerReferencesSubClass") 135910e081216ac530432ac9d0aab10d5e5e4c73ab8Jeff Sharkey@SuppressAutoDoc 13668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guypublic abstract class ColorSpace { 13768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 13868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant A, encoded in xyY. 13968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 2856K. 14068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 14168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_A = { 0.44757f, 0.40745f }; 14268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 14368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant B, encoded in xyY. 14468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 4874K. 14568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 14668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_B = { 0.34842f, 0.35161f }; 14768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 14868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant C, encoded in xyY. 14968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 6774K. 15068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 15168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_C = { 0.31006f, 0.31616f }; 15268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 15368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant D50, encoded in xyY. 15468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 5003K. This illuminant 15568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * is used by the profile connection space in ICC profiles. 15668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 15768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_D50 = { 0.34567f, 0.35850f }; 15868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 15968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant D55, encoded in xyY. 16068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 5503K. 16168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 16268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_D55 = { 0.33242f, 0.34743f }; 16368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 16468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant D60, encoded in xyY. 16568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 6004K. 16668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 16768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_D60 = { 0.32168f, 0.33767f }; 16868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 16968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant D65, encoded in xyY. 17068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 6504K. This illuminant 17168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * is commonly used in RGB color spaces such as sRGB, BT.209, etc. 17268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 17368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_D65 = { 0.31271f, 0.32902f }; 17468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 17568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant D75, encoded in xyY. 17668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 7504K. 17768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 17868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_D75 = { 0.29902f, 0.31485f }; 17968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 18068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Standard CIE 1931 2° illuminant E, encoded in xyY. 18168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This illuminant has a color temperature of 5454K. 18268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 18368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final float[] ILLUMINANT_E = { 0.33333f, 0.33333f }; 18468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 18568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 18668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The minimum ID value a color space can have. 18768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 18868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getId() 18968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 19068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static final int MIN_ID = -1; // Do not change 19168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 19268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The maximum ID value a color space can have. 19368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 19468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getId() 19568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 19677b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy public static final int MAX_ID = 63; // Do not change, used to encode in longs 19768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 19868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final float[] SRGB_PRIMARIES = { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }; 19968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final float[] NTSC_1953_PRIMARIES = { 0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f }; 20068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final float[] ILLUMINANT_D50_XYZ = { 0.964212f, 1.0f, 0.825188f }; 20168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 20268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // See static initialization block next to #get(Named) 20368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length]; 20468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 20568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final String mName; 20668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final Model mModel; 20768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @IntRange(from = MIN_ID, to = MAX_ID) private final int mId; 20868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 20968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 21068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@usesMathJax} 21168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 21268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>List of common, named color spaces. A corresponding instance of 21368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link ColorSpace} can be obtained by calling {@link ColorSpace#get(Named)}:</p> 21468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 21568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <pre class="prettyprint"> 21668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace cs = ColorSpace.get(ColorSpace.Named.DCI_P3); 21768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </pre> 21868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 219199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p>The properties of each color space are described below (see {@link #SRGB sRGB} 220199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * for instance). When applicable, the color gamut of each color space is compared 221199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * to the color gamut of sRGB using a CIE 1931 xy chromaticity diagram. This diagram 222199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * shows the location of the color space's primaries and white point.</p> 223199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * 22468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#get(Named) 22568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 22668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public enum Named { 22768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // NOTE: Do NOT change the order of the enum 22868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 22968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space sRGB standardized as IEC 61966-2.1:1999.</p> 23068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 23168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 23268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 23368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 23468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.640</td><td>0.300</td><td>0.150</td><td>0.3127</td></tr> 23568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.330</td><td>0.600</td><td>0.060</td><td>0.3290</td></tr> 23668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 23768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">sRGB IEC61966-2.1</td></tr> 23868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 23968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 240efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 24168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 242efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * C_{sRGB} = \begin{cases} 12.92 \times C_{linear} & C_{linear} \lt 0.0031308 \\ 243efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 1.055 \times C_{linear}^{\frac{1}{2.4}} - 0.055 & C_{linear} \ge 0.0031308 \end{cases} 24468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 24568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 24668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 24768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 248efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 24968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 250efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * C_{linear} = \begin{cases}\frac{C_{sRGB}}{12.92} & C_{sRGB} \lt 0.04045 \\ 251efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \left( \frac{C_{sRGB} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.04045 \end{cases} 25268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 25368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 25468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 25568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 25668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 257199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 258c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" /> 259199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">sRGB</figcaption> 260199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 26168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 26268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy SRGB, 26368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 26468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space sRGB standardized as IEC 61966-2.1:1999.</p> 26568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 26668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 26768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 26868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 26968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.640</td><td>0.300</td><td>0.150</td><td>0.3127</td></tr> 27068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.330</td><td>0.600</td><td>0.060</td><td>0.3290</td></tr> 27168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 27268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">sRGB IEC61966-2.1 (Linear)</td></tr> 27368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 27468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 275efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 27668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{sRGB} = C_{linear}\)</td> 27768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 27868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 279efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 28068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{linear} = C_{sRGB}\)</td> 28168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 28268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 28368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 284199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 285c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" /> 286199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">sRGB</figcaption> 287199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 28868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 28968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy LINEAR_SRGB, 29068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 29168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space scRGB-nl standardized as IEC 61966-2-2:2003.</p> 29268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 29368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 29468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 29568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 29668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.640</td><td>0.300</td><td>0.150</td><td>0.3127</td></tr> 29768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.330</td><td>0.600</td><td>0.060</td><td>0.3290</td></tr> 29868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 29968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">scRGB-nl IEC 61966-2-2:2003</td></tr> 30068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 30168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 302efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 30368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 30468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{scRGB} = \begin{cases} sign(C_{linear}) 12.92 \times \left| C_{linear} \right| & 305efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \left| C_{linear} \right| \lt 0.0031308 \\ 30668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * sign(C_{linear}) 1.055 \times \left| C_{linear} \right| ^{\frac{1}{2.4}} - 0.055 & 307efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \left| C_{linear} \right| \ge 0.0031308 \end{cases} 30868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 30968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 31068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 31168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 312efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 31368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 31468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{linear} = \begin{cases}sign(C_{scRGB}) \frac{\left| C_{scRGB} \right|}{12.92} & 315efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \left| C_{scRGB} \right| \lt 0.04045 \\ 31668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * sign(C_{scRGB}) \left( \frac{\left| C_{scRGB} \right| + 0.055}{1.055} \right) ^{2.4} & 317efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \left| C_{scRGB} \right| \ge 0.04045 \end{cases} 31868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 31968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 32068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 32177b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy * <tr><td>Range</td><td colspan="4">\([-0.799..2.399[\)</td></tr> 32268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 323199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 324c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" /> 32577b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy * <figcaption style="text-align: center;">Extended sRGB (orange) vs sRGB (white)</figcaption> 326199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 32768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 32868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy EXTENDED_SRGB, 32968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 33068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space scRGB standardized as IEC 61966-2-2:2003.</p> 33168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 33268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 33368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 33468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 33568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.640</td><td>0.300</td><td>0.150</td><td>0.3127</td></tr> 33668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.330</td><td>0.600</td><td>0.060</td><td>0.3290</td></tr> 33768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 33868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">scRGB IEC 61966-2-2:2003</td></tr> 33968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 34068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 341efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 34268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{scRGB} = C_{linear}\)</td> 34368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 34468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 345efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 34668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{linear} = C_{scRGB}\)</td> 34768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 34877b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy * <tr><td>Range</td><td colspan="4">\([-0.5..7.499[\)</td></tr> 34968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 350199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 351c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" /> 35277b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy * <figcaption style="text-align: center;">Extended sRGB (orange) vs sRGB (white)</figcaption> 353199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 35468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 35568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy LINEAR_EXTENDED_SRGB, 35668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 35768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space BT.709 standardized as Rec. ITU-R BT.709-5.</p> 35868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 35968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 36068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 36168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 36268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.640</td><td>0.300</td><td>0.150</td><td>0.3127</td></tr> 36368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.330</td><td>0.600</td><td>0.060</td><td>0.3290</td></tr> 36468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 36568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">Rec. ITU-R BT.709-5</td></tr> 36668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 36768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 368efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 36968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 37068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{BT709} = \begin{cases} 4.5 \times C_{linear} & C_{linear} \lt 0.018 \\ 37168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1.099 \times C_{linear}^{\frac{1}{2.2}} - 0.099 & C_{linear} \ge 0.018 \end{cases} 37268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 37368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 37468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 37568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 376efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 37768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 37868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{linear} = \begin{cases}\frac{C_{BT709}}{4.5} & C_{BT709} \lt 0.081 \\ 37968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \left( \frac{C_{BT709} + 0.099}{1.099} \right) ^{2.2} & C_{BT709} \ge 0.081 \end{cases} 38068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 38168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 38268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 38368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 38468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 385199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 386c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_bt709.png" /> 387199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">BT.709</figcaption> 388199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 38968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 39068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy BT709, 39168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 39268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space BT.2020 standardized as Rec. ITU-R BT.2020-1.</p> 39368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 39468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 39568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 39668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 39768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.708</td><td>0.170</td><td>0.131</td><td>0.3127</td></tr> 39868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.292</td><td>0.797</td><td>0.046</td><td>0.3290</td></tr> 39968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 40068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">Rec. ITU-R BT.2020-1</td></tr> 40168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 40268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 403efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 40468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 40568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{BT2020} = \begin{cases} 4.5 \times C_{linear} & C_{linear} \lt 0.0181 \\ 40668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1.0993 \times C_{linear}^{\frac{1}{2.2}} - 0.0993 & C_{linear} \ge 0.0181 \end{cases} 40768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 40868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 40968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 41068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 411efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 41268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 41368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{linear} = \begin{cases}\frac{C_{BT2020}}{4.5} & C_{BT2020} \lt 0.08145 \\ 41468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \left( \frac{C_{BT2020} + 0.0993}{1.0993} \right) ^{2.2} & C_{BT2020} \ge 0.08145 \end{cases} 41568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 41668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 41768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 41868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 41968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 420199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 421c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_bt2020.png" /> 422199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">BT.2020 (orange) vs sRGB (white)</figcaption> 423199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 42468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 42568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy BT2020, 42668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 42768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space DCI-P3 standardized as SMPTE RP 431-2-2007.</p> 42868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 42968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 43068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 43168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 43268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.680</td><td>0.265</td><td>0.150</td><td>0.314</td></tr> 43368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.320</td><td>0.690</td><td>0.060</td><td>0.351</td></tr> 43468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 43568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">SMPTE RP 431-2-2007 DCI (P3)</td></tr> 43668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">N/A</td></tr> 43768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 438efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 43968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{P3} = C_{linear}^{\frac{1}{2.6}}\)</td> 44068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 44168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 442efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 44368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{linear} = C_{P3}^{2.6}\)</td> 44468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 44568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 44668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 447199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 448c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_dci_p3.png" /> 449199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">DCI-P3 (orange) vs sRGB (white)</figcaption> 450199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 45168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 45268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy DCI_P3, 45368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 45468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space Display P3 based on SMPTE RP 431-2-2007 and IEC 61966-2.1:1999.</p> 45568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 45668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 45768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 45868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 45968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.680</td><td>0.265</td><td>0.150</td><td>0.3127</td></tr> 46068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.320</td><td>0.690</td><td>0.060</td><td>0.3290</td></tr> 46168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 46268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">Display P3</td></tr> 46368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 46468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 465efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 46668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 467494f784e47e74a65e8bce485065f5b7b077800fbRomain Guy * C_{DisplayP3} = \begin{cases} 12.92 \times C_{linear} & C_{linear} \lt 0.0030186 \\ 468494f784e47e74a65e8bce485065f5b7b077800fbRomain Guy * 1.055 \times C_{linear}^{\frac{1}{2.4}} - 0.055 & C_{linear} \ge 0.0030186 \end{cases} 46968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 47068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 47168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 47268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 473efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 47468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 475494f784e47e74a65e8bce485065f5b7b077800fbRomain Guy * C_{linear} = \begin{cases}\frac{C_{DisplayP3}}{12.92} & C_{sRGB} \lt 0.039 \\ 476494f784e47e74a65e8bce485065f5b7b077800fbRomain Guy * \left( \frac{C_{DisplayP3} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.039 \end{cases} 47768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 47868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 47968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 48068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 48168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 482199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 483c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_display_p3.png" /> 484199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">Display P3 (orange) vs sRGB (white)</figcaption> 485199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 48668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 48768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy DISPLAY_P3, 48868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 48968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space NTSC, 1953 standard.</p> 49068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 49168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 49268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 49368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 49468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.67</td><td>0.21</td><td>0.14</td><td>0.310</td></tr> 49568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.33</td><td>0.71</td><td>0.08</td><td>0.316</td></tr> 49668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 49768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">NTSC (1953)</td></tr> 49868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">C</td></tr> 49968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 500efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 50168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 50268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{BT709} = \begin{cases} 4.5 \times C_{linear} & C_{linear} \lt 0.018 \\ 50368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1.099 \times C_{linear}^{\frac{1}{2.2}} - 0.099 & C_{linear} \ge 0.018 \end{cases} 50468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 50568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 50668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 50768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 508efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 50968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 51068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{linear} = \begin{cases}\frac{C_{BT709}}{4.5} & C_{BT709} \lt 0.081 \\ 51168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \left( \frac{C_{BT709} + 0.099}{1.099} \right) ^{2.2} & C_{BT709} \ge 0.081 \end{cases} 51268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 51368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 51468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 51568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 51668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 517199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 518c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_ntsc_1953.png" /> 519199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">NTSC 1953 (orange) vs sRGB (white)</figcaption> 520199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 52168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 52268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy NTSC_1953, 52368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 52468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space SMPTE C.</p> 52568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 52668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 52768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 52868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 52968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.630</td><td>0.310</td><td>0.155</td><td>0.3127</td></tr> 53068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.340</td><td>0.595</td><td>0.070</td><td>0.3290</td></tr> 53168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 53268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">SMPTE-C RGB</td></tr> 53368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 53468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 535efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 53668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 53768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{BT709} = \begin{cases} 4.5 \times C_{linear} & C_{linear} \lt 0.018 \\ 53868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1.099 \times C_{linear}^{\frac{1}{2.2}} - 0.099 & C_{linear} \ge 0.018 \end{cases} 53968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 54068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 54168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 54268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 543efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 54468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 54568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{linear} = \begin{cases}\frac{C_{BT709}}{4.5} & C_{BT709} \lt 0.081 \\ 54668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \left( \frac{C_{BT709} + 0.099}{1.099} \right) ^{2.2} & C_{BT709} \ge 0.081 \end{cases} 54768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 54868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 54968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 55068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 55168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 552199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 553c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_smpte_c.png" /> 554199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">SMPTE-C (orange) vs sRGB (white)</figcaption> 555199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 55668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 55768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy SMPTE_C, 55868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 55968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space Adobe RGB (1998).</p> 56068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 56168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 56268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 56368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 56468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.64</td><td>0.21</td><td>0.15</td><td>0.3127</td></tr> 56568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.33</td><td>0.71</td><td>0.06</td><td>0.3290</td></tr> 56668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 56768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">Adobe RGB (1998)</td></tr> 56868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D65</td></tr> 56968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 570efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 57168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{RGB} = C_{linear}^{\frac{1}{2.2}}\)</td> 57268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 57368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 574efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 57568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{linear} = C_{RGB}^{2.2}\)</td> 57668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 57768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 57868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 579199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 580c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_adobe_rgb.png" /> 581199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">Adobe RGB (orange) vs sRGB (white)</figcaption> 582199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 58368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 58468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ADOBE_RGB, 58568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 58668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space ProPhoto RGB standardized as ROMM RGB ISO 22028-2:2013.</p> 58768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 58868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 58968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 59068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 59168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.7347</td><td>0.1596</td><td>0.0366</td><td>0.3457</td></tr> 59268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.2653</td><td>0.8404</td><td>0.0001</td><td>0.3585</td></tr> 59368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 59468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">ROMM RGB ISO 22028-2:2013</td></tr> 59568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D50</td></tr> 59668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 597efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 59868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 59968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{ROMM} = \begin{cases} 16 \times C_{linear} & C_{linear} \lt 0.001953 \\ 60068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{linear}^{\frac{1}{1.8}} & C_{linear} \ge 0.001953 \end{cases} 60168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 60268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 60368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 60468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 605efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 60668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(\begin{equation} 60768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{linear} = \begin{cases}\frac{C_{ROMM}}{16} & C_{ROMM} \lt 0.031248 \\ 60868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * C_{ROMM}^{1.8} & C_{ROMM} \ge 0.031248 \end{cases} 60968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{equation}\) 61068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </td> 61168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 61268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr> 61368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 614199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 615c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_pro_photo_rgb.png" /> 616199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">ProPhoto RGB (orange) vs sRGB (white)</figcaption> 617199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 61868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 61968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy PRO_PHOTO_RGB, 62068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 62168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space ACES standardized as SMPTE ST 2065-1:2012.</p> 62268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 62368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 62468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 62568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 62668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.73470</td><td>0.00000</td><td>0.00010</td><td>0.32168</td></tr> 62768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.26530</td><td>1.00000</td><td>-0.07700</td><td>0.33767</td></tr> 62868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 62968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">SMPTE ST 2065-1:2012 ACES</td></tr> 63068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D60</td></tr> 63168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 632efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 63368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{ACES} = C_{linear}\)</td> 63468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 63568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 636efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 63768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{linear} = C_{ACES}\)</td> 63868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 63968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([-65504.0, 65504.0]\)</td></tr> 64068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 641199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 642c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_aces.png" /> 643199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">ACES (orange) vs sRGB (white)</figcaption> 644199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 64568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 64668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ACES, 64768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 64868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link ColorSpace.Rgb RGB} color space ACEScg standardized as Academy S-2014-004.</p> 64968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 65068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 65168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <th>Chromaticity</th><th>Red</th><th>Green</th><th>Blue</th><th>White point</th> 65268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 65368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>x</td><td>0.713</td><td>0.165</td><td>0.128</td><td>0.32168</td></tr> 65468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>y</td><td>0.293</td><td>0.830</td><td>0.044</td><td>0.33767</td></tr> 65568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 65668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">Academy S-2014-004 ACEScg</td></tr> 65768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D60</td></tr> 65868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 659efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Opto-electronic transfer function (OETF)</td> 66068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{ACEScg} = C_{linear}\)</td> 66168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 66268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr> 663efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <td>Electro-optical transfer function (EOTF)</td> 66468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <td colspan="4">\(C_{linear} = C_{ACEScg}\)</td> 66568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </tr> 66668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([-65504.0, 65504.0]\)</td></tr> 66768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 668199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 669c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_acescg.png" /> 670199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">ACEScg (orange) vs sRGB (white)</figcaption> 671199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 67268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 67368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ACESCG, 67468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 67568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link Model#XYZ XYZ} color space CIE XYZ. This color space assumes standard 67668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * illuminant D50 as its white point.</p> 67768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 67868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 67968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">Generic XYZ</td></tr> 68068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D50</td></tr> 68168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\([-2.0, 2.0]\)</td></tr> 68268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 68368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 68468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy CIE_XYZ, 68568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 68668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>{@link Model#LAB Lab} color space CIE L*a*b*. This color space uses CIE XYZ D50 68768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * as a profile conversion space.</p> 68868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Color space definition"> 68968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Property</th><th colspan="4">Value</th></tr> 69068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Name</td><td colspan="4">Generic L*a*b*</td></tr> 69168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>CIE standard illuminant</td><td colspan="4">D50</td></tr> 69268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>Range</td><td colspan="4">\(L: [0.0, 100.0], a: [-128, 128], b: [-128, 128]\)</td></tr> 69368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 69468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 69568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy CIE_LAB 69668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Update the initialization block next to #get(Named) when adding new values 69768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 69868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 69968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 70068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>A render intent determines how a {@link ColorSpace.Connector connector} 70168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * maps colors from one color space to another. The choice of mapping is 70268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * important when the source color space has a larger color gamut than the 70368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * destination color space.</p> 70468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 70568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#connect(ColorSpace, ColorSpace, RenderIntent) 70668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 70768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public enum RenderIntent { 70868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 70968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Compresses the source gamut into the destination gamut. 71068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This render intent affects all colors, inside and outside 71168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * of destination gamut. The goal of this render intent is 71268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to preserve the visual relationship between colors.</p> 71368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 71468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p class="note">This render intent is currently not 71568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * implemented and behaves like {@link #RELATIVE}.</p> 71668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 71768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy PERCEPTUAL, 71868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 71968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Similar to the {@link #ABSOLUTE} render intent, this render 72068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * intent matches the closest color in the destination gamut 72168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * but makes adjustments for the destination white point. 72268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 72368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy RELATIVE, 72468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 72568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Attempts to maintain the relative saturation of colors 72668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * from the source gamut to the destination gamut, to keep 72768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * highly saturated colors as saturated as possible.</p> 72868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 72968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p class="note">This render intent is currently not 73068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * implemented and behaves like {@link #RELATIVE}.</p> 73168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 73268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy SATURATION, 73368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 73468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Colors that are in the destination gamut are left unchanged. 73568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Colors that fall outside of the destination gamut are mapped 73668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to the closest possible color within the gamut of the destination 73768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space (they are clipped). 73868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 73968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ABSOLUTE 74068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 74168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 74268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 74368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@usesMathJax} 74468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 74568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>List of adaptation matrices that can be used for chromatic adaptation 74668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * using the von Kries transform. These matrices are used to convert values 74768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * in the CIE XYZ space to values in the LMS space (Long Medium Short).</p> 74868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 74968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Given an adaptation matrix \(A\), the conversion from XYZ to 75068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * LMS is straightforward:</p> 75168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 75268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * $$\left[ \begin{array}{c} L\\ M\\ S \end{array} \right] = 75368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * A \left[ \begin{array}{c} X\\ Y\\ Z \end{array} \right]$$ 75468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 75568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The complete von Kries transform \(T\) uses a diagonal matrix 75668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * noted \(D\) to perform the adaptation in LMS space. In addition 75768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to \(A\) and \(D\), the source white point \(W1\) and the destination 75868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * white point \(W2\) must be specified:</p> 75968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 76068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * $$\begin{align*} 76168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \left[ \begin{array}{c} L_1\\ M_1\\ S_1 \end{array} \right] &= 76268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * A \left[ \begin{array}{c} W1_X\\ W1_Y\\ W1_Z \end{array} \right] \\ 76368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \left[ \begin{array}{c} L_2\\ M_2\\ S_2 \end{array} \right] &= 76468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * A \left[ \begin{array}{c} W2_X\\ W2_Y\\ W2_Z \end{array} \right] \\ 76568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * D &= \left[ \begin{matrix} \frac{L_2}{L_1} & 0 & 0 \\ 76668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 0 & \frac{M_2}{M_1} & 0 \\ 76768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 0 & 0 & \frac{S_2}{S_1} \end{matrix} \right] \\ 76868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * T &= A^{-1}.D.A 76968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \end{align*}$$ 77068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 77168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>As an example, the resulting matrix \(T\) can then be used to 77268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * perform the chromatic adaptation of sRGB XYZ transform from D65 77368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to D50:</p> 77468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 77568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * $$sRGB_{D50} = T.sRGB_{D65}$$ 77668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 77768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace.Connector 77868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#connect(ColorSpace, ColorSpace) 77968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 78068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public enum Adaptation { 78168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 7824db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy * Bradford chromatic adaptation transform, as defined in the 7834db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy * CIECAM97s color appearance model. 78468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 78568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy BRADFORD(new float[] { 78668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 0.8951f, -0.7502f, 0.0389f, 78768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 0.2664f, 1.7135f, -0.0685f, 78868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy -0.1614f, 0.0367f, 1.0296f 78968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }), 79068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 7914db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy * von Kries chromatic adaptation transform. 79268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 79368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy VON_KRIES(new float[] { 79468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 0.40024f, -0.22630f, 0.00000f, 79568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 0.70760f, 1.16532f, 0.00000f, 79668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy -0.08081f, 0.04570f, 0.91822f 7974db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy }), 7984db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy /** 7994db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy * CIECAT02 chromatic adaption transform, as defined in the 8004db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy * CIECAM02 color appearance model. 8014db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy */ 8024db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy CIECAT02(new float[] { 8034db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy 0.7328f, -0.7036f, 0.0030f, 8044db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy 0.4296f, 1.6975f, 0.0136f, 8054db2c229be8e4d243ca19fac4080cda1eeb22710Romain Guy -0.1624f, 0.0061f, 0.9834f 80668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }); 80768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 80868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy final float[] mTransform; 80968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 81068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Adaptation(@NonNull @Size(9) float[] transform) { 81168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mTransform = transform; 81268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 81368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 81468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 81568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 81668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * A color model is required by a {@link ColorSpace} to describe the 81768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * way colors can be represented as tuples of numbers. A common color 81868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * model is the {@link #RGB RGB} color model which defines a color 81968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * as represented by a tuple of 3 numbers (red, green and blue). 82068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 82168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public enum Model { 82268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 82368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The RGB model is a color model with 3 components that 82468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * refer to the three additive primiaries: red, green 82568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * andd blue. 82668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 82768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy RGB(3), 82868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 82968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The XYZ model is a color model with 3 components that 83068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are used to model human color vision on a basic sensory 83168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * level. 83268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 83368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy XYZ(3), 83468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 83568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The Lab model is a color model with 3 components used 83668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to describe a color space that is more perceptually 83768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * uniform than XYZ. 83868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 83968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy LAB(3), 84068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 84168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The CMYK model is a color model with 4 components that 84268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * refer to four inks used in color printing: cyan, magenta, 84368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * yellow and black (or key). CMYK is a subtractive color 84468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * model. 84568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 84668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy CMYK(4); 84768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 84868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private final int mComponentCount; 84968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 85068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Model(@IntRange(from = 1, to = 4) int componentCount) { 85168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mComponentCount = componentCount; 85268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 85368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 85468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 85568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the number of components for this color model. 85668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 85768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return An integer between 1 and 4 85868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 85968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @IntRange(from = 1, to = 4) 86068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public int getComponentCount() { 86168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mComponentCount; 86268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 86368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 86468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 86568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private ColorSpace( 86668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull String name, 86768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull Model model, 86868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @IntRange(from = MIN_ID, to = MAX_ID) int id) { 86968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 87068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (name == null || name.length() < 1) { 87168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy throw new IllegalArgumentException("The name of a color space cannot be null and " + 87268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "must contain at least 1 character"); 87368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 87468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 87568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (model == null) { 87668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy throw new IllegalArgumentException("A color space must have a model"); 87768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 87868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 87968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (id < MIN_ID || id > MAX_ID) { 88068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy throw new IllegalArgumentException("The id must be between " + 88168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy MIN_ID + " and " + MAX_ID); 88268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 88368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 88468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mName = name; 88568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mModel = model; 88668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mId = id; 88768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 88868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 88968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 890cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * <p>Returns the name of this color space. The name is never null 891cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * and contains always at least 1 character.</p> 892cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * 893cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * <p>Color space names are recommended to be unique but are not 894cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * guaranteed to be. There is no defined format but the name usually 895cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * falls in one of the following categories:</p> 896cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * <ul> 897cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * <li>Generic names used to identify color spaces in non-RGB 898cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * color models. For instance: {@link Named#CIE_LAB Generic L*a*b*}.</li> 899cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * <li>Names tied to a particular specification. For instance: 900cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * {@link Named#SRGB sRGB IEC61966-2.1} or 901cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * {@link Named#ACES SMPTE ST 2065-1:2012 ACES}.</li> 902cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * <li>Ad-hoc names, often generated procedurally or by the user 903cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * during a calibration workflow. These names often contain the 904cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * make and model of the display.</li> 905cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * </ul> 906cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * 907cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * <p>Because the format of color space names is not defined, it is 908cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * not recommended to programmatically identify a color space by its 909cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * name alone. Names can be used as a first approximation.</p> 910cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * 911cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * <p>It is however perfectly acceptable to display color space names to 912cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * users in a UI, or in debuggers and logs. When displaying a color space 913cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * name to the user, it is recommended to add extra information to avoid 914cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * ambiguities: color model, a representation of the color space's gamut, 915cb7a24539bc5c0595ee554f982c2e6233d232b7aRomain Guy * white point, etc.</p> 91668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 91768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null String of length >= 1 91868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 91968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 92068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public String getName() { 92168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mName; 92268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 92368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 92468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 92568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the ID of this color space. Positive IDs match the color 92668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * spaces enumerated in {@link Named}. A negative ID indicates a 92768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space created by calling one of the public constructors. 92868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 92968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return An integer between {@link #MIN_ID} and {@link #MAX_ID} 93068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 93168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @IntRange(from = MIN_ID, to = MAX_ID) 93268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public int getId() { 93368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mId; 93468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 93568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 93668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 93768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Return the color model of this color space. 93868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 93968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null {@link Model} 94068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 94168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Model 94268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getComponentCount() 94368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 94468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 94568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public Model getModel() { 94668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mModel; 94768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 94868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 94968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 95068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the number of components that form a color value according 95168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to this color space's color model. 95268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 95368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return An integer between 1 and 4 95468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 95568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Model 95668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getModel() 95768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 95868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @IntRange(from = 1, to = 4) 95968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public int getComponentCount() { 96068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mModel.getComponentCount(); 96168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 96268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 96368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 96468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns whether this color space is a wide-gamut color space. 96568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * An RGB color space is wide-gamut if its gamut entirely contains 96668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * the {@link Named#SRGB sRGB} gamut and if the area of its gamut is 96768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 90% of greater than the area of the {@link Named#NTSC_1953 NTSC} 96868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * gamut. 96968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 97068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return True if this color space is a wide-gamut color space, 97168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * false otherwise 97268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 97368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public abstract boolean isWideGamut(); 97468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 97568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 97668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Indicates whether this color space is the sRGB color space or 97768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * equivalent to the sRGB color space.</p> 97868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>A color space is considered sRGB if it meets all the following 97968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * conditions:</p> 98068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <ul> 98168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>Its color model is {@link Model#RGB}.</li> 98268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li> 98368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Its primaries are within 1e-3 of the true 98468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Named#SRGB sRGB} primaries. 98568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </li> 98668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li> 98768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Its white point is withing 1e-3 of the CIE standard 98868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * illuminant {@link #ILLUMINANT_D65 D65}. 98968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </li> 99068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>Its opto-electronic transfer function is not linear.</li> 99168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>Its electro-optical transfer function is not linear.</li> 99268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>Its range is \([0..1]\).</li> 99368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </ul> 99468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>This method always returns true for {@link Named#SRGB}.</p> 99568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 99668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return True if this color space is the sRGB color space (or a 99768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * close approximation), false otherwise 99868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 99968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public boolean isSrgb() { 100068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return false; 100168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 100268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 100368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 100468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the minimum valid value for the specified component of this 100568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space's color model. 100668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 100768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param component The index of the component 100868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A floating point value less than {@link #getMaxValue(int)} 100968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 101068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getMaxValue(int) 101168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Model#getComponentCount() 101268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 101368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public abstract float getMinValue(@IntRange(from = 0, to = 3) int component); 101468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 101568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 101668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the maximum valid value for the specified component of this 101768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space's color model. 101868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 101968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param component The index of the component 102068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A floating point value greater than {@link #getMinValue(int)} 102168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 102268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getMinValue(int) 102368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Model#getComponentCount() 102468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 102568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public abstract float getMaxValue(@IntRange(from = 0, to = 3) int component); 102668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 102768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 102868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Converts a color value from this color space's model to 102968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * tristimulus CIE XYZ values. If the color model of this color 103068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space is not {@link Model#RGB RGB}, it is assumed that the 103168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * target CIE XYZ space uses a {@link #ILLUMINANT_D50 D50} 103268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * standard illuminant.</p> 103368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 103468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>This method is a convenience for color spaces with a model 103568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * of 3 components ({@link Model#RGB RGB} or {@link Model#LAB} 103668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * for instance). With color spaces using fewer or more components, 103768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * use {@link #toXyz(float[])} instead</p>. 103868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 103968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param r The first component of the value to convert from (typically R in RGB) 104068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param g The second component of the value to convert from (typically G in RGB) 104168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param b The third component of the value to convert from (typically B in RGB) 104268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 3 floats, containing tristimulus XYZ values 104368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 104468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #toXyz(float[]) 104568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #fromXyz(float, float, float) 104668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 104768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 104868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(3) 104968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] toXyz(float r, float g, float b) { 105068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return toXyz(new float[] { r, g, b }); 105168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 105268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 105368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 105468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Converts a color value from this color space's model to 105568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * tristimulus CIE XYZ values. If the color model of this color 105668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space is not {@link Model#RGB RGB}, it is assumed that the 105768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * target CIE XYZ space uses a {@link #ILLUMINANT_D50 D50} 105868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * standard illuminant.</p> 105968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 106068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p class="note">The specified array's length must be at least 106168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * equal to to the number of color components as returned by 106268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Model#getComponentCount()}.</p> 106368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 106468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param v An array of color components containing the color space's 106568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color value to convert to XYZ, and large enough to hold 106668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * the resulting tristimulus XYZ values 106768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The array passed in parameter 106868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 106968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #toXyz(float, float, float) 107068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #fromXyz(float[]) 107168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 107268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 107368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 107468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public abstract float[] toXyz(@NonNull @Size(min = 3) float[] v); 107568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 107668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 107768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Converts tristimulus values from the CIE XYZ space to this 107868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space's color model.</p> 107968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 108068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param x The X component of the color value 108168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param y The Y component of the color value 108268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param z The Z component of the color value 108368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array whose size is equal to the number of color 108468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * components as returned by {@link Model#getComponentCount()} 108568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 108668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #fromXyz(float[]) 108768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #toXyz(float, float, float) 108868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 108968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 109068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 109168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] fromXyz(float x, float y, float z) { 109268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] xyz = new float[mModel.getComponentCount()]; 109368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyz[0] = x; 109468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyz[1] = y; 109568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyz[2] = z; 109668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return fromXyz(xyz); 109768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 109868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 109968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 110068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Converts tristimulus values from the CIE XYZ space to this color 110168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space's color model. The resulting value is passed back in the specified 110268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * array.</p> 110368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 110477b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy * <p class="note">The specified array's length must be at least equal to 110568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to the number of color components as returned by 110668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Model#getComponentCount()}, and its first 3 values must 110768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * be the XYZ components to convert from.</p> 110868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 110968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param v An array of color components containing the XYZ values 111068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to convert from, and large enough to hold the number 111168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * of components of this color space's model 111268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The array passed in parameter 111368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 111468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #fromXyz(float, float, float) 111568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #toXyz(float[]) 111668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 111768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 111868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 111968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public abstract float[] fromXyz(@NonNull @Size(min = 3) float[] v); 112068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 112168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 112268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Returns a string representation of the object. This method returns 112368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a string equal to the value of:</p> 112468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 112568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <pre class="prettyprint"> 112668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * getName() + "(id=" + getId() + ", model=" + getModel() + ")" 112768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </pre> 112868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 112968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>For instance, the string representation of the {@link Named#SRGB sRGB} 113068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space is equal to the following value:</p> 113168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 113268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <pre> 113368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * sRGB IEC61966-2.1 (id=0, model=RGB) 113468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </pre> 113568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 113668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A string representation of the object 113768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 113868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 113977b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy @NonNull 114068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public String toString() { 114168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mName + " (id=" + mId + ", model=" + mModel + ")"; 114268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 114368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 114468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 114568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public boolean equals(Object o) { 114668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (this == o) return true; 114768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (o == null || getClass() != o.getClass()) return false; 114868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 114968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ColorSpace that = (ColorSpace) o; 115068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 115168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (mId != that.mId) return false; 115268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy //noinspection SimplifiableIfStatement 115368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!mName.equals(that.mName)) return false; 115468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mModel == that.mModel; 115568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 115668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 115768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 115868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 115968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public int hashCode() { 116068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy int result = mName.hashCode(); 116168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy result = 31 * result + mModel.hashCode(); 116268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy result = 31 * result + mId; 116368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return result; 116468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 116568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 116668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 116768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Connects two color spaces to allow conversion from the source color 116868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space to the destination color space. If the source and destination 116968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color spaces do not have the same profile connection space (CIE XYZ 117068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * with the same white point), they are chromatically adapted to use the 117168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * CIE standard illuminant {@link #ILLUMINANT_D50 D50} as needed.</p> 117268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 117368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>If the source and destination are the same, an optimized connector 117468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * is returned to avoid unnecessary computations and loss of precision.</p> 117568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 117668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Colors are mapped from the source color space to the destination color 117768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space using the {@link RenderIntent#PERCEPTUAL perceptual} render intent.</p> 117868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 117968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param source The color space to convert colors from 118068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param destination The color space to convert colors to 118168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null connector between the two specified color spaces 118268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 118368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace) 118468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, RenderIntent) 118568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, ColorSpace, RenderIntent) 118668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 118768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 118868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static Connector connect(@NonNull ColorSpace source, @NonNull ColorSpace destination) { 118968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return connect(source, destination, RenderIntent.PERCEPTUAL); 119068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 119168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 119268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 119368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Connects two color spaces to allow conversion from the source color 119468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space to the destination color space. If the source and destination 119568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color spaces do not have the same profile connection space (CIE XYZ 119668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * with the same white point), they are chromatically adapted to use the 119768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * CIE standard illuminant {@link #ILLUMINANT_D50 D50} as needed.</p> 119868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 119968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>If the source and destination are the same, an optimized connector 120068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * is returned to avoid unnecessary computations and loss of precision.</p> 120168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 120268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param source The color space to convert colors from 120368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param destination The color space to convert colors to 120468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param intent The render intent to map colors from the source to the destination 120568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null connector between the two specified color spaces 120668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 120768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace) 120868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, RenderIntent) 120968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, ColorSpace) 121068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 121168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 121268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @SuppressWarnings("ConstantConditions") 121368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static Connector connect(@NonNull ColorSpace source, @NonNull ColorSpace destination, 121468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull RenderIntent intent) { 121568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (source.equals(destination)) return Connector.identity(source); 121668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 121768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (source.getModel() == Model.RGB && destination.getModel() == Model.RGB) { 1218199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy return new Connector.Rgb((Rgb) source, (Rgb) destination, intent); 121968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 122068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 122168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new Connector(source, destination, intent); 122268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 122368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 122468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 122568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Connects the specified color spaces to sRGB. 122668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * If the source color space does not use CIE XYZ D65 as its profile 122768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * connection space, the two spaces are chromatically adapted to use the 122868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * CIE standard illuminant {@link #ILLUMINANT_D50 D50} as needed.</p> 122968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 123068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>If the source is the sRGB color space, an optimized connector 123168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * is returned to avoid unnecessary computations and loss of precision.</p> 123268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 123368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Colors are mapped from the source color space to the destination color 123468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space using the {@link RenderIntent#PERCEPTUAL perceptual} render intent.</p> 123568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 123668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param source The color space to convert colors from 123768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null connector between the specified color space and sRGB 123868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 123968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, RenderIntent) 124068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, ColorSpace) 124168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, ColorSpace, RenderIntent) 124268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 124368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 124468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static Connector connect(@NonNull ColorSpace source) { 124568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return connect(source, RenderIntent.PERCEPTUAL); 124668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 124768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 124868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 124968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Connects the specified color spaces to sRGB. 125068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * If the source color space does not use CIE XYZ D65 as its profile 125168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * connection space, the two spaces are chromatically adapted to use the 125268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * CIE standard illuminant {@link #ILLUMINANT_D50 D50} as needed.</p> 125368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 125468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>If the source is the sRGB color space, an optimized connector 125568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * is returned to avoid unnecessary computations and loss of precision.</p> 125668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 125768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param source The color space to convert colors from 125868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param intent The render intent to map colors from the source to the destination 125968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null connector between the specified color space and sRGB 126068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 126168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace) 126268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, ColorSpace) 126368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #connect(ColorSpace, ColorSpace, RenderIntent) 126468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 126568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 126668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static Connector connect(@NonNull ColorSpace source, @NonNull RenderIntent intent) { 126768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (source.isSrgb()) return Connector.identity(source); 126868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 126968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (source.getModel() == Model.RGB) { 1270199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy return new Connector.Rgb((Rgb) source, (Rgb) get(Named.SRGB), intent); 127168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 127268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 127368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new Connector(source, get(Named.SRGB), intent); 127468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 127568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 127668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 127768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Performs the chromatic adaptation of a color space from its native 127868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * white point to the specified white point.</p> 127968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 128068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The chromatic adaptation is performed using the 128168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Adaptation#BRADFORD} matrix.</p> 128268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 128368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p class="note">The color space returned by this method always has 128468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * an ID of {@link #MIN_ID}.</p> 128568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 128668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param colorSpace The color space to chromatically adapt 128768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param whitePoint The new white point 128868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A {@link ColorSpace} instance with the same name, primaries, 128968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * transfer functions and range as the specified color space 129068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 129168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Adaptation 129268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #adapt(ColorSpace, float[], Adaptation) 129368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 129468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 129568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static ColorSpace adapt(@NonNull ColorSpace colorSpace, 129668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint) { 129768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return adapt(colorSpace, whitePoint, Adaptation.BRADFORD); 129868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 129968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 130068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 130168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Performs the chromatic adaptation of a color space from its native 130268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * white point to the specified white point. If the specified color space 130368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * does not have an {@link Model#RGB RGB} color model, or if the color 130468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space already has the target white point, the color space is returned 130568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * unmodified.</p> 130668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 130768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The chromatic adaptation is performed using the von Kries method 130868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * described in the documentation of {@link Adaptation}.</p> 130968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 131068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p class="note">The color space returned by this method always has 131168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * an ID of {@link #MIN_ID}.</p> 131268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 131368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param colorSpace The color space to chromatically adapt 131468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param whitePoint The new white point 131568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param adaptation The adaptation matrix 131668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new color space if the specified color space has an RGB 131768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * model and a white point different from the specified white 131868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * point; the specified color space otherwise 131968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 132068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Adaptation 132168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #adapt(ColorSpace, float[]) 132268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 132368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 132468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static ColorSpace adapt(@NonNull ColorSpace colorSpace, 132568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint, 132668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull Adaptation adaptation) { 132768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (colorSpace.getModel() == Model.RGB) { 132868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ColorSpace.Rgb rgb = (ColorSpace.Rgb) colorSpace; 132968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (compare(rgb.mWhitePoint, whitePoint)) return colorSpace; 133068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 133168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] xyz = whitePoint.length == 3 ? 133268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Arrays.copyOf(whitePoint, 3) : xyYToXyz(whitePoint); 133368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] adaptationTransform = chromaticAdaptation(adaptation.mTransform, 133468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyYToXyz(rgb.getWhitePoint()), xyz); 133568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] transform = mul3x3(adaptationTransform, rgb.mTransform); 133668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 133768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new ColorSpace.Rgb(rgb, transform, whitePoint); 133868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 133968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return colorSpace; 134068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 134168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 134268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 134326ca96ecb82cdbc058a39cebbfb16b402bf0fe03Romain Guy * <p>Returns an instance of {@link ColorSpace} whose ID matches the 134426ca96ecb82cdbc058a39cebbfb16b402bf0fe03Romain Guy * specified ID.</p> 134568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 134668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>This method always returns the same instance for a given ID.</p> 134768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 134868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>This method is thread-safe.</p> 134968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 135068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param index An integer ID between {@link #MIN_ID} and {@link #MAX_ID} 135168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null {@link ColorSpace} instance 135226ca96ecb82cdbc058a39cebbfb16b402bf0fe03Romain Guy * @throws IllegalArgumentException If the ID does not match the ID of one of the 135326ca96ecb82cdbc058a39cebbfb16b402bf0fe03Romain Guy * {@link Named named color spaces} 135468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 135568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 135668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) { 135768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (index < 0 || index > Named.values().length) { 135826ca96ecb82cdbc058a39cebbfb16b402bf0fe03Romain Guy throw new IllegalArgumentException("Invalid ID, must be in the range [0.." + 135926ca96ecb82cdbc058a39cebbfb16b402bf0fe03Romain Guy Named.values().length + "]"); 136068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 136168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return sNamedColorSpaces[index]; 136268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 136368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 136468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 136568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Returns an instance of {@link ColorSpace} identified by the specified 136668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * name. The list of names provided in the {@link Named} enum gives access 136768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to a variety of common RGB color spaces.</p> 136868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 136968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>This method always returns the same instance for a given name.</p> 137068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 137168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>This method is thread-safe.</p> 137268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 137368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param name The name of the color space to get an instance of 137468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null {@link ColorSpace} instance 137568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 137668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 137768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static ColorSpace get(@NonNull Named name) { 137868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return sNamedColorSpaces[name.ordinal()]; 137968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 138068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 138115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 1382efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Returns a {@link Named} instance of {@link ColorSpace} that matches 1383efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * the specified RGB to CIE XYZ transform and transfer functions. If no 1384efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * instance can be found, this method returns null.</p> 1385efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 1386efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The color transform matrix is assumed to target the CIE XYZ space 1387efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * a {@link #ILLUMINANT_D50 D50} standard illuminant.</p> 1388efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 1389efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param toXYZD50 3x3 column-major transform matrix from RGB to the profile 1390efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * connection space CIE XYZ as an array of 9 floats, cannot be null 1391efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param function Parameters for the transfer functions 1392efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @return A non-null {@link ColorSpace} if a match is found, null otherwise 1393efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 1394efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @Nullable 1395efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public static ColorSpace match( 1396efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(9) float[] toXYZD50, 1397efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull Rgb.TransferParameters function) { 1398efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1399efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy for (ColorSpace colorSpace : sNamedColorSpaces) { 1400efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (colorSpace.getModel() == Model.RGB) { 1401efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy ColorSpace.Rgb rgb = (ColorSpace.Rgb) adapt(colorSpace, ILLUMINANT_D50_XYZ); 1402efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (compare(toXYZD50, rgb.mTransform) && 1403efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy compare(function, rgb.mTransferParameters)) { 1404efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return colorSpace; 1405efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 1406efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 1407efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 1408efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1409efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return null; 1410efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 1411efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1412efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 141315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>Creates a new {@link Renderer} that can be used to visualize and 141415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * debug color spaces. See the documentation of {@link Renderer} for 141515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * more information.</p> 141615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 141715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @return A new non-null {@link Renderer} instance 141815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 141915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @see Renderer 142066d7da6a41d2ae2acf8220d8b146ba6eea385a28Romain Guy * 142166d7da6a41d2ae2acf8220d8b146ba6eea385a28Romain Guy * @hide 142215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 142315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull 142415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy public static Renderer createRenderer() { 142515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return new Renderer(); 142615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 142715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 142868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy static { 142968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.SRGB.ordinal()] = new ColorSpace.Rgb( 143068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "sRGB IEC61966-2.1", 143168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy SRGB_PRIMARIES, 143268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1433efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4), 143468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.SRGB.ordinal() 143568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 143668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.LINEAR_SRGB.ordinal()] = new ColorSpace.Rgb( 143768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "sRGB IEC61966-2.1 (Linear)", 143868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy SRGB_PRIMARIES, 143968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1440efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1.0, 144168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 0.0f, 1.0f, 144268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.LINEAR_SRGB.ordinal() 144368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 144468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb( 144568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "scRGB-nl IEC 61966-2-2:2003", 144668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy SRGB_PRIMARIES, 144768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1448efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy x -> absRcpResponse(x, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4), 1449efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy x -> absResponse(x, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4), 145077b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy -0.799f, 2.399f, 145168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.EXTENDED_SRGB.ordinal() 145268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 145368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb( 1454efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy "scRGB IEC 61966-2-2:2003", 145568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy SRGB_PRIMARIES, 145668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1457efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1.0, 145877b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy -0.5f, 7.499f, 145968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.LINEAR_EXTENDED_SRGB.ordinal() 146068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 146168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.BT709.ordinal()] = new ColorSpace.Rgb( 146268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "Rec. ITU-R BT.709-5", 146368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }, 146468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1465efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45), 146668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.BT709.ordinal() 146768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 146868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.BT2020.ordinal()] = new ColorSpace.Rgb( 146968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "Rec. ITU-R BT.2020-1", 147068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f }, 147168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1472efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45), 147368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.BT2020.ordinal() 147468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 147568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.DCI_P3.ordinal()] = new ColorSpace.Rgb( 147668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "SMPTE RP 431-2-2007 DCI (P3)", 147768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f }, 147868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.314f, 0.351f }, 1479efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2.6, 148068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 0.0f, 1.0f, 148168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.DCI_P3.ordinal() 148268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 148368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.DISPLAY_P3.ordinal()] = new ColorSpace.Rgb( 148468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "Display P3", 148568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f }, 148668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1487494f784e47e74a65e8bce485065f5b7b077800fbRomain Guy new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.039, 2.4), 148868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.DISPLAY_P3.ordinal() 148968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 149068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb( 149168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "NTSC (1953)", 149268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy NTSC_1953_PRIMARIES, 149368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_C, 1494efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45), 149568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.NTSC_1953.ordinal() 149668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 149768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.SMPTE_C.ordinal()] = new ColorSpace.Rgb( 149868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "SMPTE-C RGB", 149968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f }, 150068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1501efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45), 150268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.SMPTE_C.ordinal() 150368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 150468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.ADOBE_RGB.ordinal()] = new ColorSpace.Rgb( 150568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "Adobe RGB (1998)", 150668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.64f, 0.33f, 0.21f, 0.71f, 0.15f, 0.06f }, 150768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D65, 1508efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2.2, 150968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 0.0f, 1.0f, 151068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.ADOBE_RGB.ordinal() 151168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 151268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.PRO_PHOTO_RGB.ordinal()] = new ColorSpace.Rgb( 151368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "ROMM RGB ISO 22028-2:2013", 151468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f }, 151568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D50, 1516efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy new Rgb.TransferParameters(1.0, 0.0, 1 / 16.0, 0.031248, 1.8), 151768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.PRO_PHOTO_RGB.ordinal() 151868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 151968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.ACES.ordinal()] = new ColorSpace.Rgb( 152068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "SMPTE ST 2065-1:2012 ACES", 152168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.73470f, 0.26530f, 0.0f, 1.0f, 0.00010f, -0.0770f }, 152268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D60, 1523efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1.0, 152468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy -65504.0f, 65504.0f, 152568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.ACES.ordinal() 152668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 152768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.ACESCG.ordinal()] = new ColorSpace.Rgb( 152868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "Academy S-2014-004 ACEScg", 152968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 0.713f, 0.293f, 0.165f, 0.830f, 0.128f, 0.044f }, 153068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ILLUMINANT_D60, 1531efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1.0, 153268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy -65504.0f, 65504.0f, 153368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.ACESCG.ordinal() 153468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 153568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.CIE_XYZ.ordinal()] = new Xyz( 153668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "Generic XYZ", 153768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.CIE_XYZ.ordinal() 153868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 153968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sNamedColorSpaces[Named.CIE_LAB.ordinal()] = new ColorSpace.Lab( 154068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "Generic L*a*b*", 154168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Named.CIE_LAB.ordinal() 154268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ); 154368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 154468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 154568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Reciprocal piecewise gamma response 1546efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static double rcpResponse(double x, double a, double b, double c, double d, double g) { 154768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return x >= d * c ? (Math.pow(x, 1.0 / g) - b) / a : x / c; 154868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 154968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 155068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Piecewise gamma response 1551efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static double response(double x, double a, double b, double c, double d, double g) { 155268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return x >= d ? Math.pow(a * x + b, g) : c * x; 155368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 155468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 1555efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy // Reciprocal piecewise gamma response 1556efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static double rcpResponse(double x, double a, double b, double c, double d, 1557efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy double e, double f, double g) { 1558efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return x >= d * c ? (Math.pow(x - e, 1.0 / g) - b) / a : (x - f) / c; 1559efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 1560efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1561efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy // Piecewise gamma response 1562efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static double response(double x, double a, double b, double c, double d, 1563efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy double e, double f, double g) { 1564efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return x >= d ? Math.pow(a * x + b, g) + e : c * x + f; 1565efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 1566efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 156768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Reciprocal piecewise gamma response, encoded as sign(x).f(abs(x)) for color 156868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // spaces that allow negative values 156968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @SuppressWarnings("SameParameterValue") 1570efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static double absRcpResponse(double x, double a, double b, double c, double d, double g) { 1571efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return Math.copySign(rcpResponse(x < 0.0 ? -x : x, a, b, c, d, g), x); 157268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 157368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 157468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Piecewise gamma response, encoded as sign(x).f(abs(x)) for color spaces that 157568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // allow negative values 157668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @SuppressWarnings("SameParameterValue") 1577efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static double absResponse(double x, double a, double b, double c, double d, double g) { 1578efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return Math.copySign(response(x < 0.0 ? -x : x, a, b, c, d, g), x); 1579efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 1580efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 1581efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 1582efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * Compares two sets of parametric transfer functions parameters with a precision of 1e-3. 1583efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 1584efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param a The first set of parameters to compare 1585efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param b The second set of parameters to compare 1586efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @return True if the two sets are equal, false otherwise 1587efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 1588efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static boolean compare( 1589efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @Nullable Rgb.TransferParameters a, 1590efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @Nullable Rgb.TransferParameters b) { 1591efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy //noinspection SimplifiableIfStatement 1592efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (a == null && b == null) return true; 1593efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return a != null && b != null && 1594efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy Math.abs(a.a - b.a) < 1e-3 && 1595efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy Math.abs(a.b - b.b) < 1e-3 && 1596efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy Math.abs(a.c - b.c) < 1e-3 && 159755455181233cadcd6d2e28d28d0dfc9a653f7787Romain Guy Math.abs(a.d - b.d) < 2e-3 && // Special case for variations in sRGB OETF/EOTF 1598efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy Math.abs(a.e - b.e) < 1e-3 && 1599efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy Math.abs(a.f - b.f) < 1e-3 && 1600efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy Math.abs(a.g - b.g) < 1e-3; 160168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 160268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 160368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 160468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Compares two arrays of float with a precision of 1e-3. 160568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 160668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param a The first array to compare 160768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param b The second array to compare 160868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return True if the two arrays are equal, false otherwise 160968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 161068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static boolean compare(@NonNull float[] a, @NonNull float[] b) { 161168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (a == b) return true; 161268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy for (int i = 0; i < a.length; i++) { 161368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (Float.compare(a[i], b[i]) != 0 && Math.abs(a[i] - b[i]) > 1e-3f) return false; 161468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 161568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return true; 161668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 161768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 161868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 161968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Inverts a 3x3 matrix. This method assumes the matrix is invertible. 162068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 162168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param m A 3x3 matrix as a non-null array of 9 floats 162268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 9 floats containing the inverse of the input matrix 162368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 162468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 162568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(9) 162668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] inverse3x3(@NonNull @Size(9) float[] m) { 162768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float a = m[0]; 162868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float b = m[3]; 162968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float c = m[6]; 163068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float d = m[1]; 163168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float e = m[4]; 163268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float f = m[7]; 163368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float g = m[2]; 163468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float h = m[5]; 163568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float i = m[8]; 163668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 163768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float A = e * i - f * h; 163868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float B = f * g - d * i; 163968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float C = d * h - e * g; 164068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 164168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float det = a * A + b * B + c * C; 164268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 164368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float inverted[] = new float[m.length]; 164468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[0] = A / det; 164568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[1] = B / det; 164668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[2] = C / det; 164768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[3] = (c * h - b * i) / det; 164868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[4] = (a * i - c * g) / det; 164968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[5] = (b * g - a * h) / det; 165068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[6] = (b * f - c * e) / det; 165168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[7] = (c * d - a * f) / det; 165268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverted[8] = (a * e - b * d) / det; 165368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return inverted; 165468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 165568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 165668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 165768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Multiplies two 3x3 matrices, represented as non-null arrays of 9 floats. 165868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 165968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param lhs 3x3 matrix, as a non-null array of 9 floats 166068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param rhs 3x3 matrix, as a non-null array of 9 floats 166168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 9 floats containing the result of the multiplication 166268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * of rhs by lhs 166368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 166468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 166568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(9) 166668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) { 166768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] r = new float[9]; 166868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[0] = lhs[0] * rhs[0] + lhs[3] * rhs[1] + lhs[6] * rhs[2]; 166968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[1] = lhs[1] * rhs[0] + lhs[4] * rhs[1] + lhs[7] * rhs[2]; 167068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[2] = lhs[2] * rhs[0] + lhs[5] * rhs[1] + lhs[8] * rhs[2]; 167168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[3] = lhs[0] * rhs[3] + lhs[3] * rhs[4] + lhs[6] * rhs[5]; 167268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[4] = lhs[1] * rhs[3] + lhs[4] * rhs[4] + lhs[7] * rhs[5]; 167368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[5] = lhs[2] * rhs[3] + lhs[5] * rhs[4] + lhs[8] * rhs[5]; 167468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[6] = lhs[0] * rhs[6] + lhs[3] * rhs[7] + lhs[6] * rhs[8]; 167568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[7] = lhs[1] * rhs[6] + lhs[4] * rhs[7] + lhs[7] * rhs[8]; 167668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[8] = lhs[2] * rhs[6] + lhs[5] * rhs[7] + lhs[8] * rhs[8]; 167768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return r; 167868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 167968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 168068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 168168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Multiplies a vector of 3 components by a 3x3 matrix and stores the 168268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * result in the input vector. 168368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 168468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param lhs 3x3 matrix, as a non-null array of 9 floats 168568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param rhs Vector of 3 components, as a non-null array of 3 floats 168668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The array of 3 passed as the rhs parameter 168768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 168868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 168968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 169068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] mul3x3Float3( 169168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(9) float[] lhs, @NonNull @Size(min = 3) float[] rhs) { 169268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float r0 = rhs[0]; 169368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float r1 = rhs[1]; 169468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float r2 = rhs[2]; 169568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rhs[0] = lhs[0] * r0 + lhs[3] * r1 + lhs[6] * r2; 169668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rhs[1] = lhs[1] * r0 + lhs[4] * r1 + lhs[7] * r2; 169768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rhs[2] = lhs[2] * r0 + lhs[5] * r1 + lhs[8] * r2; 169868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return rhs; 169968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 170068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 170168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 170268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Multiplies a diagonal 3x3 matrix lhs, represented as an array of 3 floats, 170368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * by a 3x3 matrix represented as an array of 9 floats. 170468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 170568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param lhs Diagonal 3x3 matrix, as a non-null array of 3 floats 170668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param rhs 3x3 matrix, as a non-null array of 9 floats 170768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 9 floats containing the result of the multiplication 170868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * of rhs by lhs 170968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 171068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 171168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(9) 171268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] mul3x3Diag( 171368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(3) float[] lhs, @NonNull @Size(9) float[] rhs) { 171468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new float[] { 171568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy lhs[0] * rhs[0], lhs[1] * rhs[1], lhs[2] * rhs[2], 171668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy lhs[0] * rhs[3], lhs[1] * rhs[4], lhs[2] * rhs[5], 171768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy lhs[0] * rhs[6], lhs[1] * rhs[7], lhs[2] * rhs[8] 171868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }; 171968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 172068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 172168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 172268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Converts a value from CIE xyY to CIE XYZ. Y is assumed to be 1 so the 172368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * input xyY array only contains the x and y components. 172468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 172568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param xyY The xyY value to convert to XYZ, cannot be null, length must be 2 172668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new float array of length 3 containing XYZ values 172768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 172868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 172968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(3) 173068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] xyYToXyz(@NonNull @Size(2) float[] xyY) { 173168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new float[] { xyY[0] / xyY[1], 1.0f, (1 - xyY[0] - xyY[1]) / xyY[1] }; 173268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 173368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 173468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 17359505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * Converts values from CIE xyY to CIE L*u*v*. Y is assumed to be 1 so the 17369505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * input xyY array only contains the x and y components. After this method 17379505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * returns, the xyY array contains the converted u and v components. 17389505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * 17399505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * @param xyY The xyY value to convert to XYZ, cannot be null, 17409505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * length must be a multiple of 2 17419505a6552764461c22ce48f1ac13d025d23e1579Romain Guy */ 17429505a6552764461c22ce48f1ac13d025d23e1579Romain Guy private static void xyYToUv(@NonNull @Size(multiple = 2) float[] xyY) { 17439505a6552764461c22ce48f1ac13d025d23e1579Romain Guy for (int i = 0; i < xyY.length; i += 2) { 17449505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float x = xyY[i]; 17459505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float y = xyY[i + 1]; 17469505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 17479505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float d = -2.0f * x + 12.0f * y + 3; 17489505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float u = (4.0f * x) / d; 17499505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float v = (9.0f * y) / d; 17509505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 17519505a6552764461c22ce48f1ac13d025d23e1579Romain Guy xyY[i] = u; 17529505a6552764461c22ce48f1ac13d025d23e1579Romain Guy xyY[i + 1] = v; 17539505a6552764461c22ce48f1ac13d025d23e1579Romain Guy } 17549505a6552764461c22ce48f1ac13d025d23e1579Romain Guy } 17559505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 17569505a6552764461c22ce48f1ac13d025d23e1579Romain Guy /** 175768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Computes the chromatic adaptation transform from the specified 175868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * source white point to the specified destination white point.</p> 175968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1760efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The transform is computed using the von Kries method, described 176168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * in more details in the documentation of {@link Adaptation}. The 176268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Adaptation} enum provides different matrices that can be 176368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * used to perform the adaptation.</p> 176468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 176568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param matrix The adaptation matrix 176668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param srcWhitePoint The white point to adapt from, *will be modified* 176768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param dstWhitePoint The white point to adapt to, *will be modified* 176868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A 3x3 matrix as a non-null array of 9 floats 176968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 177068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 177168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(9) 177268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] chromaticAdaptation(@NonNull @Size(9) float[] matrix, 177368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(3) float[] srcWhitePoint, @NonNull @Size(3) float[] dstWhitePoint) { 177468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] srcLMS = mul3x3Float3(matrix, srcWhitePoint); 177568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] dstLMS = mul3x3Float3(matrix, dstWhitePoint); 177668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // LMS is a diagonal matrix stored as a float[3] 177768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] LMS = { dstLMS[0] / srcLMS[0], dstLMS[1] / srcLMS[1], dstLMS[2] / srcLMS[2] }; 177868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mul3x3(inverse3x3(matrix), mul3x3Diag(LMS, matrix)); 177968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 178068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 178168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 178268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Implementation of the CIE XYZ color space. Assumes the white point is D50. 178368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 178477b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy @AnyThread 178568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final class Xyz extends ColorSpace { 178668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private Xyz(@NonNull String name, @IntRange(from = MIN_ID, to = MAX_ID) int id) { 178768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy super(name, Model.XYZ, id); 178868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 178968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 179068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 179168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public boolean isWideGamut() { 179268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return true; 179368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 179468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 179568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 179668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float getMinValue(@IntRange(from = 0, to = 3) int component) { 179768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return -2.0f; 179868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 179968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 180068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 180168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float getMaxValue(@IntRange(from = 0, to = 3) int component) { 180268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return 2.0f; 180368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 180468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 180568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 180668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] toXyz(@NonNull @Size(min = 3) float[] v) { 180768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = clamp(v[0]); 180868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = clamp(v[1]); 180968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = clamp(v[2]); 181068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return v; 181168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 181268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 181368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 181468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] fromXyz(@NonNull @Size(min = 3) float[] v) { 181568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = clamp(v[0]); 181668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = clamp(v[1]); 181768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = clamp(v[2]); 181868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return v; 181968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 182068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 182168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float clamp(float x) { 182268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return x < -2.0f ? -2.0f : x > 2.0f ? 2.0f : x; 182368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 182468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 182568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 182668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 182768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Implementation of the CIE L*a*b* color space. Its PCS is CIE XYZ 182868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * with a white point of D50. 182968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 183077b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy @AnyThread 183168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final class Lab extends ColorSpace { 183268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final float A = 216.0f / 24389.0f; 183368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final float B = 841.0f / 108.0f; 183468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final float C = 4.0f / 29.0f; 183568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static final float D = 6.0f / 29.0f; 183668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 183768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private Lab(@NonNull String name, @IntRange(from = MIN_ID, to = MAX_ID) int id) { 183868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy super(name, Model.LAB, id); 183968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 184068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 184168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 184268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public boolean isWideGamut() { 184368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return true; 184468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 184568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 184668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 184768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float getMinValue(@IntRange(from = 0, to = 3) int component) { 184868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return component == 0 ? 0.0f : -128.0f; 184968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 185068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 185168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 185268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float getMaxValue(@IntRange(from = 0, to = 3) int component) { 185368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return component == 0 ? 100.0f : 128.0f; 185468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 185568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 185668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 185768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] toXyz(@NonNull @Size(min = 3) float[] v) { 185868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = clamp(v[0], 0.0f, 100.0f); 185968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = clamp(v[1], -128.0f, 128.0f); 186068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = clamp(v[2], -128.0f, 128.0f); 186168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 186268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float fy = (v[0] + 16.0f) / 116.0f; 186368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float fx = fy + (v[1] * 0.002f); 186468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float fz = fy - (v[2] * 0.005f); 186568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float X = fx > D ? fx * fx * fx : (1.0f / B) * (fx - C); 186668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Y = fy > D ? fy * fy * fy : (1.0f / B) * (fy - C); 186768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Z = fz > D ? fz * fz * fz : (1.0f / B) * (fz - C); 186868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 186968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = X * ILLUMINANT_D50_XYZ[0]; 187068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = Y * ILLUMINANT_D50_XYZ[1]; 187168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = Z * ILLUMINANT_D50_XYZ[2]; 187268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 187368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return v; 187468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 187568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 187668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 187768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] fromXyz(@NonNull @Size(min = 3) float[] v) { 187868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float X = v[0] / ILLUMINANT_D50_XYZ[0]; 187968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Y = v[1] / ILLUMINANT_D50_XYZ[1]; 188068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Z = v[2] / ILLUMINANT_D50_XYZ[2]; 188168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 188268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float fx = X > A ? (float) Math.pow(X, 1.0 / 3.0) : B * X + C; 188368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float fy = Y > A ? (float) Math.pow(Y, 1.0 / 3.0) : B * Y + C; 188468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float fz = Z > A ? (float) Math.pow(Z, 1.0 / 3.0) : B * Z + C; 188568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 188668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float L = 116.0f * fy - 16.0f; 188768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float a = 500.0f * (fx - fy); 188868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float b = 200.0f * (fy - fz); 188968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 189068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = clamp(L, 0.0f, 100.0f); 189168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = clamp(a, -128.0f, 128.0f); 189268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = clamp(b, -128.0f, 128.0f); 189368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 189468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return v; 189568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 189668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 189768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float clamp(float x, float min, float max) { 189868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return x < min ? min : x > max ? max : x; 189968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 190068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 190168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 190268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 190368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@usesMathJax} 190468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 190568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>An RGB color space is an additive color space using the 190668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Model#RGB RGB} color model (a color is therefore represented 190768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * by a tuple of 3 numbers).</p> 190868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 190968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>A specific RGB color space is defined by the following properties:</p> 191068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <ul> 191168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>Three chromaticities of the red, green and blue primaries, which 191268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * define the gamut of the color space.</li> 191368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>A white point chromaticity that defines the stimulus to which 191468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space values are normalized (also just called "white").</li> 191568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>An opto-electronic transfer function, also called opto-electronic 191668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * conversion function or often, and approximately, gamma function.</li> 191768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>An electro-optical transfer function, also called electo-optical 191868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * conversion function or often, and approximately, gamma function.</li> 191968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>A range of valid RGB values (most commonly \([0..1]\)).</li> 192068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </ul> 192168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 192268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The most commonly used RGB color space is {@link Named#SRGB sRGB}.</p> 192368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 192468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <h3>Primaries and white point chromaticities</h3> 192568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>In this implementation, the chromaticity of the primaries and the white 192668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * point of an RGB color space is defined in the CIE xyY color space. This 192768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space separates the chromaticity of a color, the x and y components, 192868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * and its luminance, the Y component. Since the primaries and the white 192968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * point have full brightness, the Y component is assumed to be 1 and only 193068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * the x and y components are needed to encode them.</p> 193168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>For convenience, this implementation also allows to define the 193268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * primaries and white point in the CIE XYZ space. The tristimulus XYZ values 193368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are internally converted to xyY.</p> 193468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1935199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 1936c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" /> 1937199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">sRGB primaries and white point</figcaption> 1938199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 1939199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * 194068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <h3>Transfer functions</h3> 194168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>A transfer function is a color component conversion function, defined as 194268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a single variable, monotonic mathematical function. It is applied to each 194368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * individual component of a color. They are used to perform the mapping 194468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * between linear tristimulus values and non-linear electronic signal value.</p> 194568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The <em>opto-electronic transfer function</em> (OETF or OECF) encodes 194668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * tristimulus values in a scene to a non-linear electronic signal value. 194768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * An OETF is often expressed as a power function with an exponent between 194868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 0.38 and 0.55 (the reciprocal of 1.8 to 2.6).</p> 194968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The <em>electro-optical transfer function</em> (EOTF or EOCF) decodes 195068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a non-linear electronic signal value to a tristimulus value at the display. 195168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * An EOTF is often expressed as a power function with an exponent between 195268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1.8 and 2.6.</p> 195368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Transfer functions are used as a compression scheme. For instance, 195468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * linear sRGB values would normally require 11 to 12 bits of precision to 195568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * store all values that can be perceived by the human eye. When encoding 195668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * sRGB values using the appropriate OETF (see {@link Named#SRGB sRGB} for 195768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * an exact mathematical description of that OETF), the values can be 195868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * compressed to only 8 bits precision.</p> 195968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>When manipulating RGB values, particularly sRGB values, it is safe 196068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to assume that these values have been encoded with the appropriate 196168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * OETF (unless noted otherwise). Encoded values are often said to be in 196268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * "gamma space". They are therefore defined in a non-linear space. This 196368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * in turns means that any linear operation applied to these values is 196468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * going to yield mathematically incorrect results (any linear interpolation 196568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * such as gradient generation for instance, most image processing functions 196668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * such as blurs, etc.).</p> 196768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>To properly process encoded RGB values you must first apply the 196868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * EOTF to decode the value into linear space. After processing, the RGB 196968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * value must be encoded back to non-linear ("gamma") space. Here is a 197068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * formal description of the process, where \(f\) is the processing 197168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * function to apply:</p> 197268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 197368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * $$RGB_{out} = OETF(f(EOTF(RGB_{in})))$$ 197468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1975efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>If the transfer functions of the color space can be expressed as an 1976efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * ICC parametric curve as defined in ICC.1:2004-10, the numeric parameters 1977efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * can be retrieved by calling {@link #getTransferParameters()}. This can 1978efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * be useful to match color spaces for instance.</p> 1979efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 198068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p class="note">Some RGB color spaces, such as {@link Named#ACES} and 198168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Named#LINEAR_EXTENDED_SRGB scRGB}, are said to be linear because 198268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * their transfer functions are the identity function: \(f(x) = x\). 198368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * If the source and/or destination are known to be linear, it is not 198468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * necessary to invoke the transfer functions.</p> 198568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 198668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <h3>Range</h3> 198768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Most RGB color spaces allow RGB values in the range \([0..1]\). There 198868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are however a few RGB color spaces that allow much larger ranges. For 198968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * instance, {@link Named#EXTENDED_SRGB scRGB} is used to manipulate the 199068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * range \([-0.5..7.5]\) while {@link Named#ACES ACES} can be used throughout 199168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * the range \([-65504, 65504]\).</p> 199268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 1993199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <p> 1994c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" /> 1995199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * <figcaption style="text-align: center;">Extended sRGB and its large range</figcaption> 1996199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * </p> 1997199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * 199868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <h3>Converting between RGB color spaces</h3> 199968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Conversion between two color spaces is achieved by using an intermediate 200068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space called the profile connection space (PCS). The PCS used by 200168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * this implementation is CIE XYZ. The conversion operation is defined 200268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * as such:</p> 200368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 200468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * $$RGB_{out} = OETF(T_{dst}^{-1} \cdot T_{src} \cdot EOTF(RGB_{in}))$$ 200568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 200668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Where \(T_{src}\) is the {@link #getTransform() RGB to XYZ transform} 200768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * of the source color space and \(T_{dst}^{-1}\) the {@link #getInverseTransform() 200868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * XYZ to RGB transform} of the destination color space.</p> 200968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Many RGB color spaces commonly used with electronic devices use the 201068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * standard illuminant {@link #ILLUMINANT_D65 D65}. Care must be take however 201168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * when converting between two RGB color spaces if their white points do not 201268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * match. This can be achieved by either calling 201368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link #adapt(ColorSpace, float[])} to adapt one or both color spaces to 201468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a single common white point. This can be achieved automatically by calling 201568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link ColorSpace#connect(ColorSpace, ColorSpace)}, which also handles 201668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * non-RGB color spaces.</p> 201768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>To learn more about the white point adaptation process, refer to the 201868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * documentation of {@link Adaptation}.</p> 201968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 202077b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy @AnyThread 202168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static class Rgb extends ColorSpace { 2022efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2023efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * {@usesMathJax} 2024efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2025efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Defines the parameters for the ICC parametric curve type 4, as 2026efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * defined in ICC.1:2004-10, section 10.15.</p> 2027efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2028efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The EOTF is of the form:</p> 2029efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2030efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \(\begin{equation} 2031efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * Y = \begin{cases}c X + f & X \lt d \\ 2032efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \left( a X + b \right) ^{g} + e & X \ge d \end{cases} 2033efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \end{equation}\) 2034efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2035efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The corresponding OETF is simply the inverse function.</p> 2036efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2037efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The parameters defined by this class form a valid transfer 2038efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * function only if all the following conditions are met:</p> 2039efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <ul> 2040efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>No parameter is a {@link Double#isNaN(double) Not-a-Number}</li> 2041efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>\(d\) is in the range \([0..1]\)</li> 2042efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The function is not constant</li> 2043efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The function is positive and increasing</li> 2044efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </ul> 2045efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2046efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public static class TransferParameters { 2047efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** Variable \(a\) in the equation of the EOTF described above. */ 2048efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public final double a; 2049efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** Variable \(b\) in the equation of the EOTF described above. */ 2050efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public final double b; 2051efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** Variable \(c\) in the equation of the EOTF described above. */ 2052efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public final double c; 2053efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** Variable \(d\) in the equation of the EOTF described above. */ 2054efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public final double d; 2055efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** Variable \(e\) in the equation of the EOTF described above. */ 2056efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public final double e; 2057efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** Variable \(f\) in the equation of the EOTF described above. */ 2058efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public final double f; 2059efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** Variable \(g\) in the equation of the EOTF described above. */ 2060efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public final double g; 2061efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2062efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2063efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Defines the parameters for the ICC parametric curve type 3, as 2064efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * defined in ICC.1:2004-10, section 10.15.</p> 2065efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2066efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The EOTF is of the form:</p> 2067efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2068efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \(\begin{equation} 2069efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * Y = \begin{cases}c X & X \lt d \\ 2070efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \left( a X + b \right) ^{g} & X \ge d \end{cases} 2071efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * \end{equation}\) 2072efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2073efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>This constructor is equivalent to setting \(e\) and \(f\) to 0.</p> 2074efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2075efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param a The value of \(a\) in the equation of the EOTF described above 2076efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param b The value of \(b\) in the equation of the EOTF described above 2077efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param c The value of \(c\) in the equation of the EOTF described above 2078efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param d The value of \(d\) in the equation of the EOTF described above 2079efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param g The value of \(g\) in the equation of the EOTF described above 2080efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2081efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @throws IllegalArgumentException If the parameters form an invalid transfer function 2082efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2083efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public TransferParameters(double a, double b, double c, double d, double g) { 2084efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this(a, b, c, d, 0.0, 0.0, g); 2085efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2086efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2087efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2088efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Defines the parameters for the ICC parametric curve type 4, as 2089efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * defined in ICC.1:2004-10, section 10.15.</p> 2090efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2091efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param a The value of \(a\) in the equation of the EOTF described above 2092efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param b The value of \(b\) in the equation of the EOTF described above 2093efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param c The value of \(c\) in the equation of the EOTF described above 2094efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param d The value of \(d\) in the equation of the EOTF described above 2095efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param e The value of \(e\) in the equation of the EOTF described above 2096efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param f The value of \(f\) in the equation of the EOTF described above 2097efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param g The value of \(g\) in the equation of the EOTF described above 2098efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2099efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @throws IllegalArgumentException If the parameters form an invalid transfer function 2100efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2101efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public TransferParameters(double a, double b, double c, double d, double e, 2102efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy double f, double g) { 2103efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2104efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (Double.isNaN(a) || Double.isNaN(b) || Double.isNaN(c) || 2105efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy Double.isNaN(d) || Double.isNaN(e) || Double.isNaN(f) || 2106efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy Double.isNaN(g)) { 2107efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy throw new IllegalArgumentException("Parameters cannot be NaN"); 2108efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2109efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2110bfa58aab0a7723f2757f7919f37a520f469b7b04Romain Guy // Next representable float after 1.0 2111bfa58aab0a7723f2757f7919f37a520f469b7b04Romain Guy // We use doubles here but the representation inside our native code is often floats 2112bfa58aab0a7723f2757f7919f37a520f469b7b04Romain Guy if (!(d >= 0.0 && d <= 1.0f + Math.ulp(1.0f))) { 2113bfa58aab0a7723f2757f7919f37a520f469b7b04Romain Guy throw new IllegalArgumentException("Parameter d must be in the range [0..1], " + 2114bfa58aab0a7723f2757f7919f37a520f469b7b04Romain Guy "was " + d); 2115efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2116efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2117efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (d == 0.0 && (a == 0.0 || g == 0.0)) { 2118efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy throw new IllegalArgumentException( 2119efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy "Parameter a or g is zero, the transfer function is constant"); 2120efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2121efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2122efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (d >= 1.0 && c == 0.0) { 2123efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy throw new IllegalArgumentException( 2124efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy "Parameter c is zero, the transfer function is constant"); 2125efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2126efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2127efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if ((a == 0.0 || g == 0.0) && c == 0.0) { 2128efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy throw new IllegalArgumentException("Parameter a or g is zero," + 2129efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy " and c is zero, the transfer function is constant"); 2130efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2131efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2132efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (c < 0.0) { 2133efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy throw new IllegalArgumentException("The transfer function must be increasing"); 2134efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2135efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2136efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (a < 0.0 || g < 0.0) { 2137efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy throw new IllegalArgumentException("The transfer function must be " + 2138efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy "positive or increasing"); 2139efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2140efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2141efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this.a = a; 2142efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this.b = b; 2143efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this.c = c; 2144efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this.d = d; 2145efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this.e = e; 2146efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this.f = f; 2147efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this.g = g; 2148efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2149efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2150efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @SuppressWarnings("SimplifiableIfStatement") 2151efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @Override 2152efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public boolean equals(Object o) { 2153efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (this == o) return true; 2154efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (o == null || getClass() != o.getClass()) return false; 2155efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2156efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy TransferParameters that = (TransferParameters) o; 2157efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2158efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (Double.compare(that.a, a) != 0) return false; 2159efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (Double.compare(that.b, b) != 0) return false; 2160efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (Double.compare(that.c, c) != 0) return false; 2161efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (Double.compare(that.d, d) != 0) return false; 2162efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (Double.compare(that.e, e) != 0) return false; 2163efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (Double.compare(that.f, f) != 0) return false; 2164efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return Double.compare(that.g, g) == 0; 2165efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2166efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2167efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @Override 2168efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public int hashCode() { 2169efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy int result; 2170efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy long temp; 2171efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy temp = Double.doubleToLongBits(a); 2172efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = (int) (temp ^ (temp >>> 32)); 2173efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy temp = Double.doubleToLongBits(b); 2174efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + (int) (temp ^ (temp >>> 32)); 2175efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy temp = Double.doubleToLongBits(c); 2176efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + (int) (temp ^ (temp >>> 32)); 2177efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy temp = Double.doubleToLongBits(d); 2178efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + (int) (temp ^ (temp >>> 32)); 2179efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy temp = Double.doubleToLongBits(e); 2180efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + (int) (temp ^ (temp >>> 32)); 2181efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy temp = Double.doubleToLongBits(f); 2182efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + (int) (temp ^ (temp >>> 32)); 2183efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy temp = Double.doubleToLongBits(g); 2184efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + (int) (temp ^ (temp >>> 32)); 2185efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return result; 2186efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2187efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2188efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 218968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final float[] mWhitePoint; 219068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final float[] mPrimaries; 219168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final float[] mTransform; 219268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final float[] mInverseTransform; 219368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 219468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final DoubleUnaryOperator mOetf; 219568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final DoubleUnaryOperator mEotf; 219668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final DoubleUnaryOperator mClampedOetf; 219768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final DoubleUnaryOperator mClampedEotf; 219868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 219968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private final float mMin; 220068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private final float mMax; 220168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 2202efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private final boolean mIsWideGamut; 2203efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private final boolean mIsSrgb; 2204efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2205efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @Nullable private TransferParameters mTransferParameters; 2206efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 220768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 220868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Creates a new RGB color space using a 3x3 column-major transform matrix. 220968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The transform matrix must convert from the RGB space to the profile connection 221068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * space CIE XYZ.</p> 221168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 221268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p class="note">The range of the color space is imposed to be \([0..1]\).</p> 221368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 221468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 221568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param toXYZ 3x3 column-major transform matrix from RGB to the profile 221668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * connection space CIE XYZ as an array of 9 floats, cannot be null 221768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param oetf Opto-electronic transfer function, cannot be null 221868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param eotf Electro-optical transfer function, cannot be null 221968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 222068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @throws IllegalArgumentException If any of the following conditions is met: 222168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <ul> 222268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The name is null or has a length of 0.</li> 222368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The OETF is null or the EOTF is null.</li> 222468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The minimum valid value is >= the maximum valid value.</li> 222568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </ul> 222668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 222768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #get(Named) 222868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 222968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public Rgb( 223068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 1) String name, 223168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(9) float[] toXYZ, 223268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull DoubleUnaryOperator oetf, 223368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull DoubleUnaryOperator eotf) { 2234efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ), 223568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy oetf, eotf, 0.0f, 1.0f, MIN_ID); 223668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 223768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 223868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 223968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Creates a new RGB color space using a specified set of primaries 224068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * and a specified white point.</p> 224168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 224268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The primaries and white point can be specified in the CIE xyY space 224368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * or in CIE XYZ. The length of the arrays depends on the chosen space:</p> 224468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 224568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Parameters length"> 224668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr> 224768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>xyY</td><td>6</td><td>2</td></tr> 224868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>XYZ</td><td>9</td><td>3</td></tr> 224968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 225068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 225168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>When the primaries and/or white point are specified in xyY, the Y component 225268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * does not need to be specified and is assumed to be 1.0. Only the xy components 225368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are required.</p> 225468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 225568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p class="note">The ID, areturned by {@link #getId()}, of an object created by 225668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * this constructor is always {@link #MIN_ID}.</p> 225768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 225868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 225968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats 226068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats 226168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param oetf Opto-electronic transfer function, cannot be null 226268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param eotf Electro-optical transfer function, cannot be null 226368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param min The minimum valid value in this color space's RGB range 226468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param max The maximum valid value in this color space's RGB range 226568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 226668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @throws IllegalArgumentException <p>If any of the following conditions is met:</p> 226768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <ul> 226868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The name is null or has a length of 0.</li> 226968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The primaries array is null or has a length that is neither 6 or 9.</li> 227068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The white point array is null or has a length that is neither 2 or 3.</li> 227168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The OETF is null or the EOTF is null.</li> 227268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The minimum valid value is >= the maximum valid value.</li> 227368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </ul> 227468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 227568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #get(Named) 227668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 227768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public Rgb( 227868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 1) String name, 227968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 6, max = 9) float[] primaries, 228068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint, 228168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull DoubleUnaryOperator oetf, 228268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull DoubleUnaryOperator eotf, 228368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float min, 228468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float max) { 228568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy this(name, primaries, whitePoint, oetf, eotf, min, max, MIN_ID); 228668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 228768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 228868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 2289efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Creates a new RGB color space using a 3x3 column-major transform matrix. 2290efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * The transform matrix must convert from the RGB space to the profile connection 2291efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * space CIE XYZ.</p> 2292efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2293efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p class="note">The range of the color space is imposed to be \([0..1]\).</p> 2294efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2295efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 2296efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param toXYZ 3x3 column-major transform matrix from RGB to the profile 2297efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * connection space CIE XYZ as an array of 9 floats, cannot be null 2298efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param function Parameters for the transfer functions 2299efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2300efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @throws IllegalArgumentException If any of the following conditions is met: 2301efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <ul> 2302efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The name is null or has a length of 0.</li> 2303efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>Gamma is negative.</li> 2304efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </ul> 2305efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2306efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @see #get(Named) 2307efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2308efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public Rgb( 2309efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 1) String name, 2310efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(9) float[] toXYZ, 2311efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull TransferParameters function) { 2312efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ), function, MIN_ID); 2313efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2314efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2315efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2316efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Creates a new RGB color space using a specified set of primaries 2317efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * and a specified white point.</p> 2318efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2319efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The primaries and white point can be specified in the CIE xyY space 2320efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * or in CIE XYZ. The length of the arrays depends on the chosen space:</p> 2321efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2322efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <table summary="Parameters length"> 2323efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr> 2324efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><td>xyY</td><td>6</td><td>2</td></tr> 2325efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><td>XYZ</td><td>9</td><td>3</td></tr> 2326efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </table> 2327efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2328efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>When the primaries and/or white point are specified in xyY, the Y component 2329efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * does not need to be specified and is assumed to be 1.0. Only the xy components 2330efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * are required.</p> 2331efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2332efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 2333efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats 2334efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats 2335efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param function Parameters for the transfer functions 2336efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2337efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @throws IllegalArgumentException If any of the following conditions is met: 2338efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <ul> 2339efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The name is null or has a length of 0.</li> 2340efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The primaries array is null or has a length that is neither 6 or 9.</li> 2341efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The white point array is null or has a length that is neither 2 or 3.</li> 2342efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The transfer parameters are invalid.</li> 2343efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </ul> 2344efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2345efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @see #get(Named) 2346efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2347efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public Rgb( 2348efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 1) String name, 2349efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 6, max = 9) float[] primaries, 2350efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint, 2351efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull TransferParameters function) { 2352efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this(name, primaries, whitePoint, function, MIN_ID); 2353efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2354efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2355efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2356efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Creates a new RGB color space using a specified set of primaries 2357efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * and a specified white point.</p> 2358efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2359efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The primaries and white point can be specified in the CIE xyY space 2360efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * or in CIE XYZ. The length of the arrays depends on the chosen space:</p> 2361efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2362efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <table summary="Parameters length"> 2363efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr> 2364efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><td>xyY</td><td>6</td><td>2</td></tr> 2365efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><td>XYZ</td><td>9</td><td>3</td></tr> 2366efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </table> 2367efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2368efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>When the primaries and/or white point are specified in xyY, the Y component 2369efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * does not need to be specified and is assumed to be 1.0. Only the xy components 2370efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * are required.</p> 2371efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2372efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 2373efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats 2374efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats 2375efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param function Parameters for the transfer functions 2376efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param id ID of this color space as an integer between {@link #MIN_ID} and {@link #MAX_ID} 2377efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2378efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @throws IllegalArgumentException If any of the following conditions is met: 2379efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <ul> 2380efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The name is null or has a length of 0.</li> 2381efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The primaries array is null or has a length that is neither 6 or 9.</li> 2382efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The white point array is null or has a length that is neither 2 or 3.</li> 2383efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The ID is not between {@link #MIN_ID} and {@link #MAX_ID}.</li> 2384efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The transfer parameters are invalid.</li> 2385efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </ul> 2386efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2387efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @see #get(Named) 2388efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2389efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private Rgb( 2390efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 1) String name, 2391efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 6, max = 9) float[] primaries, 2392efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint, 2393efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull TransferParameters function, 2394efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @IntRange(from = MIN_ID, to = MAX_ID) int id) { 2395efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this(name, primaries, whitePoint, 2396efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy function.e == 0.0 && function.f == 0.0 ? 2397efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy x -> rcpResponse(x, function.a, function.b, 2398efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy function.c, function.d, function.g) : 2399efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy x -> rcpResponse(x, function.a, function.b, function.c, 2400efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy function.d, function.e, function.f, function.g), 2401efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy function.e == 0.0 && function.f == 0.0 ? 2402efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy x -> response(x, function.a, function.b, 2403efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy function.c, function.d, function.g) : 2404efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy x -> response(x, function.a, function.b, function.c, 2405efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy function.d, function.e, function.f, function.g), 2406efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 0.0f, 1.0f, id); 2407efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy mTransferParameters = function; 2408efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2409efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2410efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2411efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Creates a new RGB color space using a 3x3 column-major transform matrix. 2412efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * The transform matrix must convert from the RGB space to the profile connection 2413efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * space CIE XYZ.</p> 2414efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2415efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p class="note">The range of the color space is imposed to be \([0..1]\).</p> 2416efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2417efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 2418efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param toXYZ 3x3 column-major transform matrix from RGB to the profile 2419efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * connection space CIE XYZ as an array of 9 floats, cannot be null 2420efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param gamma Gamma to use as the transfer function 2421efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2422efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @throws IllegalArgumentException If any of the following conditions is met: 2423efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <ul> 2424efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The name is null or has a length of 0.</li> 2425efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>Gamma is negative.</li> 2426efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </ul> 2427efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2428efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @see #get(Named) 2429efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2430efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public Rgb( 2431efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 1) String name, 2432efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(9) float[] toXYZ, 2433efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy double gamma) { 2434efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ), gamma, 0.0f, 1.0f, MIN_ID); 2435efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2436efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2437efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2438efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Creates a new RGB color space using a specified set of primaries 2439efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * and a specified white point.</p> 2440efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2441efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The primaries and white point can be specified in the CIE xyY space 2442efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * or in CIE XYZ. The length of the arrays depends on the chosen space:</p> 2443efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2444efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <table summary="Parameters length"> 2445efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr> 2446efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><td>xyY</td><td>6</td><td>2</td></tr> 2447efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><td>XYZ</td><td>9</td><td>3</td></tr> 2448efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </table> 2449efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2450efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>When the primaries and/or white point are specified in xyY, the Y component 2451efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * does not need to be specified and is assumed to be 1.0. Only the xy components 2452efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * are required.</p> 2453efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2454efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 2455efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats 2456efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats 2457efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param gamma Gamma to use as the transfer function 2458efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2459efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @throws IllegalArgumentException If any of the following conditions is met: 2460efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <ul> 2461efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The name is null or has a length of 0.</li> 2462efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The primaries array is null or has a length that is neither 6 or 9.</li> 2463efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The white point array is null or has a length that is neither 2 or 3.</li> 2464efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>Gamma is negative.</li> 2465efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </ul> 2466efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2467efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @see #get(Named) 2468efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2469efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public Rgb( 2470efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 1) String name, 2471efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 6, max = 9) float[] primaries, 2472efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint, 2473efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy double gamma) { 2474efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this(name, primaries, whitePoint, gamma, 0.0f, 1.0f, MIN_ID); 2475efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2476efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2477efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2478efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Creates a new RGB color space using a specified set of primaries 2479efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * and a specified white point.</p> 2480efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2481efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>The primaries and white point can be specified in the CIE xyY space 2482efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * or in CIE XYZ. The length of the arrays depends on the chosen space:</p> 2483efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2484efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <table summary="Parameters length"> 2485efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr> 2486efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><td>xyY</td><td>6</td><td>2</td></tr> 2487efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <tr><td>XYZ</td><td>9</td><td>3</td></tr> 2488efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </table> 2489efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2490efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>When the primaries and/or white point are specified in xyY, the Y component 2491efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * does not need to be specified and is assumed to be 1.0. Only the xy components 2492efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * are required.</p> 2493efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2494efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 2495efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats 2496efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats 2497efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param gamma Gamma to use as the transfer function 2498efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param min The minimum valid value in this color space's RGB range 2499efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param max The maximum valid value in this color space's RGB range 2500efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @param id ID of this color space as an integer between {@link #MIN_ID} and {@link #MAX_ID} 2501efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2502efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @throws IllegalArgumentException If any of the following conditions is met: 2503efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <ul> 2504efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The name is null or has a length of 0.</li> 2505efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The primaries array is null or has a length that is neither 6 or 9.</li> 2506efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The white point array is null or has a length that is neither 2 or 3.</li> 2507efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The minimum valid value is >= the maximum valid value.</li> 2508efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>The ID is not between {@link #MIN_ID} and {@link #MAX_ID}.</li> 2509efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <li>Gamma is negative.</li> 2510efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * </ul> 2511efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2512efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @see #get(Named) 2513efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2514efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private Rgb( 2515efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 1) String name, 2516efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 6, max = 9) float[] primaries, 2517efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint, 2518efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy double gamma, 2519efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy float min, 2520efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy float max, 2521efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @IntRange(from = MIN_ID, to = MAX_ID) int id) { 2522efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy this(name, primaries, whitePoint, 2523efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy gamma == 1.0 ? DoubleUnaryOperator.identity() : 2524efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy x -> Math.pow(x < 0.0 ? 0.0 : x, 1 / gamma), 2525efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy gamma == 1.0 ? DoubleUnaryOperator.identity() : 2526efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy x -> Math.pow(x < 0.0 ? 0.0 : x, gamma), 2527efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy min, max, id); 2528efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy mTransferParameters = gamma == 1.0 ? 2529bfa58aab0a7723f2757f7919f37a520f469b7b04Romain Guy new TransferParameters(0.0, 0.0, 1.0, 1.0 + Math.ulp(1.0f), gamma) : 2530efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma); 2531efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2532efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2533efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 253468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Creates a new RGB color space using a specified set of primaries 253568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * and a specified white point.</p> 253668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 253768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The primaries and white point can be specified in the CIE xyY space 253868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * or in CIE XYZ. The length of the arrays depends on the chosen space:</p> 253968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 254068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <table summary="Parameters length"> 254168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><th>Space</th><th>Primaries length</th><th>White point length</th></tr> 254268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>xyY</td><td>6</td><td>2</td></tr> 254368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <tr><td>XYZ</td><td>9</td><td>3</td></tr> 254468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </table> 254568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 254668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>When the primaries and/or white point are specified in xyY, the Y component 254768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * does not need to be specified and is assumed to be 1.0. Only the xy components 254868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are required.</p> 254968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 255068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param name Name of the color space, cannot be null, its length must be >= 1 255168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats 255268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats 255368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param oetf Opto-electronic transfer function, cannot be null 255468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param eotf Electro-optical transfer function, cannot be null 255568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param min The minimum valid value in this color space's RGB range 255668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param max The maximum valid value in this color space's RGB range 255768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param id ID of this color space as an integer between {@link #MIN_ID} and {@link #MAX_ID} 255868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 255968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @throws IllegalArgumentException If any of the following conditions is met: 256068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <ul> 256168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The name is null or has a length of 0.</li> 256268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The primaries array is null or has a length that is neither 6 or 9.</li> 256368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The white point array is null or has a length that is neither 2 or 3.</li> 256468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The OETF is null or the EOTF is null.</li> 256568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The minimum valid value is >= the maximum valid value.</li> 256668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <li>The ID is not between {@link #MIN_ID} and {@link #MAX_ID}.</li> 256768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </ul> 256868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 256968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #get(Named) 257068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 257168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private Rgb( 257268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 1) String name, 257368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 6, max = 9) float[] primaries, 257468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint, 257568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull DoubleUnaryOperator oetf, 257668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull DoubleUnaryOperator eotf, 257768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float min, 257868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float max, 257968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @IntRange(from = MIN_ID, to = MAX_ID) int id) { 258068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 258168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy super(name, Model.RGB, id); 258268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 258368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (primaries == null || (primaries.length != 6 && primaries.length != 9)) { 258468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy throw new IllegalArgumentException("The color space's primaries must be " + 258568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "defined as an array of 6 floats in xyY or 9 floats in XYZ"); 258668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 258768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 258868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (whitePoint == null || (whitePoint.length != 2 && whitePoint.length != 3)) { 258968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy throw new IllegalArgumentException("The color space's white point must be " + 259068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "defined as an array of 2 floats in xyY or 3 float in XYZ"); 259168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 259268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 259368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (oetf == null || eotf == null) { 259468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy throw new IllegalArgumentException("The transfer functions of a color space " + 259568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "cannot be null"); 259668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 259768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 259868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (min >= max) { 259968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy throw new IllegalArgumentException("Invalid range: min=" + min + ", max=" + max + 260068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy "; min must be strictly < max"); 260168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 260268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 260368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mWhitePoint = xyWhitePoint(whitePoint); 260468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mPrimaries = xyPrimaries(primaries); 260568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 260668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mTransform = computeXYZMatrix(mPrimaries, mWhitePoint); 260768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mInverseTransform = inverse3x3(mTransform); 260868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 260968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mOetf = oetf; 261068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mEotf = eotf; 261168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 261268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mMin = min; 261368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mMax = max; 261468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 261568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy DoubleUnaryOperator clamp = this::clamp; 261668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mClampedOetf = oetf.andThen(clamp); 261768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mClampedEotf = clamp.andThen(eotf); 261868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 261968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // A color space is wide-gamut if its area is >90% of NTSC 1953 and 262068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // if it entirely contains the Color space definition in xyY 2621199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy mIsWideGamut = isWideGamut(mPrimaries, min, max); 2622199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy mIsSrgb = isSrgb(mPrimaries, mWhitePoint, oetf, eotf, min, max, id); 262368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 262468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 262568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 262668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Creates a copy of the specified color space with a new transform. 262768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 262868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param colorSpace The color space to create a copy of 262968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 263068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private Rgb(Rgb colorSpace, 263168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(9) float[] transform, 263268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(min = 2, max = 3) float[] whitePoint) { 263368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy super(colorSpace.getName(), Model.RGB, -1); 263468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 263568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mWhitePoint = xyWhitePoint(whitePoint); 263668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mPrimaries = colorSpace.mPrimaries; 263768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 263868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mTransform = transform; 263968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mInverseTransform = inverse3x3(transform); 264068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 264168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mMin = colorSpace.mMin; 264268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mMax = colorSpace.mMax; 264368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 264468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mOetf = colorSpace.mOetf; 264568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mEotf = colorSpace.mEotf; 264668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 264768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mClampedOetf = colorSpace.mClampedOetf; 264868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mClampedEotf = colorSpace.mClampedEotf; 264968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 265068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mIsWideGamut = colorSpace.mIsWideGamut; 265168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mIsSrgb = colorSpace.mIsSrgb; 2652efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 2653efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy mTransferParameters = colorSpace.mTransferParameters; 265468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 265568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 265668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 265768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Copies the non-adapted CIE xyY white point of this color space in 265868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * specified array. The Y component is assumed to be 1 and is therefore 265968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * not copied into the destination. The x and y components are written 266068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * in the array at positions 0 and 1 respectively. 266168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 266268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param whitePoint The destination array, cannot be null, its length 266368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * must be >= 2 266468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 266568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The destination array passed as a parameter 266668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 266768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getWhitePoint(float[]) 266868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 266968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 267068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 2) 267168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] getWhitePoint(@NonNull @Size(min = 2) float[] whitePoint) { 267268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy whitePoint[0] = mWhitePoint[0]; 267368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy whitePoint[1] = mWhitePoint[1]; 267468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return whitePoint; 267568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 267668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 267768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 267868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the non-adapted CIE xyY white point of this color space as 267968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a new array of 2 floats. The Y component is assumed to be 1 and is 268068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * therefore not copied into the destination. The x and y components 268168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are written in the array at positions 0 and 1 respectively. 268268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 268368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new non-null array of 2 floats 268468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 268568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getWhitePoint() 268668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 268768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 268868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(2) 268968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] getWhitePoint() { 269068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return Arrays.copyOf(mWhitePoint, mWhitePoint.length); 269168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 269268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 269368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 269468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Copies the primaries of this color space in specified array. The Y 269568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * component is assumed to be 1 and is therefore not copied into the 269668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * destination. The x and y components of the first primary are written 269768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * in the array at positions 0 and 1 respectively. 269868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 269968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param primaries The destination array, cannot be null, its length 270068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * must be >= 6 270168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 270268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The destination array passed as a parameter 270368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 270468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getPrimaries(float[]) 270568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 270668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 270768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 6) 270868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] getPrimaries(@NonNull @Size(min = 6) float[] primaries) { 270968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy System.arraycopy(mPrimaries, 0, primaries, 0, mPrimaries.length); 271068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return primaries; 271168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 271268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 271368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 271468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the primaries of this color space as a new array of 6 floats. 271568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The Y component is assumed to be 1 and is therefore not copied into 271668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * the destination. The x and y components of the first primary are 271768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * written in the array at positions 0 and 1 respectively. 271868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 271968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new non-null array of 2 floats 272068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 272168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getWhitePoint() 272268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 272368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 272468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(6) 272568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] getPrimaries() { 272668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return Arrays.copyOf(mPrimaries, mPrimaries.length); 272768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 272868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 272968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 273068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Copies the transform of this color space in specified array. The 273168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * transform is used to convert from RGB to XYZ (with the same white 273268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * point as this color space). To connect color spaces, you must first 273368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link ColorSpace#adapt(ColorSpace, float[]) adapt} them to the 273468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * same white point.</p> 273568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>It is recommended to use {@link ColorSpace#connect(ColorSpace, ColorSpace)} 273668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to convert between color spaces.</p> 273768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 273868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param transform The destination array, cannot be null, its length 273968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * must be >= 9 274068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 274168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The destination array passed as a parameter 274268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 274368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getInverseTransform() 274468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 274568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 274668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 9) 274768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] getTransform(@NonNull @Size(min = 9) float[] transform) { 274868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy System.arraycopy(mTransform, 0, transform, 0, mTransform.length); 274968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return transform; 275068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 275168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 275268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 275368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Returns the transform of this color space as a new array. The 275468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * transform is used to convert from RGB to XYZ (with the same white 275568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * point as this color space). To connect color spaces, you must first 275668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link ColorSpace#adapt(ColorSpace, float[]) adapt} them to the 275768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * same white point.</p> 275868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>It is recommended to use {@link ColorSpace#connect(ColorSpace, ColorSpace)} 275968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to convert between color spaces.</p> 276068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 276168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 9 floats 276268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 276368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getInverseTransform(float[]) 276468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 276568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 276668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(9) 276768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] getTransform() { 276868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return Arrays.copyOf(mTransform, mTransform.length); 276968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 277068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 277168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 277268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Copies the inverse transform of this color space in specified array. 277368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The inverse transform is used to convert from XYZ to RGB (with the 277468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * same white point as this color space). To connect color spaces, you 277568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * must first {@link ColorSpace#adapt(ColorSpace, float[]) adapt} them 277668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to the same white point.</p> 277768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>It is recommended to use {@link ColorSpace#connect(ColorSpace, ColorSpace)} 277868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to convert between color spaces.</p> 277968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 278068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param inverseTransform The destination array, cannot be null, its length 278168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * must be >= 9 278268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 278368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The destination array passed as a parameter 278468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 278568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getTransform() 278668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 278768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 278868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 9) 278968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] getInverseTransform(@NonNull @Size(min = 9) float[] inverseTransform) { 279068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy System.arraycopy(mInverseTransform, 0, inverseTransform, 0, mInverseTransform.length); 279168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return inverseTransform; 279268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 279368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 279468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 279568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Returns the inverse transform of this color space as a new array. 279668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The inverse transform is used to convert from XYZ to RGB (with the 279768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * same white point as this color space). To connect color spaces, you 279868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * must first {@link ColorSpace#adapt(ColorSpace, float[]) adapt} them 279968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to the same white point.</p> 280068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>It is recommended to use {@link ColorSpace#connect(ColorSpace, ColorSpace)} 280168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to convert between color spaces.</p> 280268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 280368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 9 floats 280468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 280568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getTransform(float[]) 280668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 280768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 280868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(9) 280968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] getInverseTransform() { 281068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return Arrays.copyOf(mInverseTransform, mInverseTransform.length); 281168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 281268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 281368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 281468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Returns the opto-electronic transfer function (OETF) of this color space. 281568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The inverse function is the electro-optical transfer function (EOTF) returned 281668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * by {@link #getEotf()}. These functions are defined to satisfy the following 281768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * equality for \(x \in [0..1]\):</p> 281868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 281968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * $$OETF(EOTF(x)) = EOTF(OETF(x)) = x$$ 282068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 282168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>For RGB colors, this function can be used to convert from linear space 282268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to "gamma space" (gamma encoded). The terms gamma space and gamma encoded 282368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are frequently used because many OETFs can be closely approximated using 282468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a simple power function of the form \(x^{\frac{1}{\gamma}}\) (the 282577b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy * approximation of the {@link Named#SRGB sRGB} OETF uses \(\gamma=2.2\) 282668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * for instance).</p> 282768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 282868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A transfer function that converts from linear space to "gamma space" 282968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 283068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getEotf() 2831efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @see #getTransferParameters() 283268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 283368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 283468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public DoubleUnaryOperator getOetf() { 283577b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy return mClampedOetf; 283668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 283768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 283868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 283968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Returns the electro-optical transfer function (EOTF) of this color space. 284068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The inverse function is the opto-electronic transfer function (OETF) 284168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * returned by {@link #getOetf()}. These functions are defined to satisfy the 284268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * following equality for \(x \in [0..1]\):</p> 284368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 284468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * $$OETF(EOTF(x)) = EOTF(OETF(x)) = x$$ 284568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 284668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>For RGB colors, this function can be used to convert from "gamma space" 284768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * (gamma encoded) to linear space. The terms gamma space and gamma encoded 284868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * are frequently used because many EOTFs can be closely approximated using 284968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a simple power function of the form \(x^\gamma\) (the approximation of the 285068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Named#SRGB sRGB} EOTF uses \(\gamma=2.2\) for instance).</p> 285168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 285268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A transfer function that converts from "gamma space" to linear space 285368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 285468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getOetf() 2855efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @see #getTransferParameters() 285668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 285768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 285868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public DoubleUnaryOperator getEotf() { 285977b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy return mClampedEotf; 286068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 286168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 2862efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy /** 2863efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>Returns the parameters used by the {@link #getEotf() electro-optical} 2864efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * and {@link #getOetf() opto-electronic} transfer functions. If the transfer 2865efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * functions do not match the ICC parametric curves defined in ICC.1:2004-10 2866efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * (section 10.15), this method returns null.</p> 2867efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2868efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * <p>See {@link TransferParameters} for a full description of the transfer 2869efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * functions.</p> 2870efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * 2871efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * @return An instance of {@link TransferParameters} or null if this color 2872efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * space's transfer functions do not match the equation defined in 2873efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy * {@link TransferParameters} 2874efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy */ 2875efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @Nullable 2876efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy public TransferParameters getTransferParameters() { 2877efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return mTransferParameters; 2878efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 2879efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy 288068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 288168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public boolean isSrgb() { 288268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mIsSrgb; 288368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 288468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 288568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 288668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public boolean isWideGamut() { 288768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mIsWideGamut; 288868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 288968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 289068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 289168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float getMinValue(int component) { 289268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mMin; 289368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 289468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 289568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 289668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float getMaxValue(int component) { 289768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mMax; 289868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 289968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 290068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 290168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Decodes an RGB value to linear space. This is achieved by 290268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * applying this color space's electro-optical transfer function 290368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to the supplied values.</p> 290468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 290568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Refer to the documentation of {@link ColorSpace.Rgb} for 290668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * more information about transfer functions and their use for 290768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * encoding and decoding RGB values.</p> 290868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 290968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param r The red component to decode to linear space 291068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param g The green component to decode to linear space 291168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param b The blue component to decode to linear space 291268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 3 floats containing linear RGB values 291368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 291468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #toLinear(float[]) 291568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #fromLinear(float, float, float) 291668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 291768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 291868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(3) 291968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] toLinear(float r, float g, float b) { 292068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return toLinear(new float[] { r, g, b }); 292168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 292268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 292368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 292468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Decodes an RGB value to linear space. This is achieved by 292568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * applying this color space's electro-optical transfer function 292668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to the first 3 values of the supplied array. The result is 292768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * stored back in the input array.</p> 292868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 292968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Refer to the documentation of {@link ColorSpace.Rgb} for 293068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * more information about transfer functions and their use for 293168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * encoding and decoding RGB values.</p> 293268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 293368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param v A non-null array of non-linear RGB values, its length 293468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * must be at least 3 293568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The specified array 293668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 293768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #toLinear(float, float, float) 293868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #fromLinear(float[]) 293968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 294068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 294168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 294268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] toLinear(@NonNull @Size(min = 3) float[] v) { 294368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = (float) mClampedEotf.applyAsDouble(v[0]); 294468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = (float) mClampedEotf.applyAsDouble(v[1]); 294568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = (float) mClampedEotf.applyAsDouble(v[2]); 294668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return v; 294768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 294868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 294968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 295068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Encodes an RGB value from linear space to this color space's 295168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * "gamma space". This is achieved by applying this color space's 295268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * opto-electronic transfer function to the supplied values.</p> 295368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 295468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Refer to the documentation of {@link ColorSpace.Rgb} for 295568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * more information about transfer functions and their use for 295668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * encoding and decoding RGB values.</p> 295768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 295868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param r The red component to encode from linear space 295968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param g The green component to encode from linear space 296068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param b The blue component to encode from linear space 296168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 3 floats containing non-linear RGB values 296268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 296368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #fromLinear(float[]) 296468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #toLinear(float, float, float) 296568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 296668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 296768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(3) 296868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] fromLinear(float r, float g, float b) { 296968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return fromLinear(new float[] { r, g, b }); 297068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 297168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 297268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 297368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Encodes an RGB value from linear space to this color space's 297468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * "gamma space". This is achieved by applying this color space's 297568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * opto-electronic transfer function to the first 3 values of the 297668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * supplied array. The result is stored back in the input array.</p> 297768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 297868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Refer to the documentation of {@link ColorSpace.Rgb} for 297968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * more information about transfer functions and their use for 298068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * encoding and decoding RGB values.</p> 298168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 298268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param v A non-null array of linear RGB values, its length 298368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * must be at least 3 298468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 3 floats containing non-linear RGB values 298568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 298668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #fromLinear(float[]) 298768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #toLinear(float, float, float) 298868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 298968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 299068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 299168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] fromLinear(@NonNull @Size(min = 3) float[] v) { 299268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = (float) mClampedOetf.applyAsDouble(v[0]); 299368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = (float) mClampedOetf.applyAsDouble(v[1]); 299468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = (float) mClampedOetf.applyAsDouble(v[2]); 299568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return v; 299668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 299768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 299868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 299968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 300068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 300168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] toXyz(@NonNull @Size(min = 3) float[] v) { 300268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = (float) mClampedEotf.applyAsDouble(v[0]); 300368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = (float) mClampedEotf.applyAsDouble(v[1]); 300468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = (float) mClampedEotf.applyAsDouble(v[2]); 300568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mul3x3Float3(mTransform, v); 300668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 300768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 300868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 300968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 301068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 301168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] fromXyz(@NonNull @Size(min = 3) float[] v) { 301268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mul3x3Float3(mInverseTransform, v); 301368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[0] = (float) mClampedOetf.applyAsDouble(v[0]); 301468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[1] = (float) mClampedOetf.applyAsDouble(v[1]); 301568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy v[2] = (float) mClampedOetf.applyAsDouble(v[2]); 301668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return v; 301768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 301868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 301968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private double clamp(double x) { 302068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return x < mMin ? mMin : x > mMax ? mMax : x; 302168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 302268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 302368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 302468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public boolean equals(Object o) { 302568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (this == o) return true; 302668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (o == null || getClass() != o.getClass()) return false; 302768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!super.equals(o)) return false; 302868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 302968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Rgb rgb = (Rgb) o; 303068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 303168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (Float.compare(rgb.mMin, mMin) != 0) return false; 303268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (Float.compare(rgb.mMax, mMax) != 0) return false; 303368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!Arrays.equals(mWhitePoint, rgb.mWhitePoint)) return false; 303468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!Arrays.equals(mPrimaries, rgb.mPrimaries)) return false; 3035efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (mTransferParameters != null) { 3036efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return mTransferParameters.equals(rgb.mTransferParameters); 3037efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } else if (rgb.mTransferParameters == null) { 3038efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy return true; 3039efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 304068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy //noinspection SimplifiableIfStatement 304168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!mOetf.equals(rgb.mOetf)) return false; 304268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mEotf.equals(rgb.mEotf); 304368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 304468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 304568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 304668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public int hashCode() { 304768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy int result = super.hashCode(); 304868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy result = 31 * result + Arrays.hashCode(mWhitePoint); 304968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy result = 31 * result + Arrays.hashCode(mPrimaries); 305068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy result = 31 * result + (mMin != +0.0f ? Float.floatToIntBits(mMin) : 0); 305168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy result = 31 * result + (mMax != +0.0f ? Float.floatToIntBits(mMax) : 0); 3052efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + 3053efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy (mTransferParameters != null ? mTransferParameters.hashCode() : 0); 3054efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy if (mTransferParameters == null) { 3055efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + mOetf.hashCode(); 3056efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy result = 31 * result + mEotf.hashCode(); 3057efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy } 305868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return result; 305968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 306068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 306168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 306268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Computes whether a color space is the sRGB color space or at least 306368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a close approximation. 306468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 306568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param primaries The set of RGB primaries in xyY as an array of 6 floats 306668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param whitePoint The white point in xyY as an array of 2 floats 306768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param OETF The opto-electronic transfer function 306868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param EOTF The electro-optical transfer function 306968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param min The minimum value of the color space's range 307068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param max The minimum value of the color space's range 307168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param id The ID of the color space 307268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return True if the color space can be considered as the sRGB color space 307368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 307468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #isSrgb() 307568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 307668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @SuppressWarnings("RedundantIfStatement") 307768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static boolean isSrgb( 307868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(6) float[] primaries, 307968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(2) float[] whitePoint, 308068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull DoubleUnaryOperator OETF, 308168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull DoubleUnaryOperator EOTF, 308268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float min, 308368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float max, 308468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @IntRange(from = MIN_ID, to = MAX_ID) int id) { 308568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (id == 0) return true; 308668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!compare(primaries, SRGB_PRIMARIES)) { 308768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return false; 308868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 308968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!compare(whitePoint, ILLUMINANT_D65)) { 309068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return false; 309168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 309268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (OETF.applyAsDouble(0.5) < 0.5001) return false; 309368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (EOTF.applyAsDouble(0.5) > 0.5001) return false; 309468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (min != 0.0f) return false; 309568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (max != 1.0f) return false; 309668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return true; 309768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 309868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 309968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 310068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Computes whether the specified CIE xyY or XYZ primaries (with Y set to 1) form 310168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a wide color gamut. A color gamut is considered wide if its area is > 90% 310268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * of the area of NTSC 1953 and if it contains the sRGB color gamut entirely. 310368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * If the conditions above are not met, the color space is considered as having 310468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a wide color gamut if its range is larger than [0..1]. 310568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 3106199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy * @param primaries RGB primaries in CIE xyY as an array of 6 floats 310768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param min The minimum value of the color space's range 310868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param max The minimum value of the color space's range 310968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return True if the color space has a wide gamut, false otherwise 311068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 311168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #isWideGamut() 311268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #area(float[]) 311368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 3114199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy private static boolean isWideGamut(@NonNull @Size(6) float[] primaries, 311568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float min, float max) { 311668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return (area(primaries) / area(NTSC_1953_PRIMARIES) > 0.9f && 311768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy contains(primaries, SRGB_PRIMARIES)) || (min < 0.0f && max > 1.0f); 311868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 311968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 312068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 312168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Computes the area of the triangle represented by a set of RGB primaries 312268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * in the CIE xyY space. 312368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 312468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param primaries The triangle's vertices, as RGB primaries in an array of 6 floats 312568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The area of the triangle 312668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 312768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #isWideGamut(float[], float, float) 312868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 312968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float area(@NonNull @Size(6) float[] primaries) { 313068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Rx = primaries[0]; 313168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Ry = primaries[1]; 313268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Gx = primaries[2]; 313368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Gy = primaries[3]; 313468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Bx = primaries[4]; 313568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float By = primaries[5]; 313668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float det = Rx * Gy + Ry * Bx + Gx * By - Gy * Bx - Ry * Gx - Rx * By; 313768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float r = 0.5f * det; 313868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return r < 0.0f ? -r : r; 313968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 314068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 314168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 314268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Computes the cross product of two 2D vectors. 314368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 314468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param ax The x coordinate of the first vector 314568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param ay The y coordinate of the first vector 314668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param bx The x coordinate of the second vector 314768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param by The y coordinate of the second vector 314868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The result of a x b 314968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 315068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float cross(float ax, float ay, float bx, float by) { 315168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return ax * by - ay * bx; 315268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 315368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 315468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 315568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Decides whether a 2D triangle, identified by the 6 coordinates of its 315668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 3 vertices, is contained within another 2D triangle, also identified 315768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * by the 6 coordinates of its 3 vertices. 315868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 315968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * In the illustration below, we want to test whether the RGB triangle 316068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * is contained within the triangle XYZ formed by the 3 vertices at 316168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * the "+" locations. 316268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 316368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Y . 316468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * . + . 316568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * . .. 316668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * . . 316768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * . . 316868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * . G 316968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * 317068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * * 317168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ** * 317268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * ** 317368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * * 317468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ** * 317568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * * 317668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * * 317768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ** * 317868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * * 317968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * ** 318068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ** * R ... 318168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * * ..... 318268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * * ***** .. 318368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ** ************ . + 318468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * B * ************ . X 318568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ......***** . 318668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ...... . . 318768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * .. 318868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * + . 318968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Z . 319068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 319168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * RGB is contained within XYZ if all the following conditions are true 319268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * (with "x" the cross product operator): 319368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 319468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * --> --> 319568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * GR x RX >= 0 319668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * --> --> 319768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * RX x BR >= 0 319868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * --> --> 319968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * RG x GY >= 0 320068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * --> --> 320168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * GY x RG >= 0 320268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * --> --> 320368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * RB x BZ >= 0 320468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * --> --> 320568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * BZ x GB >= 0 320668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 320768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param p1 The enclosing triangle 320868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param p2 The enclosed triangle 320968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return True if the triangle p1 contains the triangle p2 321068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 321168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #isWideGamut(float[], float, float) 321268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 321368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @SuppressWarnings("RedundantIfStatement") 321468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static boolean contains(@NonNull @Size(6) float[] p1, @NonNull @Size(6) float[] p2) { 321568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Translate the vertices p1 in the coordinates system 321668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // with the vertices p2 as the origin 321768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] p0 = new float[] { 321868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy p1[0] - p2[0], p1[1] - p2[1], 321968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy p1[2] - p2[2], p1[3] - p2[3], 322068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy p1[4] - p2[4], p1[5] - p2[5], 322168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }; 322268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Check the first vertex of p1 322368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (cross(p0[0], p0[1], p2[0] - p2[4], p2[1] - p2[5]) < 0 || 322468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy cross(p2[0] - p2[2], p2[1] - p2[3], p0[0], p0[1]) < 0) { 322568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return false; 322668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 322768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Check the second vertex of p1 322868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (cross(p0[2], p0[3], p2[2] - p2[0], p2[3] - p2[1]) < 0 || 322968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy cross(p2[2] - p2[4], p2[3] - p2[5], p0[2], p0[3]) < 0) { 323068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return false; 323168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 323268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // Check the third vertex of p1 323368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (cross(p0[4], p0[5], p2[4] - p2[2], p2[5] - p2[3]) < 0 || 323468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy cross(p2[4] - p2[0], p2[5] - p2[1], p0[4], p0[5]) < 0) { 323568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return false; 323668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 323768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return true; 323868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 323968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 324068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 324168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Computes the primaries of a color space identified only by 324268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * its RGB->XYZ transform matrix. This method assumes that the 324368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * range of the color space is [0..1]. 324468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 324568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param toXYZ The color space's 3x3 transform matrix to XYZ 324668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 6 floats containing the color space's 324768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * primaries in CIE xyY 324868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 324968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 325068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(6) 3251efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static float[] computePrimaries(@NonNull @Size(9) float[] toXYZ) { 3252efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy float[] r = mul3x3Float3(toXYZ, new float[] { 1.0f, 0.0f, 0.0f }); 3253efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy float[] g = mul3x3Float3(toXYZ, new float[] { 0.0f, 1.0f, 0.0f }); 3254efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy float[] b = mul3x3Float3(toXYZ, new float[] { 0.0f, 0.0f, 1.0f }); 325568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 325668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float rSum = r[0] + r[1] + r[2]; 325768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float gSum = g[0] + g[1] + g[2]; 325868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float bSum = b[0] + b[1] + b[2]; 325968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 326068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new float[] { 326168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy r[0] / rSum, r[1] / rSum, 326268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy g[0] / gSum, g[1] / gSum, 326368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy b[0] / bSum, b[1] / bSum, 326468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }; 326568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 326668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 326768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 326868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Computes the white point of a color space identified only by 326968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * its RGB->XYZ transform matrix. This method assumes that the 327068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * range of the color space is [0..1]. 327168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 327268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param toXYZ The color space's 3x3 transform matrix to XYZ 327368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 2 floats containing the color space's 327468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * white point in CIE xyY 327568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 327668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 327768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(2) 3278efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy private static float[] computeWhitePoint(@NonNull @Size(9) float[] toXYZ) { 3279efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy float[] w = mul3x3Float3(toXYZ, new float[] { 1.0f, 1.0f, 1.0f }); 328068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float sum = w[0] + w[1] + w[2]; 328168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new float[] { w[0] / sum, w[1] / sum }; 328268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 328368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 328468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 328568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Converts the specified RGB primaries point to xyY if needed. The primaries 328668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * can be specified as an array of 6 floats (in CIE xyY) or 9 floats 328768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * (in CIE XYZ). If no conversion is needed, the input array is copied. 328868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 328968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param primaries The primaries in xyY or XYZ 329068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 6 floats containing the primaries in xyY 329168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 329268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 3293199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy @Size(6) 329468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] xyPrimaries(@NonNull @Size(min = 6, max = 9) float[] primaries) { 329568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] xyPrimaries = new float[6]; 329668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 329768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // XYZ to xyY 329868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (primaries.length == 9) { 329968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float sum; 330068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 330168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sum = primaries[0] + primaries[1] + primaries[2]; 330268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyPrimaries[0] = primaries[0] / sum; 330368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyPrimaries[1] = primaries[1] / sum; 330468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 330568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sum = primaries[3] + primaries[4] + primaries[5]; 330668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyPrimaries[2] = primaries[3] / sum; 330768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyPrimaries[3] = primaries[4] / sum; 330868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 330968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy sum = primaries[6] + primaries[7] + primaries[8]; 331068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyPrimaries[4] = primaries[6] / sum; 331168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyPrimaries[5] = primaries[7] / sum; 331268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } else { 331368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy System.arraycopy(primaries, 0, xyPrimaries, 0, 6); 331468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 331568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 331668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return xyPrimaries; 331768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 331868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 331968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 332068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Converts the specified white point to xyY if needed. The white point 332168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * can be specified as an array of 2 floats (in CIE xyY) or 3 floats 332268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * (in CIE XYZ). If no conversion is needed, the input array is copied. 332368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 332468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param whitePoint The white point in xyY or XYZ 332568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 2 floats containing the white point in xyY 332668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 332768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 332868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(2) 332968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] xyWhitePoint(@Size(min = 2, max = 3) float[] whitePoint) { 333068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] xyWhitePoint = new float[2]; 333168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 333268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // XYZ to xyY 333368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (whitePoint.length == 3) { 333468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float sum = whitePoint[0] + whitePoint[1] + whitePoint[2]; 333568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyWhitePoint[0] = whitePoint[0] / sum; 333668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyWhitePoint[1] = whitePoint[1] / sum; 333768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } else { 333868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy System.arraycopy(whitePoint, 0, xyWhitePoint, 0, 2); 333968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 334068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 334168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return xyWhitePoint; 334268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 334368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 334468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 334568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Computes the matrix that converts from RGB to XYZ based on RGB 334668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * primaries and a white point, both specified in the CIE xyY space. 334768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * The Y component of the primaries and white point is implied to be 1. 334868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 334968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param primaries The RGB primaries in xyY, as an array of 6 floats 335068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param whitePoint The white point in xyY, as an array of 2 floats 335168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A 3x3 matrix as a new array of 9 floats 335268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 335368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 335468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(9) 335568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] computeXYZMatrix( 335668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(6) float[] primaries, 335768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(2) float[] whitePoint) { 335868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Rx = primaries[0]; 335968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Ry = primaries[1]; 336068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Gx = primaries[2]; 336168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Gy = primaries[3]; 336268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Bx = primaries[4]; 336368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float By = primaries[5]; 336468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Wx = whitePoint[0]; 336568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float Wy = whitePoint[1]; 336668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 336768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float oneRxRy = (1 - Rx) / Ry; 336868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float oneGxGy = (1 - Gx) / Gy; 336968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float oneBxBy = (1 - Bx) / By; 337068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float oneWxWy = (1 - Wx) / Wy; 337168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 337268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float RxRy = Rx / Ry; 337368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float GxGy = Gx / Gy; 337468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float BxBy = Bx / By; 337568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float WxWy = Wx / Wy; 337668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 337768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float BY = 337868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ((oneWxWy - oneRxRy) * (GxGy - RxRy) - (WxWy - RxRy) * (oneGxGy - oneRxRy)) / 337968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ((oneBxBy - oneRxRy) * (GxGy - RxRy) - (BxBy - RxRy) * (oneGxGy - oneRxRy)); 338068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float GY = (WxWy - RxRy - BY * (BxBy - RxRy)) / (GxGy - RxRy); 338168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float RY = 1 - GY - BY; 338268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 338368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float RYRy = RY / Ry; 338468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float GYGy = GY / Gy; 338568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float BYBy = BY / By; 338668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 338768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new float[] { 338868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy RYRy * Rx, RY, RYRy * (1 - Rx - Ry), 338968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy GYGy * Gx, GY, GYGy * (1 - Gx - Gy), 339068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy BYBy * Bx, BY, BYBy * (1 - Bx - By) 339168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }; 339268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 339368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 339468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 339568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 339668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@usesMathJax} 339768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 339868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>A connector transforms colors from a source color space to a destination 339968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color space.</p> 340068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 340168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>A source color space is connected to a destination color space using the 340268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * color transform \(C\) computed from their respective transforms noted 340368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * \(T_{src}\) and \(T_{dst}\) in the following equation:</p> 340468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 340568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * $$C = T^{-1}_{dst} . T_{src}$$ 340668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 340768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>The transform \(C\) shown above is only valid when the source and 340868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * destination color spaces have the same profile connection space (PCS). 340968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * We know that instances of {@link ColorSpace} always use CIE XYZ as their 341068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * PCS but their white points might differ. When they do, we must perform 341168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * a chromatic adaptation of the color spaces' transforms. To do so, we 341268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * use the von Kries method described in the documentation of {@link Adaptation}, 341368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * using the CIE standard illuminant {@link ColorSpace#ILLUMINANT_D50 D50} 341468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * as the target white point.</p> 341568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 341668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Example of conversion from {@link Named#SRGB sRGB} to 341768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link Named#DCI_P3 DCI-P3}:</p> 341868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 341968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <pre class="prettyprint"> 342068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.Connector connector = ColorSpace.connect( 342168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.get(ColorSpace.Named.SRGB), 342268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * ColorSpace.get(ColorSpace.Named.DCI_P3)); 342368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * float[] p3 = connector.transform(1.0f, 0.0f, 0.0f); 342468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * // p3 contains { 0.9473, 0.2740, 0.2076 } 342568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * </pre> 342668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 342768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see Adaptation 342868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#adapt(ColorSpace, float[], Adaptation) 342968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#adapt(ColorSpace, float[]) 343068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#connect(ColorSpace, ColorSpace, RenderIntent) 343168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#connect(ColorSpace, ColorSpace) 343268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#connect(ColorSpace, RenderIntent) 343368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#connect(ColorSpace) 343468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 343577b161e0b14372e3eb124ed19321a9639aeb4271Romain Guy @AnyThread 343668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public static class Connector { 343768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final ColorSpace mSource; 343868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final ColorSpace mDestination; 343968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final ColorSpace mTransformSource; 344068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final ColorSpace mTransformDestination; 344168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final RenderIntent mIntent; 344268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull @Size(3) private final float[] mTransform; 344368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 344468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 344568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Creates a new connector between a source and a destination color space. 344668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 344768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param source The source color space, cannot be null 344868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param destination The destination color space, cannot be null 344968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param intent The render intent to use when compressing gamuts 345068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 345168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Connector(@NonNull ColorSpace source, @NonNull ColorSpace destination, 345268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull RenderIntent intent) { 345368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy this(source, destination, 345468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy source.getModel() == Model.RGB ? adapt(source, ILLUMINANT_D50_XYZ) : source, 345568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy destination.getModel() == Model.RGB ? 345668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy adapt(destination, ILLUMINANT_D50_XYZ) : destination, 345768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy intent, computeTransform(source, destination, intent)); 345868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 345968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 346068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 346168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * To connect between color spaces, we might need to use adapted transforms. 346268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * This should be transparent to the user so this constructor takes the 346368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * original source and destinations (returned by the getters), as well as 346468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * possibly adapted color spaces used by transform(). 346568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 346668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private Connector( 346768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull ColorSpace source, @NonNull ColorSpace destination, 346868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull ColorSpace transformSource, @NonNull ColorSpace transformDestination, 3469199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy @NonNull RenderIntent intent, @Nullable @Size(3) float[] transform) { 347068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mSource = source; 347168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mDestination = destination; 347268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mTransformSource = transformSource; 347368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mTransformDestination = transformDestination; 347468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mIntent = intent; 347568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mTransform = transform; 347668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 347768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 347868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 347968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Computes an extra transform to apply in XYZ space depending on the 348068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * selected rendering intent. 348168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 3482efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy @Nullable 348368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] computeTransform(@NonNull ColorSpace source, 348468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull ColorSpace destination, @NonNull RenderIntent intent) { 348568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (intent != RenderIntent.ABSOLUTE) return null; 348668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 348768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy boolean srcRGB = source.getModel() == Model.RGB; 348868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy boolean dstRGB = destination.getModel() == Model.RGB; 348968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 349068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (srcRGB && dstRGB) return null; 349168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 349268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (srcRGB || dstRGB) { 349368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy ColorSpace.Rgb rgb = (ColorSpace.Rgb) (srcRGB ? source : destination); 349468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] srcXYZ = srcRGB ? xyYToXyz(rgb.mWhitePoint) : ILLUMINANT_D50_XYZ; 349568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] dstXYZ = dstRGB ? xyYToXyz(rgb.mWhitePoint) : ILLUMINANT_D50_XYZ; 349668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new float[] { 349768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy srcXYZ[0] / dstXYZ[0], 349868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy srcXYZ[1] / dstXYZ[1], 349968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy srcXYZ[2] / dstXYZ[2], 350068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }; 350168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 350268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 350368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return null; 350468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 350568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 350668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 350768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the source color space this connector will convert from. 350868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 350968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null instance of {@link ColorSpace} 351068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 351168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getDestination() 351268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 351368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 351468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public ColorSpace getSource() { 351568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mSource; 351668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 351768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 351868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 351968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the destination color space this connector will convert to. 352068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 352168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null instance of {@link ColorSpace} 352268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 352368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #getSource() 352468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 352568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 352668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public ColorSpace getDestination() { 352768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mDestination; 352868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 352968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 353068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 353168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the render intent this connector will use when mapping the 353268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * source color space to the destination color space. 353368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 353468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null {@link RenderIntent} 353568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 353668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see RenderIntent 353768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 35381cf7b4fcb3b2c239e3f0a68ec78cfedff510b779Romain Guy public RenderIntent getRenderIntent() { 353968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mIntent; 354068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 354168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 354268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 354368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Transforms the specified color from the source color space 354468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to a color in the destination color space. This convenience 354568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * method assumes a source color model with 3 components 354668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * (typically RGB). To transform from color models with more than 354768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 3 components, such as {@link Model#CMYK CMYK}, use 354868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * {@link #transform(float[])} instead.</p> 354968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 355068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param r The red component of the color to transform 355168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param g The green component of the color to transform 355268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param b The blue component of the color to transform 355368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A new array of 3 floats containing the specified color 355468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * transformed from the source space to the destination space 355568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 355668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #transform(float[]) 355768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 355868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 355968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(3) 356068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] transform(float r, float g, float b) { 356168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return transform(new float[] { r, g, b }); 356268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 356368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 356468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 356568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Transforms the specified color from the source color space 356668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * to a color in the destination color space.</p> 356768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 356868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param v A non-null array of 3 floats containing the value to transform 356968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * and that will hold the result of the transform 357068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return The v array passed as a parameter, containing the specified color 357168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * transformed from the source space to the destination space 357268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 357368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see #transform(float, float, float) 357468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 357568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 357668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(min = 3) 357768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] transform(@NonNull @Size(min = 3) float[] v) { 357868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] xyz = mTransformSource.toXyz(v); 357968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (mTransform != null) { 358068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyz[0] *= mTransform[0]; 358168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyz[1] *= mTransform[1]; 358268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy xyz[2] *= mTransform[2]; 358368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 358468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mTransformDestination.fromXyz(xyz); 358568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 358668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 358768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 358868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Optimized connector for RGB->RGB conversions. 358968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 3590199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy private static class Rgb extends Connector { 359168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final ColorSpace.Rgb mSource; 359268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final ColorSpace.Rgb mDestination; 359368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull private final float[] mTransform; 359468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 3595199e5a98ddc4402ba4b4cdafaa3d8deb58ef3c7dRomain Guy Rgb(@NonNull ColorSpace.Rgb source, @NonNull ColorSpace.Rgb destination, 359668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull RenderIntent intent) { 359768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy super(source, destination, source, destination, intent, null); 359868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mSource = source; 359968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mDestination = destination; 360068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mTransform = computeTransform(source, destination, intent); 360168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 360268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 360368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 360468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] transform(@NonNull @Size(min = 3) float[] rgb) { 360568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rgb[0] = (float) mSource.mClampedEotf.applyAsDouble(rgb[0]); 360668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rgb[1] = (float) mSource.mClampedEotf.applyAsDouble(rgb[1]); 360768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rgb[2] = (float) mSource.mClampedEotf.applyAsDouble(rgb[2]); 360868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy mul3x3Float3(mTransform, rgb); 360968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rgb[0] = (float) mDestination.mClampedOetf.applyAsDouble(rgb[0]); 361068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rgb[1] = (float) mDestination.mClampedOetf.applyAsDouble(rgb[1]); 361168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy rgb[2] = (float) mDestination.mClampedOetf.applyAsDouble(rgb[2]); 361268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return rgb; 361368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 361468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 361568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 361668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>Computes the color transform that connects two RGB color spaces.</p> 361768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 361868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * <p>We can only connect color spaces if they use the same profile 361968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * connection space. We assume the connection space is always 362068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * CIE XYZ but we maye need to perform a chromatic adaptation to 362168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * match the white points. If an adaptation is needed, we use the 362268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * CIE standard illuminant D50. The unmatched color space is adapted 362368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * using the von Kries transform and the {@link Adaptation#BRADFORD} 362468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * matrix.</p> 362568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 362668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param source The source color space, cannot be null 362768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param destination The destination color space, cannot be null 362868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param intent The render intent to use when compressing gamuts 362968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return An array of 9 floats containing the 3x3 matrix transform 363068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 363168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull 363268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Size(9) 363368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy private static float[] computeTransform( 363468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull ColorSpace.Rgb source, 363568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull ColorSpace.Rgb destination, 363668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @NonNull RenderIntent intent) { 363768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (compare(source.mWhitePoint, destination.mWhitePoint)) { 363868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // RGB->RGB using the PCS of both color spaces since they have the same 363968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mul3x3(destination.mInverseTransform, source.mTransform); 364068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } else { 364168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy // RGB->RGB using CIE XYZ D50 as the PCS 364268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] transform = source.mTransform; 364368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] inverseTransform = destination.mInverseTransform; 364468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 364568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] srcXYZ = xyYToXyz(source.mWhitePoint); 364668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] dstXYZ = xyYToXyz(destination.mWhitePoint); 364768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 364868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!compare(source.mWhitePoint, ILLUMINANT_D50)) { 364968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] srcAdaptation = chromaticAdaptation( 365068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Adaptation.BRADFORD.mTransform, srcXYZ, 365168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Arrays.copyOf(ILLUMINANT_D50_XYZ, 3)); 365268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy transform = mul3x3(srcAdaptation, source.mTransform); 365368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 365468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 365568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (!compare(destination.mWhitePoint, ILLUMINANT_D50)) { 365668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy float[] dstAdaptation = chromaticAdaptation( 365768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Adaptation.BRADFORD.mTransform, dstXYZ, 365868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy Arrays.copyOf(ILLUMINANT_D50_XYZ, 3)); 365968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy inverseTransform = inverse3x3(mul3x3(dstAdaptation, destination.mTransform)); 366068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 366168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 366268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy if (intent == RenderIntent.ABSOLUTE) { 366368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy transform = mul3x3Diag( 366468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy new float[] { 366568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy srcXYZ[0] / dstXYZ[0], 366668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy srcXYZ[1] / dstXYZ[1], 366768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy srcXYZ[2] / dstXYZ[2], 366868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }, transform); 366968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 367068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 367168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return mul3x3(inverseTransform, transform); 367268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 367368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 367468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 367568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy 367668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy /** 367768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * Returns the identity connector for a given color space. 367868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 367968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @param source The source and destination color space 368068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @return A non-null connector that does not perform any transform 368168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * 368268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy * @see ColorSpace#connect(ColorSpace, ColorSpace) 368368bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy */ 368468bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy static Connector identity(ColorSpace source) { 368568bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return new Connector(source, source, RenderIntent.RELATIVE) { 368668bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy @Override 368768bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy public float[] transform(@NonNull @Size(min = 3) float[] v) { 368868bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy return v; 368968bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 369068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy }; 369168bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 369268bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy } 369315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 369415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 369515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>A color space renderer can be used to visualize and compare the gamut and 369615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * white point of one or more color spaces. The output is an sRGB {@link Bitmap} 36979505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * showing a CIE 1931 xyY or a CIE 1976 UCS chromaticity diagram.</p> 369815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 369915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>The following code snippet shows how to compare the {@link Named#SRGB} 37009505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * and {@link Named#DCI_P3} color spaces in a CIE 1931 diagram:</p> 370115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 370215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <pre class="prettyprint"> 370315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Bitmap bitmap = ColorSpace.createRenderer() 370415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .size(768) 370515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .clip(true) 370615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff) 370715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845) 370815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .render(); 370915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </pre> 371015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p> 3711c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_clipped.png" /> 371215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption> 371315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </p> 371415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 371515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>A renderer can also be used to show the location of specific colors, 371615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * associated with a color space, in the CIE 1931 xyY chromaticity diagram. 371715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * See {@link #add(ColorSpace, float, float, float, int)} for more information.</p> 371815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 371915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @see ColorSpace#createRenderer() 372066d7da6a41d2ae2acf8220d8b146ba6eea385a28Romain Guy * 372166d7da6a41d2ae2acf8220d8b146ba6eea385a28Romain Guy * @hide 372215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 372315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy public static class Renderer { 372415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private static final int NATIVE_SIZE = 1440; 37259505a6552764461c22ce48f1ac13d025d23e1579Romain Guy private static final float UCS_SCALE = 9.0f / 6.0f; 37269505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 37279505a6552764461c22ce48f1ac13d025d23e1579Romain Guy // Number of subdivision of the inside of the spectral locus 37289505a6552764461c22ce48f1ac13d025d23e1579Romain Guy private static final int CHROMATICITY_RESOLUTION = 32; 37299505a6552764461c22ce48f1ac13d025d23e1579Romain Guy private static final double ONE_THIRD = 1.0 / 3.0; 373015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 373115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @IntRange(from = 128, to = Integer.MAX_VALUE) 373215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private int mSize = 1024; 373315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 373415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private boolean mShowWhitePoint = true; 373515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private boolean mClip = false; 37369505a6552764461c22ce48f1ac13d025d23e1579Romain Guy private boolean mUcs = false; 373715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 373815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private final List<Pair<ColorSpace, Integer>> mColorSpaces = new ArrayList<>(2); 373915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private final List<Point> mPoints = new ArrayList<>(0); 374015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 374115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private Renderer() { 374215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 374315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 374415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 374515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>Defines whether the chromaticity diagram should be clipped by the first 374615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * registered color space. The default value is false.</p> 374715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 374815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>The following code snippet and image show the default behavior:</p> 374915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <pre class="prettyprint"> 375015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Bitmap bitmap = ColorSpace.createRenderer() 375115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff) 375215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845) 375315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .render(); 375415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </pre> 375515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p> 3756c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_comparison.png" /> 375715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <figcaption style="text-align: center;">Clipping disabled</figcaption> 375815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </p> 375915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 376015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>Here is the same example with clipping enabled:</p> 376115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <pre class="prettyprint"> 376215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Bitmap bitmap = ColorSpace.createRenderer() 376315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .clip(true) 376415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff) 376515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845) 376615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .render(); 376715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </pre> 376815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p> 3769c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_clipped.png" /> 377015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <figcaption style="text-align: center;">Clipping enabled</figcaption> 377115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </p> 377215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 377315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param clip True to clip the chromaticity diagram to the first registered color space, 377415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * false otherwise 377515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @return This instance of {@link Renderer} 377615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 377715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull 377815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy public Renderer clip(boolean clip) { 377915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy mClip = clip; 378015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return this; 378115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 378215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 378315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 37849505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * <p>Defines whether the chromaticity diagram should use the uniform 37859505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * chromaticity scale (CIE 1976 UCS). When the uniform chromaticity scale 37869505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * is used, the distance between two points on the diagram is approximately 37879505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * proportional to the perceived color difference.</p> 37889505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * 37899505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * <p>The following code snippet shows how to enable the uniform chromaticity 37909505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * scale. The image below shows the result:</p> 37919505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * <pre class="prettyprint"> 37929505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * Bitmap bitmap = ColorSpace.createRenderer() 37939505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * .uniformChromaticityScale(true) 37949505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff) 37959505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845) 37969505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * .render(); 37979505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * </pre> 37989505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * <p> 3799c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_ucs.png" /> 38009505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * <figcaption style="text-align: center;">CIE 1976 UCS diagram</figcaption> 38019505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * </p> 38029505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * 38039505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * @param ucs True to render the chromaticity diagram as the CIE 1976 UCS diagram 38049505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * @return This instance of {@link Renderer} 38059505a6552764461c22ce48f1ac13d025d23e1579Romain Guy */ 38069505a6552764461c22ce48f1ac13d025d23e1579Romain Guy @NonNull 38079505a6552764461c22ce48f1ac13d025d23e1579Romain Guy public Renderer uniformChromaticityScale(boolean ucs) { 38089505a6552764461c22ce48f1ac13d025d23e1579Romain Guy mUcs = ucs; 38099505a6552764461c22ce48f1ac13d025d23e1579Romain Guy return this; 38109505a6552764461c22ce48f1ac13d025d23e1579Romain Guy } 38119505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 38129505a6552764461c22ce48f1ac13d025d23e1579Romain Guy /** 381315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Sets the dimensions (width and height) in pixels of the output bitmap. 381415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * The size must be at least 128px and defaults to 1024px. 381515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 381615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param size The size in pixels of the output bitmap 381715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @return This instance of {@link Renderer} 381815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 381915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull 382015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy public Renderer size(@IntRange(from = 128, to = Integer.MAX_VALUE) int size) { 382115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy mSize = Math.max(128, size); 382215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return this; 382315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 382415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 382515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 382615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Shows or hides the white point of each color space in the output bitmap. 382715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * The default is true. 382815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 382915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param show True to show the white point of each color space, false 383015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * otherwise 383115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @return This instance of {@link Renderer} 383215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 383315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull 383415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy public Renderer showWhitePoint(boolean show) { 383515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy mShowWhitePoint = show; 383615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return this; 383715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 383815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 383915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 384015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>Adds a color space to represent on the output CIE 1931 chromaticity 384115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * diagram. The color space is represented as a triangle showing the 384215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * footprint of its color gamut and, optionally, the location of its 384315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * white point.</p> 384415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 384515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p class="note">Color spaces with a color model that is not RGB are 384615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * accepted but ignored.</p> 384715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 384815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>The following code snippet and image show an example of calling this 384915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * method to compare {@link Named#SRGB sRGB} and {@link Named#DCI_P3 DCI-P3}:</p> 385015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <pre class="prettyprint"> 385115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Bitmap bitmap = ColorSpace.createRenderer() 385215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff) 385315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845) 385415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .render(); 385515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </pre> 385615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p> 3857c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_comparison.png" /> 385815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption> 385915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </p> 386015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 386115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>Adding a color space extending beyond the boundaries of the 386215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * spectral locus will alter the size of the diagram within the output 386315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * bitmap as shown in this example:</p> 386415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <pre class="prettyprint"> 386515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Bitmap bitmap = ColorSpace.createRenderer() 386615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff) 386715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845) 386815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.ACES), 0xff097ae9) 386915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), 0xff000000) 387015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .render(); 387115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </pre> 387215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p> 3873c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_comparison2.png" /> 38749505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * <figcaption style="text-align: center;">sRGB, DCI-P3, ACES and scRGB</figcaption> 387515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </p> 387615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 387715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param colorSpace The color space whose gamut to render on the diagram 387815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param color The sRGB color to use to render the color space's gamut and white point 387915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @return This instance of {@link Renderer} 388015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 388115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @see #clip(boolean) 388215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @see #showWhitePoint(boolean) 388315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 388415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull 388515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy public Renderer add(@NonNull ColorSpace colorSpace, @ColorInt int color) { 388615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy mColorSpaces.add(new Pair<>(colorSpace, color)); 388715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return this; 388815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 388915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 389015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 389115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>Adds a color to represent as a point on the chromaticity diagram. 389215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * The color is associated with a color space which will be used to 389315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * perform the conversion to CIE XYZ and compute the location of the point 389415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * on the diagram. The point is rendered as a colored circle.</p> 389515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 389615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>The following code snippet and image show an example of calling this 389715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * method to render the location of several sRGB colors as white circles:</p> 389815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <pre class="prettyprint"> 389915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Bitmap bitmap = ColorSpace.createRenderer() 390015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .clip(true) 390115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff) 390215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.0f, 0.1f, 0xffffffff) 390315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.1f, 0.1f, 0xffffffff) 390415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.2f, 0.1f, 0xffffffff) 390515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.3f, 0.1f, 0xffffffff) 390615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.4f, 0.1f, 0xffffffff) 390715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.5f, 0.1f, 0xffffffff) 390815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * .render(); 390915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </pre> 391015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p> 3911c7dacca00828e586ce4496d83a25a4d60a6fb60fRomain Guy * <img style="display: block; margin: 0 auto;" src="{@docRoot}reference/android/images/graphics/colorspace_points.png" /> 391215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <figcaption style="text-align: center;"> 391315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Locating colors on the chromaticity diagram 391415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </figcaption> 391515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * </p> 391615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 391715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param colorSpace The color space of the color to locate on the diagram 391815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param r The first component of the color to locate on the diagram 391915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param g The second component of the color to locate on the diagram 392015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param b The third component of the color to locate on the diagram 392115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param pointColor The sRGB color to use to render the point on the diagram 392215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @return This instance of {@link Renderer} 392315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 392415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull 392515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy public Renderer add(@NonNull ColorSpace colorSpace, float r, float g, float b, 392615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @ColorInt int pointColor) { 392715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy mPoints.add(new Point(colorSpace, new float[] { r, g, b }, pointColor)); 392815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return this; 392915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 393015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 393115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 393215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * <p>Renders the {@link #add(ColorSpace, int) color spaces} and 393315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * {@link #add(ColorSpace, float, float, float, int) points} registered 393415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * with this renderer. The output bitmap is an sRGB image with the 393515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * dimensions specified by calling {@link #size(int)} (1204x1024px by 393615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * default).</p> 393715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 393815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @return A new non-null {@link Bitmap} with the dimensions specified 393915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * by {@link #size(int)} (1024x1024 by default) 394015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 394115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull 394215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy public Bitmap render() { 394315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 394415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Bitmap bitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888); 394515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Canvas canvas = new Canvas(bitmap); 394615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 394715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float[] primaries = new float[6]; 394815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float[] whitePoint = new float[2]; 394915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 395015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int width = NATIVE_SIZE; 395115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int height = NATIVE_SIZE; 395215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 395315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Path path = new Path(); 395415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 395515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy setTransform(canvas, width, height, primaries); 395615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy drawBox(canvas, width, height, paint, path); 39579505a6552764461c22ce48f1ac13d025d23e1579Romain Guy setUcsTransform(canvas, height); 395815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy drawLocus(canvas, width, height, paint, path, primaries); 395915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy drawGamuts(canvas, width, height, paint, path, primaries, whitePoint); 396015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy drawPoints(canvas, width, height, paint); 396115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 396215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return bitmap; 396315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 396415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 396515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 396615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Draws registered points at their correct position in the xyY coordinates. 396715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Each point is positioned according to its associated color space. 396815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 396915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param canvas The canvas to transform 397015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param width Width in pixel of the final image 397115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param height Height in pixel of the final image 397215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param paint A pre-allocated paint used to avoid temporary allocations 397315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 397415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private void drawPoints(@NonNull Canvas canvas, int width, int height, 397515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull Paint paint) { 397615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 397715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStyle(Paint.Style.FILL); 397815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 39799505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float radius = 4.0f / (mUcs ? UCS_SCALE : 1.0f); 39809505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 398115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float[] v = new float[3]; 39829505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float[] xy = new float[2]; 39839505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 398415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy for (final Point point : mPoints) { 398515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy v[0] = point.mRgb[0]; 398615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy v[1] = point.mRgb[1]; 398715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy v[2] = point.mRgb[2]; 398815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy point.mColorSpace.toXyz(v); 398915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 399015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setColor(point.mColor); 399115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 39929505a6552764461c22ce48f1ac13d025d23e1579Romain Guy // XYZ to xyY, assuming Y=1.0, then to L*u*v* if needed 399315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float sum = v[0] + v[1] + v[2]; 39949505a6552764461c22ce48f1ac13d025d23e1579Romain Guy xy[0] = v[0] / sum; 39959505a6552764461c22ce48f1ac13d025d23e1579Romain Guy xy[1] = v[1] / sum; 39969505a6552764461c22ce48f1ac13d025d23e1579Romain Guy if (mUcs) xyYToUv(xy); 39979505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 39989505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.drawCircle(width * xy[0], height - height * xy[1], radius, paint); 399915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 400015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 400115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 400215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 400315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Draws the color gamuts and white points of all the registered color 400415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * spaces. Only color spaces with an RGB color model are rendered, the 400515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * others are ignored. 400615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 400715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param canvas The canvas to transform 400815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param width Width in pixel of the final image 400915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param height Height in pixel of the final image 401015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param paint A pre-allocated paint used to avoid temporary allocations 401115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param path A pre-allocated path used to avoid temporary allocations 401215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param primaries A pre-allocated array of 6 floats to avoid temporary allocations 401315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param whitePoint A pre-allocated array of 2 floats to avoid temporary allocations 401415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 401515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private void drawGamuts( 401615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull Canvas canvas, int width, int height, 401715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull Paint paint, @NonNull Path path, 401815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull @Size(6) float[] primaries, @NonNull @Size(2) float[] whitePoint) { 401915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 40209505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float radius = 4.0f / (mUcs ? UCS_SCALE : 1.0f); 40219505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 402215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy for (final Pair<ColorSpace, Integer> item : mColorSpaces) { 402315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy ColorSpace colorSpace = item.first; 402415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int color = item.second; 402515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 402615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy if (colorSpace.getModel() != Model.RGB) continue; 402715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 402815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Rgb rgb = (Rgb) colorSpace; 40299505a6552764461c22ce48f1ac13d025d23e1579Romain Guy getPrimaries(rgb, primaries, mUcs); 403015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 403115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.rewind(); 403215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.moveTo(width * primaries[0], height - height * primaries[1]); 403315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.lineTo(width * primaries[2], height - height * primaries[3]); 403415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.lineTo(width * primaries[4], height - height * primaries[5]); 403515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.close(); 403615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 403715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStyle(Paint.Style.STROKE); 403815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setColor(color); 403915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.drawPath(path, paint); 404015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 404115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Draw the white point 404215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy if (mShowWhitePoint) { 404315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy rgb.getWhitePoint(whitePoint); 40449505a6552764461c22ce48f1ac13d025d23e1579Romain Guy if (mUcs) xyYToUv(whitePoint); 404515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 404615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStyle(Paint.Style.FILL); 404715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setColor(color); 40489505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.drawCircle( 40499505a6552764461c22ce48f1ac13d025d23e1579Romain Guy width * whitePoint[0], height - height * whitePoint[1], radius, paint); 405015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 405115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 405215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 405315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 405415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 405515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Returns the primaries of the specified RGB color space. This method handles 405615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * the special case of the {@link Named#EXTENDED_SRGB} family of color spaces. 405715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 405815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param rgb The color space whose primaries to extract 405915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param primaries A pre-allocated array of 6 floats that will hold the result 40609505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * @param asUcs True if the primaries should be returned in Luv, false for xyY 406115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 406215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull 406315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @Size(6) 406466d7da6a41d2ae2acf8220d8b146ba6eea385a28Romain Guy private static void getPrimaries(@NonNull Rgb rgb, 40659505a6552764461c22ce48f1ac13d025d23e1579Romain Guy @NonNull @Size(6) float[] primaries, boolean asUcs) { 406615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // TODO: We should find a better way to handle these cases 406715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy if (rgb.equals(ColorSpace.get(Named.EXTENDED_SRGB)) || 406815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy rgb.equals(ColorSpace.get(Named.LINEAR_EXTENDED_SRGB))) { 406915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primaries[0] = 1.41f; 407015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primaries[1] = 0.33f; 407115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primaries[2] = 0.27f; 407215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primaries[3] = 1.24f; 407315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primaries[4] = -0.23f; 407415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primaries[5] = -0.57f; 40759505a6552764461c22ce48f1ac13d025d23e1579Romain Guy } else { 40769505a6552764461c22ce48f1ac13d025d23e1579Romain Guy rgb.getPrimaries(primaries); 407715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 40789505a6552764461c22ce48f1ac13d025d23e1579Romain Guy if (asUcs) xyYToUv(primaries); 407915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 408015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 408115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 408215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Draws the CIE 1931 chromaticity diagram: the spectral locus and its inside. 408315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * This method respect the clip parameter. 408415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 408515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param canvas The canvas to transform 408615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param width Width in pixel of the final image 408715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param height Height in pixel of the final image 408815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param paint A pre-allocated paint used to avoid temporary allocations 408915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param path A pre-allocated path used to avoid temporary allocations 409015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param primaries A pre-allocated array of 6 floats to avoid temporary allocations 409115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 409215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private void drawLocus( 409315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull Canvas canvas, int width, int height, @NonNull Paint paint, 409415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull Path path, @NonNull @Size(6) float[] primaries) { 409515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 409615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int vertexCount = SPECTRUM_LOCUS_X.length * CHROMATICITY_RESOLUTION * 6; 409715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float[] vertices = new float[vertexCount * 2]; 409815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int[] colors = new int[vertices.length]; 40999505a6552764461c22ce48f1ac13d025d23e1579Romain Guy computeChromaticityMesh(vertices, colors); 41009505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 41019505a6552764461c22ce48f1ac13d025d23e1579Romain Guy if (mUcs) xyYToUv(vertices); 41029505a6552764461c22ce48f1ac13d025d23e1579Romain Guy for (int i = 0; i < vertices.length; i += 2) { 41039505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[i] *= width; 41049505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[i + 1] = height - vertices[i + 1] * height; 41059505a6552764461c22ce48f1ac13d025d23e1579Romain Guy } 410615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 410715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Draw the spectral locus 410815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy if (mClip && mColorSpaces.size() > 0) { 410915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy for (final Pair<ColorSpace, Integer> item : mColorSpaces) { 411015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy ColorSpace colorSpace = item.first; 411115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy if (colorSpace.getModel() != Model.RGB) continue; 411215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 411315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Rgb rgb = (Rgb) colorSpace; 41149505a6552764461c22ce48f1ac13d025d23e1579Romain Guy getPrimaries(rgb, primaries, mUcs); 41159505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 411615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy break; 411715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 411815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 411915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.rewind(); 412015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.moveTo(width * primaries[0], height - height * primaries[1]); 412115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.lineTo(width * primaries[2], height - height * primaries[3]); 412215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.lineTo(width * primaries[4], height - height * primaries[5]); 412315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.close(); 412415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 412515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int[] solid = new int[colors.length]; 412615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Arrays.fill(solid, 0xff6c6c6c); 412715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0, 412815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy null, 0, solid, 0, null, 0, 0, paint); 412915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 413015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.save(); 413115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.clipPath(path); 413215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 413315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0, 413415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy null, 0, colors, 0, null, 0, 0, paint); 413515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 413615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.restore(); 413715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } else { 413815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0, 413915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy null, 0, colors, 0, null, 0, 0, paint); 414015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 414115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 414215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Draw the non-spectral locus 414315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int index = (CHROMATICITY_RESOLUTION - 1) * 12; 414415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.reset(); 414515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.moveTo(vertices[index], vertices[index + 1]); 414615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy for (int x = 2; x < SPECTRUM_LOCUS_X.length; x++) { 414715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy index += CHROMATICITY_RESOLUTION * 12; 414815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.lineTo(vertices[index], vertices[index + 1]); 414915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 415015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.close(); 415115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 41529505a6552764461c22ce48f1ac13d025d23e1579Romain Guy paint.setStrokeWidth(4.0f / (mUcs ? UCS_SCALE : 1.0f)); 415315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStyle(Paint.Style.STROKE); 415415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setColor(0xff000000); 415515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.drawPath(path, paint); 415615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 415715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 415815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 415915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Draws the diagram box, including borders, tick marks, grid lines 416015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * and axis labels. 416115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 416215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param canvas The canvas to transform 416315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param width Width in pixel of the final image 416415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param height Height in pixel of the final image 416515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param paint A pre-allocated paint used to avoid temporary allocations 416615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param path A pre-allocated path used to avoid temporary allocations 416715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 416815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private void drawBox(@NonNull Canvas canvas, int width, int height, @NonNull Paint paint, 416915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull Path path) { 41709505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 41719505a6552764461c22ce48f1ac13d025d23e1579Romain Guy int lineCount = 10; 41729505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float scale = 1.0f; 41739505a6552764461c22ce48f1ac13d025d23e1579Romain Guy if (mUcs) { 41749505a6552764461c22ce48f1ac13d025d23e1579Romain Guy lineCount = 7; 41759505a6552764461c22ce48f1ac13d025d23e1579Romain Guy scale = UCS_SCALE; 41769505a6552764461c22ce48f1ac13d025d23e1579Romain Guy } 41779505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 417815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Draw the unit grid 417915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStyle(Paint.Style.STROKE); 418015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStrokeWidth(2.0f); 418115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setColor(0xffc0c0c0); 41829505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 41839505a6552764461c22ce48f1ac13d025d23e1579Romain Guy for (int i = 1; i < lineCount - 1; i++) { 41849505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float v = i / 10.0f; 41859505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float x = (width * v) * scale; 41869505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float y = height - (height * v) * scale; 41879505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 41889505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.drawLine(0.0f, y, 0.9f * width, y, paint); 41899505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.drawLine(x, height, x, 0.1f * height, paint); 419015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 419115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 419215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Draw tick marks 419315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStrokeWidth(4.0f); 419415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setColor(0xff000000); 41959505a6552764461c22ce48f1ac13d025d23e1579Romain Guy for (int i = 1; i < lineCount - 1; i++) { 41969505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float v = i / 10.0f; 41979505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float x = (width * v) * scale; 41989505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float y = height - (height * v) * scale; 41999505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 42009505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.drawLine(0.0f, y, width / 100.0f, y, paint); 42019505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.drawLine(x, height, x, height - (height / 100.0f), paint); 420215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 420315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 420415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Draw the axis labels 420515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStyle(Paint.Style.FILL); 420615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setTextSize(36.0f); 420715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL)); 420815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 420915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Rect bounds = new Rect(); 42109505a6552764461c22ce48f1ac13d025d23e1579Romain Guy for (int i = 1; i < lineCount - 1; i++) { 421115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy String text = "0." + i; 421215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.getTextBounds(text, 0, text.length(), bounds); 421315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 42149505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float v = i / 10.0f; 42159505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float x = (width * v) * scale; 42169505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float y = height - (height * v) * scale; 421715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 42189505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.drawText(text, -0.05f * width + 10, y + bounds.height() / 2.0f, paint); 421915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.drawText(text, x - bounds.width() / 2.0f, 422015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy height + bounds.height() + 16, paint); 422115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 422215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy paint.setStyle(Paint.Style.STROKE); 422315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 422415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Draw the diagram box 422515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.moveTo(0.0f, height); 422615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.lineTo(0.9f * width, height); 422715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.lineTo(0.9f * width, 0.1f * height); 422815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.lineTo(0.0f, 0.1f * height); 422915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy path.close(); 423015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.drawPath(path, paint); 423115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 423215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 423315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 423415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Computes and applies the Canvas transforms required to make the color 423515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * gamut of each color space visible in the final image. 423615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 423715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param canvas The canvas to transform 423815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param width Width in pixel of the final image 423915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param height Height in pixel of the final image 424015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param primaries Array of 6 floats used to avoid temporary allocations 424115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 424215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private void setTransform(@NonNull Canvas canvas, int width, int height, 424315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull @Size(6) float[] primaries) { 424415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 424515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy RectF primariesBounds = new RectF(); 424615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy for (final Pair<ColorSpace, Integer> item : mColorSpaces) { 424715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy ColorSpace colorSpace = item.first; 424815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy if (colorSpace.getModel() != Model.RGB) continue; 424915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 425015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Rgb rgb = (Rgb) colorSpace; 42519505a6552764461c22ce48f1ac13d025d23e1579Romain Guy getPrimaries(rgb, primaries, mUcs); 425215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 425315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primariesBounds.left = Math.min(primariesBounds.left, primaries[4]); 425415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primariesBounds.top = Math.min(primariesBounds.top, primaries[5]); 425515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primariesBounds.right = Math.max(primariesBounds.right, primaries[0]); 425615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primariesBounds.bottom = Math.max(primariesBounds.bottom, primaries[3]); 425715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 425815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 42599505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float max = mUcs ? 0.6f : 0.9f; 42609505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 426115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primariesBounds.left = Math.min(0.0f, primariesBounds.left); 426215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy primariesBounds.top = Math.min(0.0f, primariesBounds.top); 42639505a6552764461c22ce48f1ac13d025d23e1579Romain Guy primariesBounds.right = Math.max(max, primariesBounds.right); 42649505a6552764461c22ce48f1ac13d025d23e1579Romain Guy primariesBounds.bottom = Math.max(max, primariesBounds.bottom); 426515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 42669505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float scaleX = max / primariesBounds.width(); 42679505a6552764461c22ce48f1ac13d025d23e1579Romain Guy float scaleY = max / primariesBounds.height(); 426815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float scale = Math.min(scaleX, scaleY); 426915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 427015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.scale(mSize / (float) NATIVE_SIZE, mSize / (float) NATIVE_SIZE); 427115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.scale(scale, scale); 427215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.translate( 42739505a6552764461c22ce48f1ac13d025d23e1579Romain Guy (primariesBounds.width() - max) * width / 2.0f, 42749505a6552764461c22ce48f1ac13d025d23e1579Romain Guy (primariesBounds.height() - max) * height / 2.0f); 427515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 427615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // The spectrum extends ~0.85 vertically and ~0.65 horizontally 427715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // We shift the canvas a little bit to get nicer margins 427815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy canvas.translate(0.05f * width, -0.05f * height); 427915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 428015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 42819505a6552764461c22ce48f1ac13d025d23e1579Romain Guy /** 42829505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * Computes and applies the Canvas transforms required to render the CIE 42839505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * 197 UCS chromaticity diagram. 42849505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * 42859505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * @param canvas The canvas to transform 42869505a6552764461c22ce48f1ac13d025d23e1579Romain Guy * @param height Height in pixel of the final image 42879505a6552764461c22ce48f1ac13d025d23e1579Romain Guy */ 42889505a6552764461c22ce48f1ac13d025d23e1579Romain Guy private void setUcsTransform(@NonNull Canvas canvas, int height) { 42899505a6552764461c22ce48f1ac13d025d23e1579Romain Guy if (mUcs) { 42909505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.translate(0.0f, (height - height * UCS_SCALE)); 42919505a6552764461c22ce48f1ac13d025d23e1579Romain Guy canvas.scale(UCS_SCALE, UCS_SCALE); 42929505a6552764461c22ce48f1ac13d025d23e1579Romain Guy } 42939505a6552764461c22ce48f1ac13d025d23e1579Romain Guy } 42949505a6552764461c22ce48f1ac13d025d23e1579Romain Guy 429515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // X coordinates of the spectral locus in CIE 1931 429615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private static final float[] SPECTRUM_LOCUS_X = { 429715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.175596f, 0.172787f, 0.170806f, 0.170085f, 0.160343f, 429815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.146958f, 0.139149f, 0.133536f, 0.126688f, 0.115830f, 429915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.109616f, 0.099146f, 0.091310f, 0.078130f, 0.068717f, 430015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.054675f, 0.040763f, 0.027497f, 0.016270f, 0.008169f, 430115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.004876f, 0.003983f, 0.003859f, 0.004646f, 0.007988f, 430215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.013870f, 0.022244f, 0.027273f, 0.032820f, 0.038851f, 430315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.045327f, 0.052175f, 0.059323f, 0.066713f, 0.074299f, 430415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.089937f, 0.114155f, 0.138695f, 0.154714f, 0.192865f, 430515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.229607f, 0.265760f, 0.301588f, 0.337346f, 0.373083f, 430615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.408717f, 0.444043f, 0.478755f, 0.512467f, 0.544767f, 430715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.575132f, 0.602914f, 0.627018f, 0.648215f, 0.665746f, 430815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.680061f, 0.691487f, 0.700589f, 0.707901f, 0.714015f, 430915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.719017f, 0.723016f, 0.734674f, 0.717203f, 0.699732f, 431015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.682260f, 0.664789f, 0.647318f, 0.629847f, 0.612376f, 431115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.594905f, 0.577433f, 0.559962f, 0.542491f, 0.525020f, 431215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.507549f, 0.490077f, 0.472606f, 0.455135f, 0.437664f, 431315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.420193f, 0.402721f, 0.385250f, 0.367779f, 0.350308f, 431415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.332837f, 0.315366f, 0.297894f, 0.280423f, 0.262952f, 431515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.245481f, 0.228010f, 0.210538f, 0.193067f, 0.175596f 431615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy }; 431715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Y coordinates of the spectral locus in CIE 1931 431815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private static final float[] SPECTRUM_LOCUS_Y = { 431915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.005295f, 0.004800f, 0.005472f, 0.005976f, 0.014496f, 432015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.026643f, 0.035211f, 0.042704f, 0.053441f, 0.073601f, 432115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.086866f, 0.112037f, 0.132737f, 0.170464f, 0.200773f, 432215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.254155f, 0.317049f, 0.387997f, 0.463035f, 0.538504f, 432315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.587196f, 0.610526f, 0.654897f, 0.675970f, 0.715407f, 432415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.750246f, 0.779682f, 0.792153f, 0.802971f, 0.812059f, 432515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.819430f, 0.825200f, 0.829460f, 0.832306f, 0.833833f, 432615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.833316f, 0.826231f, 0.814796f, 0.805884f, 0.781648f, 432715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.754347f, 0.724342f, 0.692326f, 0.658867f, 0.624470f, 432815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.589626f, 0.554734f, 0.520222f, 0.486611f, 0.454454f, 432915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.424252f, 0.396516f, 0.372510f, 0.351413f, 0.334028f, 433015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.319765f, 0.308359f, 0.299317f, 0.292044f, 0.285945f, 433115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.280951f, 0.276964f, 0.265326f, 0.257200f, 0.249074f, 433215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.240948f, 0.232822f, 0.224696f, 0.216570f, 0.208444f, 433315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.200318f, 0.192192f, 0.184066f, 0.175940f, 0.167814f, 433415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.159688f, 0.151562f, 0.143436f, 0.135311f, 0.127185f, 433515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.119059f, 0.110933f, 0.102807f, 0.094681f, 0.086555f, 433615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.078429f, 0.070303f, 0.062177f, 0.054051f, 0.045925f, 433715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.037799f, 0.029673f, 0.021547f, 0.013421f, 0.005295f 433815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy }; 433915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 434015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy /** 434115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * Computes a 2D mesh representation of the CIE 1931 chromaticity 434215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * diagram. 434315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * 434415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param vertices Array of floats that will hold the mesh vertices 434515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy * @param colors Array of floats that will hold the mesh colors 434615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy */ 43479505a6552764461c22ce48f1ac13d025d23e1579Romain Guy private static void computeChromaticityMesh(@NonNull float[] vertices, 43489505a6552764461c22ce48f1ac13d025d23e1579Romain Guy @NonNull int[] colors) { 434915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 435015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy ColorSpace colorSpace = get(Named.SRGB); 435115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 435215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float[] color = new float[3]; 435315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 435415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int vertexIndex = 0; 435515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int colorIndex = 0; 435615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 435715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy for (int x = 0; x < SPECTRUM_LOCUS_X.length; x++) { 435815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy int nextX = (x % (SPECTRUM_LOCUS_X.length - 1)) + 1; 435915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 436015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float a1 = (float) Math.atan2( 436115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy SPECTRUM_LOCUS_Y[x] - ONE_THIRD, 436215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy SPECTRUM_LOCUS_X[x] - ONE_THIRD); 436315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float a2 = (float) Math.atan2( 436415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy SPECTRUM_LOCUS_Y[nextX] - ONE_THIRD, 436515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy SPECTRUM_LOCUS_X[nextX] - ONE_THIRD); 436615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 436715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float radius1 = (float) Math.pow( 436815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy sqr(SPECTRUM_LOCUS_X[x] - ONE_THIRD) + 436915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy sqr(SPECTRUM_LOCUS_Y[x] - ONE_THIRD), 437015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.5); 437115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float radius2 = (float) Math.pow( 437215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy sqr(SPECTRUM_LOCUS_X[nextX] - ONE_THIRD) + 437315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy sqr(SPECTRUM_LOCUS_Y[nextX] - ONE_THIRD), 437415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 0.5); 437515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 437615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Compute patches; each patch is a quad with a different 437715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // color associated with each vertex 437815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy for (int c = 1; c <= CHROMATICITY_RESOLUTION; c++) { 437915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float f1 = c / (float) CHROMATICITY_RESOLUTION; 438015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float f2 = (c - 1) / (float) CHROMATICITY_RESOLUTION; 438115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 438215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy double cr1 = radius1 * Math.cos(a1); 438315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy double sr1 = radius1 * Math.sin(a1); 438415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy double cr2 = radius2 * Math.cos(a2); 438515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy double sr2 = radius2 * Math.sin(a2); 438615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 438715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Compute the XYZ coordinates of the 4 vertices of the patch 438815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v1x = (float) (ONE_THIRD + cr1 * f1); 438915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v1y = (float) (ONE_THIRD + sr1 * f1); 439015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v1z = 1 - v1x - v1y; 439115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 439215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v2x = (float) (ONE_THIRD + cr1 * f2); 439315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v2y = (float) (ONE_THIRD + sr1 * f2); 439415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v2z = 1 - v2x - v2y; 439515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 439615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v3x = (float) (ONE_THIRD + cr2 * f2); 439715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v3y = (float) (ONE_THIRD + sr2 * f2); 439815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v3z = 1 - v3x - v3y; 439915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 440015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v4x = (float) (ONE_THIRD + cr2 * f1); 440115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v4y = (float) (ONE_THIRD + sr2 * f1); 440215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float v4z = 1 - v4x - v4y; 440315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 440415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Compute the sRGB representation of each XYZ coordinate of the patch 440515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy colors[colorIndex ] = computeColor(color, v1x, v1y, v1z, colorSpace); 440615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy colors[colorIndex + 1] = computeColor(color, v2x, v2y, v2z, colorSpace); 440715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy colors[colorIndex + 2] = computeColor(color, v3x, v3y, v3z, colorSpace); 440815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy colors[colorIndex + 3] = colors[colorIndex]; 440915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy colors[colorIndex + 4] = colors[colorIndex + 2]; 441015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy colors[colorIndex + 5] = computeColor(color, v4x, v4y, v4z, colorSpace); 441115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy colorIndex += 6; 441215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 441315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy // Flip the mesh upside down to match Canvas' coordinates system 44149505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v1x; 44159505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v1y; 44169505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v2x; 44179505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v2y; 44189505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v3x; 44199505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v3y; 44209505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v1x; 44219505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v1y; 44229505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v3x; 44239505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v3y; 44249505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v4x; 44259505a6552764461c22ce48f1ac13d025d23e1579Romain Guy vertices[vertexIndex++] = v4y; 442615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 442715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 442815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 442915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 443015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @ColorInt 443115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private static int computeColor(@NonNull @Size(3) float[] color, 443215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy float x, float y, float z, @NonNull ColorSpace cs) { 443315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy color[0] = x; 443415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy color[1] = y; 443515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy color[2] = z; 443615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy cs.fromXyz(color); 443715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return 0xff000000 | 443815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy (((int) (color[0] * 255.0f) & 0xff) << 16) | 443915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy (((int) (color[1] * 255.0f) & 0xff) << 8) | 444015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy (((int) (color[2] * 255.0f) & 0xff) ); 444115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 444215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 444315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private static double sqr(double v) { 444415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy return v * v; 444515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 444615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 444715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy private static class Point { 444815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull final ColorSpace mColorSpace; 444915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull final float[] mRgb; 445015296a2d3478f53402e2d98f49724bb791eb339dRomain Guy final int mColor; 445115296a2d3478f53402e2d98f49724bb791eb339dRomain Guy 445215296a2d3478f53402e2d98f49724bb791eb339dRomain Guy Point(@NonNull ColorSpace colorSpace, 445315296a2d3478f53402e2d98f49724bb791eb339dRomain Guy @NonNull @Size(3) float[] rgb, @ColorInt int color) { 445415296a2d3478f53402e2d98f49724bb791eb339dRomain Guy mColorSpace = colorSpace; 445515296a2d3478f53402e2d98f49724bb791eb339dRomain Guy mRgb = rgb; 445615296a2d3478f53402e2d98f49724bb791eb339dRomain Guy mColor = color; 445715296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 445815296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 445915296a2d3478f53402e2d98f49724bb791eb339dRomain Guy } 446068bd5fdd1ad3cf0b74c225b31adf1f68393bfbb6Romain Guy} 4461