Krita Source Code Documentation
Loading...
Searching...
No Matches
WGCommonColorsCalculationRunner.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2021 Mathias Wein <lynx.mw+kde@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
8
9/*
10 * NOTE: Implementation is taken from KisCommonColorsRecalculationRunner
11 * from Advanced Color Selector Docker, originally written by Adam Celarek
12 *
13 * It is currently limited to sRGB and is more of a placeholder
14 */
15
16#include <QImage>
17
18#include "kis_image.h"
19#include "KoColor.h"
21
22namespace {
23
25
26class Color
27{
28public:
29 explicit Color(QRgb rgb) : r(qRed(rgb)), g(qGreen(rgb)), b(qBlue(rgb)) {}
30 unsigned char r;
31 unsigned char g;
32 unsigned char b;
33 inline unsigned char operator[](ColorAxis i) const
34 {
35 if(i==RedAxis) return r;
36 if(i==GreenAxis) return g;
37 return b;
38 }
39};
40
41class VBox
42{
44public:
45 explicit VBox(const QList<QRgb> &rgbList)
46 {
47 QList<Color> colorList;
48 for(int i=0; i<rgbList.size(); i++) {
49 colorList.append(Color(rgbList.at(i)));
50 }
51 m_colors = colorList;
52 }
53
54 explicit VBox(const QList<Color> &colorList) : m_colors(colorList) {}
55
56 int population() const { return m_colors.size(); }
57
58 VBox divide()
59 {
60 ColorAxis axis = biggestAxis();
61 Q_ASSERT(axisSize(axis)>=3);
62
63 unsigned char divpos = divPos(axis);
64 QList<Color> newVBoxColors;
65 for(int i=m_colors.size()-1; i>=0; i--) {
66 Color c = m_colors.at(i);
67 if(c[axis]>divpos) {
68 m_colors.removeAt(i);
69 newVBoxColors.append(c);
70 }
71 }
72
73 return VBox(newVBoxColors);
74 }
75
76 QRgb mean() const
77 {
78 int r=0;
79 int g=0;
80 int b=0;
81 for(int i=0;i<m_colors.size(); i++) {
82 r+=(int) m_colors.at(i)[RedAxis];
83 g+=(int) m_colors.at(i)[GreenAxis];
84 b+=(int) m_colors.at(i)[BlueAxis];
85 }
86 int size = m_colors.size();
87 Q_ASSERT(size>0);
88
89 return qRgb(r/size, g/size, b/size);
90 }
91
92 unsigned char axisSize(ColorAxis axis) const
93 {
94 unsigned char valMin = 255;
95 unsigned char valMax = 0;
96 for(int i=0; i<m_colors.size(); i++) {
97 if(m_colors.at(i)[axis]>valMax)
98 valMax=m_colors.at(i)[axis];
99 if(m_colors.at(i)[axis]<valMin)
100 valMin=m_colors.at(i)[axis];
101 }
102 return valMax-valMin;
103 }
104
105 ColorAxis biggestAxis() const
106 {
107 unsigned char sR = axisSize(RedAxis);
108 unsigned char sG = axisSize(GreenAxis);
109 unsigned char sB = axisSize(BlueAxis);
110 if(sR>sG && sR>sB) return RedAxis;
111 if(sG>sR && sG>sB) return GreenAxis;
112 return BlueAxis;
113 }
114
115private:
116// unsigned char divPos(ColorAxis axis) const
117// {
118// QList<unsigned char> values;
119// for(int i=0;i<m_colors.size(); i++) {
120// values.append(m_colors.at(i)[axis]);
121// }
122// std::sort(values.begin(), values.end());
123// return values.at(values.size()*4/5);
124// }
125 unsigned char divPos(ColorAxis axis) const
126 {
127 short min=m_colors.at(0)[axis];
128 short max=m_colors.at(0)[axis];
129 for(int i=0;i<m_colors.size(); i++) {
130 if(min>m_colors.at(i)[axis]) min=m_colors.at(i)[axis];
131 if(max<m_colors.at(i)[axis]) max=m_colors.at(i)[axis];
132 }
133
134 return (min+max)/2;
135 }
136};
137
138} // anonymous namespace
139
141 : m_numColors(numberOfColors)
142 , m_commonColors(colorStore)
143{
144 // TODO: can this be done in the worker thread too?
145 KisPaintDeviceSP device = image->projection();
147
148}
149
151{
153 Q_EMIT sigDone();
154}
155
157{
158 QList<QRgb> colors = getColors();
159
160 VBox startBox(colors);
161 QList<VBox> boxes;
162 boxes.append(startBox);
163
164 while (boxes.size()<m_numColors*3/5 && colors.size()>m_numColors*3/5) {
165 int biggestBox=-1;
166 int biggestBoxPopulation=-1;
167
168 for(int i=0; i<boxes.size(); i++) {
169 if(boxes.at(i).population()>biggestBoxPopulation &&
170 boxes.at(i).axisSize(boxes.at(i).biggestAxis())>=3) {
171 biggestBox=i;
172 biggestBoxPopulation=boxes.at(i).population();
173 }
174 }
175
176 if(biggestBox==-1 || boxes[biggestBox].population()<=3)
177 break;
178 VBox newBox = boxes[biggestBox].divide();
179 boxes.append(newBox);
180 }
181
182
183 while (boxes.size()<m_numColors && colors.size()>m_numColors) {
184 int biggestBox=-1;
185 int biggestBoxAxisSize=-1;
186
187 for(int i=0; i<boxes.size(); i++) {
188 if(boxes.at(i).axisSize(boxes.at(i).biggestAxis())>biggestBoxAxisSize &&
189 boxes.at(i).axisSize(boxes.at(i).biggestAxis())>=3) {
190 biggestBox=i;
191 biggestBoxAxisSize=boxes.at(i).axisSize(boxes.at(i).biggestAxis());
192 }
193 }
194
195 if(biggestBox==-1 || boxes[biggestBox].population()<=3)
196 break;
197 VBox newBox = boxes[biggestBox].divide();
198 boxes.append(newBox);
199 }
200
201 const KoColorSpace* colorSpace = KoColorSpaceRegistry::instance()->rgb8();
202 QVector<KoColor> &colorList = *m_commonColors;
203
204 for(int i=0; i<boxes.size(); i++) {
205 if(boxes.at(i).population()>=1) {
206 colorList.append(KoColor(QColor(boxes.at(i).mean()), colorSpace));
207 }
208 }
209}
210
212{
213 int width = m_imageData.width();
214 int height = m_imageData.height();
215
216 QImage tmpImage;
217 int pixelCount = height*width;
218 if(pixelCount> (1<<16)) {
219 qreal factor = sqrt((1<<16)/(qreal) pixelCount);
220 tmpImage = m_imageData.scaledToWidth(width*factor);
221 }
222 else {
223 tmpImage = m_imageData;
224 }
225 width=tmpImage.width();
226 height=tmpImage.height();
227
228 QSet<QRgb> colorList;
229
230 for (int i=0; i<width; i++) {
231 for (int j=0; j<height; j++) {
232 colorList.insert(tmpImage.pixel(i, j)|qRgba(0,0,0,255));
233 }
234 }
235 return QList<QRgb>(colorList.begin(), colorList.end());
236}
unsigned char operator[](ColorAxis i) const
KisPaintDeviceSP projection() const
QRect bounds() const override
QImage createThumbnail(qint32 maxw, qint32 maxh, QRect rect, qreal oversample=1, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags())
VBox(QList< QRgb > rgbList)
unsigned char divPos(ColorAxis axis) const
unsigned char axisSize(ColorAxis axis) const
QSharedPointer< QVector< KoColor > > m_commonColors
WGCommonColorsCalculationRunner(KisImageSP image, int numberOfColors, QSharedPointer< QVector< KoColor > > colorStore)
unsigned int QRgb
T min(T a, T b, T c)
int size(const Forest< T > &forest)
Definition KisForest.h:1232
constexpr std::enable_if< sizeof...(values)==0, size_t >::type max()
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())