summary refs log tree commit diff
path: root/src/Utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Utils.cpp')
-rw-r--r--src/Utils.cpp110
1 files changed, 105 insertions, 5 deletions
diff --git a/src/Utils.cpp b/src/Utils.cpp

index 6229d42a..6a5c3491 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp
@@ -383,20 +383,120 @@ utils::linkColor() } QString -utils::generateHexColor(const QString &input) +utils::generateHexColor(const int hash) +{ + QString colour("#"); + for (int i = 0; i < 3; i++) { + int value = (hash >> (i * 8)) & 0xFF; + colour.append(("00" + QString::number(value, 16)).right(2)); + } + // nhlog::ui()->debug("Hex Generated {} -> {}", QString::number(hash).toStdString(), + // colour.toStdString()); + return colour.toUpper(); +} + +int +utils::hashQString(const QString &input) { auto hash = 0; for (int i = 0; i < input.length(); i++) { hash = input.at(i).digitValue() + ((hash << 5) - hash); } + hash *= 13; - QString colour("#"); + + return hash; +} + +QString +utils::generateContrastingHexColor(const QString &input, const QString &background) +{ + nhlog::ui()->debug("Background hex {}", background.toStdString()); + const QColor backgroundCol(background); + const qreal backgroundLum = luminance(background); + + // Create a color for the input + auto hash = hashQString(input); + auto colorHex = generateHexColor(hash); + + // converting to a QColor makes the luminance calc easier. + QColor inputColor = QColor(colorHex); + + // attempt to score both the luminance and the contrast. + // contrast should have a higher precedence, but luminance + // helps dictate how exciting the colors are. + auto colorLum = luminance(inputColor); + auto contrast = computeContrast(colorLum, backgroundLum); + + // If the contrast or luminance don't meet our criteria, + // try again and again until they do. After 10 tries, + // the best-scoring color will be chosen. + int att = 0; + while ((contrast < 5 || (colorLum < 0.05 || colorLum > 0.95)) && ++att < 10) { + hash = hashQString(input) + ((hash << 2) * 13); + auto newHex = generateHexColor(hash); + inputColor.setNamedColor(newHex); + auto tmpLum = luminance(inputColor); + auto tmpContrast = computeContrast(tmpLum, backgroundLum); + + // Prioritize contrast over luminance + // If both values are better, it's a no brainer. + if (tmpContrast > contrast && (tmpLum > 0.05 && tmpLum < 0.95)) { + contrast = tmpContrast; + colorHex = newHex; + colorLum = tmpLum; + } + // Otherwise, if we still can get a more + // vibrant color and have met our contrast + // threshold, pick the more vibrant color, + // even if contrast will drop somewhat. + // choosing 50% luminance as ideal. + else if ((qAbs(tmpLum - 0.50) < qAbs(colorLum - 0.50)) && tmpContrast >= 5) { + contrast = tmpContrast; + colorHex = newHex; + colorLum = tmpLum; + } + // Otherwise, just take the better contrast. + else if (tmpContrast > contrast) { + contrast = tmpContrast; + colorHex = newHex; + colorLum = tmpLum; + } + } + + nhlog::ui()->debug("Hex Generated for {}: [hex: {}, contrast: {}, luminance: {}]", + input.toStdString(), + colorHex.toStdString(), + QString::number(contrast).toStdString(), + QString::number(colorLum).toStdString()); + return colorHex; +} + +qreal +utils::computeContrast(const qreal &one, const qreal &two) +{ + auto ratio = (one + 0.05) / (two + 0.05); + + if (two > one) { + ratio = 1 / ratio; + } + + return ratio; +} + +qreal +utils::luminance(const QColor &col) +{ + int colRgb[3] = {col.red(), col.green(), col.blue()}; + qreal lumRgb[3]; + for (int i = 0; i < 3; i++) { - int value = (hash >> (i * 8)) & 0xFF; - colour.append(("00" + QString::number(value, 16)).right(2)); + qreal v = colRgb[i] / 255.0; + v <= 0.03928 ? lumRgb[i] = v / 12.92 : lumRgb[i] = qPow((v + 0.055) / 1.055, 2.4); } - return colour; + + return lumRgb[0] * 0.2126 + lumRgb[1] * 0.7152 + lumRgb[2] * 0.0722; } void