-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathcolormapper.cpp
80 lines (70 loc) · 2.94 KB
/
colormapper.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include "controllers/scripting/colormapper.h"
#include <QVariant>
#include <cmath>
#include <cstdint>
#include "util/logger.h"
namespace {
const mixxx::Logger kLogger("ColorMapper");
double colorDistance(QRgb a, QRgb b) {
// This algorithm calculates the distance between two colors. In
// contrast to the L2 norm, this also tries take the human perception
// of colors into account. More accurate algorithms like the CIELAB2000
// Delta-E rely on sophisticated color space conversions and need a lot
// of costly computations. In contrast, this is a low-cost
// approximation and should be sufficiently accurate.
// More details: https://www.compuphase.com/cmetric.htm
long mean_red = (static_cast<long>(qRed(a)) + static_cast<long>(qRed(b))) / 2;
long delta_red = static_cast<long>(qRed(a)) - static_cast<long>(qRed(b));
long delta_green = static_cast<long>(qGreen(a)) - static_cast<long>(qGreen(b));
long delta_blue = static_cast<long>(qBlue(a)) - static_cast<long>(qBlue(b));
return sqrt(
(((512 + mean_red) * delta_red * delta_red) >> 8) +
(4 * delta_green * delta_green) +
(((767 - mean_red) * delta_blue * delta_blue) >> 8));
}
} // namespace
QRgb ColorMapper::getNearestColor(QRgb desiredColor) {
// If desired color is already in cache, use cache entry
const auto iCachedColor = m_cache.constFind(desiredColor);
if (iCachedColor != m_cache.constEnd()) {
const QRgb cachedColor = iCachedColor.value();
DEBUG_ASSERT(m_availableColors.contains(cachedColor));
if (kLogger.traceEnabled()) {
kLogger.trace()
<< "Found cached color"
<< cachedColor
<< "for"
<< desiredColor;
}
return cachedColor;
}
// Color is not cached
auto iNearestColor = m_availableColors.constEnd();
double nearestColorDistance = qInf();
for (auto i = m_availableColors.constBegin(); i != m_availableColors.constEnd(); ++i) {
const QRgb availableColor = i.key();
double distance = colorDistance(desiredColor, availableColor);
if (distance < nearestColorDistance) {
nearestColorDistance = distance;
iNearestColor = i;
}
}
if (iNearestColor != m_availableColors.constEnd()) {
const QRgb nearestColor = iNearestColor.key();
if (kLogger.traceEnabled()) {
kLogger.trace()
<< "Found matching color"
<< nearestColor
<< "for"
<< desiredColor;
}
m_cache.insert(desiredColor, nearestColor);
return nearestColor;
}
DEBUG_ASSERT(m_availableColors.isEmpty());
DEBUG_ASSERT(!"Unreachable: No matching color found");
return desiredColor;
}
QVariant ColorMapper::getValueForNearestColor(QRgb desiredColor) {
return m_availableColors.value(getNearestColor(desiredColor));
}