diff --git a/src/main/java/com/others/ColorContrastRatio.java b/src/main/java/com/others/ColorContrastRatio.java new file mode 100644 index 000000000000..c1225913b55b --- /dev/null +++ b/src/main/java/com/others/ColorContrastRatio.java @@ -0,0 +1,71 @@ +package com.others; + +import java.awt.Color; + +/** + * A Java implementation of the official W3 documented procedure + * to calculate contrast ratio between colors on the web. + * + * This is used to calculate the readability of a foreground color + * on top of a background color. + * + * @since 2020-10-15 + * @see Color Contrast Ratio Procedure + */ +public class ColorContrastRatio { + + /** + * Calculates the contrast ratio between two given colors. + * + * @param a Any color, used to get the red, green, and blue values. + * @param b Another color, which will be compared against the first color. + * @return The contrast ratio between the two colors. + */ + public double getContrastRatio(Color a, Color b) { + final double aColorLuminance = getRelativeLuminance(a); + final double bColorLuminance = getRelativeLuminance(b); + + if (aColorLuminance > bColorLuminance) + return (aColorLuminance + 0.05) / (bColorLuminance + 0.05); + else + return (bColorLuminance + 0.05) / (aColorLuminance + 0.05); + } + + /** + * Calculates the relative luminance of a given color. + * + * @param color Any color, used to get the red, green, and blue values. + * @return The relative luminance of the color. + * @see More info on relative luminance. + */ + public double getRelativeLuminance(Color color) { + final double red = getColor(color.getRed()); + final double green = getColor(color.getGreen()); + final double blue = getColor(color.getBlue()); + + return 0.2126 * red + 0.7152 * green + 0.0722 * blue; + } + + /** + * Calculates the final value for a color to be used in the + * relative luminance formula as described in step 1. + * + * @param value The 8-bit representation of a color component value. + * @return Value for the provided color component to be used in the relative luminance formula. + */ + public double getColor(int value) { + final double sRgb = getColorSRgb(value); + return (sRgb <= 0.03928) ? sRgb / 12.92 : Math.pow((sRgb + 0.055) / 1.055, 2.4); + } + + /** + * Calculates the Color sRGB value as denoted in step 1 + * of the procedure document. + * + * @param color8Bit The 8-bit representation of a color component value. + * @return A percentile value of the color component. + */ + private double getColorSRgb(double color8Bit) { + return color8Bit / 255.0; + } +} diff --git a/src/test/java/com/others/ColorContrastRatioTest.java b/src/test/java/com/others/ColorContrastRatioTest.java new file mode 100644 index 000000000000..e9c286793da5 --- /dev/null +++ b/src/test/java/com/others/ColorContrastRatioTest.java @@ -0,0 +1,56 @@ +package com.others; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.awt.Color; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * You can check the examples against another open-source implementation available on GitHub. + * + * @see Online Contrast Ratio + * @see GitHub Repository for Online Contrast Ratio + */ +public class ColorContrastRatioTest { + + private static ColorContrastRatio ccr; + + @BeforeAll + public static void before() { + ccr = new ColorContrastRatio(); + } + + @Test + public void testRelativeLuminance() { + final double expected = 0.12215748057375966; + final double actual = ccr.getRelativeLuminance(new Color(23, 103, 154)); + + assertEquals(expected, actual); + } + + @Test + public void testRelativeLuminance2() { + final double expected = 0.7898468477881603; + final double actual = ccr.getRelativeLuminance(new Color(226, 229, 248)); + + assertEquals(expected, actual); + } + + @Test + public void testColorContrastRatio() { + final double expected = 4.878363954846178; + final double actual = ccr.getContrastRatio(new Color(23, 103, 154), new Color(226, 229, 248)); + + assertEquals(expected, actual); + } + + @Test + public void testColorContrastRatioInverse() { + final double expected = 4.878363954846178; + final double actual = ccr.getContrastRatio(new Color(226, 229, 248), new Color(23, 103, 154)); + + assertEquals(expected, actual); + } +}