From 68fb72311eff595bfa28b710e7529b33432ad708 Mon Sep 17 00:00:00 2001 From: Gaute Lindkvist Date: Fri, 21 Dec 2018 08:50:47 +0100 Subject: [PATCH] #3919 Implement a better threshold check for contrast colors --- .../Application/Tools/RiaColorTools.cpp | 65 +++++++++++++++---- .../Application/Tools/RiaColorTools.h | 13 ++-- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/ApplicationCode/Application/Tools/RiaColorTools.cpp b/ApplicationCode/Application/Tools/RiaColorTools.cpp index 37d08c6072..9e8389348d 100644 --- a/ApplicationCode/Application/Tools/RiaColorTools.cpp +++ b/ApplicationCode/Application/Tools/RiaColorTools.cpp @@ -1,17 +1,18 @@ ///////////////////////////////////////////////////////////////////////////////// // +// Copyright (C) 2018- Equinor ASA // Copyright (C) 2017 Statoil ASA -// +// // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. -// -// See the GNU General Public License at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -21,11 +22,13 @@ #include //-------------------------------------------------------------------------------------------------- -/// +/// Uses W3.org relative luminance calculation taking into account the different luminance of the different colors +/// https://www.w3.org/TR/WCAG20-TECHS/G18.html +/// Luminance is between [0, 1] so anything above 0.5 is considered in the bright half of the spectrum. //-------------------------------------------------------------------------------------------------- bool RiaColorTools::isBrightnessAboveThreshold(cvf::Color3f backgroundColor) { - if (backgroundColor.r() + backgroundColor.g() + backgroundColor.b() > 1.5f) + if (relativeLuminance(backgroundColor) > 0.5) { return true; } @@ -34,7 +37,7 @@ bool RiaColorTools::isBrightnessAboveThreshold(cvf::Color3f backgroundColor) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Color3f RiaColorTools::computeOffsetColor(cvf::Color3f color, float offsetFactor) { @@ -55,13 +58,12 @@ cvf::Color3f RiaColorTools::computeOffsetColor(cvf::Color3f color, float offsetF gridB = color.b() + (1.0f - color.b()) * offsetFactor; } - return cvf::Color3f(cvf::Math::clamp(gridR, 0.0f, 1.0f), - cvf::Math::clamp(gridG, 0.0f, 1.0f), - cvf::Math::clamp(gridB, 0.0f, 1.0f)); + return cvf::Color3f( + cvf::Math::clamp(gridR, 0.0f, 1.0f), cvf::Math::clamp(gridG, 0.0f, 1.0f), cvf::Math::clamp(gridB, 0.0f, 1.0f)); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Color3f RiaColorTools::darkContrastColor() { @@ -69,7 +71,7 @@ cvf::Color3f RiaColorTools::darkContrastColor() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Color3f RiaColorTools::brightContrastColor() { @@ -77,7 +79,7 @@ cvf::Color3f RiaColorTools::brightContrastColor() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Color3f RiaColorTools::constrastColor(cvf::Color3f backgroundColor) { @@ -85,7 +87,7 @@ cvf::Color3f RiaColorTools::constrastColor(cvf::Color3f backgroundColor) { return darkContrastColor(); } - + return brightContrastColor(); } @@ -106,3 +108,38 @@ QColor RiaColorTools::toQColor(cvf::Color4f color) { return toQColor(color.toColor3f(), color.a()); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RiaColorTools::contrastRatio(cvf::Color3f color1, cvf::Color3f color2) +{ + float L1 = relativeLuminance(color1); + float L2 = relativeLuminance(color2); + + float Lmin = std::min(L1, L2); + float Lmax = std::max(L1, L2); + + return (Lmax + 0.05) / (Lmin + 0.05); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RiaColorTools::relativeLuminance(cvf::Color3f backgroundColor) +{ + float R = calculateNonLinearColorValue(backgroundColor.r()); + float G = calculateNonLinearColorValue(backgroundColor.g()); + float B = calculateNonLinearColorValue(backgroundColor.b()); + + double luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B; + return luminance; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RiaColorTools::calculateNonLinearColorValue(float colorFraction) +{ + return colorFraction <= 0.03928 ? colorFraction / 12.92 : std::pow((colorFraction + 0.055) / 1.055, 2.4); +} diff --git a/ApplicationCode/Application/Tools/RiaColorTools.h b/ApplicationCode/Application/Tools/RiaColorTools.h index 8db509194c..cbd15ecf6b 100644 --- a/ApplicationCode/Application/Tools/RiaColorTools.h +++ b/ApplicationCode/Application/Tools/RiaColorTools.h @@ -1,17 +1,18 @@ ///////////////////////////////////////////////////////////////////////////////// // +// Copyright (C) 2018- Equinor ASA // Copyright (C) 2017 Statoil ASA -// +// // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. -// -// See the GNU General Public License at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -38,4 +39,8 @@ public: static cvf::Color3f constrastColor(cvf::Color3f backgroundColor); static QColor toQColor(cvf::Color3f color, float alpha = 1.0f); static QColor toQColor(cvf::Color4f color); + static float contrastRatio(cvf::Color3f color1, cvf::Color3f color2); +private: + static float relativeLuminance(cvf::Color3f backgroundColor); + static float calculateNonLinearColorValue(float colorFraction); };