Krita Source Code Documentation
Loading...
Searching...
No Matches
HistogramComputationStrokeStrategy.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2020 Agata Cacko <tamtamy.tymona@gmail.com>
3 * SPDX-FileCopyrightText: 2023 Dmitry Kazakov <dimula73@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
8
9#include "KoColorSpace.h"
10
11#include "krita_utils.h"
12#include "kis_image.h"
14
16{
17
19 {
20 public:
21 ProcessData(QRect rect, int _jobId)
24 , jobId(_jobId)
25 {}
26
28 int jobId; // id in the list of results
29 };
30
32 std::vector<HistVector> results;
33};
34
35
37 : KisIdleTaskStrokeStrategy(QLatin1String("ComputeHistogram"), kundo2_i18n("Update histogram"))
38 , m_d(new Private)
39{
40 m_d->image = image;
41}
42
46
48{
50
52 int i = 0;
54 m_d->results.resize(tileRects.size());
55
56 Q_FOREACH (const QRect &tileRectangle, tileRects) {
57 jobsData << new HistogramComputationStrokeStrategy::Private::ProcessData(tileRectangle, i);
58 i++;
59 }
60 addMutatedJobs(jobsData);
61}
62
64{
65 Private::ProcessData *d_pd = dynamic_cast<Private::ProcessData*>(data);
66
67 if (!d_pd) {
69 return;
70 }
71
72 QRect calculate = d_pd->rectToCalculate;
73
74 KisPaintDeviceSP m_dev = m_d->image->projection();
75 QRect imageBounds = m_d->image->bounds();
76
77 const KoColorSpace *cs = m_dev->colorSpace();
78 quint32 channelCount = m_dev->channelCount();
79 quint32 pixelSize = m_dev->pixelSize();
80
81 int imageSize = imageBounds.width() * imageBounds.height();
82 int nSkip = 1 + (imageSize >> 20); //for speed use about 1M pixels for computing histograms
83
84 if (calculate.isEmpty())
85 return;
86
87 initiateVector(m_d->results[d_pd->jobId], cs);
88
89 quint32 toSkip = nSkip;
90
91 KisSequentialConstIterator it(m_dev, calculate);
92
93 int numConseqPixels = it.nConseqPixels();
94 while (it.nextPixels(numConseqPixels)) {
95
96 numConseqPixels = it.nConseqPixels();
97 const quint8* pixel = it.rawDataConst();
98 for (int k = 0; k < numConseqPixels; ++k) {
99 if (--toSkip == 0) {
100 for (int chan = 0; chan < (int)channelCount; ++chan) {
101 m_d->results[d_pd->jobId][chan][cs->scaleToU8(pixel, chan)]++;
102 }
103 toSkip = nSkip;
104 }
105 pixel += pixelSize;
106 }
107 }
108}
109
111{
112 HistogramData hisData;
113 hisData.colorSpace = m_d->image->projection()->colorSpace();
114
115 if (m_d->results.size() == 1) {
116 hisData.bins = m_d->results[0];
117 Q_EMIT computationResultReady(hisData);
118 } else {
119
120 quint32 channelCount = m_d->image->projection()->channelCount();
121
122 initiateVector(hisData.bins, hisData.colorSpace);
123
124 for (int chan = 0; chan < (int)channelCount; chan++) {
125 int bsize = hisData.bins[chan].size();
126
127 for (int bi = 0; bi < bsize; bi++) {
128 hisData.bins[chan][bi] = 0;
129 for (int i = 0; i < (int)m_d->results.size(); i++) {
130 hisData.bins[chan][bi] += m_d->results[i][chan][bi];
131 }
132 }
133 }
134
135 Q_EMIT computationResultReady(hisData);
136 }
137
139}
140
142{
143 vec.resize(colorSpace->channelCount());
144 for (auto &bin : vec) {
145 bin.resize(std::numeric_limits<quint8>::max() + 1);
146 }
147}
std::vector< std::vector< quint32 > > HistVector
void initiateVector(HistVector &vec, const KoColorSpace *colorSpace)
void computationResultReady(HistogramData data)
void doStrokeCallback(KisStrokeJobData *data) override
quint32 pixelSize() const
quint32 channelCount() const
const KoColorSpace * colorSpace() const
ALWAYS_INLINE const quint8 * rawDataConst() const
virtual void doStrokeCallback(KisStrokeJobData *data)
void addMutatedJobs(const QVector< KisStrokeJobData * > list)
virtual quint8 scaleToU8(const quint8 *srcPixel, qint32 channelPos) const =0
virtual quint32 channelCount() const =0
KUndo2MagicString kundo2_i18n(const char *text)
QVector< QRect > splitRectIntoPatches(const QRect &rc, const QSize &patchSize)
QSize optimalPatchSize()