diff --git a/docs/contrast.md b/docs/contrast.md index 4c392a240..318da8dbf 100644 --- a/docs/contrast.md +++ b/docs/contrast.md @@ -67,7 +67,7 @@ It is commonly used in lighting design, and also to examine small, sharp edged symbols and text on larger, uniformly-colored backgrounds. -> WC = Ymax - Ymin / Ymin +> WC = (Ymax - Ymin) / Ymin Any two colors can be used, and this formula does not care which is the text color and which is the background. @@ -85,7 +85,7 @@ Weber contrast is typically used with printed test charts with positive polarity (black text, white background). The formula thus can be expressed as: -> WCpp = Ybackground - Ytext / Ytext +> WCpp = (Ybackground - Ytext) / Ytext Hwang and Peli used a modified Weber contrast for tablet-based, negative polarity testing (white text on black background), @@ -95,8 +95,20 @@ and wrote: The formula for negative polarity is -> WCnp = Ytext - Ybackground / Ytext +> WCnp = (Ytext - Ybackground) / Ytext +In another paper, Hwang and Peli proposed to add +a fixed luminance to both colors to account for viewing flare: + +> WC = (Ymax - Ymin) / (Ymin + Yambient) + +The value of that offset depends on the viewing conditions. + +```js +let color1 = new Color("p3", [0.9, 0.8, 0.1]); +let color2 = new Color("slategrey"); +let contrast = color1.contrast(color2, {algorithm: "weber", offset: .05}); +``` ## Michelson Contrast @@ -123,6 +135,22 @@ let color2 = new Color("slategrey"); let contrast = color1.contrast(color2, "Michelson"); ``` +## Stevens Contrast + +Stevens contrast is often considered to supersede the Weber contrast. +It is based on powers rather than logarithms. + +> SC = Ymaxexp - Yminexp + +The value of that exponent depends on the viewing conditions. +It is also possible to use an offset to model flare. + +```js +let color1 = new Color("p3", [0.9, 0.8, 0.1]); +let color2 = new Color("slategrey"); +let contrast = color1.contrast(color2, {algorithm: "stevens", exponent: 1 / 3, offset: .0025}); +``` + ## Accessible Perceptual Contrast Algorithm (APCA) APCA is part of a color appearance system to determine _readability contrast_ @@ -209,7 +237,7 @@ _This value is much higher than that in the sRGB standard, which puts white at 80 cd/m2 and black at 0.2cd/m2, a relative luminance boost of 0.0025._ -> WCAG21 = = (Ymax + 0.05) / (Ymin + 0.05) +> WCAG21 = (Ymax + 0.05) / (Ymin + 0.05) Because of it's widespread use, color.js provides this method, mainly to aid comparison. @@ -235,6 +263,8 @@ let contrast = color1.contrast(color2, "WCAG21"); - Alex D. Hwang and Eli Peli (2016) _Positive and negative polarity contrast sensitivity measuring app_. IS&T Int Symp Electron Imaging 2016: 10.2352. [full article](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5481843/) +- Alex D. Hwang and Eli Peli (2016) _New Contrast Metric for Realistic Display Performance Measure._. Dig Tech Pap. 2016: 10.1002. [full article](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5489230/) + - Gordon E. Legge, David H. Parish, Andrew Luebker, and Lee H. Wurm (1990) _Psychophysics of reading. XI. Comparing color contrast and luminance contrast_. Journal of the Optical Society of America vol **7** issue 10 pp. 2002-2010 [https://doi.org/10.1364/JOSAA.7.002002](https://doi.org/10.1364/JOSAA.7.002002) - Gordon E.Legge, Gary S.Rubin, Andrew Luebker (1987) _Psychophysics of reading—V. The role of contrast in normal vision_. Vision Research vol **27**, Issue 7, pp. 1165-1177 [abstract](https://www.sciencedirect.com/science/article/abs/pii/0042698987900289) diff --git a/src/contrast/Stevens.js b/src/contrast/Stevens.js new file mode 100644 index 000000000..70987a198 --- /dev/null +++ b/src/contrast/Stevens.js @@ -0,0 +1,19 @@ +// Stevens contrast +// Symmetric, does not matter which is foreground and which is background +// Viewing conditions can be modified by changing exponent and offset + +import getColor from "../getColor.js"; +import {getLuminance} from "../luminance.js"; + +export default function contrastStevens (color1, color2, {exponent = 1 / 3, offset = .0025} = {}) { + color1 = getColor(color1); + color2 = getColor(color2); + + let Y1 = Math.max(getLuminance(color1), 0) + offset; + let Y2 = Math.max(getLuminance(color2), 0) + offset; + + let J1 = Math.pow(Y1, exponent); + let J2 = Math.pow(Y2, exponent); + + return Math.abs(J1 - J2); +}; diff --git a/src/contrast/Weber.js b/src/contrast/Weber.js index c70cdf50d..f2fd240e9 100644 --- a/src/contrast/Weber.js +++ b/src/contrast/Weber.js @@ -1,7 +1,7 @@ // Weber luminance contrast // The difference between the two luminances divided by the lower luminance // Symmetric, does not matter which is foreground and which is background -// No black level compensation for flare. +// Optional offset for flare contribution import getColor from "../getColor.js"; import {getLuminance} from "../luminance.js"; @@ -12,12 +12,12 @@ import {getLuminance} from "../luminance.js"; // max clamp for the plain Weber const max = 50000; -export default function contrastWeber (color1, color2) { +export default function contrastWeber (color1, color2, {offset = 0} = {}) { color1 = getColor(color1); color2 = getColor(color2); - let Y1 = Math.max(getLuminance(color1), 0); - let Y2 = Math.max(getLuminance(color2), 0); + let Y1 = Math.max(getLuminance(color1), 0) + offset; + let Y2 = Math.max(getLuminance(color2), 0) + offset; if (Y2 > Y1) { [Y1, Y2] = [Y2, Y1]; diff --git a/src/contrast/index.js b/src/contrast/index.js index 5a54c25a8..b30e7e40a 100644 --- a/src/contrast/index.js +++ b/src/contrast/index.js @@ -2,5 +2,6 @@ export {default as contrastWCAG21} from "./WCAG21.js"; export {default as contrastAPCA} from "./APCA.js"; export {default as contrastMichelson} from "./Michelson.js"; export {default as contrastWeber} from "./Weber.js"; +export {default as contrastStevens} from "./Stevens.js"; export {default as contrastLstar} from "./Lstar.js"; export {default as contrastDeltaPhi} from "./deltaPhi.js"; diff --git a/tests/contrast.html b/tests/contrast.html index 04e0c5885..b02c5027a 100644 --- a/tests/contrast.html +++ b/tests/contrast.html @@ -461,6 +461,28 @@
| white | +white | ++ + | +0 | +
| white | +black | ++ + | +20 | +
Same test color pairs as apca-w3 test.
@@ -533,6 +555,92 @@| white | +black | ++ + | +0.8651117590220451 | +
| white | +white | ++ + | +0 | +
| #888 | +#fff | ++ + | +0.37196482640638906 | +
| #fff | +#888 | ++ + | +0.37196482640638906 | +
| #000 | +#aaa | ++ + | +0.6038246032876674 | +
| #aaa | +#000 | ++ + | +0.6038246032876674 | +
| #123 | +#def | ++ + | +0.6837707144018808 | +
| #def | +#123 | ++ + | +0.6837707144018808 | +
| #123 | +#444 | ++ + | +0.13241705354214078 | +
| #444 | +#123 | ++ + | +0.13241705354214078 | +