• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // This file is automatically generated. Do not modify it.
18 
19 package com.google.ux.material.libmonet.utils;
20 
21 /**
22  * Color science utilities.
23  *
24  * <p>Utility methods for color science constants and color space conversions that aren't HCT or
25  * CAM16.
26  */
27 public class ColorUtils {
ColorUtils()28   private ColorUtils() {}
29 
30   static final double[][] SRGB_TO_XYZ =
31       new double[][] {
32         new double[] {0.41233895, 0.35762064, 0.18051042},
33         new double[] {0.2126, 0.7152, 0.0722},
34         new double[] {0.01932141, 0.11916382, 0.95034478},
35       };
36 
37   static final double[][] XYZ_TO_SRGB =
38       new double[][] {
39         new double[] {
40           3.2413774792388685, -1.5376652402851851, -0.49885366846268053,
41         },
42         new double[] {
43           -0.9691452513005321, 1.8758853451067872, 0.04156585616912061,
44         },
45         new double[] {
46           0.05562093689691305, -0.20395524564742123, 1.0571799111220335,
47         },
48       };
49 
50   static final double[] WHITE_POINT_D65 = new double[] {95.047, 100.0, 108.883};
51 
52   /** Converts a color from RGB components to ARGB format. */
argbFromRgb(int red, int green, int blue)53   public static int argbFromRgb(int red, int green, int blue) {
54     return (255 << 24) | ((red & 255) << 16) | ((green & 255) << 8) | (blue & 255);
55   }
56 
57   /** Converts a color from linear RGB components to ARGB format. */
argbFromLinrgb(double[] linrgb)58   public static int argbFromLinrgb(double[] linrgb) {
59     int r = delinearized(linrgb[0]);
60     int g = delinearized(linrgb[1]);
61     int b = delinearized(linrgb[2]);
62     return argbFromRgb(r, g, b);
63   }
64 
65   /** Returns the alpha component of a color in ARGB format. */
alphaFromArgb(int argb)66   public static int alphaFromArgb(int argb) {
67     return (argb >> 24) & 255;
68   }
69 
70   /** Returns the red component of a color in ARGB format. */
redFromArgb(int argb)71   public static int redFromArgb(int argb) {
72     return (argb >> 16) & 255;
73   }
74 
75   /** Returns the green component of a color in ARGB format. */
greenFromArgb(int argb)76   public static int greenFromArgb(int argb) {
77     return (argb >> 8) & 255;
78   }
79 
80   /** Returns the blue component of a color in ARGB format. */
blueFromArgb(int argb)81   public static int blueFromArgb(int argb) {
82     return argb & 255;
83   }
84 
85   /** Returns whether a color in ARGB format is opaque. */
isOpaque(int argb)86   public static boolean isOpaque(int argb) {
87     return alphaFromArgb(argb) >= 255;
88   }
89 
90   /** Converts a color from ARGB to XYZ. */
argbFromXyz(double x, double y, double z)91   public static int argbFromXyz(double x, double y, double z) {
92     double[][] matrix = XYZ_TO_SRGB;
93     double linearR = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z;
94     double linearG = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z;
95     double linearB = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z;
96     int r = delinearized(linearR);
97     int g = delinearized(linearG);
98     int b = delinearized(linearB);
99     return argbFromRgb(r, g, b);
100   }
101 
102   /** Converts a color from XYZ to ARGB. */
xyzFromArgb(int argb)103   public static double[] xyzFromArgb(int argb) {
104     double r = linearized(redFromArgb(argb));
105     double g = linearized(greenFromArgb(argb));
106     double b = linearized(blueFromArgb(argb));
107     return MathUtils.matrixMultiply(new double[] {r, g, b}, SRGB_TO_XYZ);
108   }
109 
110   /** Converts a color represented in Lab color space into an ARGB integer. */
argbFromLab(double l, double a, double b)111   public static int argbFromLab(double l, double a, double b) {
112     double[] whitePoint = WHITE_POINT_D65;
113     double fy = (l + 16.0) / 116.0;
114     double fx = a / 500.0 + fy;
115     double fz = fy - b / 200.0;
116     double xNormalized = labInvf(fx);
117     double yNormalized = labInvf(fy);
118     double zNormalized = labInvf(fz);
119     double x = xNormalized * whitePoint[0];
120     double y = yNormalized * whitePoint[1];
121     double z = zNormalized * whitePoint[2];
122     return argbFromXyz(x, y, z);
123   }
124 
125   /**
126    * Converts a color from ARGB representation to L*a*b* representation.
127    *
128    * @param argb the ARGB representation of a color
129    * @return a Lab object representing the color
130    */
labFromArgb(int argb)131   public static double[] labFromArgb(int argb) {
132     double linearR = linearized(redFromArgb(argb));
133     double linearG = linearized(greenFromArgb(argb));
134     double linearB = linearized(blueFromArgb(argb));
135     double[][] matrix = SRGB_TO_XYZ;
136     double x = matrix[0][0] * linearR + matrix[0][1] * linearG + matrix[0][2] * linearB;
137     double y = matrix[1][0] * linearR + matrix[1][1] * linearG + matrix[1][2] * linearB;
138     double z = matrix[2][0] * linearR + matrix[2][1] * linearG + matrix[2][2] * linearB;
139     double[] whitePoint = WHITE_POINT_D65;
140     double xNormalized = x / whitePoint[0];
141     double yNormalized = y / whitePoint[1];
142     double zNormalized = z / whitePoint[2];
143     double fx = labF(xNormalized);
144     double fy = labF(yNormalized);
145     double fz = labF(zNormalized);
146     double l = 116.0 * fy - 16;
147     double a = 500.0 * (fx - fy);
148     double b = 200.0 * (fy - fz);
149     return new double[] {l, a, b};
150   }
151 
152   /**
153    * Converts an L* value to an ARGB representation.
154    *
155    * @param lstar L* in L*a*b*
156    * @return ARGB representation of grayscale color with lightness matching L*
157    */
argbFromLstar(double lstar)158   public static int argbFromLstar(double lstar) {
159     double y = yFromLstar(lstar);
160     int component = delinearized(y);
161     return argbFromRgb(component, component, component);
162   }
163 
164   /**
165    * Computes the L* value of a color in ARGB representation.
166    *
167    * @param argb ARGB representation of a color
168    * @return L*, from L*a*b*, coordinate of the color
169    */
lstarFromArgb(int argb)170   public static double lstarFromArgb(int argb) {
171     double y = xyzFromArgb(argb)[1];
172     return 116.0 * labF(y / 100.0) - 16.0;
173   }
174 
175   /**
176    * Converts an L* value to a Y value.
177    *
178    * <p>L* in L*a*b* and Y in XYZ measure the same quantity, luminance.
179    *
180    * <p>L* measures perceptual luminance, a linear scale. Y in XYZ measures relative luminance, a
181    * logarithmic scale.
182    *
183    * @param lstar L* in L*a*b*
184    * @return Y in XYZ
185    */
yFromLstar(double lstar)186   public static double yFromLstar(double lstar) {
187     return 100.0 * labInvf((lstar + 16.0) / 116.0);
188   }
189 
190   /**
191    * Converts a Y value to an L* value.
192    *
193    * <p>L* in L*a*b* and Y in XYZ measure the same quantity, luminance.
194    *
195    * <p>L* measures perceptual luminance, a linear scale. Y in XYZ measures relative luminance, a
196    * logarithmic scale.
197    *
198    * @param y Y in XYZ
199    * @return L* in L*a*b*
200    */
lstarFromY(double y)201   public static double lstarFromY(double y) {
202     return labF(y / 100.0) * 116.0 - 16.0;
203   }
204 
205   /**
206    * Linearizes an RGB component.
207    *
208    * @param rgbComponent 0 <= rgb_component <= 255, represents R/G/B channel
209    * @return 0.0 <= output <= 100.0, color channel converted to linear RGB space
210    */
linearized(int rgbComponent)211   public static double linearized(int rgbComponent) {
212     double normalized = rgbComponent / 255.0;
213     if (normalized <= 0.040449936) {
214       return normalized / 12.92 * 100.0;
215     } else {
216       return Math.pow((normalized + 0.055) / 1.055, 2.4) * 100.0;
217     }
218   }
219 
220   /**
221    * Delinearizes an RGB component.
222    *
223    * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents linear R/G/B channel
224    * @return 0 <= output <= 255, color channel converted to regular RGB space
225    */
delinearized(double rgbComponent)226   public static int delinearized(double rgbComponent) {
227     double normalized = rgbComponent / 100.0;
228     double delinearized = 0.0;
229     if (normalized <= 0.0031308) {
230       delinearized = normalized * 12.92;
231     } else {
232       delinearized = 1.055 * Math.pow(normalized, 1.0 / 2.4) - 0.055;
233     }
234     return MathUtils.clampInt(0, 255, (int) Math.round(delinearized * 255.0));
235   }
236 
237   /**
238    * Returns the standard white point; white on a sunny day.
239    *
240    * @return The white point
241    */
whitePointD65()242   public static double[] whitePointD65() {
243     return WHITE_POINT_D65;
244   }
245 
labF(double t)246   static double labF(double t) {
247     double e = 216.0 / 24389.0;
248     double kappa = 24389.0 / 27.0;
249     if (t > e) {
250       return Math.pow(t, 1.0 / 3.0);
251     } else {
252       return (kappa * t + 16) / 116;
253     }
254   }
255 
labInvf(double ft)256   static double labInvf(double ft) {
257     double e = 216.0 / 24389.0;
258     double kappa = 24389.0 / 27.0;
259     double ft3 = ft * ft * ft;
260     if (ft3 > e) {
261       return ft3;
262     } else {
263       return (116 * ft - 16) / kappa;
264     }
265   }
266 }
267 
268