Krita Source Code Documentation
Loading...
Searching...
No Matches
KisMaskingBrushCompositeOp.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
3 * SPDX-FileCopyrightText: 2021 Deif Lou <ginoba@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#ifndef KISMASKINGBRUSHCOMPOSITEOP_H
9#define KISMASKINGBRUSHCOMPOSITEOP_H
10
11#include <type_traits>
12
13#ifdef HAVE_OPENEXR
14#include "half.h"
15#endif
16
17#include <KoColorSpaceTraits.h>
19#include <KoColorSpaceMaths.h>
21#include <kritaui_export.h>
22
24
42
44{
45
46template <typename channels_type>
48{
49 const channels_type strength;
51 : strength(KoColorSpaceMaths<qreal, channels_type>::scaleToA(strength))
52 {}
53};
54
55template <typename channels_type, int composite_function, bool use_strength, bool use_soft_texturing>
57
58template <typename channels_type>
59struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_MULT, false, false>
60{
61 channels_type apply(channels_type src, channels_type dst)
62 {
63 return cfMultiply(src, dst);
64 }
65};
66
67template <typename channels_type>
68struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_MULT, true, false>
69 : public StrengthCompositeFunctionBase<channels_type>
70{
71 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
72
73 channels_type apply(channels_type src, channels_type dst)
74 {
76 }
77};
78
79template <typename channels_type>
80struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_MULT, true, true>
81 : public StrengthCompositeFunctionBase<channels_type>
82{
83 const channels_type invertedStrength;
84
85 CompositeFunction(qreal strength)
86 : StrengthCompositeFunctionBase<channels_type>(strength)
87 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
88 {}
89
90 channels_type apply(channels_type src, channels_type dst)
91 {
92 return Arithmetic::mul(Arithmetic::unionShapeOpacity(src, invertedStrength), dst);
93 }
94};
95
96template <typename channels_type>
97struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_DARKEN, false, false>
98{
99 channels_type apply(channels_type src, channels_type dst)
100 {
101 return cfDarkenOnly(src, dst);
102 }
103};
104
105template <typename channels_type>
106struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_DARKEN, true, false>
107 : public StrengthCompositeFunctionBase<channels_type>
108{
109 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
110
111 channels_type apply(channels_type src, channels_type dst)
112 {
114 }
115};
116
117template <typename channels_type>
119 : public StrengthCompositeFunctionBase<channels_type>
120{
121 const channels_type invertedStrength;
122
123 CompositeFunction(qreal strength)
124 : StrengthCompositeFunctionBase<channels_type>(strength)
125 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
126 {}
127
128 channels_type apply(channels_type src, channels_type dst)
129 {
130 return cfDarkenOnly(Arithmetic::unionShapeOpacity(src, invertedStrength), dst);
131 }
132};
133
134template <typename channels_type>
135struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_OVERLAY, false, false>
136{
137 channels_type apply(channels_type src, channels_type dst)
138 {
140 }
141};
142
143template <typename channels_type>
145 : public StrengthCompositeFunctionBase<channels_type>
146{
147 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
148
149 channels_type apply(channels_type src, channels_type dst)
150 {
152 }
153};
154
155template <typename channels_type>
157 : public StrengthCompositeFunctionBase<channels_type>
158{
159 const channels_type invertedStrength;
160
161 CompositeFunction(qreal strength)
162 : StrengthCompositeFunctionBase<channels_type>(strength)
163 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
164 {}
165
166 channels_type apply(channels_type src, channels_type dst)
167 {
169 }
170};
171
180template<class T>
181inline T colorDodgeAlphaHelper(T src, T dst)
182{
183 using composite_type = typename KoColorSpaceMathsTraits<T>::compositetype;
184 using namespace Arithmetic;
185 // Handle the case where the denominator is 0.
186 // When src is 1 then the denominator (1 - src) becomes 0, and to avoid
187 // dividing by 0 we treat the denominator as an infinitely small number,
188 // so the result of the formula would approach infinity.
189 // For alpha values, the result should be clamped to the unit range,
190 // contrary to the color version, where the values should be clamped to
191 // the min/max range.
192 // Another special case is when both numerator and denominator are 0. In
193 // this case we also treat the denominator as an infinitely small number,
194 // and the numerator can remain as 0, so dividing 0 over a number (no matter
195 // how small it is) gives 0.
196 if (isUnitValueFuzzy<T>(src)) {
197 return isZeroValueFuzzy<T>(dst) ? zeroValue<T>() : unitValue<T>();
198 }
200 div(dst, inv(src)),
202}
203
204// Integer version of color dodge alpha
205template<class T>
206inline typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
207colorDodgeAlpha(T src, T dst)
208{
209 return colorDodgeAlphaHelper(src, dst);
210}
211
212// Floating point version of color dodge alpha
213template<class T>
214inline typename std::enable_if<!std::numeric_limits<T>::is_integer, T>::type
215colorDodgeAlpha(T src, T dst)
216{
217 const T result = colorDodgeAlphaHelper(src, dst);
218 // Constantly dividing by small numbers can quickly make the result
219 // become infinity or NaN, so we check that and correct (kind of clamping)
220 return std::isfinite(result) ? result : KoColorSpaceMathsTraits<T>::unitValue;
221}
222
223template <typename channels_type>
224struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_DODGE, false, false>
225{
226 channels_type apply(channels_type src, channels_type dst)
227 {
228 return colorDodgeAlpha(src, dst);
229 }
230};
231
232template <typename channels_type, bool use_soft_texturing>
233struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_DODGE, true, use_soft_texturing>
234 : public StrengthCompositeFunctionBase<channels_type>
235{
236 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
237
238 channels_type apply(channels_type src, channels_type dst)
239 {
240 if constexpr (use_soft_texturing) {
242 } else {
244 }
245 }
246};
247
256template<class T>
257inline T colorBurnAlphaHelper(T src, T dst)
258{
259 using composite_type = typename KoColorSpaceMathsTraits<T>::compositetype;
260 using namespace Arithmetic;
261 // Handle the case where the denominator is 0. See color dodge for a
262 // detailed explanation
263 if(isZeroValueFuzzy<T>(src)) {
264 return isUnitValueFuzzy<T>(dst) ? zeroValue<T>() : unitValue<T>();
265 }
267 div(inv(dst), src),
269}
270
271template<class T>
272inline T colorBurnAlpha(T src, T dst)
273{
274 using namespace Arithmetic;
275 using namespace KoCompositeOpClampPolicy;
276 return CFColorBurn<T>::composeChannel(src, dst);
277}
278
279template <typename channels_type>
280struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_BURN, false, false>
281{
282 channels_type apply(channels_type src, channels_type dst)
283 {
284 return colorBurnAlpha(src, dst);
285 }
286};
287
288template <typename channels_type>
289struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_BURN, true, false>
290 : public StrengthCompositeFunctionBase<channels_type>
291{
292 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
293
294 channels_type apply(channels_type src, channels_type dst)
295 {
297 }
298};
299
300template <typename channels_type>
301struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_BURN, true, true>
302 : public StrengthCompositeFunctionBase<channels_type>
303{
304 const channels_type invertedStrength;
305
306 CompositeFunction(qreal strength)
307 : StrengthCompositeFunctionBase<channels_type>(strength)
308 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
309 {}
310
311 channels_type apply(channels_type src, channels_type dst)
312 {
313 return colorBurnAlpha(Arithmetic::unionShapeOpacity(src, invertedStrength), dst);
314 }
315};
316
324template <typename channels_type>
326{
327 channels_type apply(channels_type src, channels_type dst)
328 {
329 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
330 using namespace Arithmetic;
331 if (isZeroValueFuzzy<channels_type>(dst)) {
332 return zeroValue<channels_type>();
333 }
334 return qMin(composite_type(src) + dst, composite_type(unitValue<channels_type>()));
335 }
336};
337
338template <typename channels_type, bool use_soft_texturing>
339struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_LINEAR_DODGE, true, use_soft_texturing>
340 : public StrengthCompositeFunctionBase<channels_type>
341{
342 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
343
344 channels_type apply(channels_type src, channels_type dst)
345 {
346 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
347 using namespace Arithmetic;
348 if (isZeroValueFuzzy<channels_type>(dst)) {
349 return zeroValue<channels_type>();
350 }
351 if constexpr (use_soft_texturing) {
352 return qMin(composite_type(mul(src, StrengthCompositeFunctionBase<channels_type>::strength) + dst),
353 composite_type(unitValue<channels_type>()));
354 } else {
355 return qMin(composite_type(src) + mul(dst, StrengthCompositeFunctionBase<channels_type>::strength),
356 composite_type(unitValue<channels_type>()));
357 }
358 }
359};
360
368template <typename channels_type>
370{
371 channels_type apply(channels_type src, channels_type dst)
372 {
373 using namespace Arithmetic;
374 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
375 return qMax(composite_type(KoColorSpaceMathsTraits<channels_type>::zeroValue),
376 composite_type(src) + dst - unitValue<channels_type>());
377 }
378};
379
380template <typename channels_type>
382 : public StrengthCompositeFunctionBase<channels_type>
383{
384 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
385
386 channels_type apply(channels_type src, channels_type dst)
387 {
388 using namespace Arithmetic;
389 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
390 return qMax(composite_type(zeroValue<channels_type>()),
391 composite_type(src) + mul(dst, StrengthCompositeFunctionBase<channels_type>::strength)
392 - unitValue<channels_type>());
393 }
394};
395
396template <typename channels_type>
398 : public StrengthCompositeFunctionBase<channels_type>
399{
400 const channels_type invertedStrength;
401
402 CompositeFunction(qreal strength)
403 : StrengthCompositeFunctionBase<channels_type>(strength)
404 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
405 {}
406
407 channels_type apply(channels_type src, channels_type dst)
408 {
409 using namespace Arithmetic;
410 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
411 return qMax(composite_type(zeroValue<channels_type>()),
412 composite_type(unionShapeOpacity(src, invertedStrength) + dst - unitValue<channels_type>()));
413 }
414};
415
416template <typename channels_type>
418{
419 channels_type apply(channels_type src, channels_type dst)
420 {
422 }
423};
424
425template <typename channels_type>
427 : public StrengthCompositeFunctionBase<channels_type>
428{
429 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
430
431 channels_type apply(channels_type src, channels_type dst)
432 {
434 }
435};
436
437template <typename channels_type>
439 : public StrengthCompositeFunctionBase<channels_type>
440{
441 const channels_type invertedStrength;
442
443 CompositeFunction(qreal strength)
444 : StrengthCompositeFunctionBase<channels_type>(strength)
445 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
446 {}
447
448 channels_type apply(channels_type src, channels_type dst)
449 {
450 using namespace Arithmetic;
451 return mul(CFHardMixPhotoshop<channels_type>::composeChannel(unionShapeOpacity(src, invertedStrength), dst),
453 }
454};
455
463template<class T>
464inline T hardMixSofterPhotoshopAlpha(T src, T dst) {
465 using namespace Arithmetic;
466 typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
467 const composite_type srcScaleFactor = static_cast<composite_type>(2);
468 const composite_type dstScaleFactor = static_cast<composite_type>(3);
470 dstScaleFactor * dst - srcScaleFactor * inv(src),
472}
473
474template <typename channels_type>
476{
477 channels_type apply(channels_type src, channels_type dst)
478 {
479 return hardMixSofterPhotoshopAlpha(src, dst);
480 }
481};
482
483template <typename channels_type, bool use_soft_texturing>
484struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_HARD_MIX_SOFTER_PHOTOSHOP, true, use_soft_texturing>
485 : public StrengthCompositeFunctionBase<channels_type>
486{
487 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
488
489 channels_type apply(channels_type src, channels_type dst)
490 {
491 if constexpr (use_soft_texturing) {
493 } else {
495 }
496 }
497};
498
507template <typename channels_type>
508struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_SUBTRACT, false, false>
509{
510 channels_type apply(channels_type src, channels_type dst)
511 {
512 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
513 using namespace Arithmetic;
514 return qMax(composite_type(KoColorSpaceMathsTraits<channels_type>::zeroValue),
515 composite_type(dst) - src);
516 }
517};
518
519template <typename channels_type>
521 : public StrengthCompositeFunctionBase<channels_type>
522{
523 const channels_type invertedStrength;
524
525 CompositeFunction(qreal strength)
526 : StrengthCompositeFunctionBase<channels_type>(strength)
527 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
528 {}
529
530 channels_type apply(channels_type src, channels_type dst)
531 {
532 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
533 using namespace Arithmetic;
534 return qMax(composite_type(zeroValue<channels_type>()),
535 composite_type(dst) - (composite_type(src) + invertedStrength));
536 }
537};
538
539template <typename channels_type>
541 : public StrengthCompositeFunctionBase<channels_type>
542{
543 CompositeFunction(qreal strength) : StrengthCompositeFunctionBase<channels_type>(strength) {}
544
545 channels_type apply(channels_type src, channels_type dst)
546 {
547 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
548 using namespace Arithmetic;
549 return qMax(composite_type(KoColorSpaceMathsTraits<channels_type>::zeroValue),
550 composite_type(dst) - mul(src, StrengthCompositeFunctionBase<channels_type>::strength));
551 }
552};
553
554template <typename channels_type, bool use_soft_texturing>
555struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_HEIGHT, true, use_soft_texturing>
556 : public StrengthCompositeFunctionBase<channels_type>
557{
558 const channels_type invertedStrength;
559
560 CompositeFunction(qreal strength)
561 : StrengthCompositeFunctionBase<channels_type>(0.99 * strength)
562 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
563 {}
564
565 channels_type apply(channels_type src, channels_type dst)
566 {
567 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
568 using namespace Arithmetic;
569 if constexpr (use_soft_texturing) {
570 return kisBoundFast(composite_type(zeroValue<channels_type>()),
571 div(dst, invertedStrength) -
573 composite_type(unitValue<channels_type>()));
574 } else {
575 return kisBoundFast(composite_type(zeroValue<channels_type>()),
576 div(dst, invertedStrength) - (composite_type(src) + invertedStrength),
577 composite_type(unitValue<channels_type>()));
578 }
579 }
580};
581
582template <typename channels_type, bool use_soft_texturing>
583struct CompositeFunction<channels_type, KIS_MASKING_BRUSH_COMPOSITE_LINEAR_HEIGHT, true, use_soft_texturing>
584 : public StrengthCompositeFunctionBase<channels_type>
585{
586 const channels_type invertedStrength;
587
588 CompositeFunction(qreal strength)
589 : StrengthCompositeFunctionBase<channels_type>(0.99 * strength)
590 , invertedStrength(Arithmetic::inv(StrengthCompositeFunctionBase<channels_type>::strength))
591 {}
592
593 channels_type apply(channels_type src, channels_type dst)
594 {
595 using composite_type = typename KoColorSpaceMathsTraits<channels_type>::compositetype;
596 using namespace Arithmetic;
597
598 if constexpr (use_soft_texturing) {
599 const composite_type modifiedDst = div(dst, invertedStrength);
600 const channels_type srcTimesStrength = mul(src, StrengthCompositeFunctionBase<channels_type>::strength);
601 const composite_type multiply = modifiedDst * inv(srcTimesStrength) / unitValue<channels_type>();
602 const composite_type height = modifiedDst - srcTimesStrength;
603 return kisBoundFast(composite_type(zeroValue<channels_type>()),
604 qMax(multiply, height),
605 composite_type(unitValue<channels_type>()));
606 } else {
607 const composite_type modifiedDst = div(dst, invertedStrength) - invertedStrength;
608 const composite_type multiply = modifiedDst * inv(src) / unitValue<channels_type>();
609 const composite_type height = modifiedDst - src;
610 return kisBoundFast(composite_type(zeroValue<channels_type>()),
611 qMax(multiply, height),
612 composite_type(unitValue<channels_type>()));
613 }
614 }
615};
616
617template <typename channels_type>
619 : public StrengthCompositeFunctionBase<channels_type>
620{
623
624 CompositeFunction(qreal strength)
625 : StrengthCompositeFunctionBase<channels_type>(strength)
626 , weight(composite_type(10) * StrengthCompositeFunctionBase<channels_type>::strength)
627 {}
628
629 channels_type apply(channels_type src, channels_type dst)
630 {
631 using namespace Arithmetic;
632 return kisBoundFast(composite_type(zeroValue<channels_type>()),
633 dst * weight / unitValue<channels_type>() - src,
634 composite_type(unitValue<channels_type>()));
635 }
636};
637
638template <typename channels_type>
640 : public StrengthCompositeFunctionBase<channels_type>
641{
644
645 CompositeFunction(qreal strength)
646 : StrengthCompositeFunctionBase<channels_type>(strength)
647 , weight(composite_type(9) * StrengthCompositeFunctionBase<channels_type>::strength)
648 {}
649
650 channels_type apply(channels_type src, channels_type dst)
651 {
652 using namespace Arithmetic;
653 return kisBoundFast(composite_type(zeroValue<channels_type>()),
654 composite_type(dst) + dst * weight / unitValue<channels_type>() -
656 composite_type(unitValue<channels_type>()));
657 }
658};
659
660template <typename channels_type>
662 : public StrengthCompositeFunctionBase<channels_type>
663{
665
667
668 CompositeFunction(qreal strength)
669 : StrengthCompositeFunctionBase<channels_type>(strength)
670 , weight(composite_type(10) * StrengthCompositeFunctionBase<channels_type>::strength)
671 {}
672
673 channels_type apply(channels_type src, channels_type dst)
674 {
675 using namespace Arithmetic;
676 const composite_type modifiedDst = dst * weight / unitValue<channels_type>();
677 const composite_type multiply = inv(src) * modifiedDst / unitValue<channels_type>();
678 const composite_type height = modifiedDst - src;
679 return kisBoundFast(composite_type(zeroValue<channels_type>()),
680 qMax(multiply, height),
681 composite_type(unitValue<channels_type>()));
682 }
683};
684
685template <typename channels_type>
687 : public StrengthCompositeFunctionBase<channels_type>
688{
690
692
693 CompositeFunction(qreal strength)
694 : StrengthCompositeFunctionBase<channels_type>(strength)
695 , weight(composite_type(9) * StrengthCompositeFunctionBase<channels_type>::strength)
696 {}
697
698 channels_type apply(channels_type src, channels_type dst)
699 {
700 using namespace Arithmetic;
701 const composite_type modifiedDst = dst + dst * weight / unitValue<channels_type>();
702 const channels_type srcTimesStrength = mul(src, StrengthCompositeFunctionBase<channels_type>::strength);
703 const composite_type multiply = modifiedDst * inv(srcTimesStrength) / unitValue<channels_type>();
704 const composite_type height = modifiedDst - srcTimesStrength;
705 return kisBoundFast(composite_type(zeroValue<channels_type>()),
706 qMax(multiply, height),
707 composite_type(unitValue<channels_type>()));
708 }
709};
710
711}
712
713template <typename channels_type, int composite_function, bool mask_is_alpha = false,
714 bool use_strength = false, bool use_soft_texturing = false>
716{
717public:
718 using MaskPixel = typename std::conditional<mask_is_alpha, quint8, KoGrayU8Traits::Pixel>::type;
719
720 template <bool use_strength_ = use_strength, typename = typename std::enable_if<!use_strength_>::type>
721 KisMaskingBrushCompositeOp(int dstPixelSize, int dstAlphaOffset)
722 : m_dstPixelSize(dstPixelSize)
723 , m_dstAlphaOffset(dstAlphaOffset)
724 {}
725
726 template <bool use_strength_ = use_strength, typename = typename std::enable_if<use_strength_>::type>
727 KisMaskingBrushCompositeOp(int dstPixelSize, int dstAlphaOffset, qreal strength)
728 : m_dstPixelSize(dstPixelSize)
729 , m_dstAlphaOffset(dstAlphaOffset)
730 , m_compositeFunction(strength)
731 {}
732
733 void composite(const quint8 *srcRowStart, int srcRowStride,
734 quint8 *dstRowStart, int dstRowStride,
735 int columns, int rows) override
736 {
737 dstRowStart += m_dstAlphaOffset;
738
739 for (int y = 0; y < rows; y++) {
740 const quint8 *srcPtr = srcRowStart;
741 quint8 *dstPtr = dstRowStart;
742
743 for (int x = 0; x < columns; x++) {
744
745 const MaskPixel *srcDataPtr = reinterpret_cast<const MaskPixel*>(srcPtr);
746
747 const quint8 mask = preprocessMask(srcDataPtr);
748 const channels_type maskScaled = KoColorSpaceMaths<quint8, channels_type>::scaleToA(mask);
749
750 channels_type *dstDataPtr = reinterpret_cast<channels_type*>(dstPtr);
751 *dstDataPtr = m_compositeFunction.apply(maskScaled, *dstDataPtr);
752
753 srcPtr += sizeof(MaskPixel);
754 dstPtr += m_dstPixelSize;
755 }
756
757 srcRowStart += srcRowStride;
758 dstRowStart += dstRowStride;
759 }
760 }
761
762
763private:
764 inline quint8 preprocessMask(const quint8 *pixel)
765 {
766 return *pixel;
767 }
768
769 inline quint8 preprocessMask(const KoGrayU8Traits::Pixel *pixel)
770 {
771 return KoColorSpaceMaths<quint8>::multiply(pixel->gray, pixel->alpha);
772 }
773
774private:
778 <channels_type, composite_function, use_strength, use_soft_texturing> m_compositeFunction;
779};
780
781#endif // KISMASKINGBRUSHCOMPOSITEOP_H
KisMaskingBrushCompositeFuncTypes
@ KIS_MASKING_BRUSH_COMPOSITE_BURN
@ KIS_MASKING_BRUSH_COMPOSITE_LINEAR_HEIGHT_PHOTOSHOP
@ KIS_MASKING_BRUSH_COMPOSITE_SUBTRACT
@ KIS_MASKING_BRUSH_COMPOSITE_HEIGHT
@ KIS_MASKING_BRUSH_COMPOSITE_DODGE
@ KIS_MASKING_BRUSH_COMPOSITE_LINEAR_DODGE
@ KIS_MASKING_BRUSH_COMPOSITE_MULT
@ KIS_MASKING_BRUSH_COMPOSITE_OVERLAY
@ KIS_MASKING_BRUSH_COMPOSITE_HARD_MIX_SOFTER_PHOTOSHOP
@ KIS_MASKING_BRUSH_COMPOSITE_HARD_MIX_PHOTOSHOP
@ KIS_MASKING_BRUSH_COMPOSITE_DARKEN
@ KIS_MASKING_BRUSH_COMPOSITE_HEIGHT_PHOTOSHOP
@ KIS_MASKING_BRUSH_COMPOSITE_LINEAR_HEIGHT
@ KIS_MASKING_BRUSH_COMPOSITE_LINEAR_BURN
T cfMultiply(T src, T dst)
T cfDarkenOnly(T src, T dst)
KisMaskingBrushCompositeDetail::CompositeFunction< channels_type, composite_function, use_strength, use_soft_texturing > m_compositeFunction
quint8 preprocessMask(const KoGrayU8Traits::Pixel *pixel)
void composite(const quint8 *srcRowStart, int srcRowStride, quint8 *dstRowStart, int dstRowStride, int columns, int rows) override
KisMaskingBrushCompositeOp(int dstPixelSize, int dstAlphaOffset)
quint8 preprocessMask(const quint8 *pixel)
typename std::conditional< mask_is_alpha, quint8, KoGrayU8Traits::Pixel >::type MaskPixel
KisMaskingBrushCompositeOp(int dstPixelSize, int dstAlphaOffset, qreal strength)
static _Tdst multiply(_T a, _Tdst b)
static _Tdst scaleToA(_T a)
constexpr const T & kisBoundFast(const T &min, const T &val, const T &max)
Definition kis_global.h:37
T mul(T a, T b)
T unionShapeOpacity(T a, T b)
std::enable_if< std::numeric_limits< T >::is_integer, T >::type colorDodgeAlpha(T src, T dst)
static T composeChannel(T src, T dst)
static T composeChannel(T src, T dst)
static T composeChannel(T src, T dst)