All Classes Namespaces Functions Variables Enumerations Properties Pages
colorref.cpp
1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2020 Matthew Chiawen Chang
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2 of the License.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 */
17 #include "colorref.h"
18 
19 #include <cmath>
20 #include <QtMath>
21 #include <QDebug>
22 
23 #include "util/colordictionary.h"
24 
25 ColorRef::ColorRef()
26 {
27  color = Qt::green;
28  name = tr("Green");
29 }
30 
31 ColorRef::ColorRef(QColor theColor, QString theName)
32 {
33  color = theColor;
34  name = theName.isNull() ? ColorRef::getDefaultColorName(theColor) : theName;
35 }
36 
37 bool ColorRef::operator==(ColorRef colorRef1)
38 {
39  if ( (color == colorRef1.color) && (name == colorRef1.name) )
40  {
41  return true;
42  }
43  else
44  {
45  return false;
46  }
47 }
48 
49 bool ColorRef::operator!=(ColorRef colorRef1)
50 {
51  if ( (color != colorRef1.color) || (name != colorRef1.name) )
52  {
53  return true;
54  }
55  else
56  {
57  return false;
58  }
59 }
60 
61 QDebug& operator<<(QDebug debug, const ColorRef& colorRef)
62 {
63  debug.nospace() << "ColorRef(" << colorRef.color << " " << colorRef.name <<")";
64  return debug.maybeSpace();
65 }
66 
67 QString ColorRef::getDefaultColorName(const QColor c)
68 {
69  // Separate rgb values for convenience
70  const int r = c.red();
71  const int g = c.green();
72  const int b = c.blue();
73 
74  // Convert RGB to XYZ with D65 white point
75  // (algorithm source: https://www.cs.rit.edu/%7Encs/color/t_convert.html#RGB%20to%20XYZ%20&%20XYZ%20to%20RGB)
76  const qreal x = 0.412453*r + 0.357580*g + 0.180423*b;
77  const qreal y = 0.212671*r + 0.715160*g + 0.072169*b;
78  const qreal z = 0.019334*r + 0.119193*g + 0.950227*b;
79 
80  // Convert XYZ to CEI L*u*v
81  // (algorithm source: https://www.cs.rit.edu/~ncs/color/t_convert.html#XYZ%20to%20CIE%20L*a*b*%20(CIELAB)%20&%20CIELAB%20to%20XYZ)
82  // Helper function for the conversion
83  auto f = [](const double a) { return a > 0.008856 ? std::cbrt(a) : 7.787 * a + 16 / 116; };
84  // XYZ tristimulus values for D65 (taken from: https://en.wikipedia.org/wiki/Illuminant_D65#Definition)
85  const qreal xn = 95.047,
86  yn = 100,
87  zn = 108.883;
88  const qreal l = y / yn > 0.008856 ? 116 * cbrt(y / yn) - 16 : 903.3*y / yn,
89  u = 500 * (f(x / xn) - f(y / yn)),
90  v = 200 * (f(y / yn) - f(z / zn));
91 
92  // Find closest color match in colorDict to the luv values
93  int minLoc = 0;
94  if (u < 0.01 && u > -0.01 && v < 0.01 && v > -0.01)
95  {
96  // The color is grayscale so only compare to gray centroids so there is no 'false hue'
97  qreal minDist = qPow(colorDict[dictSize - 5][0] - l, 2) + qPow(colorDict[dictSize - 5][1] - u, 2) + qPow(colorDict[dictSize - 5][2] - v, 2);
98  for (int i = dictSize - 4; i < dictSize; i++)
99  {
100  qreal curDist = qPow(colorDict[i][0] - l, 2) + qPow(colorDict[i][1] - u, 2) + qPow(colorDict[i][2] - v, 2);
101  if (curDist < minDist)
102  {
103  minDist = curDist;
104  minLoc = i;
105  }
106  }
107  }
108  else
109  {
110  qreal minDist = qPow(colorDict[0][0] - l, 2) + qPow(colorDict[0][1] - u, 2) + qPow(colorDict[0][2] - v, 2);
111  for (int i = 1; i < dictSize; i++)
112  {
113  qreal curDist = qPow(colorDict[i][0] - l, 2) + qPow(colorDict[i][1] - u, 2) + qPow(colorDict[i][2] - v, 2);
114  if (curDist < minDist)
115  {
116  minDist = curDist;
117  minLoc = i;
118  }
119  }
120  }
121  return tr(nameDict[minLoc]);
122 }
123 
QDebug & nospace()
bool isNull() const const
int red() const const
QDebug & maybeSpace()
int green() const const
int blue() const const