Krita Source Code Documentation
Loading...
Searching...
No Matches
KisScreentoneGenerator.cpp
Go to the documentation of this file.
1/*
2 * KDE. Krita Project.
3 *
4 * SPDX-FileCopyrightText: 2020 Deif Lou <ginoba@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include <kpluginfactory.h>
10#include <KoUpdater.h>
16#include <kis_selection.h>
17#include <kis_painter.h>
19#include <KoColorProfile.h>
21
29
30KisScreentoneGenerator::KisScreentoneGenerator() : KisGenerator(id(), KoID("basic"), i18n("&Screentone..."))
31{
33}
34
36 const QSize &size,
37 const KisFilterConfigurationSP config,
38 KoUpdater *progressUpdater) const
39{
41
42 const KisScreentoneGeneratorConfigurationSP generatorConfiguration =
44 const_cast<KisFilterConfiguration*>(config.data())
45 );
46
47 return generate(dst, size, generatorConfiguration, progressUpdater);
48}
49
51 const QSize &size,
53 KoUpdater *progressUpdater) const
54{
55 const int equalizationMode = config->equalizationMode();
56
57 if (equalizationMode == KisScreentoneEqualizationMode_TemplateBased) {
58 const KisScreentoneGeneratorTemplate &t = config->getTemplate();
59 if (config->alignToPixelGrid()) {
61 generate(dst, size, config, progressUpdater, sampler);
62 } else {
64 generate(dst, size, config, progressUpdater, sampler);
65 }
66 return;
67 }
68
69 const int pattern = config->pattern();
70 const int shape = config->shape();
71 const int interpolation = config->interpolation();
72
73 {
75
76 if (pattern == KisScreentonePatternType_Dots) {
78 if (interpolation == KisScreentoneInterpolationType_Linear) {
79 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
81 generate(dst, size, config, progressUpdater, sampler);
82 } else {
84 generate(dst, size, config, progressUpdater, sampler);
85 }
86 } else if (interpolation == KisScreentoneInterpolationType_Sinusoidal) {
87 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
89 generate(dst, size, config, progressUpdater, sampler);
90 } else {
92 generate(dst, size, config, progressUpdater, sampler);
93 }
94 }
95 } else if (shape == KisScreentoneShapeType_EllipseDotsLegacy) {
96 if (interpolation == KisScreentoneInterpolationType_Linear) {
97 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
99 generate(dst, size, config, progressUpdater, sampler);
100 } else {
102 generate(dst, size, config, progressUpdater, sampler);
103 }
104 } else if (interpolation == KisScreentoneInterpolationType_Sinusoidal) {
105 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
107 generate(dst, size, config, progressUpdater, sampler);
108 } else {
110 generate(dst, size, config, progressUpdater, sampler);
111 }
112 }
113 } else if (shape == KisScreentoneShapeType_EllipseDots) {
114 if (interpolation == KisScreentoneInterpolationType_Linear) {
115 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
117 generate(dst, size, config, progressUpdater, sampler);
118 } else {
120 generate(dst, size, config, progressUpdater, sampler);
121 }
122 } else if (interpolation == KisScreentoneInterpolationType_Sinusoidal) {
123 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
125 generate(dst, size, config, progressUpdater, sampler);
126 } else {
128 generate(dst, size, config, progressUpdater, sampler);
129 }
130 }
131 } else if (shape == KisScreentoneShapeType_DiamondDots) {
132 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
134 generate(dst, size, config, progressUpdater, sampler);
135 } else {
137 generate(dst, size, config, progressUpdater, sampler);
138 }
139 } else if (shape == KisScreentoneShapeType_SquareDots) {
140 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
142 generate(dst, size, config, progressUpdater, sampler);
143 } else {
145 generate(dst, size, config, progressUpdater, sampler);
146 }
147 }
148 } else if (pattern == KisScreentonePatternType_Lines) {
150 if (interpolation == KisScreentoneInterpolationType_Linear) {
151 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
153 generate(dst, size, config, progressUpdater, sampler);
154 } else {
156 generate(dst, size, config, progressUpdater, sampler);
157 }
158 } else if (interpolation == KisScreentoneInterpolationType_Sinusoidal) {
159 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
161 generate(dst, size, config, progressUpdater, sampler);
162 } else {
164 generate(dst, size, config, progressUpdater, sampler);
165 }
166 }
167 } else if (shape == KisScreentoneShapeType_SineWaveLines) {
168 if (interpolation == KisScreentoneInterpolationType_Linear) {
169 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
171 generate(dst, size, config, progressUpdater, sampler);
172 } else {
174 generate(dst, size, config, progressUpdater, sampler);
175 }
176 } else if (interpolation == KisScreentoneInterpolationType_Sinusoidal) {
177 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
179 generate(dst, size, config, progressUpdater, sampler);
180 } else {
182 generate(dst, size, config, progressUpdater, sampler);
183 }
184 }
185 } else if (shape == KisScreentoneShapeType_TriangularWaveLines) {
186 if (interpolation == KisScreentoneInterpolationType_Linear) {
187 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
189 generate(dst, size, config, progressUpdater, sampler);
190 } else {
192 generate(dst, size, config, progressUpdater, sampler);
193 }
194 } else if (interpolation == KisScreentoneInterpolationType_Sinusoidal) {
195 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
197 generate(dst, size, config, progressUpdater, sampler);
198 } else {
200 generate(dst, size, config, progressUpdater, sampler);
201 }
202 }
203 } else if (shape == KisScreentoneShapeType_SawtoothWaveLines) {
204 if (interpolation == KisScreentoneInterpolationType_Linear) {
205 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
207 generate(dst, size, config, progressUpdater, sampler);
208 } else {
210 generate(dst, size, config, progressUpdater, sampler);
211 }
212 } else if (interpolation == KisScreentoneInterpolationType_Sinusoidal) {
213 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
215 generate(dst, size, config, progressUpdater, sampler);
216 } else {
218 generate(dst, size, config, progressUpdater, sampler);
219 }
220 }
221 } else if (shape == KisScreentoneShapeType_CurtainsLines) {
222 if (interpolation == KisScreentoneInterpolationType_Linear) {
223 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
225 generate(dst, size, config, progressUpdater, sampler);
226 } else {
228 generate(dst, size, config, progressUpdater, sampler);
229 }
230 } else if (interpolation == KisScreentoneInterpolationType_Sinusoidal) {
231 if (equalizationMode == KisScreentoneEqualizationMode_FunctionBased) {
233 generate(dst, size, config, progressUpdater, sampler);
234 } else {
236 generate(dst, size, config, progressUpdater, sampler);
237 }
238 }
239 }
240 }
241 }
242}
243
244template <class Sampler>
246 const QSize &size,
248 KoUpdater *progressUpdater,
249 const Sampler &sampler) const
250{
251 const qreal contrast = config->contrast() / 50.0 - 1.0;
252 const bool useThresholdFunction = qFuzzyCompare(contrast, 1.0);
253
254 if (useThresholdFunction) {
255 const qreal brightness = config->brightness() / 100.0;
256 KisScreentoneBrightnessContrastFunctions::Threshold thresholdFunction(1.0 - brightness);
257 generate(dst, size, config, progressUpdater, sampler, thresholdFunction);
258 } else {
259 const qreal brightness = config->brightness() / 50.0 - 1.0;
260 const bool bypassBrightnessContrast = qFuzzyIsNull(brightness) && qFuzzyIsNull(contrast);
261 if (bypassBrightnessContrast) {
263 generate(dst, size, config, progressUpdater, sampler, brightnessContrastFunction);
264 } else {
265 KisScreentoneBrightnessContrastFunctions::BrightnessContrast brightnessContrastFunction(brightness, contrast);
266 generate(dst, size, config, progressUpdater, sampler, brightnessContrastFunction);
267 }
268 }
269}
270
272{
273 // The updater is null so return false to keep going
274 // with the computations
275 if (!progressUpdater) {
276 return false;
277 }
278
279 if (progressUpdater->interrupted()) {
280 return true;
281 }
282
283 progressUpdater->setProgress(percent);
284 return false;
285}
286
287template <class Sampler, class PostprocessingFunction>
289 const QSize &size,
291 KoUpdater *progressUpdater,
292 const Sampler &sampler,
293 const PostprocessingFunction &postprocessingFunction) const
294{
295 KisPaintDeviceSP device = dst.paintDevice();
296 Q_ASSERT(!device.isNull());
298
299 checkUpdaterInterruptedAndSetPercent(progressUpdater, 0);
300
301 const QRect bounds = QRect(dst.topLeft(), size);
302 const KoColorSpace *colorSpace;
303 if (device->colorSpace()->profile()->isLinear()) {
304 colorSpace = KoColorSpaceRegistry::instance()->rgb8();
305 } else {
306 colorSpace = device->colorSpace();
307 }
308
309 KoColor foregroundColor = config->foregroundColor();
310 KoColor backgroundColor = config->backgroundColor();
311 qreal foregroundOpacity = config->foregroundOpacity() / 100.0;
312 qreal backgroundOpacity = config->backgroundOpacity() / 100.0;
313 foregroundColor.convertTo(colorSpace);
314 backgroundColor.convertTo(colorSpace);
315 foregroundColor.setOpacity(foregroundOpacity);
316 backgroundColor.setOpacity(backgroundOpacity);
317
318 KisPaintDeviceSP foregroundDevice = new KisPaintDevice(colorSpace, "screentone_generator_foreground_paint_device");
319 KisPaintDeviceSP backgroundDevice;
320 if (device->colorSpace()->profile()->isLinear()) {
321 backgroundDevice = new KisPaintDevice(colorSpace, "screentone_generator_background_paint_device");
322 } else {
323 backgroundDevice = device;
324 }
325
326 foregroundDevice->fill(bounds, foregroundColor);
327 checkUpdaterInterruptedAndSetPercent(progressUpdater, 25);
328 backgroundDevice->fill(bounds, backgroundColor);
329 checkUpdaterInterruptedAndSetPercent(progressUpdater, 50);
330
333
334 if (!config->invert()) {
335 while (it.nextPixel()) {
336 qreal v = std::round(sampler(it.x(), it.y()) * 10000.0) / 10000.0;
337 v = qBound(0.0, postprocessingFunction(v), 1.0);
338 *it.rawData() = 255 - static_cast<quint8>(qRound(v * 255.0));
339 }
340 } else {
341 while (it.nextPixel()) {
342 qreal v = std::round(sampler(it.x(), it.y()) * 10000.0) / 10000.0;
343 v = qBound(0.0, postprocessingFunction(v), 1.0);
344 *it.rawData() = static_cast<quint8>(qRound(v * 255.0));
345 }
346 }
347 checkUpdaterInterruptedAndSetPercent(progressUpdater, 25);
348
349 {
350 KisPainter gc(backgroundDevice, selection);
352 gc.bitBlt(bounds.topLeft(), foregroundDevice, bounds);
353 }
354 if (device->colorSpace()->profile()->isLinear()) {
355 KisPainter gc(device);
357 gc.bitBlt(bounds.topLeft(), backgroundDevice, bounds);
358 }
359 checkUpdaterInterruptedAndSetPercent(progressUpdater, 100);
360}
361
366
368{
370 dynamic_cast<KisScreentoneGeneratorConfiguration*>(factoryConfiguration(resourcesInterface).data());
371 config->setDefaults();
372 return config;
373}
374
376{
377 Q_UNUSED(dev);
378 return new KisScreentoneConfigWidget(parent);
379}
qreal v
@ KisScreentoneShapeType_TriangularWaveLines
@ KisScreentoneInterpolationType_Sinusoidal
@ KisScreentoneEqualizationMode_TemplateBased
@ KisScreentoneEqualizationMode_FunctionBased
const QString COMPOSITE_OVER
const QString COMPOSITE_COPY
static KisImageResolutionProxySP identity()
void fill(const QRect &rc, const KoColor &color)
const KoColorSpace * colorSpace() const
KisDefaultBoundsBaseSP defaultBounds() const
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void setCompositeOpId(const KoCompositeOp *op)
bool checkUpdaterInterruptedAndSetPercent(KoUpdater *progressUpdater, int percent) const
KisFilterConfigurationSP defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const override
KisFilterConfigurationSP factoryConfiguration(KisResourcesInterfaceSP resourcesInterface) const override
KisConfigWidget * createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev, bool useForMasks) const override
virtual void generate(KisProcessingInformation dst, const QSize &size, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const override
ALWAYS_INLINE quint8 * rawData()
ALWAYS_INLINE int x() const
ALWAYS_INLINE int y() const
bool isNull() const
virtual const KoColorProfile * profile() const =0
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
Definition KoColor.cpp:136
void setOpacity(quint8 alpha)
Definition KoColor.cpp:333
Definition KoID.h:30
bool interrupted() const
Definition KoUpdater.cpp:54
void setProgress(int percent)
Definition KoUpdater.cpp:38
static bool qFuzzyCompare(half p1, half p2)
static bool qFuzzyIsNull(half h)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define bounds(x, a, b)
void setSupportsPainting(bool v)
KisPixelSelectionSP pixelSelection
virtual bool isLinear() const =0
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())