2
* Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public License
15
* along with this program; if not, write to the Free Software
19
#include <KoColorSpace.h>
20
#include <KoIntegerMaths.h>
22
#include "KoRgbU8CompositeOp.h"
23
#include "KoRgbU8ColorSpace.h"
24
#include "KoColorConversions.h"
26
#define PixelIntensity(pixel) ((unsigned int) \
27
(((qreal)306.0 * (pixel[RgbU8Traits::red_pos]) + \
28
(qreal)601.0 * (pixel[RgbU8Traits::green_pos]) + \
29
(qreal)117.0 * (pixel[RgbU8Traits::blue_pos)) \
32
#define PixelIntensityToQuantum(pixel) ((quint8)PixelIntensity(pixel))
34
#define PixelIntensityToDouble(pixel) ((qreal)PixelIntensity(pixel))
36
#define RoundSignedToQuantum(value) ((quint8) (value < 0 ? 0 : \
37
(value > UINT8_MAX) ? UINT8_MAX : value + 0.5))
39
#define RoundToQuantum(value) ((quint8) (value > UINT8_MAX ? UINT8_MAX : \
43
#define AbsoluteValue(x) ((x) < 0 ? -(x) : (x))
46
KoRgbU8CompositeOp::KoRgbU8CompositeOp(KoColorSpace * cs, const QString& id, const QString& description, const bool userVisible)
47
: KoCompositeOp(cs, id, description, "", userVisible)
49
m_pixelSize = cs->pixelSize();
53
void KoRgbU8CompositeOp::composite(quint8 *dst, qint32 dstRowStride,
54
const quint8 *src, qint32 srcRowStride,
55
const quint8 *mask, qint32 maskRowStride,
56
qint32 rows, qint32 cols,
58
const QBitArray & channelFlags) const
60
Q_ASSERT( channelFlags.size() == 4 || channelFlags.isEmpty() );
62
if ( id() == COMPOSITE_UNDEF ) {
63
// Undefined == no composition
65
else if ( id() == COMPOSITE_IN ) {
66
compositeIn(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
68
else if ( id() == COMPOSITE_OUT ) {
69
compositeOut(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
71
else if ( id() == COMPOSITE_ATOP ) {
72
compositeAtop(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
74
else if ( id() == COMPOSITE_XOR ) {
75
compositeXor(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
77
else if ( id() == COMPOSITE_PLUS ) {
78
compositePlus(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
80
else if (id() == COMPOSITE_MINUS) {
81
compositeMinus(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
83
else if (id() == COMPOSITE_DIFF) {
84
compositeDiff(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
86
else if (id() == COMPOSITE_BUMPMAP) {
87
compositeBumpmap(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
89
else if (id() == COMPOSITE_COPY) {
90
compositeCopy(m_pixelSize, dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity, channelFlags);
92
else if (id() == COMPOSITE_COPY_RED) {
93
compositeCopyRed(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
95
else if (id() == COMPOSITE_COPY_GREEN) {
96
compositeCopyGreen(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
98
else if (id() == COMPOSITE_COPY_BLUE) {
99
compositeCopyBlue(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
101
else if (id() == COMPOSITE_COPY_OPACITY) {
102
compositeCopyOpacity(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
104
else if (id() == COMPOSITE_CLEAR) {
105
compositeClear(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
107
else if (id() == COMPOSITE_DISSOLVE) {
108
compositeDissolve(m_pixelSize, dst, dstRowStride, src, srcRowStride, rows, cols, opacity, channelFlags);
110
else if (id() == COMPOSITE_NO) {
113
else if (id() == COMPOSITE_DARKEN) {
114
compositeDarken(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity, channelFlags);
116
else if (id() == COMPOSITE_LIGHTEN) {
117
compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity, channelFlags);
119
else if (id() == COMPOSITE_HUE) {
120
compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity, channelFlags);
122
else if (id() == COMPOSITE_SATURATION) {
123
compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity, channelFlags);
125
else if (id() == COMPOSITE_VALUE) {
126
compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity, channelFlags);
128
else if (id() == COMPOSITE_COLOR) {
129
compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity, channelFlags);
134
void KoRgbU8CompositeOp::compositeDarken(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, quint8 opacity, const QBitArray & channelFlags) const
138
const quint8 *src = srcRowStart;
139
quint8 *dst = dstRowStart;
140
qint32 columns = numColumns;
141
const quint8 *mask = maskRowStart;
143
while (columns > 0) {
145
quint8 srcAlpha = src[RgbU8Traits::alpha_pos];
146
quint8 dstAlpha = dst[RgbU8Traits::alpha_pos];
148
srcAlpha = qMin(srcAlpha, dstAlpha);
150
// apply the alphamask
153
if(*mask != OPACITY_OPAQUE)
154
srcAlpha = UINT8_MULT(srcAlpha, *mask);
158
if (srcAlpha != OPACITY_TRANSPARENT) {
160
if (opacity != OPACITY_OPAQUE) {
161
srcAlpha = UINT8_MULT(src[RgbU8Traits::alpha_pos], opacity);
166
if (dstAlpha == OPACITY_OPAQUE) {
169
quint8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
170
dst[RgbU8Traits::alpha_pos] = newAlpha;
173
srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
179
for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
181
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) ) {
182
quint8 srcColor = src[channel];
183
quint8 dstColor = dst[channel];
185
srcColor = qMin(srcColor, dstColor);
187
quint8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
189
dst[channel] = newColor;
195
src += RgbU8Traits::channels_nb;
196
dst += RgbU8Traits::channels_nb;
200
srcRowStart += srcRowStride;
201
dstRowStart += dstRowStride;
203
maskRowStart += maskRowStride;
207
void KoRgbU8CompositeOp::compositeLighten(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, quint8 opacity, const QBitArray & channelFlags) const
211
const quint8 *src = srcRowStart;
212
quint8 *dst = dstRowStart;
213
qint32 columns = numColumns;
214
const quint8 *mask = maskRowStart;
216
while (columns > 0) {
218
quint8 srcAlpha = src[RgbU8Traits::alpha_pos];
219
quint8 dstAlpha = dst[RgbU8Traits::alpha_pos];
221
srcAlpha = qMin(srcAlpha, dstAlpha);
223
// apply the alphamask
226
if(*mask != OPACITY_OPAQUE)
227
srcAlpha = UINT8_MULT(srcAlpha, *mask);
231
if (srcAlpha != OPACITY_TRANSPARENT) {
233
if (opacity != OPACITY_OPAQUE) {
234
srcAlpha = UINT8_MULT(src[RgbU8Traits::alpha_pos], opacity);
239
if (dstAlpha == OPACITY_OPAQUE) {
242
quint8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
243
dst[RgbU8Traits::alpha_pos] = newAlpha;
246
srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
252
for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
253
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) ) {
254
quint8 srcColor = src[channel];
255
quint8 dstColor = dst[channel];
257
srcColor = qMax(srcColor, dstColor);
259
quint8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
261
dst[channel] = newColor;
267
src += RgbU8Traits::channels_nb;
268
dst += RgbU8Traits::channels_nb;
272
srcRowStart += srcRowStride;
273
dstRowStart += dstRowStride;
275
maskRowStart += maskRowStride;
279
void KoRgbU8CompositeOp::compositeHue(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, quint8 opacity, const QBitArray & channelFlags) const
283
const quint8 *src = srcRowStart;
284
quint8 *dst = dstRowStart;
285
qint32 columns = numColumns;
286
const quint8 *mask = maskRowStart;
288
while (columns > 0) {
290
quint8 srcAlpha = src[RgbU8Traits::alpha_pos];
291
quint8 dstAlpha = dst[RgbU8Traits::alpha_pos];
293
srcAlpha = qMin(srcAlpha, dstAlpha);
295
// apply the alphamask
298
if(*mask != OPACITY_OPAQUE)
299
srcAlpha = UINT8_MULT(srcAlpha, *mask);
303
if (srcAlpha != OPACITY_TRANSPARENT) {
305
if (opacity != OPACITY_OPAQUE) {
306
srcAlpha = UINT8_MULT(src[RgbU8Traits::alpha_pos], opacity);
311
if (dstAlpha == OPACITY_OPAQUE) {
314
quint8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
315
dst[RgbU8Traits::alpha_pos] = newAlpha;
318
srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
324
int dstRed = dst[RgbU8Traits::red_pos];
325
int dstGreen = dst[RgbU8Traits::green_pos];
326
int dstBlue = dst[RgbU8Traits::blue_pos];
335
rgb_to_hsv(src[RgbU8Traits::red_pos], src[RgbU8Traits::green_pos], src[RgbU8Traits::blue_pos], &srcHue, &srcSaturation, &srcValue);
336
rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
342
hsv_to_rgb(srcHue, dstSaturation, dstValue, &srcRed, &srcGreen, &srcBlue);
344
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
345
dst[RgbU8Traits::red_pos] = UINT8_BLEND(srcRed, dstRed, srcBlend);
346
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
347
dst[RgbU8Traits::green_pos] = UINT8_BLEND(srcGreen, dstGreen, srcBlend);
348
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
349
dst[RgbU8Traits::blue_pos] = UINT8_BLEND(srcBlue, dstBlue, srcBlend);
353
src += RgbU8Traits::channels_nb;
354
dst += RgbU8Traits::channels_nb;
358
srcRowStart += srcRowStride;
359
dstRowStart += dstRowStride;
361
maskRowStart += maskRowStride;
365
void KoRgbU8CompositeOp::compositeSaturation(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, quint8 opacity, const QBitArray & channelFlags) const
369
const quint8 *src = srcRowStart;
370
quint8 *dst = dstRowStart;
371
qint32 columns = numColumns;
372
const quint8 *mask = maskRowStart;
374
while (columns > 0) {
376
quint8 srcAlpha = src[RgbU8Traits::alpha_pos];
377
quint8 dstAlpha = dst[RgbU8Traits::alpha_pos];
379
srcAlpha = qMin(srcAlpha, dstAlpha);
381
// apply the alphamask
384
if(*mask != OPACITY_OPAQUE)
385
srcAlpha = UINT8_MULT(srcAlpha, *mask);
389
if (srcAlpha != OPACITY_TRANSPARENT) {
391
if (opacity != OPACITY_OPAQUE) {
392
srcAlpha = UINT8_MULT(src[RgbU8Traits::alpha_pos], opacity);
397
if (dstAlpha == OPACITY_OPAQUE) {
400
quint8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
401
dst[RgbU8Traits::alpha_pos] = newAlpha;
404
srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
410
int dstRed = dst[RgbU8Traits::red_pos];
411
int dstGreen = dst[RgbU8Traits::green_pos];
412
int dstBlue = dst[RgbU8Traits::blue_pos];
421
rgb_to_hsv(src[RgbU8Traits::red_pos], src[RgbU8Traits::green_pos], src[RgbU8Traits::blue_pos], &srcHue, &srcSaturation, &srcValue);
422
rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
428
hsv_to_rgb(dstHue, srcSaturation, dstValue, &srcRed, &srcGreen, &srcBlue);
429
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
430
dst[RgbU8Traits::red_pos] = UINT8_BLEND(srcRed, dstRed, srcBlend);
431
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
432
dst[RgbU8Traits::green_pos] = UINT8_BLEND(srcGreen, dstGreen, srcBlend);
433
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
434
dst[RgbU8Traits::blue_pos] = UINT8_BLEND(srcBlue, dstBlue, srcBlend);
438
src += RgbU8Traits::channels_nb;
439
dst += RgbU8Traits::channels_nb;
443
srcRowStart += srcRowStride;
444
dstRowStart += dstRowStride;
446
maskRowStart += maskRowStride;
450
void KoRgbU8CompositeOp::compositeValue(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, quint8 opacity, const QBitArray & channelFlags) const
454
const quint8 *src = srcRowStart;
455
quint8 *dst = dstRowStart;
456
qint32 columns = numColumns;
457
const quint8 *mask = maskRowStart;
459
while (columns > 0) {
461
quint8 srcAlpha = src[RgbU8Traits::alpha_pos];
462
quint8 dstAlpha = dst[RgbU8Traits::alpha_pos];
464
srcAlpha = qMin(srcAlpha, dstAlpha);
466
// apply the alphamask
469
if(*mask != OPACITY_OPAQUE)
470
srcAlpha = UINT8_MULT(srcAlpha, *mask);
474
if (srcAlpha != OPACITY_TRANSPARENT) {
476
if (opacity != OPACITY_OPAQUE) {
477
srcAlpha = UINT8_MULT(src[RgbU8Traits::alpha_pos], opacity);
482
if (dstAlpha == OPACITY_OPAQUE) {
485
quint8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
486
dst[RgbU8Traits::alpha_pos] = newAlpha;
489
srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
495
int dstRed = dst[RgbU8Traits::red_pos];
496
int dstGreen = dst[RgbU8Traits::green_pos];
497
int dstBlue = dst[RgbU8Traits::blue_pos];
506
rgb_to_hsv(src[RgbU8Traits::red_pos], src[RgbU8Traits::green_pos], src[RgbU8Traits::blue_pos], &srcHue, &srcSaturation, &srcValue);
507
rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
513
hsv_to_rgb(dstHue, dstSaturation, srcValue, &srcRed, &srcGreen, &srcBlue);
514
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
515
dst[RgbU8Traits::red_pos] = UINT8_BLEND(srcRed, dstRed, srcBlend);
516
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
517
dst[RgbU8Traits::green_pos] = UINT8_BLEND(srcGreen, dstGreen, srcBlend);
518
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
519
dst[RgbU8Traits::blue_pos] = UINT8_BLEND(srcBlue, dstBlue, srcBlend);
523
src += RgbU8Traits::channels_nb;
524
dst += RgbU8Traits::channels_nb;
528
srcRowStart += srcRowStride;
529
dstRowStart += dstRowStride;
531
maskRowStart += maskRowStride;
535
void KoRgbU8CompositeOp::compositeColor(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, quint8 opacity, const QBitArray & channelFlags) const
540
const quint8 *src = srcRowStart;
541
quint8 *dst = dstRowStart;
542
qint32 columns = numColumns;
543
const quint8 *mask = maskRowStart;
545
while (columns > 0) {
547
quint8 srcAlpha = src[RgbU8Traits::alpha_pos];
548
quint8 dstAlpha = dst[RgbU8Traits::alpha_pos];
550
srcAlpha = qMin(srcAlpha, dstAlpha);
552
// apply the alphamask
555
if(*mask != OPACITY_OPAQUE)
556
srcAlpha = UINT8_MULT(srcAlpha, *mask);
560
if (srcAlpha != OPACITY_TRANSPARENT) {
562
if (opacity != OPACITY_OPAQUE) {
563
srcAlpha = UINT8_MULT(src[RgbU8Traits::alpha_pos], opacity);
568
if (dstAlpha == OPACITY_OPAQUE) {
571
quint8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
572
dst[RgbU8Traits::alpha_pos] = newAlpha;
575
srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
581
int dstRed = dst[RgbU8Traits::red_pos];
582
int dstGreen = dst[RgbU8Traits::green_pos];
583
int dstBlue = dst[RgbU8Traits::blue_pos];
592
rgb_to_hls(src[RgbU8Traits::red_pos], src[RgbU8Traits::green_pos], src[RgbU8Traits::blue_pos], &srcHue, &srcLightness, &srcSaturation);
593
rgb_to_hls(dstRed, dstGreen, dstBlue, &dstHue, &dstLightness, &dstSaturation);
599
hls_to_rgb(srcHue, dstLightness, srcSaturation, &srcRed, &srcGreen, &srcBlue);
601
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
602
dst[RgbU8Traits::red_pos] = UINT8_BLEND(srcRed, dstRed, srcBlend);
603
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
604
dst[RgbU8Traits::green_pos] = UINT8_BLEND(srcGreen, dstGreen, srcBlend);
605
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
606
dst[RgbU8Traits::blue_pos] = UINT8_BLEND(srcBlue, dstBlue, srcBlend);
610
src += RgbU8Traits::channels_nb;
611
dst += RgbU8Traits::channels_nb;
615
srcRowStart += srcRowStride;
616
dstRowStart += dstRowStride;
618
maskRowStart += maskRowStride;
624
void KoRgbU8CompositeOp::compositeIn(qint32 pixelSize,
631
quint8 opacity, const QBitArray & channelFlags) const
634
if (opacity == OPACITY_TRANSPARENT)
642
qreal sAlpha, dAlpha;
648
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
650
if (s[RgbU8Traits::alpha_pos] == OPACITY_TRANSPARENT)
652
memcpy(d, s, pixelSize * sizeof(quint8));
655
if (d[RgbU8Traits::alpha_pos] == OPACITY_TRANSPARENT)
658
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
659
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
661
alpha=(qreal) (((qreal) UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) / UINT8_MAX);
662
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
663
d[RgbU8Traits::red_pos]=(quint8) (((qreal) UINT8_MAX - sAlpha) *
664
(UINT8_MAX-dAlpha) * s[RgbU8Traits::red_pos] / UINT8_MAX / alpha + 0.5);
665
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
666
d[RgbU8Traits::green_pos]=(quint8) (((qreal) UINT8_MAX - sAlpha)*
667
(UINT8_MAX-dAlpha) * s[RgbU8Traits::green_pos] / UINT8_MAX / alpha + 0.5);
668
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
669
d[RgbU8Traits::blue_pos]=(quint8) (((qreal) UINT8_MAX - sAlpha)*
670
(UINT8_MAX - dAlpha) * s[RgbU8Traits::blue_pos] / UINT8_MAX / alpha + 0.5);
671
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) )
672
d[RgbU8Traits::alpha_pos]=(quint8) ((d[RgbU8Traits::alpha_pos] * (UINT8_MAX - alpha) / UINT8_MAX) + 0.5);
680
void KoRgbU8CompositeOp::compositeOut(qint32 pixelSize,
687
quint8 opacity, const QBitArray & channelFlags) const
689
if (opacity == OPACITY_TRANSPARENT)
697
qreal sAlpha, dAlpha;
703
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
704
if (s[RgbU8Traits::alpha_pos] == OPACITY_TRANSPARENT)
706
memcpy(d, s, pixelSize * sizeof(quint8));
709
if (d[RgbU8Traits::alpha_pos] == OPACITY_OPAQUE)
711
d[RgbU8Traits::alpha_pos]=OPACITY_TRANSPARENT;
714
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
715
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
717
alpha=(qreal) (UINT8_MAX - sAlpha) * d[RgbU8Traits::alpha_pos]/UINT8_MAX;
718
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
719
d[RgbU8Traits::red_pos] = (quint8) (((qreal) UINT8_MAX - sAlpha) * dAlpha * s[RgbU8Traits::red_pos] / UINT8_MAX / alpha + 0.5);
720
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
721
d[RgbU8Traits::green_pos] = (quint8) (((qreal) UINT8_MAX - sAlpha) * dAlpha * s[RgbU8Traits::green_pos] / UINT8_MAX / alpha + 0.5);
722
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
723
d[RgbU8Traits::blue_pos] = (quint8) (((qreal) UINT8_MAX - sAlpha) * dAlpha * s[RgbU8Traits::blue_pos] / UINT8_MAX / alpha + 0.5);
724
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) )
725
d[RgbU8Traits::alpha_pos]=(quint8) ((d[RgbU8Traits::alpha_pos] * (UINT8_MAX - alpha) / UINT8_MAX) + 0.5);
733
void KoRgbU8CompositeOp::compositeAtop(qint32 pixelSize,
740
quint8 opacity, const QBitArray & channelFlags) const
743
if (opacity == OPACITY_TRANSPARENT)
751
qreal sAlpha, dAlpha;
752
qreal alpha, red, green, blue;
757
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
758
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
759
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
761
alpha = ((qreal)(UINT8_MAX - sAlpha) *
762
(UINT8_MAX - dAlpha) + (qreal) sAlpha *
763
(UINT8_MAX - dAlpha)) / UINT8_MAX;
765
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) ) {
766
red = ((qreal)(UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) * s[RgbU8Traits::red_pos] / UINT8_MAX +
767
(qreal) sAlpha * (UINT8_MAX-dAlpha) * d[RgbU8Traits::red_pos]/UINT8_MAX) / alpha;
768
d[RgbU8Traits::red_pos] = (quint8) (red > UINT8_MAX ? UINT8_MAX : red + 0.5);
770
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) ) {
771
green = ((qreal) (UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) * s[RgbU8Traits::green_pos] / UINT8_MAX +
772
(qreal) sAlpha * (UINT8_MAX-dAlpha) * d[RgbU8Traits::green_pos]/UINT8_MAX)/alpha;
773
d[RgbU8Traits::green_pos] = (quint8) (green > UINT8_MAX ? UINT8_MAX : green + 0.5);
775
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) ) {
776
blue = ((qreal) (UINT8_MAX - sAlpha) * (UINT8_MAX- dAlpha) * s[RgbU8Traits::blue_pos] / UINT8_MAX +
777
(qreal) sAlpha * (UINT8_MAX - dAlpha) * d[RgbU8Traits::blue_pos]/UINT8_MAX) / alpha;
778
d[RgbU8Traits::blue_pos] = (quint8) (blue > UINT8_MAX ? UINT8_MAX : blue + 0.5);
780
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) )
781
d[RgbU8Traits::alpha_pos]=(quint8) (UINT8_MAX - (alpha > UINT8_MAX ? UINT8_MAX : alpha) + 0.5);
790
void KoRgbU8CompositeOp::compositeXor(qint32 pixelSize,
797
quint8 opacity, const QBitArray & channelFlags) const
799
if (opacity == OPACITY_TRANSPARENT)
807
qreal sAlpha, dAlpha;
808
qreal alpha, red, green, blue;
813
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
814
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
815
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
817
alpha =((qreal) (UINT8_MAX -sAlpha)*
818
dAlpha+(qreal) (UINT8_MAX -dAlpha)*
820
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) ) {
821
red=((qreal) (UINT8_MAX -sAlpha)*dAlpha*
822
s[RgbU8Traits::red_pos]/UINT8_MAX +(qreal) (UINT8_MAX -dAlpha)*
823
sAlpha*d[RgbU8Traits::red_pos]/UINT8_MAX )/alpha ;
824
d[RgbU8Traits::red_pos]=RoundSignedToQuantum(Qt::red);
826
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) ) {
827
green=((qreal) (UINT8_MAX -sAlpha)*dAlpha*
828
s[RgbU8Traits::green_pos]/UINT8_MAX +(qreal) (UINT8_MAX -dAlpha)*
829
sAlpha*d[RgbU8Traits::green_pos]/UINT8_MAX )/alpha ;
830
d[RgbU8Traits::green_pos]=RoundSignedToQuantum(Qt::green);
832
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) ) {
833
blue=((qreal) (UINT8_MAX -sAlpha)*dAlpha*
834
s[RgbU8Traits::blue_pos]/UINT8_MAX +(qreal) (UINT8_MAX -dAlpha)*
835
sAlpha*d[RgbU8Traits::blue_pos]/UINT8_MAX )/alpha ;
836
d[RgbU8Traits::blue_pos]=RoundSignedToQuantum(Qt::blue);
838
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) )
839
d[RgbU8Traits::alpha_pos]=UINT8_MAX -RoundSignedToQuantum(alpha );
848
void KoRgbU8CompositeOp::compositePlus(qint32 pixelSize,
855
quint8 opacity, const QBitArray & channelFlags) const
857
if (opacity == OPACITY_TRANSPARENT)
865
qreal sAlpha, dAlpha;
866
qreal alpha, red, green, blue;
871
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
872
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
873
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
875
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) ) {
876
red=((qreal) (UINT8_MAX -sAlpha)*s[RgbU8Traits::red_pos]+(qreal)
877
(UINT8_MAX -dAlpha)*d[RgbU8Traits::red_pos])/UINT8_MAX ;
878
d[RgbU8Traits::red_pos]=RoundSignedToQuantum(Qt::red);
881
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) ) {
882
green=((qreal) (UINT8_MAX -sAlpha)*s[RgbU8Traits::green_pos]+(qreal)
883
(UINT8_MAX -dAlpha)*d[RgbU8Traits::green_pos])/UINT8_MAX ;
884
d[RgbU8Traits::green_pos]=RoundSignedToQuantum(Qt::green);
887
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) ) {
888
blue=((qreal) (UINT8_MAX -sAlpha)*s[RgbU8Traits::blue_pos]+(qreal)
889
(UINT8_MAX -dAlpha)*d[RgbU8Traits::blue_pos])/UINT8_MAX ;
890
d[RgbU8Traits::blue_pos]=RoundSignedToQuantum(Qt::blue);
893
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) ) {
894
alpha =((qreal) (UINT8_MAX -sAlpha)+
895
(qreal) (UINT8_MAX -dAlpha))/UINT8_MAX ;
896
d[RgbU8Traits::alpha_pos]=UINT8_MAX -RoundSignedToQuantum(alpha );
907
void KoRgbU8CompositeOp::compositeMinus(qint32 pixelSize,
914
quint8 opacity, const QBitArray & channelFlags) const
916
if (opacity == OPACITY_TRANSPARENT)
924
qreal sAlpha, dAlpha;
925
qreal alpha, red, green, blue;
930
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
931
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
932
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
934
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) ) {
935
red=((qreal) (UINT8_MAX -dAlpha)*d[RgbU8Traits::red_pos]-
936
(qreal) (UINT8_MAX -sAlpha)*s[RgbU8Traits::red_pos])/UINT8_MAX ;
937
d[RgbU8Traits::red_pos]=RoundSignedToQuantum(Qt::red);
940
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) ) {
941
green=((qreal) (UINT8_MAX -dAlpha)*d[RgbU8Traits::green_pos]-
942
(qreal) (UINT8_MAX -sAlpha)*s[RgbU8Traits::green_pos])/UINT8_MAX ;
943
d[RgbU8Traits::green_pos]=RoundSignedToQuantum(Qt::green);
946
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) ) {
947
blue=((qreal) (UINT8_MAX -dAlpha)*d[RgbU8Traits::blue_pos]-
948
(qreal) (UINT8_MAX -sAlpha)*s[RgbU8Traits::blue_pos])/UINT8_MAX ;
949
d[RgbU8Traits::blue_pos]=RoundSignedToQuantum(Qt::blue);
952
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) ) {
953
alpha =((qreal) (UINT8_MAX -dAlpha)-
954
(qreal) (UINT8_MAX -sAlpha))/UINT8_MAX ;
955
d[RgbU8Traits::alpha_pos]=UINT8_MAX -RoundSignedToQuantum(alpha );
964
void KoRgbU8CompositeOp::compositeAdd(qint32 pixelSize,
971
quint8 opacity, const QBitArray & channelFlags) const
973
if (opacity == OPACITY_TRANSPARENT)
981
qreal sAlpha, dAlpha;
982
qreal red, green, blue;
987
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
988
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
989
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
991
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) ) {
992
red=(qreal) s[RgbU8Traits::red_pos]+d[RgbU8Traits::red_pos];
993
d[RgbU8Traits::red_pos]=(quint8)
994
(red > UINT8_MAX ? red-=UINT8_MAX : red+0.5);
997
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) ) {
998
green=(qreal) s[RgbU8Traits::green_pos]+d[RgbU8Traits::green_pos];
999
d[RgbU8Traits::green_pos]=(quint8)
1000
(green > UINT8_MAX ? green-=UINT8_MAX : green+0.5);
1003
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) ) {
1004
blue=(qreal) s[RgbU8Traits::blue_pos]+d[RgbU8Traits::blue_pos];
1005
d[RgbU8Traits::blue_pos]=(quint8)
1006
(blue > UINT8_MAX ? blue-=UINT8_MAX : blue+0.5);
1008
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) )
1009
d[RgbU8Traits::alpha_pos]=OPACITY_OPAQUE;
1018
void KoRgbU8CompositeOp::compositeDiff(qint32 pixelSize,
1025
quint8 opacity, const QBitArray & channelFlags) const
1027
if (opacity == OPACITY_TRANSPARENT)
1035
qreal sAlpha, dAlpha;
1037
while (rows-- > 0) {
1040
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
1041
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
1042
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
1044
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
1045
d[RgbU8Traits::red_pos]=(quint8)
1046
AbsoluteValue(s[RgbU8Traits::red_pos]-(qreal) d[RgbU8Traits::red_pos]);
1048
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
1049
d[RgbU8Traits::green_pos]=(quint8)
1050
AbsoluteValue(s[RgbU8Traits::green_pos]-(qreal) d[RgbU8Traits::green_pos]);
1053
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
1054
d[RgbU8Traits::blue_pos]=(quint8)
1055
AbsoluteValue(s[RgbU8Traits::blue_pos]-(qreal) d[RgbU8Traits::blue_pos]);
1057
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) )
1058
d[RgbU8Traits::alpha_pos]=UINT8_MAX - (quint8)
1059
AbsoluteValue(sAlpha-(qreal) dAlpha);
1068
void KoRgbU8CompositeOp::compositeBumpmap(qint32 pixelSize,
1075
quint8 opacity, const QBitArray & channelFlags) const
1077
if (opacity == OPACITY_TRANSPARENT)
1087
while (rows-- > 0) {
1090
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
1091
// Is this correct? It's not this way in GM.
1092
if (s[RgbU8Traits::alpha_pos] == OPACITY_TRANSPARENT)
1095
// And I'm not sure whether this is correct, either.
1096
intensity = ((qreal)306.0 * s[RgbU8Traits::red_pos] +
1097
(qreal)601.0 * s[RgbU8Traits::green_pos] +
1098
(qreal)117.0 * s[RgbU8Traits::blue_pos]) / 1024.0;
1100
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
1101
d[RgbU8Traits::red_pos]=(quint8) (((qreal)
1102
intensity * d[RgbU8Traits::red_pos])/UINT8_MAX +0.5);
1104
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
1105
d[RgbU8Traits::green_pos]=(quint8) (((qreal)
1106
intensity * d[RgbU8Traits::green_pos])/UINT8_MAX +0.5);
1108
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
1109
d[RgbU8Traits::blue_pos]=(quint8) (((qreal)
1110
intensity * d[RgbU8Traits::blue_pos])/UINT8_MAX +0.5);
1112
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) )
1113
d[RgbU8Traits::alpha_pos]= (quint8) (((qreal)
1114
intensity * d[RgbU8Traits::alpha_pos])/UINT8_MAX +0.5);
1125
void KoRgbU8CompositeOp::compositeCopyChannel(quint8 pixel, quint32 pixelSize, quint8 *dst, qint32 dstRowSize, const quint8 *src, qint32 srcRowSize,qint32 rows, qint32 cols, quint8 opacity, const QBitArray & channelFlags) const
1127
Q_UNUSED( channelFlags );
1128
Q_UNUSED( opacity );
1133
while (rows-- > 0) {
1137
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
1138
d[pixel] = s[pixel];
1146
void KoRgbU8CompositeOp::compositeCopyRed(qint32 pixelSize,
1153
quint8 opacity, const QBitArray & channelFlags) const
1155
compositeCopyChannel(RgbU8Traits::red_pos, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity, channelFlags);
1158
void KoRgbU8CompositeOp::compositeCopyGreen(qint32 pixelSize,
1165
quint8 opacity, const QBitArray & channelFlags) const
1167
compositeCopyChannel(RgbU8Traits::green_pos, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity, channelFlags);
1170
void KoRgbU8CompositeOp::compositeCopyBlue(qint32 pixelSize,
1177
quint8 opacity, const QBitArray & channelFlags) const
1179
compositeCopyChannel(RgbU8Traits::blue_pos, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity, channelFlags);
1183
void KoRgbU8CompositeOp::compositeCopyOpacity(qint32 pixelSize,
1190
quint8 opacity, const QBitArray & channelFlags) const
1193
// XXX: mess with intensity if there isn't an alpha channel, according to GM.
1194
compositeCopyChannel(RgbU8Traits::alpha_pos, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity, channelFlags);
1199
void KoRgbU8CompositeOp::compositeClear(qint32 pixelSize,
1206
quint8 opacity, const QBitArray & channelFlags) const
1208
Q_UNUSED( opacity );
1209
Q_UNUSED( srcRowSize );
1211
qint32 linesize = pixelSize * sizeof(quint8) * cols;
1217
if ( channelFlags.isEmpty() ) {
1218
while (rows-- > 0) {
1219
memset(d, 0, linesize);
1224
while ( rows-- > 0 ) {
1225
for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
1226
if ( channelFlags.testBit( channel ) )
1227
memset( d, 0, pixelSize );
1235
void KoRgbU8CompositeOp::compositeDissolve(qint32 pixelSize,
1242
quint8 opacity, const QBitArray & channelFlags) const
1244
if (opacity == OPACITY_TRANSPARENT)
1252
qreal sAlpha, dAlpha;
1254
while (rows-- > 0) {
1257
for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
1259
if (s[RgbU8Traits::alpha_pos] == OPACITY_TRANSPARENT) continue;
1261
sAlpha = UINT8_MAX - s[RgbU8Traits::alpha_pos];
1262
dAlpha = UINT8_MAX - d[RgbU8Traits::alpha_pos];
1264
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::red_pos ) )
1265
d[RgbU8Traits::red_pos]=(quint8) (((qreal) sAlpha*s[RgbU8Traits::red_pos]+
1266
(UINT8_MAX -sAlpha)*d[RgbU8Traits::red_pos])/UINT8_MAX +0.5);
1268
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::green_pos ) )
1269
d[RgbU8Traits::green_pos]= (quint8) (((qreal) sAlpha*s[RgbU8Traits::green_pos]+
1270
(UINT8_MAX -sAlpha)*d[RgbU8Traits::green_pos])/UINT8_MAX +0.5);
1272
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::blue_pos ) )
1273
d[RgbU8Traits::blue_pos] = (quint8) (((qreal) sAlpha*s[RgbU8Traits::blue_pos]+
1274
(UINT8_MAX -sAlpha)*d[RgbU8Traits::blue_pos])/UINT8_MAX +0.5);
1276
if ( channelFlags.isEmpty() || channelFlags.testBit( RgbU8Traits::alpha_pos ) )
1277
d[RgbU8Traits::alpha_pos] = OPACITY_OPAQUE;
1286
void KoRgbU8CompositeOp::compositeCopy(qint32 pixelSize,
1287
quint8 *dstRowStart,
1288
qint32 dstRowStride,
1289
const quint8 *srcRowStart,
1290
qint32 srcRowStride,
1291
const quint8 *maskRowStart,
1292
qint32 maskRowStride,
1295
quint8 opacity, const QBitArray & channelFlags) const
1298
Q_UNUSED(maskRowStart);
1299
Q_UNUSED(maskRowStride);
1301
quint8 *dst = dstRowStart;
1302
const quint8 *src = srcRowStart;
1304
if ( channelFlags.isEmpty() ) {
1307
memcpy(dst, src, numColumns * pixelSize);
1309
if (opacity != OPACITY_OPAQUE) {
1310
colorSpace()->multiplyAlpha(dst, opacity, numColumns);
1313
dst += dstRowStride;
1314
src += srcRowStride;
1319
while ( rows > 0 ) {
1320
for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
1321
if ( channelFlags.testBit( channel ) ) {
1322
memcpy( dst, src, pixelSize );
1327
// XXX: how about the opacity here?