CAM16 instances also have coordinates in the CAM16-UCS space, called J*, a*, b*, or jstar, - * astar, bstar in code. CAM16-UCS is included in the CAM16 specification, and should be used when - * measuring distances between colors. - * - *
In traditional color spaces, a color can be identified solely by the observer's measurement of - * the color. Color appearance models such as CAM16 also use information about the environment where - * the color was observed, known as the viewing conditions. - * - *
For example, white under the traditional assumption of a midday sun white point is accurately - * measured as a slightly chromatic blue by CAM16. (roughly, hue 203, chroma 3, lightness 100) - */ -public final class Cam16 { - // Transforms XYZ color space coordinates to 'cone'/'RGB' responses in CAM16. - static final double[][] XYZ_TO_CAM16RGB = { - {0.401288, 0.650173, -0.051461}, - {-0.250268, 1.204414, 0.045854}, - {-0.002079, 0.048952, 0.953127} - }; - - // Transforms 'cone'/'RGB' responses in CAM16 to XYZ color space coordinates. - static final double[][] CAM16RGB_TO_XYZ = { - {1.8620678, -1.0112547, 0.14918678}, - {0.38752654, 0.62144744, -0.00897398}, - {-0.01584150, -0.03412294, 1.0499644} - }; - - // CAM16 color dimensions, see getters for documentation. - private final double hue; - private final double chroma; - private final double j; - private final double q; - private final double m; - private final double s; - - // Coordinates in UCS space. Used to determine color distance, like delta E equations in L*a*b*. - private final double jstar; - private final double astar; - private final double bstar; - - /** - * CAM16 instances also have coordinates in the CAM16-UCS space, called J*, a*, b*, or jstar, - * astar, bstar in code. CAM16-UCS is included in the CAM16 specification, and is used to measure - * distances between colors. - */ - double distance(Cam16 other) { - double dJ = getJstar() - other.getJstar(); - double dA = getAstar() - other.getAstar(); - double dB = getBstar() - other.getBstar(); - double dEPrime = Math.sqrt(dJ * dJ + dA * dA + dB * dB); - double dE = 1.41 * Math.pow(dEPrime, 0.63); - return dE; - } - - /** Hue in CAM16 */ - public double getHue() { - return hue; - } - - /** Chroma in CAM16 */ - public double getChroma() { - return chroma; - } - - /** Lightness in CAM16 */ - public double getJ() { - return j; - } - - /** - * Brightness in CAM16. - * - *
Prefer lightness, brightness is an absolute quantity. For example, a sheet of white paper is - * much brighter viewed in sunlight than in indoor light, but it is the lightest object under any - * lighting. - */ - public double getQ() { - return q; - } - - /** - * Colorfulness in CAM16. - * - *
Prefer chroma, colorfulness is an absolute quantity. For example, a yellow toy car is much - * more colorful outside than inside, but it has the same chroma in both environments. - */ - public double getM() { - return m; - } - - /** - * Saturation in CAM16. - * - *
Colorfulness in proportion to brightness. Prefer chroma, saturation measures colorfulness - * relative to the color's own brightness, where chroma is colorfulness relative to white. - */ - public double getS() { - return s; - } - - /** Lightness coordinate in CAM16-UCS */ - public double getJstar() { - return jstar; - } - - /** a* coordinate in CAM16-UCS */ - public double getAstar() { - return astar; - } - - /** b* coordinate in CAM16-UCS */ - public double getBstar() { - return bstar; - } - - /** - * All of the CAM16 dimensions can be calculated from 3 of the dimensions, in the following - * combinations: - {j or q} and {c, m, or s} and hue - jstar, astar, bstar Prefer using a static - * method that constructs from 3 of those dimensions. This constructor is intended for those - * methods to use to return all possible dimensions. - * - * @param hue for example, red, orange, yellow, green, etc. - * @param chroma informally, colorfulness / color intensity. like saturation in HSL, except - * perceptually accurate. - * @param j lightness - * @param q brightness; ratio of lightness to white point's lightness - * @param m colorfulness - * @param s saturation; ratio of chroma to white point's chroma - * @param jstar CAM16-UCS J coordinate - * @param astar CAM16-UCS a coordinate - * @param bstar CAM16-UCS b coordinate - */ - private Cam16( - double hue, - double chroma, - double j, - double q, - double m, - double s, - double jstar, - double astar, - double bstar) { - this.hue = hue; - this.chroma = chroma; - this.j = j; - this.q = q; - this.m = m; - this.s = s; - this.jstar = jstar; - this.astar = astar; - this.bstar = bstar; - } - - /** - * Create a CAM16 color from a color, assuming the color was viewed in default viewing conditions. - * - * @param argb ARGB representation of a color. - */ - public static Cam16 fromInt(int argb) { - return fromIntInViewingConditions(argb, ViewingConditions.DEFAULT); - } - - /** - * Create a CAM16 color from a color in defined viewing conditions. - * - * @param argb ARGB representation of a color. - * @param viewingConditions Information about the environment where the color was observed. - */ - // The RGB => XYZ conversion matrix elements are derived scientific constants. While the values - // may differ at runtime due to floating point imprecision, keeping the values the same, and - // accurate, across implementations takes precedence. - @SuppressWarnings("FloatingPointLiteralPrecision") - static Cam16 fromIntInViewingConditions(int argb, ViewingConditions viewingConditions) { - // Transform ARGB int to XYZ - int red = (argb & 0x00ff0000) >> 16; - int green = (argb & 0x0000ff00) >> 8; - int blue = (argb & 0x000000ff); - double redL = ColorUtils.linearized(red); - double greenL = ColorUtils.linearized(green); - double blueL = ColorUtils.linearized(blue); - double x = 0.41233895 * redL + 0.35762064 * greenL + 0.18051042 * blueL; - double y = 0.2126 * redL + 0.7152 * greenL + 0.0722 * blueL; - double z = 0.01932141 * redL + 0.11916382 * greenL + 0.95034478 * blueL; - - // Transform XYZ to 'cone'/'rgb' responses - double[][] matrix = XYZ_TO_CAM16RGB; - double rT = (x * matrix[0][0]) + (y * matrix[0][1]) + (z * matrix[0][2]); - double gT = (x * matrix[1][0]) + (y * matrix[1][1]) + (z * matrix[1][2]); - double bT = (x * matrix[2][0]) + (y * matrix[2][1]) + (z * matrix[2][2]); - - // Discount illuminant - double rD = viewingConditions.getRgbD()[0] * rT; - double gD = viewingConditions.getRgbD()[1] * gT; - double bD = viewingConditions.getRgbD()[2] * bT; - - // Chromatic adaptation - double rAF = Math.pow(viewingConditions.getFl() * Math.abs(rD) / 100.0, 0.42); - double gAF = Math.pow(viewingConditions.getFl() * Math.abs(gD) / 100.0, 0.42); - double bAF = Math.pow(viewingConditions.getFl() * Math.abs(bD) / 100.0, 0.42); - double rA = Math.signum(rD) * 400.0 * rAF / (rAF + 27.13); - double gA = Math.signum(gD) * 400.0 * gAF / (gAF + 27.13); - double bA = Math.signum(bD) * 400.0 * bAF / (bAF + 27.13); - - // redness-greenness - double a = (11.0 * rA + -12.0 * gA + bA) / 11.0; - // yellowness-blueness - double b = (rA + gA - 2.0 * bA) / 9.0; - - // auxiliary components - double u = (20.0 * rA + 20.0 * gA + 21.0 * bA) / 20.0; - double p2 = (40.0 * rA + 20.0 * gA + bA) / 20.0; - - // hue - double atan2 = Math.atan2(b, a); - double atanDegrees = Math.toDegrees(atan2); - double hue = - atanDegrees < 0 - ? atanDegrees + 360.0 - : atanDegrees >= 360 ? atanDegrees - 360.0 : atanDegrees; - double hueRadians = Math.toRadians(hue); - - // achromatic response to color - double ac = p2 * viewingConditions.getNbb(); - - // CAM16 lightness and brightness - double j = - 100.0 - * Math.pow( - ac / viewingConditions.getAw(), - viewingConditions.getC() * viewingConditions.getZ()); - double q = - 4.0 - / viewingConditions.getC() - * Math.sqrt(j / 100.0) - * (viewingConditions.getAw() + 4.0) - * viewingConditions.getFlRoot(); - - // CAM16 chroma, colorfulness, and saturation. - double huePrime = (hue < 20.14) ? hue + 360 : hue; - double eHue = 0.25 * (Math.cos(Math.toRadians(huePrime) + 2.0) + 3.8); - double p1 = 50000.0 / 13.0 * eHue * viewingConditions.getNc() * viewingConditions.getNcb(); - double t = p1 * Math.hypot(a, b) / (u + 0.305); - double alpha = - Math.pow(1.64 - Math.pow(0.29, viewingConditions.getN()), 0.73) * Math.pow(t, 0.9); - // CAM16 chroma, colorfulness, saturation - double c = alpha * Math.sqrt(j / 100.0); - double m = c * viewingConditions.getFlRoot(); - double s = - 50.0 * Math.sqrt((alpha * viewingConditions.getC()) / (viewingConditions.getAw() + 4.0)); - - // CAM16-UCS components - double jstar = (1.0 + 100.0 * 0.007) * j / (1.0 + 0.007 * j); - double mstar = 1.0 / 0.0228 * Math.log1p(0.0228 * m); - double astar = mstar * Math.cos(hueRadians); - double bstar = mstar * Math.sin(hueRadians); - - return new Cam16(hue, c, j, q, m, s, jstar, astar, bstar); - } - - /** - * @param j CAM16 lightness - * @param c CAM16 chroma - * @param h CAM16 hue - */ - static Cam16 fromJch(double j, double c, double h) { - return fromJchInViewingConditions(j, c, h, ViewingConditions.DEFAULT); - } - - /** - * @param j CAM16 lightness - * @param c CAM16 chroma - * @param h CAM16 hue - * @param viewingConditions Information about the environment where the color was observed. - */ - private static Cam16 fromJchInViewingConditions( - double j, double c, double h, ViewingConditions viewingConditions) { - double q = - 4.0 - / viewingConditions.getC() - * Math.sqrt(j / 100.0) - * (viewingConditions.getAw() + 4.0) - * viewingConditions.getFlRoot(); - double m = c * viewingConditions.getFlRoot(); - double alpha = c / Math.sqrt(j / 100.0); - double s = - 50.0 * Math.sqrt((alpha * viewingConditions.getC()) / (viewingConditions.getAw() + 4.0)); - - double hueRadians = Math.toRadians(h); - double jstar = (1.0 + 100.0 * 0.007) * j / (1.0 + 0.007 * j); - double mstar = 1.0 / 0.0228 * Math.log1p(0.0228 * m); - double astar = mstar * Math.cos(hueRadians); - double bstar = mstar * Math.sin(hueRadians); - return new Cam16(h, c, j, q, m, s, jstar, astar, bstar); - } - - /** - * Create a CAM16 color from CAM16-UCS coordinates. - * - * @param jstar CAM16-UCS lightness. - * @param astar CAM16-UCS a dimension. Like a* in L*a*b*, it is a Cartesian coordinate on the Y - * axis. - * @param bstar CAM16-UCS b dimension. Like a* in L*a*b*, it is a Cartesian coordinate on the X - * axis. - */ - public static Cam16 fromUcs(double jstar, double astar, double bstar) { - - return fromUcsInViewingConditions(jstar, astar, bstar, ViewingConditions.DEFAULT); - } - - /** - * Create a CAM16 color from CAM16-UCS coordinates in defined viewing conditions. - * - * @param jstar CAM16-UCS lightness. - * @param astar CAM16-UCS a dimension. Like a* in L*a*b*, it is a Cartesian coordinate on the Y - * axis. - * @param bstar CAM16-UCS b dimension. Like a* in L*a*b*, it is a Cartesian coordinate on the X - * axis. - * @param viewingConditions Information about the environment where the color was observed. - */ - public static Cam16 fromUcsInViewingConditions( - double jstar, double astar, double bstar, ViewingConditions viewingConditions) { - - double m = Math.hypot(astar, bstar); - double m2 = Math.expm1(m * 0.0228) / 0.0228; - double c = m2 / viewingConditions.getFlRoot(); - double h = Math.atan2(bstar, astar) * (180.0 / Math.PI); - if (h < 0.0) { - h += 360.0; - } - double j = jstar / (1. - (jstar - 100.) * 0.007); - return fromJchInViewingConditions(j, c, h, viewingConditions); - } - - /** - * ARGB representation of the color. Assumes the color was viewed in default viewing conditions, - * which are near-identical to the default viewing conditions for sRGB. - */ - public int toInt() { - return viewed(ViewingConditions.DEFAULT); - } - - /** - * ARGB representation of the color, in defined viewing conditions. - * - * @param viewingConditions Information about the environment where the color will be viewed. - * @return ARGB representation of color - */ - int viewed(ViewingConditions viewingConditions) { - double alpha = - (getChroma() == 0.0 || getJ() == 0.0) ? 0.0 : getChroma() / Math.sqrt(getJ() / 100.0); - - double t = - Math.pow( - alpha / Math.pow(1.64 - Math.pow(0.29, viewingConditions.getN()), 0.73), 1.0 / 0.9); - double hRad = Math.toRadians(getHue()); - - double eHue = 0.25 * (Math.cos(hRad + 2.0) + 3.8); - double ac = - viewingConditions.getAw() - * Math.pow(getJ() / 100.0, 1.0 / viewingConditions.getC() / viewingConditions.getZ()); - double p1 = eHue * (50000.0 / 13.0) * viewingConditions.getNc() * viewingConditions.getNcb(); - double p2 = (ac / viewingConditions.getNbb()); - - double hSin = Math.sin(hRad); - double hCos = Math.cos(hRad); - - double gamma = 23.0 * (p2 + 0.305) * t / (23.0 * p1 + 11.0 * t * hCos + 108.0 * t * hSin); - double a = gamma * hCos; - double b = gamma * hSin; - double rA = (460.0 * p2 + 451.0 * a + 288.0 * b) / 1403.0; - double gA = (460.0 * p2 - 891.0 * a - 261.0 * b) / 1403.0; - double bA = (460.0 * p2 - 220.0 * a - 6300.0 * b) / 1403.0; - - double rCBase = max(0, (27.13 * Math.abs(rA)) / (400.0 - Math.abs(rA))); - double rC = - Math.signum(rA) * (100.0 / viewingConditions.getFl()) * Math.pow(rCBase, 1.0 / 0.42); - double gCBase = max(0, (27.13 * Math.abs(gA)) / (400.0 - Math.abs(gA))); - double gC = - Math.signum(gA) * (100.0 / viewingConditions.getFl()) * Math.pow(gCBase, 1.0 / 0.42); - double bCBase = max(0, (27.13 * Math.abs(bA)) / (400.0 - Math.abs(bA))); - double bC = - Math.signum(bA) * (100.0 / viewingConditions.getFl()) * Math.pow(bCBase, 1.0 / 0.42); - double rF = rC / viewingConditions.getRgbD()[0]; - double gF = gC / viewingConditions.getRgbD()[1]; - double bF = bC / viewingConditions.getRgbD()[2]; - - double[][] matrix = CAM16RGB_TO_XYZ; - double x = (rF * matrix[0][0]) + (gF * matrix[0][1]) + (bF * matrix[0][2]); - double y = (rF * matrix[1][0]) + (gF * matrix[1][1]) + (bF * matrix[1][2]); - double z = (rF * matrix[2][0]) + (gF * matrix[2][1]) + (bF * matrix[2][2]); - - return ColorUtils.argbFromXyz(x, y, z); - } -} diff --git a/material-color-utilities/src/main/java/hct/Hct.java b/material-color-utilities/src/main/java/hct/Hct.java deleted file mode 100644 index 4bcdb7810..000000000 --- a/material-color-utilities/src/main/java/hct/Hct.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package hct; - -import utils.ColorUtils; - -/** - * A color system built using CAM16 hue and chroma, and L* from L*a*b*. - * - *
Using L* creates a link between the color system, contrast, and thus accessibility. Contrast - * ratio depends on relative luminance, or Y in the XYZ color space. L*, or perceptual luminance can - * be calculated from Y. - * - *
Unlike Y, L* is linear to human perception, allowing trivial creation of accurate color tones. - * - *
Unlike contrast ratio, measuring contrast in L* is linear, and simple to calculate. A - * difference of 40 in HCT tone guarantees a contrast ratio >= 3.0, and a difference of 50 - * guarantees a contrast ratio >= 4.5. - */ - -/** - * HCT, hue, chroma, and tone. A color system that provides a perceptually accurate color - * measurement system that can also accurately render what colors will appear as in different - * lighting environments. - */ -public final class Hct { - private double hue; - private double chroma; - private double tone; - private int argb; - - /** - * Create an HCT color from hue, chroma, and tone. - * - * @param hue 0 <= hue < 360; invalid values are corrected. - * @param chroma 0 <= chroma < ?; Informally, colorfulness. The color returned may be lower than - * the requested chroma. Chroma has a different maximum for any given hue and tone. - * @param tone 0 <= tone <= 100; invalid values are corrected. - * @return HCT representation of a color in default viewing conditions. - */ - public static Hct from(double hue, double chroma, double tone) { - int argb = HctSolver.solveToInt(hue, chroma, tone); - return new Hct(argb); - } - - /** - * Create an HCT color from a color. - * - * @param argb ARGB representation of a color. - * @return HCT representation of a color in default viewing conditions - */ - public static Hct fromInt(int argb) { - return new Hct(argb); - } - - private Hct(int argb) { - setInternalState(argb); - } - - public double getHue() { - return hue; - } - - public double getChroma() { - return chroma; - } - - public double getTone() { - return tone; - } - - public int toInt() { - return argb; - } - - /** - * Set the hue of this color. Chroma may decrease because chroma has a different maximum for any - * given hue and tone. - * - * @param newHue 0 <= newHue < 360; invalid values are corrected. - */ - public void setHue(double newHue) { - setInternalState(HctSolver.solveToInt(newHue, chroma, tone)); - } - - /** - * Set the chroma of this color. Chroma may decrease because chroma has a different maximum for - * any given hue and tone. - * - * @param newChroma 0 <= newChroma < ? - */ - public void setChroma(double newChroma) { - setInternalState(HctSolver.solveToInt(hue, newChroma, tone)); - } - - /** - * Set the tone of this color. Chroma may decrease because chroma has a different maximum for any - * given hue and tone. - * - * @param newTone 0 <= newTone <= 100; invalid valids are corrected. - */ - public void setTone(double newTone) { - setInternalState(HctSolver.solveToInt(hue, chroma, newTone)); - } - - private void setInternalState(int argb) { - this.argb = argb; - Cam16 cam = Cam16.fromInt(argb); - hue = cam.getHue(); - chroma = cam.getChroma(); - this.tone = ColorUtils.lstarFromArgb(argb); - } -} diff --git a/material-color-utilities/src/main/java/hct/HctSolver.java b/material-color-utilities/src/main/java/hct/HctSolver.java deleted file mode 100644 index 955080c1c..000000000 --- a/material-color-utilities/src/main/java/hct/HctSolver.java +++ /dev/null @@ -1,672 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This file is automatically generated. Do not modify it. - -package hct; - -import utils.ColorUtils; -import utils.MathUtils; - -/** A class that solves the HCT equation. */ -public class HctSolver { - private HctSolver() {} - - static final double[][] SCALED_DISCOUNT_FROM_LINRGB = - new double[][] { - new double[] { - 0.001200833568784504, 0.002389694492170889, 0.0002795742885861124, - }, - new double[] { - 0.0005891086651375999, 0.0029785502573438758, 0.0003270666104008398, - }, - new double[] { - 0.00010146692491640572, 0.0005364214359186694, 0.0032979401770712076, - }, - }; - - static final double[][] LINRGB_FROM_SCALED_DISCOUNT = - new double[][] { - new double[] { - 1373.2198709594231, -1100.4251190754821, -7.278681089101213, - }, - new double[] { - -271.815969077903, 559.6580465940733, -32.46047482791194, - }, - new double[] { - 1.9622899599665666, -57.173814538844006, 308.7233197812385, - }, - }; - - static final double[] Y_FROM_LINRGB = new double[] {0.2126, 0.7152, 0.0722}; - - static final double[] CRITICAL_PLANES = - new double[] { - 0.015176349177441876, - 0.045529047532325624, - 0.07588174588720938, - 0.10623444424209313, - 0.13658714259697685, - 0.16693984095186062, - 0.19729253930674434, - 0.2276452376616281, - 0.2579979360165119, - 0.28835063437139563, - 0.3188300904430532, - 0.350925934958123, - 0.3848314933096426, - 0.42057480301049466, - 0.458183274052838, - 0.4976837250274023, - 0.5391024159806381, - 0.5824650784040898, - 0.6277969426914107, - 0.6751227633498623, - 0.7244668422128921, - 0.775853049866786, - 0.829304845476233, - 0.8848452951698498, - 0.942497089126609, - 1.0022825574869039, - 1.0642236851973577, - 1.1283421258858297, - 1.1946592148522128, - 1.2631959812511864, - 1.3339731595349034, - 1.407011200216447, - 1.4823302800086415, - 1.5599503113873272, - 1.6398909516233677, - 1.7221716113234105, - 1.8068114625156377, - 1.8938294463134073, - 1.9832442801866852, - 2.075074464868551, - 2.1693382909216234, - 2.2660538449872063, - 2.36523901573795, - 2.4669114995532007, - 2.5710888059345764, - 2.6777882626779785, - 2.7870270208169257, - 2.898822059350997, - 3.0131901897720907, - 3.1301480604002863, - 3.2497121605402226, - 3.3718988244681087, - 3.4967242352587946, - 3.624204428461639, - 3.754355295633311, - 3.887192587735158, - 4.022731918402185, - 4.160988767090289, - 4.301978482107941, - 4.445716283538092, - 4.592217266055746, - 4.741496401646282, - 4.893568542229298, - 5.048448422192488, - 5.20615066083972, - 5.3666897647573375, - 5.5300801301023865, - 5.696336044816294, - 5.865471690767354, - 6.037501145825082, - 6.212438385869475, - 6.390297286737924, - 6.571091626112461, - 6.7548350853498045, - 6.941541251256611, - 7.131223617812143, - 7.323895587840543, - 7.5195704746346665, - 7.7182615035334345, - 7.919981813454504, - 8.124744458384042, - 8.332562408825165, - 8.543448553206703, - 8.757415699253682, - 8.974476575321063, - 9.194643831691977, - 9.417930041841839, - 9.644347703669503, - 9.873909240696694, - 10.106627003236781, - 10.342513269534024, - 10.58158024687427, - 10.8238400726681, - 11.069304815507364, - 11.317986476196008, - 11.569896988756009, - 11.825048221409341, - 12.083451977536606, - 12.345119996613247, - 12.610063955123938, - 12.878295467455942, - 13.149826086772048, - 13.42466730586372, - 13.702830557985108, - 13.984327217668513, - 14.269168601521828, - 14.55736596900856, - 14.848930523210871, - 15.143873411576273, - 15.44220572664832, - 15.743938506781891, - 16.04908273684337, - 16.35764934889634, - 16.66964922287304, - 16.985093187232053, - 17.30399201960269, - 17.62635644741625, - 17.95219714852476, - 18.281524751807332, - 18.614349837764564, - 18.95068293910138, - 19.290534541298456, - 19.633915083172692, - 19.98083495742689, - 20.331304511189067, - 20.685334046541502, - 21.042933821039977, - 21.404114048223256, - 21.76888489811322, - 22.137256497705877, - 22.50923893145328, - 22.884842241736916, - 23.264076429332462, - 23.6469514538663, - 24.033477234264016, - 24.42366364919083, - 24.817520537484558, - 25.21505769858089, - 25.61628489293138, - 26.021211842414342, - 26.429848230738664, - 26.842203703840827, - 27.258287870275353, - 27.678110301598522, - 28.10168053274597, - 28.529008062403893, - 28.96010235337422, - 29.39497283293396, - 29.83362889318845, - 30.276079891419332, - 30.722335150426627, - 31.172403958865512, - 31.62629557157785, - 32.08401920991837, - 32.54558406207592, - 33.010999283389665, - 33.4802739966603, - 33.953417292456834, - 34.430438229418264, - 34.911345834551085, - 35.39614910352207, - 35.88485700094671, - 36.37747846067349, - 36.87402238606382, - 37.37449765026789, - 37.87891309649659, - 38.38727753828926, - 38.89959975977785, - 39.41588851594697, - 39.93615253289054, - 40.460400508064545, - 40.98864111053629, - 41.520882981230194, - 42.05713473317016, - 42.597404951718396, - 43.141702194811224, - 43.6900349931913, - 44.24241185063697, - 44.798841244188324, - 45.35933162437017, - 45.92389141541209, - 46.49252901546552, - 47.065252796817916, - 47.64207110610409, - 48.22299226451468, - 48.808024568002054, - 49.3971762874833, - 49.9904556690408, - 50.587870934119984, - 51.189430279724725, - 51.79514187861014, - 52.40501387947288, - 53.0190544071392, - 53.637271562750364, - 54.259673423945976, - 54.88626804504493, - 55.517063457223934, - 56.15206766869424, - 56.79128866487574, - 57.43473440856916, - 58.08241284012621, - 58.734331877617365, - 59.39049941699807, - 60.05092333227251, - 60.715611475655585, - 61.38457167773311, - 62.057811747619894, - 62.7353394731159, - 63.417162620860914, - 64.10328893648692, - 64.79372614476921, - 65.48848194977529, - 66.18756403501224, - 66.89098006357258, - 67.59873767827808, - 68.31084450182222, - 69.02730813691093, - 69.74813616640164, - 70.47333615344107, - 71.20291564160104, - 71.93688215501312, - 72.67524319850172, - 73.41800625771542, - 74.16517879925733, - 74.9167682708136, - 75.67278210128072, - 76.43322770089146, - 77.1981124613393, - 77.96744375590167, - 78.74122893956174, - 79.51947534912904, - 80.30219030335869, - 81.08938110306934, - 81.88105503125999, - 82.67721935322541, - 83.4778813166706, - 84.28304815182372, - 85.09272707154808, - 85.90692527145302, - 86.72564993000343, - 87.54890820862819, - 88.3767072518277, - 89.2090541872801, - 90.04595612594655, - 90.88742016217518, - 91.73345337380438, - 92.58406282226491, - 93.43925555268066, - 94.29903859396902, - 95.16341895893969, - 96.03240364439274, - 96.9059996312159, - 97.78421388448044, - 98.6670533535366, - 99.55452497210776, - }; - - /** - * Sanitizes a small enough angle in radians. - * - * @param angle An angle in radians; must not deviate too much from 0. - * @return A coterminal angle between 0 and 2pi. - */ - static double sanitizeRadians(double angle) { - return (angle + Math.PI * 8) % (Math.PI * 2); - } - - /** - * Delinearizes an RGB component, returning a floating-point number. - * - * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents linear R/G/B channel - * @return 0.0 <= output <= 255.0, color channel converted to regular RGB space - */ - static double trueDelinearized(double rgbComponent) { - double normalized = rgbComponent / 100.0; - double delinearized = 0.0; - if (normalized <= 0.0031308) { - delinearized = normalized * 12.92; - } else { - delinearized = 1.055 * Math.pow(normalized, 1.0 / 2.4) - 0.055; - } - return delinearized * 255.0; - } - - static double chromaticAdaptation(double component) { - double af = Math.pow(Math.abs(component), 0.42); - return MathUtils.signum(component) * 400.0 * af / (af + 27.13); - } - - /** - * Returns the hue of a linear RGB color in CAM16. - * - * @param linrgb The linear RGB coordinates of a color. - * @return The hue of the color in CAM16, in radians. - */ - static double hueOf(double[] linrgb) { - double[] scaledDiscount = MathUtils.matrixMultiply(linrgb, SCALED_DISCOUNT_FROM_LINRGB); - double rA = chromaticAdaptation(scaledDiscount[0]); - double gA = chromaticAdaptation(scaledDiscount[1]); - double bA = chromaticAdaptation(scaledDiscount[2]); - // redness-greenness - double a = (11.0 * rA + -12.0 * gA + bA) / 11.0; - // yellowness-blueness - double b = (rA + gA - 2.0 * bA) / 9.0; - return Math.atan2(b, a); - } - - static boolean areInCyclicOrder(double a, double b, double c) { - double deltaAB = sanitizeRadians(b - a); - double deltaAC = sanitizeRadians(c - a); - return deltaAB < deltaAC; - } - - /** - * Solves the lerp equation. - * - * @param source The starting number. - * @param mid The number in the middle. - * @param target The ending number. - * @return A number t such that lerp(source, target, t) = mid. - */ - static double intercept(double source, double mid, double target) { - return (mid - source) / (target - source); - } - - static double[] lerpPoint(double[] source, double t, double[] target) { - return new double[] { - source[0] + (target[0] - source[0]) * t, - source[1] + (target[1] - source[1]) * t, - source[2] + (target[2] - source[2]) * t, - }; - } - - /** - * Intersects a segment with a plane. - * - * @param source The coordinates of point A. - * @param coordinate The R-, G-, or B-coordinate of the plane. - * @param target The coordinates of point B. - * @param axis The axis the plane is perpendicular with. (0: R, 1: G, 2: B) - * @return The intersection point of the segment AB with the plane R=coordinate, G=coordinate, or - * B=coordinate - */ - static double[] setCoordinate(double[] source, double coordinate, double[] target, int axis) { - double t = intercept(source[axis], coordinate, target[axis]); - return lerpPoint(source, t, target); - } - - static boolean isBounded(double x) { - return 0.0 <= x && x <= 100.0; - } - - /** - * Returns the nth possible vertex of the polygonal intersection. - * - * @param y The Y value of the plane. - * @param n The zero-based index of the point. 0 <= n <= 11. - * @return The nth possible vertex of the polygonal intersection of the y plane and the RGB cube, - * in linear RGB coordinates, if it exists. If this possible vertex lies outside of the cube, - * [-1.0, -1.0, -1.0] is returned. - */ - static double[] nthVertex(double y, int n) { - double kR = Y_FROM_LINRGB[0]; - double kG = Y_FROM_LINRGB[1]; - double kB = Y_FROM_LINRGB[2]; - double coordA = n % 4 <= 1 ? 0.0 : 100.0; - double coordB = n % 2 == 0 ? 0.0 : 100.0; - if (n < 4) { - double g = coordA; - double b = coordB; - double r = (y - g * kG - b * kB) / kR; - if (isBounded(r)) { - return new double[] {r, g, b}; - } else { - return new double[] {-1.0, -1.0, -1.0}; - } - } else if (n < 8) { - double b = coordA; - double r = coordB; - double g = (y - r * kR - b * kB) / kG; - if (isBounded(g)) { - return new double[] {r, g, b}; - } else { - return new double[] {-1.0, -1.0, -1.0}; - } - } else { - double r = coordA; - double g = coordB; - double b = (y - r * kR - g * kG) / kB; - if (isBounded(b)) { - return new double[] {r, g, b}; - } else { - return new double[] {-1.0, -1.0, -1.0}; - } - } - } - - /** - * Finds the segment containing the desired color. - * - * @param y The Y value of the color. - * @param targetHue The hue of the color. - * @return A list of two sets of linear RGB coordinates, each corresponding to an endpoint of the - * segment containing the desired color. - */ - static double[][] bisectToSegment(double y, double targetHue) { - double[] left = new double[] {-1.0, -1.0, -1.0}; - double[] right = left; - double leftHue = 0.0; - double rightHue = 0.0; - boolean initialized = false; - boolean uncut = true; - for (int n = 0; n < 12; n++) { - double[] mid = nthVertex(y, n); - if (mid[0] < 0) { - continue; - } - double midHue = hueOf(mid); - if (!initialized) { - left = mid; - right = mid; - leftHue = midHue; - rightHue = midHue; - initialized = true; - continue; - } - if (uncut || areInCyclicOrder(leftHue, midHue, rightHue)) { - uncut = false; - if (areInCyclicOrder(leftHue, targetHue, midHue)) { - right = mid; - rightHue = midHue; - } else { - left = mid; - leftHue = midHue; - } - } - } - return new double[][] {left, right}; - } - - static double[] midpoint(double[] a, double[] b) { - return new double[] { - (a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2, - }; - } - - static int criticalPlaneBelow(double x) { - return (int) Math.floor(x - 0.5); - } - - static int criticalPlaneAbove(double x) { - return (int) Math.ceil(x - 0.5); - } - - /** - * Finds a color with the given Y and hue on the boundary of the cube. - * - * @param y The Y value of the color. - * @param targetHue The hue of the color. - * @return The desired color, in linear RGB coordinates. - */ - static double[] bisectToLimit(double y, double targetHue) { - double[][] segment = bisectToSegment(y, targetHue); - double[] left = segment[0]; - double leftHue = hueOf(left); - double[] right = segment[1]; - for (int axis = 0; axis < 3; axis++) { - if (left[axis] != right[axis]) { - int lPlane = -1; - int rPlane = 255; - if (left[axis] < right[axis]) { - lPlane = criticalPlaneBelow(trueDelinearized(left[axis])); - rPlane = criticalPlaneAbove(trueDelinearized(right[axis])); - } else { - lPlane = criticalPlaneAbove(trueDelinearized(left[axis])); - rPlane = criticalPlaneBelow(trueDelinearized(right[axis])); - } - for (int i = 0; i < 8; i++) { - if (Math.abs(rPlane - lPlane) <= 1) { - break; - } else { - int mPlane = (int) Math.floor((lPlane + rPlane) / 2.0); - double midPlaneCoordinate = CRITICAL_PLANES[mPlane]; - double[] mid = setCoordinate(left, midPlaneCoordinate, right, axis); - double midHue = hueOf(mid); - if (areInCyclicOrder(leftHue, targetHue, midHue)) { - right = mid; - rPlane = mPlane; - } else { - left = mid; - leftHue = midHue; - lPlane = mPlane; - } - } - } - } - } - return midpoint(left, right); - } - - static double inverseChromaticAdaptation(double adapted) { - double adaptedAbs = Math.abs(adapted); - double base = Math.max(0, 27.13 * adaptedAbs / (400.0 - adaptedAbs)); - return MathUtils.signum(adapted) * Math.pow(base, 1.0 / 0.42); - } - - /** - * Finds a color with the given hue, chroma, and Y. - * - * @param hueRadians The desired hue in radians. - * @param chroma The desired chroma. - * @param y The desired Y. - * @return The desired color as a hexadecimal integer, if found; 0 otherwise. - */ - static int findResultByJ(double hueRadians, double chroma, double y) { - // Initial estimate of j. - double j = Math.sqrt(y) * 11.0; - // =========================================================== - // Operations inlined from Cam16 to avoid repeated calculation - // =========================================================== - ViewingConditions viewingConditions = ViewingConditions.DEFAULT; - double tInnerCoeff = 1 / Math.pow(1.64 - Math.pow(0.29, viewingConditions.getN()), 0.73); - double eHue = 0.25 * (Math.cos(hueRadians + 2.0) + 3.8); - double p1 = eHue * (50000.0 / 13.0) * viewingConditions.getNc() * viewingConditions.getNcb(); - double hSin = Math.sin(hueRadians); - double hCos = Math.cos(hueRadians); - for (int iterationRound = 0; iterationRound < 5; iterationRound++) { - // =========================================================== - // Operations inlined from Cam16 to avoid repeated calculation - // =========================================================== - double jNormalized = j / 100.0; - double alpha = chroma == 0.0 || j == 0.0 ? 0.0 : chroma / Math.sqrt(jNormalized); - double t = Math.pow(alpha * tInnerCoeff, 1.0 / 0.9); - double ac = - viewingConditions.getAw() - * Math.pow(jNormalized, 1.0 / viewingConditions.getC() / viewingConditions.getZ()); - double p2 = ac / viewingConditions.getNbb(); - double gamma = 23.0 * (p2 + 0.305) * t / (23.0 * p1 + 11 * t * hCos + 108.0 * t * hSin); - double a = gamma * hCos; - double b = gamma * hSin; - double rA = (460.0 * p2 + 451.0 * a + 288.0 * b) / 1403.0; - double gA = (460.0 * p2 - 891.0 * a - 261.0 * b) / 1403.0; - double bA = (460.0 * p2 - 220.0 * a - 6300.0 * b) / 1403.0; - double rCScaled = inverseChromaticAdaptation(rA); - double gCScaled = inverseChromaticAdaptation(gA); - double bCScaled = inverseChromaticAdaptation(bA); - double[] linrgb = - MathUtils.matrixMultiply( - new double[] {rCScaled, gCScaled, bCScaled}, LINRGB_FROM_SCALED_DISCOUNT); - // =========================================================== - // Operations inlined from Cam16 to avoid repeated calculation - // =========================================================== - if (linrgb[0] < 0 || linrgb[1] < 0 || linrgb[2] < 0) { - return 0; - } - double kR = Y_FROM_LINRGB[0]; - double kG = Y_FROM_LINRGB[1]; - double kB = Y_FROM_LINRGB[2]; - double fnj = kR * linrgb[0] + kG * linrgb[1] + kB * linrgb[2]; - if (fnj <= 0) { - return 0; - } - if (iterationRound == 4 || Math.abs(fnj - y) < 0.002) { - if (linrgb[0] > 100.01 || linrgb[1] > 100.01 || linrgb[2] > 100.01) { - return 0; - } - return ColorUtils.argbFromLinrgb(linrgb); - } - // Iterates with Newton method, - // Using 2 * fn(j) / j as the approximation of fn'(j) - j = j - (fnj - y) * j / (2 * fnj); - } - return 0; - } - - /** - * Finds an sRGB color with the given hue, chroma, and L*, if possible. - * - * @param hueDegrees The desired hue, in degrees. - * @param chroma The desired chroma. - * @param lstar The desired L*. - * @return A hexadecimal representing the sRGB color. The color has sufficiently close hue, - * chroma, and L* to the desired values, if possible; otherwise, the hue and L* will be - * sufficiently close, and chroma will be maximized. - */ - public static int solveToInt(double hueDegrees, double chroma, double lstar) { - if (chroma < 0.0001 || lstar < 0.0001 || lstar > 99.9999) { - return ColorUtils.argbFromLstar(lstar); - } - hueDegrees = MathUtils.sanitizeDegreesDouble(hueDegrees); - double hueRadians = hueDegrees / 180 * Math.PI; - double y = ColorUtils.yFromLstar(lstar); - int exactAnswer = findResultByJ(hueRadians, chroma, y); - if (exactAnswer != 0) { - return exactAnswer; - } - double[] linrgb = bisectToLimit(y, hueRadians); - return ColorUtils.argbFromLinrgb(linrgb); - } - - /** - * Finds an sRGB color with the given hue, chroma, and L*, if possible. - * - * @param hueDegrees The desired hue, in degrees. - * @param chroma The desired chroma. - * @param lstar The desired L*. - * @return An CAM16 object representing the sRGB color. The color has sufficiently close hue, - * chroma, and L* to the desired values, if possible; otherwise, the hue and L* will be - * sufficiently close, and chroma will be maximized. - */ - public static Cam16 solveToCam(double hueDegrees, double chroma, double lstar) { - return Cam16.fromInt(solveToInt(hueDegrees, chroma, lstar)); - } -} - diff --git a/material-color-utilities/src/main/java/hct/ViewingConditions.java b/material-color-utilities/src/main/java/hct/ViewingConditions.java deleted file mode 100644 index 93a3a6bb5..000000000 --- a/material-color-utilities/src/main/java/hct/ViewingConditions.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package hct; - -import utils.ColorUtils; -import utils.MathUtils; - -/** - * In traditional color spaces, a color can be identified solely by the observer's measurement of - * the color. Color appearance models such as CAM16 also use information about the environment where - * the color was observed, known as the viewing conditions. - * - *
For example, white under the traditional assumption of a midday sun white point is accurately - * measured as a slightly chromatic blue by CAM16. (roughly, hue 203, chroma 3, lightness 100) - * - *
This class caches intermediate values of the CAM16 conversion process that depend only on
- * viewing conditions, enabling speed ups.
- */
-public final class ViewingConditions {
- /** sRGB-like viewing conditions. */
- public static final ViewingConditions DEFAULT =
- ViewingConditions.make(
- new double[] {
- ColorUtils.whitePointD65()[0],
- ColorUtils.whitePointD65()[1],
- ColorUtils.whitePointD65()[2]
- },
- (200.0 / Math.PI * ColorUtils.yFromLstar(50.0) / 100.f),
- 50.0,
- 2.0,
- false);
-
- private final double aw;
- private final double nbb;
- private final double ncb;
- private final double c;
- private final double nc;
- private final double n;
- private final double[] rgbD;
- private final double fl;
- private final double flRoot;
- private final double z;
-
- public double getAw() {
- return aw;
- }
-
- public double getN() {
- return n;
- }
-
- public double getNbb() {
- return nbb;
- }
-
- double getNcb() {
- return ncb;
- }
-
- double getC() {
- return c;
- }
-
- double getNc() {
- return nc;
- }
-
- public double[] getRgbD() {
- return rgbD;
- }
-
- double getFl() {
- return fl;
- }
-
- public double getFlRoot() {
- return flRoot;
- }
-
- double getZ() {
- return z;
- }
-
- /**
- * Create ViewingConditions from a simple, physically relevant, set of parameters.
- *
- * @param whitePoint White point, measured in the XYZ color space. default = D65, or sunny day
- * afternoon
- * @param adaptingLuminance The luminance of the adapting field. Informally, how bright it is in
- * the room where the color is viewed. Can be calculated from lux by multiplying lux by
- * 0.0586. default = 11.72, or 200 lux.
- * @param backgroundLstar The lightness of the area surrounding the color. measured by L* in
- * L*a*b*. default = 50.0
- * @param surround A general description of the lighting surrounding the color. 0 is pitch dark,
- * like watching a movie in a theater. 1.0 is a dimly light room, like watching TV at home at
- * night. 2.0 means there is no difference between the lighting on the color and around it.
- * default = 2.0
- * @param discountingIlluminant Whether the eye accounts for the tint of the ambient lighting,
- * such as knowing an apple is still red in green light. default = false, the eye does not
- * perform this process on self-luminous objects like displays.
- */
- static ViewingConditions make(
- double[] whitePoint,
- double adaptingLuminance,
- double backgroundLstar,
- double surround,
- boolean discountingIlluminant) {
- // Transform white point XYZ to 'cone'/'rgb' responses
- double[][] matrix = Cam16.XYZ_TO_CAM16RGB;
- double[] xyz = whitePoint;
- double rW = (xyz[0] * matrix[0][0]) + (xyz[1] * matrix[0][1]) + (xyz[2] * matrix[0][2]);
- double gW = (xyz[0] * matrix[1][0]) + (xyz[1] * matrix[1][1]) + (xyz[2] * matrix[1][2]);
- double bW = (xyz[0] * matrix[2][0]) + (xyz[1] * matrix[2][1]) + (xyz[2] * matrix[2][2]);
- double f = 0.8 + (surround / 10.0);
- double c =
- (f >= 0.9)
- ? MathUtils.lerp(0.59, 0.69, ((f - 0.9) * 10.0))
- : MathUtils.lerp(0.525, 0.59, ((f - 0.8) * 10.0));
- double d =
- discountingIlluminant
- ? 1.0
- : f * (1.0 - ((1.0 / 3.6) * Math.exp((-adaptingLuminance - 42.0) / 92.0)));
- d = MathUtils.clampDouble(0.0, 1.0, d);
- double nc = f;
- double[] rgbD =
- new double[] {
- d * (100.0 / rW) + 1.0 - d, d * (100.0 / gW) + 1.0 - d, d * (100.0 / bW) + 1.0 - d
- };
- double k = 1.0 / (5.0 * adaptingLuminance + 1.0);
- double k4 = k * k * k * k;
- double k4F = 1.0 - k4;
- double fl = (k4 * adaptingLuminance) + (0.1 * k4F * k4F * Math.cbrt(5.0 * adaptingLuminance));
- double n = (ColorUtils.yFromLstar(backgroundLstar) / whitePoint[1]);
- double z = 1.48 + Math.sqrt(n);
- double nbb = 0.725 / Math.pow(n, 0.2);
- double ncb = nbb;
- double[] rgbAFactors =
- new double[] {
- Math.pow(fl * rgbD[0] * rW / 100.0, 0.42),
- Math.pow(fl * rgbD[1] * gW / 100.0, 0.42),
- Math.pow(fl * rgbD[2] * bW / 100.0, 0.42)
- };
-
- double[] rgbA =
- new double[] {
- (400.0 * rgbAFactors[0]) / (rgbAFactors[0] + 27.13),
- (400.0 * rgbAFactors[1]) / (rgbAFactors[1] + 27.13),
- (400.0 * rgbAFactors[2]) / (rgbAFactors[2] + 27.13)
- };
-
- double aw = ((2.0 * rgbA[0]) + rgbA[1] + (0.05 * rgbA[2])) * nbb;
- return new ViewingConditions(n, aw, nbb, ncb, c, nc, rgbD, fl, Math.pow(fl, 0.25), z);
- }
-
- /**
- * Parameters are intermediate values of the CAM16 conversion process. Their names are shorthand
- * for technical color science terminology, this class would not benefit from documenting them
- * individually. A brief overview is available in the CAM16 specification, and a complete overview
- * requires a color science textbook, such as Fairchild's Color Appearance Models.
- */
- private ViewingConditions(
- double n,
- double aw,
- double nbb,
- double ncb,
- double c,
- double nc,
- double[] rgbD,
- double fl,
- double flRoot,
- double z) {
- this.n = n;
- this.aw = aw;
- this.nbb = nbb;
- this.ncb = ncb;
- this.c = c;
- this.nc = nc;
- this.rgbD = rgbD;
- this.fl = fl;
- this.flRoot = flRoot;
- this.z = z;
- }
-}
diff --git a/material-color-utilities/src/main/java/palettes/CorePalette.java b/material-color-utilities/src/main/java/palettes/CorePalette.java
deleted file mode 100644
index 9a47ee79e..000000000
--- a/material-color-utilities/src/main/java/palettes/CorePalette.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package palettes;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import hct.Hct;
-
-/**
- * An intermediate concept between the key color for a UI theme, and a full color scheme. 5 sets of
- * tones are generated, all except one use the same hue as the key color, and all vary in chroma.
- */
-public final class CorePalette {
- public TonalPalette a1;
- public TonalPalette a2;
- public TonalPalette a3;
- public TonalPalette n1;
- public TonalPalette n2;
- public TonalPalette error;
-
- /**
- * Create key tones from a color.
- *
- * @param argb ARGB representation of a color
- */
- public static CorePalette of(int argb) {
- return new CorePalette(argb, false);
- }
-
- /**
- * Create content key tones from a color.
- *
- * @param argb ARGB representation of a color
- */
- public static CorePalette contentOf(int argb) {
- return new CorePalette(argb, true);
- }
-
- private CorePalette(int argb, boolean isContent) {
- Hct hct = Hct.fromInt(argb);
- double hue = hct.getHue();
- double chroma = hct.getChroma();
- if (isContent) {
- this.a1 = TonalPalette.fromHueAndChroma(hue, chroma);
- this.a2 = TonalPalette.fromHueAndChroma(hue, chroma / 3.);
- this.a3 = TonalPalette.fromHueAndChroma(hue + 60., chroma / 2.);
- this.n1 = TonalPalette.fromHueAndChroma(hue, min(chroma / 12., 4.));
- this.n2 = TonalPalette.fromHueAndChroma(hue, min(chroma / 6., 8.));
- } else {
- this.a1 = TonalPalette.fromHueAndChroma(hue, max(48., chroma));
- this.a2 = TonalPalette.fromHueAndChroma(hue, 16.);
- this.a3 = TonalPalette.fromHueAndChroma(hue + 60., 24.);
- this.n1 = TonalPalette.fromHueAndChroma(hue, 4.);
- this.n2 = TonalPalette.fromHueAndChroma(hue, 8.);
- }
- this.error = TonalPalette.fromHueAndChroma(25, 84.);
- }
-}
diff --git a/material-color-utilities/src/main/java/palettes/TonalPalette.java b/material-color-utilities/src/main/java/palettes/TonalPalette.java
deleted file mode 100644
index fdcdd2de9..000000000
--- a/material-color-utilities/src/main/java/palettes/TonalPalette.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package palettes;
-
-import hct.Hct;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A convenience class for retrieving colors that are constant in hue and chroma, but vary in tone.
- */
-public final class TonalPalette {
- Map This relatively minor optimization is helpful because this method is called at least once
- * for each pixel in an image.
- */
- @Override
- public double distance(double[] one, double[] two) {
- double dL = (one[0] - two[0]);
- double dA = (one[1] - two[1]);
- double dB = (one[2] - two[2]);
- return (dL * dL + dA * dA + dB * dB);
- }
-}
diff --git a/material-color-utilities/src/main/java/quantize/Quantizer.java b/material-color-utilities/src/main/java/quantize/Quantizer.java
deleted file mode 100644
index ab2a0585b..000000000
--- a/material-color-utilities/src/main/java/quantize/Quantizer.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package quantize;
-
-interface Quantizer {
- public QuantizerResult quantize(int[] pixels, int maxColors);
-}
diff --git a/material-color-utilities/src/main/java/quantize/QuantizerCelebi.java b/material-color-utilities/src/main/java/quantize/QuantizerCelebi.java
deleted file mode 100644
index d0520fe2f..000000000
--- a/material-color-utilities/src/main/java/quantize/QuantizerCelebi.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package quantize;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * An image quantizer that improves on the quality of a standard K-Means algorithm by setting the
- * K-Means initial state to the output of a Wu quantizer, instead of random centroids. Improves on
- * speed by several optimizations, as implemented in Wsmeans, or Weighted Square Means, K-Means with
- * those optimizations.
- *
- * This algorithm was designed by M. Emre Celebi, and was found in their 2011 paper, Improving
- * the Performance of K-Means for Color Quantization. https://arxiv.org/abs/1101.0395
- */
-public final class QuantizerCelebi {
- private QuantizerCelebi() {}
-
- /**
- * Reduce the number of colors needed to represented the input, minimizing the difference between
- * the original image and the recolored image.
- *
- * @param pixels Colors in ARGB format.
- * @param maxColors The number of colors to divide the image into. A lower number of colors may be
- * returned.
- * @return Map with keys of colors in ARGB format, and values of number of pixels in the original
- * image that correspond to the color in the quantized image.
- */
- public static Map Wsmeans stands for Weighted Square Means.
- *
- * This algorithm was designed by M. Emre Celebi, and was found in their 2011 paper, Improving
- * the Performance of K-Means for Color Quantization. https://arxiv.org/abs/1101.0395
- */
-public final class QuantizerWsmeans {
- private QuantizerWsmeans() {}
-
- private static final class Distance implements Comparable The algorithm was described by Xiaolin Wu in Graphic Gems II, published in 1991.
- */
-public final class QuantizerWu implements Quantizer {
- int[] weights;
- int[] momentsR;
- int[] momentsG;
- int[] momentsB;
- double[] moments;
- Box[] cubes;
-
- // A histogram of all the input colors is constructed. It has the shape of a
- // cube. The cube would be too large if it contained all 16 million colors:
- // historical best practice is to use 5 bits of the 8 in each channel,
- // reducing the histogram to a volume of ~32,000.
- private static final int INDEX_BITS = 5;
- private static final int INDEX_COUNT = 33; // ((1 << INDEX_BITS) + 1)
- private static final int TOTAL_SIZE = 35937; // INDEX_COUNT * INDEX_COUNT * INDEX_COUNT
-
- @Override
- public QuantizerResult quantize(int[] pixels, int colorCount) {
- QuantizerResult mapResult = new QuantizerMap().quantize(pixels, colorCount);
- constructHistogram(mapResult.colorToCount);
- createMoments();
- CreateBoxesResult createBoxesResult = createBoxes(colorCount);
- List Enables use of a high cluster count for image quantization, thus ensuring colors aren't
- * muddied, while curating the high cluster count to a much smaller number of appropriate choices.
- */
-public final class Score {
- private static final double CUTOFF_CHROMA = 15.;
- private static final double CUTOFF_EXCITED_PROPORTION = 0.01;
- private static final double CUTOFF_TONE = 10.;
- private static final double TARGET_CHROMA = 48.;
- private static final double WEIGHT_PROPORTION = 0.7;
- private static final double WEIGHT_CHROMA_ABOVE = 0.3;
- private static final double WEIGHT_CHROMA_BELOW = 0.1;
-
- private Score() {}
-
- /**
- * Given a map with keys of colors and values of how often the color appears, rank the colors
- * based on suitability for being used for a UI theme.
- *
- * @param colorsToPopulation map with keys of colors and values of how often the color appears,
- * usually from a source image.
- * @return Colors sorted by suitability for a UI theme. The most suitable color is the first item,
- * the least suitable is the last. There will always be at least one color returned. If all
- * the input colors were not suitable for a theme, a default fallback color will be provided,
- * Google Blue.
- */
- public static List Utility methods for color science constants and color space conversions that aren't HCT or
- * CAM16.
- */
-public class ColorUtils {
- private ColorUtils() {}
-
- static final double[][] SRGB_TO_XYZ =
- new double[][] {
- new double[] {0.41233895, 0.35762064, 0.18051042},
- new double[] {0.2126, 0.7152, 0.0722},
- new double[] {0.01932141, 0.11916382, 0.95034478},
- };
-
- static final double[][] XYZ_TO_SRGB =
- new double[][] {
- new double[] {
- 3.2413774792388685, -1.5376652402851851, -0.49885366846268053,
- },
- new double[] {
- -0.9691452513005321, 1.8758853451067872, 0.04156585616912061,
- },
- new double[] {
- 0.05562093689691305, -0.20395524564742123, 1.0571799111220335,
- },
- };
-
- static final double[] WHITE_POINT_D65 = new double[] {95.047, 100.0, 108.883};
-
- /** Converts a color from RGB components to ARGB format. */
- public static int argbFromRgb(int red, int green, int blue) {
- return (255 << 24) | ((red & 255) << 16) | ((green & 255) << 8) | (blue & 255);
- }
-
- /** Converts a color from linear RGB components to ARGB format. */
- public static int argbFromLinrgb(double[] linrgb) {
- int r = delinearized(linrgb[0]);
- int g = delinearized(linrgb[1]);
- int b = delinearized(linrgb[2]);
- return argbFromRgb(r, g, b);
- }
-
- /** Returns the alpha component of a color in ARGB format. */
- public static int alphaFromArgb(int argb) {
- return (argb >> 24) & 255;
- }
-
- /** Returns the red component of a color in ARGB format. */
- public static int redFromArgb(int argb) {
- return (argb >> 16) & 255;
- }
-
- /** Returns the green component of a color in ARGB format. */
- public static int greenFromArgb(int argb) {
- return (argb >> 8) & 255;
- }
-
- /** Returns the blue component of a color in ARGB format. */
- public static int blueFromArgb(int argb) {
- return argb & 255;
- }
-
- /** Returns whether a color in ARGB format is opaque. */
- public static boolean isOpaque(int argb) {
- return alphaFromArgb(argb) >= 255;
- }
-
- /** Converts a color from ARGB to XYZ. */
- public static int argbFromXyz(double x, double y, double z) {
- double[][] matrix = XYZ_TO_SRGB;
- double linearR = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z;
- double linearG = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z;
- double linearB = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z;
- int r = delinearized(linearR);
- int g = delinearized(linearG);
- int b = delinearized(linearB);
- return argbFromRgb(r, g, b);
- }
-
- /** Converts a color from XYZ to ARGB. */
- public static double[] xyzFromArgb(int argb) {
- double r = linearized(redFromArgb(argb));
- double g = linearized(greenFromArgb(argb));
- double b = linearized(blueFromArgb(argb));
- return MathUtils.matrixMultiply(new double[] {r, g, b}, SRGB_TO_XYZ);
- }
-
- /** Converts a color represented in Lab color space into an ARGB integer. */
- public static int argbFromLab(double l, double a, double b) {
- double[] whitePoint = WHITE_POINT_D65;
- double fy = (l + 16.0) / 116.0;
- double fx = a / 500.0 + fy;
- double fz = fy - b / 200.0;
- double xNormalized = labInvf(fx);
- double yNormalized = labInvf(fy);
- double zNormalized = labInvf(fz);
- double x = xNormalized * whitePoint[0];
- double y = yNormalized * whitePoint[1];
- double z = zNormalized * whitePoint[2];
- return argbFromXyz(x, y, z);
- }
-
- /**
- * Converts a color from ARGB representation to L*a*b* representation.
- *
- * @param argb the ARGB representation of a color
- * @return a Lab object representing the color
- */
- public static double[] labFromArgb(int argb) {
- double linearR = linearized(redFromArgb(argb));
- double linearG = linearized(greenFromArgb(argb));
- double linearB = linearized(blueFromArgb(argb));
- double[][] matrix = SRGB_TO_XYZ;
- double x = matrix[0][0] * linearR + matrix[0][1] * linearG + matrix[0][2] * linearB;
- double y = matrix[1][0] * linearR + matrix[1][1] * linearG + matrix[1][2] * linearB;
- double z = matrix[2][0] * linearR + matrix[2][1] * linearG + matrix[2][2] * linearB;
- double[] whitePoint = WHITE_POINT_D65;
- double xNormalized = x / whitePoint[0];
- double yNormalized = y / whitePoint[1];
- double zNormalized = z / whitePoint[2];
- double fx = labF(xNormalized);
- double fy = labF(yNormalized);
- double fz = labF(zNormalized);
- double l = 116.0 * fy - 16;
- double a = 500.0 * (fx - fy);
- double b = 200.0 * (fy - fz);
- return new double[] {l, a, b};
- }
-
- /**
- * Converts an L* value to an ARGB representation.
- *
- * @param lstar L* in L*a*b*
- * @return ARGB representation of grayscale color with lightness matching L*
- */
- public static int argbFromLstar(double lstar) {
- double y = yFromLstar(lstar);
- int component = delinearized(y);
- return argbFromRgb(component, component, component);
- }
-
- /**
- * Computes the L* value of a color in ARGB representation.
- *
- * @param argb ARGB representation of a color
- * @return L*, from L*a*b*, coordinate of the color
- */
- public static double lstarFromArgb(int argb) {
- double y = xyzFromArgb(argb)[1];
- return 116.0 * labF(y / 100.0) - 16.0;
- }
-
- /**
- * Converts an L* value to a Y value.
- *
- * L* in L*a*b* and Y in XYZ measure the same quantity, luminance.
- *
- * L* measures perceptual luminance, a linear scale. Y in XYZ measures relative luminance, a
- * logarithmic scale.
- *
- * @param lstar L* in L*a*b*
- * @return Y in XYZ
- */
- public static double yFromLstar(double lstar) {
- return 100.0 * labInvf((lstar + 16.0) / 116.0);
- }
-
- /**
- * Linearizes an RGB component.
- *
- * @param rgbComponent 0 <= rgb_component <= 255, represents R/G/B channel
- * @return 0.0 <= output <= 100.0, color channel converted to linear RGB space
- */
- public static double linearized(int rgbComponent) {
- double normalized = rgbComponent / 255.0;
- if (normalized <= 0.040449936) {
- return normalized / 12.92 * 100.0;
- } else {
- return Math.pow((normalized + 0.055) / 1.055, 2.4) * 100.0;
- }
- }
-
- /**
- * Delinearizes an RGB component.
- *
- * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents linear R/G/B channel
- * @return 0 <= output <= 255, color channel converted to regular RGB space
- */
- public static int delinearized(double rgbComponent) {
- double normalized = rgbComponent / 100.0;
- double delinearized = 0.0;
- if (normalized <= 0.0031308) {
- delinearized = normalized * 12.92;
- } else {
- delinearized = 1.055 * Math.pow(normalized, 1.0 / 2.4) - 0.055;
- }
- return MathUtils.clampInt(0, 255, (int) Math.round(delinearized * 255.0));
- }
-
- /**
- * Returns the standard white point; white on a sunny day.
- *
- * @return The white point
- */
- public static double[] whitePointD65() {
- return WHITE_POINT_D65;
- }
-
- static double labF(double t) {
- double e = 216.0 / 24389.0;
- double kappa = 24389.0 / 27.0;
- if (t > e) {
- return Math.pow(t, 1.0 / 3.0);
- } else {
- return (kappa * t + 16) / 116;
- }
- }
-
- static double labInvf(double ft) {
- double e = 216.0 / 24389.0;
- double kappa = 24389.0 / 27.0;
- double ft3 = ft * ft * ft;
- if (ft3 > e) {
- return ft3;
- } else {
- return (116 * ft - 16) / kappa;
- }
- }
-}
-
diff --git a/material-color-utilities/src/main/java/utils/MathUtils.java b/material-color-utilities/src/main/java/utils/MathUtils.java
deleted file mode 100644
index a1de23497..000000000
--- a/material-color-utilities/src/main/java/utils/MathUtils.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// This file is automatically generated. Do not modify it.
-
-package utils;
-
-/** Utility methods for mathematical operations. */
-public class MathUtils {
- private MathUtils() {}
-
- /**
- * The signum function.
- *
- * @return 1 if num > 0, -1 if num < 0, and 0 if num = 0
- */
- public static int signum(double num) {
- if (num < 0) {
- return -1;
- } else if (num == 0) {
- return 0;
- } else {
- return 1;
- }
- }
-
- /**
- * The linear interpolation function.
- *
- * @return start if amount = 0 and stop if amount = 1
- */
- public static double lerp(double start, double stop, double amount) {
- return (1.0 - amount) * start + amount * stop;
- }
-
- /**
- * Clamps an integer between two integers.
- *
- * @return input when min <= input <= max, and either min or max otherwise.
- */
- public static int clampInt(int min, int max, int input) {
- if (input < min) {
- return min;
- } else if (input > max) {
- return max;
- }
-
- return input;
- }
-
- /**
- * Clamps an integer between two floating-point numbers.
- *
- * @return input when min <= input <= max, and either min or max otherwise.
- */
- public static double clampDouble(double min, double max, double input) {
- if (input < min) {
- return min;
- } else if (input > max) {
- return max;
- }
-
- return input;
- }
-
- /**
- * Sanitizes a degree measure as an integer.
- *
- * @return a degree measure between 0 (inclusive) and 360 (exclusive).
- */
- public static int sanitizeDegreesInt(int degrees) {
- degrees = degrees % 360;
- if (degrees < 0) {
- degrees = degrees + 360;
- }
- return degrees;
- }
-
- /**
- * Sanitizes a degree measure as a floating-point number.
- *
- * @return a degree measure between 0.0 (inclusive) and 360.0 (exclusive).
- */
- public static double sanitizeDegreesDouble(double degrees) {
- degrees = degrees % 360.0;
- if (degrees < 0) {
- degrees = degrees + 360.0;
- }
- return degrees;
- }
-
- /**
- * Sign of direction change needed to travel from one angle to another.
- *
- * For angles that are 180 degrees apart from each other, both directions have the same travel
- * distance, so either direction is shortest. The value 1.0 is returned in this case.
- *
- * @param from The angle travel starts from, in degrees.
- * @param to The angle travel ends at, in degrees.
- * @return -1 if decreasing from leads to the shortest travel distance, 1 if increasing from leads
- * to the shortest travel distance.
- */
- public static double rotationDirection(double from, double to) {
- double increasingDifference = sanitizeDegreesDouble(to - from);
- return increasingDifference <= 180.0 ? 1.0 : -1.0;
- }
-
- /** Distance of two points on a circle, represented using degrees. */
- public static double differenceDegrees(double a, double b) {
- return 180.0 - Math.abs(Math.abs(a - b) - 180.0);
- }
-
- /** Multiplies a 1x3 row vector with a 3x3 matrix. */
- public static double[] matrixMultiply(double[] row, double[][] matrix) {
- double a = row[0] * matrix[0][0] + row[1] * matrix[0][1] + row[2] * matrix[0][2];
- double b = row[0] * matrix[1][0] + row[1] * matrix[1][1] + row[2] * matrix[1][2];
- double c = row[0] * matrix[2][0] + row[1] * matrix[2][1] + row[2] * matrix[2][2];
- return new double[] {a, b, c};
- }
-}
-
diff --git a/material-color-utilities/src/main/java/utils/StringUtils.java b/material-color-utilities/src/main/java/utils/StringUtils.java
deleted file mode 100644
index 75aa5b1b4..000000000
--- a/material-color-utilities/src/main/java/utils/StringUtils.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package utils;
-
-/** Utility methods for string representations of colors. */
-final class StringUtils {
- private StringUtils() {}
-
- /**
- * Hex string representing color, ex. #ff0000 for red.
- *
- * @param argb ARGB representation of a color.
- */
- public static String hexFromArgb(int argb) {
- int red = ColorUtils.redFromArgb(argb);
- int blue = ColorUtils.blueFromArgb(argb);
- int green = ColorUtils.greenFromArgb(argb);
- return String.format("#%02x%02x%02x", red, green, blue);
- }
-}
diff --git a/scripts/analysis/findbugs-results.txt b/scripts/analysis/findbugs-results.txt
index b4f334f26..93e780324 100644
--- a/scripts/analysis/findbugs-results.txt
+++ b/scripts/analysis/findbugs-results.txt
@@ -1 +1 @@
-141
+138
diff --git a/settings.gradle b/settings.gradle
index 794d972f1..bb0692b16 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -19,4 +19,10 @@
*/
include ':app'
-include ':material-color-utilities'
+
+//// uncomment to use local build of common-ui
+//includeBuild('../android-common') {
+// dependencySubstitution {
+// substitute module('com.github.nextcloud.android-common:ui') using project(':ui')
+// }
+//}