UNPKG

chroma-js

Version:

JavaScript library for color conversions

69 lines (62 loc) 2.1 kB
import Color from '../Color.js'; import mix from '../generator/mix.js'; /** * @license * * The APCA contrast prediction algorithm is based of the formulas published * in the APCA-1.0.98G specification by Myndex. The specification is available at: * https://raw.githubusercontent.com/Myndex/apca-w3/master/images/APCAw3_0.1.17_APCA0.0.98G.svg * * Note that the APCA implementation is still beta, so please update to * future versions of chroma.js when they become available. * * You can read more about the APCA Readability Criterion at * https://readtech.org/ARC/ */ // constants const W_offset = 0.027; const P_in = 0.0005; const P_out = 0.1; const R_scale = 1.14; const B_threshold = 0.022; const B_exp = 1.414; export default (text, bg) => { // parse input colors text = new Color(text); bg = new Color(bg); // if text color has alpha, blend against background if (text.alpha() < 1) { text = mix(bg, text, text.alpha(), 'rgb'); } const l_text = lum(...text.rgb()); const l_bg = lum(...bg.rgb()); // soft clamp black levels const Y_text = l_text >= B_threshold ? l_text : l_text + Math.pow(B_threshold - l_text, B_exp); const Y_bg = l_bg >= B_threshold ? l_bg : l_bg + Math.pow(B_threshold - l_bg, B_exp); // normal polarity (dark text on light background) const S_norm = Math.pow(Y_bg, 0.56) - Math.pow(Y_text, 0.57); // reverse polarity (light text on dark background) const S_rev = Math.pow(Y_bg, 0.65) - Math.pow(Y_text, 0.62); // clamp noise then scale const C = Math.abs(Y_bg - Y_text) < P_in ? 0 : Y_text < Y_bg ? S_norm * R_scale : S_rev * R_scale; // clamp minimum contrast then offset const S_apc = Math.abs(C) < P_out ? 0 : C > 0 ? C - W_offset : C + W_offset; // scale to 100 return S_apc * 100; }; function lum(r, g, b) { return ( 0.2126729 * Math.pow(r / 255, 2.4) + 0.7151522 * Math.pow(g / 255, 2.4) + 0.072175 * Math.pow(b / 255, 2.4) ); }