Krita Source Code Documentation
Loading...
Searching...
No Matches
KisColorSmudgeSampleUtils Namespace Reference

Classes

struct  AveragedSampleWrapper
 
struct  WeightedSampleWrapper
 

Functions

template<class WeightingModeWrapper >
void sampleColor (const QRect &srcRect, qreal sampleRadiusValue, KisColorSmudgeSourceSP sourceDevice, KisFixedPaintDeviceSP tempFixedDevice, KisFixedPaintDeviceSP maskDab, KoColor *resultColor)
 

Function Documentation

◆ sampleColor()

template<class WeightingModeWrapper >
void KisColorSmudgeSampleUtils::sampleColor ( const QRect & srcRect,
qreal sampleRadiusValue,
KisColorSmudgeSourceSP sourceDevice,
KisFixedPaintDeviceSP tempFixedDevice,
KisFixedPaintDeviceSP maskDab,
KoColor * resultColor )

Sample color from srcRect in weighted way

The function samples srcRect in an efficient way. It samples "random" pixels using Halton sequence and waits until the sampled color "converges" to stable value. The sampled area is defined by sampleRadiusValue.

The way of weighting the pixels is defined by WeightingModeWrapper template policy. If WeightedSampleWrapper is used, then the sampled color is weighted by the passed brush mask in maskDab. If AveragedSampleWrapper is used, then maskDab is not used and all sampled pixels are averaged in a uniform way.

Parameters
sampleRadiusValuedefines how many pixels are sampled. When sampleRadiusValue is 0.0, only the central pixel is sampled. When sampleRadiusValue is 1.0, the entire range of srcRect is sampled. If AveragedSampleWrapper is used, then sampleRadiusValue may be increased up to 3.0 to sample outside srcRect.

When WeightedSampleWrapper is used, the sampler may sample more pixels than actually requested by sampleRadiusValue. It may happen if all the pixels in the sample radius area are masked out by maskDab.

Parameters
tempFixedDeviceis a temporary device that may be used by the function for internal purposes.

Definition at line 135 of file KisColorSmudgeSampleUtils.h.

142{
143 WeightingModeWrapper::verifySampleRadiusValue(&sampleRadiusValue);
144
145 KIS_ASSERT_RECOVER_RETURN(*resultColor->colorSpace() == *sourceDevice->colorSpace());
146 KIS_ASSERT_RECOVER_RETURN(*tempFixedDevice->colorSpace() == *sourceDevice->colorSpace());
147
148 const QRect minimalRect = QRect(srcRect.center(), QSize(1,1));
149
150 do {
151 const QRect sampleRect = sampleRadiusValue > 0 ?
152 KisAlgebra2D::blowRect(srcRect, 0.5 * (sampleRadiusValue - 1.0)) | minimalRect :
153 minimalRect;
154
155 tempFixedDevice->setRect(sampleRect);
156 tempFixedDevice->lazyGrowBufferWithoutInitialization();
157
158 const KoColorSpace *cs = tempFixedDevice->colorSpace();
159 const int numPixels = sampleRect.width() * sampleRect.height();
160 sourceDevice->readRect(sampleRect);
161 sourceDevice->readBytes(tempFixedDevice->data(), sampleRect);
162
165
166 QScopedPointer<KoMixColorsOp::Mixer> mixer(cs->mixColorsOp()->createMixer());
167
168 const int minSamples =
169 qMin(numPixels, qMax(64, qRound(0.02 * numPixels)));
170
171 WeightingModeWrapper weightingModeWrapper(mixer.data(),
172 maskDab, srcRect,
173 tempFixedDevice, sampleRect);
174
175 KoColor lastPickedColor(*resultColor);
176
177 for (int i = 0; i < minSamples; i++) {
178 const QPoint pt(hGen.generate(sampleRect.width() - 1),
179 vGen.generate(sampleRect.height() - 1));
180
181 weightingModeWrapper.samplePixel(pt);
182 }
183
184 mixer->computeMixedColor(resultColor->data());
185 lastPickedColor = *resultColor;
186
187 const int batchSize = 16;
188 int numSamplesLeft = numPixels - minSamples;
189
190 while (numSamplesLeft > 0) {
191 const int currentBatchSize = qMin(numSamplesLeft, batchSize);
192 for (int i = 0; i < currentBatchSize; i++) {
193 const QPoint pt(hGen.generate(sampleRect.width() - 1),
194 vGen.generate(sampleRect.height() - 1));
195
196 weightingModeWrapper.samplePixel(pt);
197 }
198
199 mixer->computeMixedColor(resultColor->data());
200
201 const quint8 difference =
202 cs->differenceA(resultColor->data(), lastPickedColor.data());
203
204 if (difference <= 2) break;
205
206 lastPickedColor = *resultColor;
207 numSamplesLeft -= currentBatchSize;
208 }
209
210 if (!weightingModeWrapper.shouldRestartWithBiggerRadius() || sampleRadiusValue >= 1.0) {
211 break;
212 }
213
214 sampleRadiusValue = qMin(1.0, sampleRadiusValue + 0.05);
215
216 } while (1);
217}
a simple class to generate Halton sequence
void setRect(const QRect &rc)
const KoColorSpace * colorSpace() const
virtual quint8 differenceA(const quint8 *src1, const quint8 *src2) const =0
KoMixColorsOp * mixColorsOp
quint8 * data()
Definition KoColor.h:144
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
virtual Mixer * createMixer() const =0
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
Rect blowRect(const Rect &rect, qreal coeff)

References KisAlgebra2D::blowRect(), KisFixedPaintDevice::colorSpace(), KoColor::colorSpace(), KoMixColorsOp::createMixer(), KisFixedPaintDevice::data(), KoColor::data(), KoColorSpace::differenceA(), KisAlgebra2D::HaltonSequenceGenerator::generate(), KIS_ASSERT_RECOVER_RETURN, KisFixedPaintDevice::lazyGrowBufferWithoutInitialization(), KoColorSpace::mixColorsOp, and KisFixedPaintDevice::setRect().