File indexing completed on 2024-12-22 04:14:49
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Agata Cacko <tamtamy.tymona@gmail.com> 0003 * SPDX-FileCopyrightText: 2023 Dmitry Kazakov <dimula73@gmail.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 #include "HistogramComputationStrokeStrategy.h" 0008 0009 #include "KoColorSpace.h" 0010 0011 #include "krita_utils.h" 0012 #include "kis_image.h" 0013 #include "kis_sequential_iterator.h" 0014 0015 struct HistogramComputationStrokeStrategy::Private 0016 { 0017 0018 class ProcessData : public KisStrokeJobData 0019 { 0020 public: 0021 ProcessData(QRect rect, int _jobId) 0022 : KisStrokeJobData(CONCURRENT) 0023 , rectToCalculate(rect) 0024 , jobId(_jobId) 0025 {} 0026 0027 QRect rectToCalculate; 0028 int jobId; // id in the list of results 0029 }; 0030 0031 KisImageSP image; 0032 std::vector<HistVector> results; 0033 }; 0034 0035 0036 HistogramComputationStrokeStrategy::HistogramComputationStrokeStrategy(KisImageSP image) 0037 : KisIdleTaskStrokeStrategy(QLatin1String("ComputeHistogram"), kundo2_i18n("Update histogram")) 0038 , m_d(new Private) 0039 { 0040 m_d->image = image; 0041 } 0042 0043 HistogramComputationStrokeStrategy::~HistogramComputationStrokeStrategy() 0044 { 0045 } 0046 0047 void HistogramComputationStrokeStrategy::initStrokeCallback() 0048 { 0049 KisIdleTaskStrokeStrategy::initStrokeCallback(); 0050 0051 QVector<KisStrokeJobData*> jobsData; 0052 int i = 0; 0053 QVector<QRect> tileRects = KritaUtils::splitRectIntoPatches(m_d->image->bounds(), KritaUtils::optimalPatchSize()); 0054 m_d->results.resize(tileRects.size()); 0055 0056 Q_FOREACH (const QRect &tileRectangle, tileRects) { 0057 jobsData << new HistogramComputationStrokeStrategy::Private::ProcessData(tileRectangle, i); 0058 i++; 0059 } 0060 addMutatedJobs(jobsData); 0061 } 0062 0063 void HistogramComputationStrokeStrategy::doStrokeCallback(KisStrokeJobData *data) 0064 { 0065 Private::ProcessData *d_pd = dynamic_cast<Private::ProcessData*>(data); 0066 0067 if (!d_pd) { 0068 KisIdleTaskStrokeStrategy::doStrokeCallback(data); 0069 return; 0070 } 0071 0072 QRect calculate = d_pd->rectToCalculate; 0073 0074 KisPaintDeviceSP m_dev = m_d->image->projection(); 0075 QRect imageBounds = m_d->image->bounds(); 0076 0077 const KoColorSpace *cs = m_dev->colorSpace(); 0078 quint32 channelCount = m_dev->channelCount(); 0079 quint32 pixelSize = m_dev->pixelSize(); 0080 0081 int imageSize = imageBounds.width() * imageBounds.height(); 0082 int nSkip = 1 + (imageSize >> 20); //for speed use about 1M pixels for computing histograms 0083 0084 if (calculate.isEmpty()) 0085 return; 0086 0087 initiateVector(m_d->results[d_pd->jobId], cs); 0088 0089 quint32 toSkip = nSkip; 0090 0091 KisSequentialConstIterator it(m_dev, calculate); 0092 0093 int numConseqPixels = it.nConseqPixels(); 0094 while (it.nextPixels(numConseqPixels)) { 0095 0096 numConseqPixels = it.nConseqPixels(); 0097 const quint8* pixel = it.rawDataConst(); 0098 for (int k = 0; k < numConseqPixels; ++k) { 0099 if (--toSkip == 0) { 0100 for (int chan = 0; chan < (int)channelCount; ++chan) { 0101 m_d->results[d_pd->jobId][chan][cs->scaleToU8(pixel, chan)]++; 0102 } 0103 toSkip = nSkip; 0104 } 0105 pixel += pixelSize; 0106 } 0107 } 0108 } 0109 0110 void HistogramComputationStrokeStrategy::finishStrokeCallback() 0111 { 0112 HistogramData hisData; 0113 hisData.colorSpace = m_d->image->projection()->colorSpace(); 0114 0115 if (m_d->results.size() == 1) { 0116 hisData.bins = m_d->results[0]; 0117 emit computationResultReady(hisData); 0118 } else { 0119 0120 quint32 channelCount = m_d->image->projection()->channelCount(); 0121 0122 initiateVector(hisData.bins, hisData.colorSpace); 0123 0124 for (int chan = 0; chan < (int)channelCount; chan++) { 0125 int bsize = hisData.bins[chan].size(); 0126 0127 for (int bi = 0; bi < bsize; bi++) { 0128 hisData.bins[chan][bi] = 0; 0129 for (int i = 0; i < (int)m_d->results.size(); i++) { 0130 hisData.bins[chan][bi] += m_d->results[i][chan][bi]; 0131 } 0132 } 0133 } 0134 0135 emit computationResultReady(hisData); 0136 } 0137 0138 KisIdleTaskStrokeStrategy::finishStrokeCallback(); 0139 } 0140 0141 void HistogramComputationStrokeStrategy::initiateVector(HistVector &vec, const KoColorSpace *colorSpace) 0142 { 0143 vec.resize(colorSpace->channelCount()); 0144 for (auto &bin : vec) { 0145 bin.resize(std::numeric_limits<quint8>::max() + 1); 0146 } 0147 }