38
38
* @param _compositeOp this class should define a function with the
39
39
* following signature: inline static void composeColorChannels
41
template<class _CSTraits, class _compositeOp>
42
class KoCompositeOpAlphaBase : public KoCompositeOp {
41
template<class _CSTraits, class _compositeOp, bool _alphaLocked>
42
class KoCompositeOpAlphaBase : public KoCompositeOp
43
44
typedef typename _CSTraits::channels_type channels_type;
46
KoCompositeOpAlphaBase(const KoColorSpace * cs, const QString& id, const QString& description, const QString& category )
47
: KoCompositeOp(cs, id, description, category )
47
KoCompositeOpAlphaBase(const KoColorSpace * cs, const QString& id, const QString& description, const QString& category)
48
: KoCompositeOp(cs, id, description, category) {
52
52
using KoCompositeOp::composite;
63
const QBitArray & channelFlags) const
65
qint32 srcInc = (srcstride == 0) ? 0 : _CSTraits::channels_nb;
66
if ( _CSTraits::alpha_pos == -1 ) {
68
qint32 pixelSize = colorSpace()->pixelSize();
70
// XXX: if cols == (dststride/dstPixelSize) == (srcstride/srcPixelSize) == maskstride/maskpixelsize)
71
// then don't loop through rows and cols, but composite everything in one go
73
const channels_type *srcN = reinterpret_cast<const channels_type *>(srcRowStart);
74
channels_type *dstN = reinterpret_cast<channels_type *>(dstRowStart);
75
const quint8 *mask = maskRowStart;
77
qint32 columns = cols;
82
// Don't blend dst with src if the mask is fully
86
if (*mask == OPACITY_TRANSPARENT) {
89
srcN+=_CSTraits::channels_nb;
90
dstN+=_CSTraits::channels_nb;
96
_compositeOp::composeColorChannels( NATIVE_OPACITY_OPAQUE, srcN, dstN, pixelSize, channelFlags );
100
dstN += _CSTraits::channels_nb;
104
srcRowStart += srcstride;
105
dstRowStart += dststride;
107
maskRowStart += maskstride;
113
channels_type opacity = KoColorSpaceMaths<quint8, channels_type>::scaleToA(U8_opacity);
114
qint32 pixelSize = colorSpace()->pixelSize();
117
const channels_type *srcN = reinterpret_cast<const channels_type *>(srcRowStart);
118
channels_type *dstN = reinterpret_cast<channels_type *>(dstRowStart);
119
const quint8 *mask = maskRowStart;
121
qint32 columns = cols;
123
while (columns > 0) {
125
channels_type srcAlpha = _compositeOp::selectAlpha(srcN[_CSTraits::alpha_pos], dstN[_CSTraits::alpha_pos]);
127
// apply the alphamask
129
if (*mask != OPACITY_OPAQUE) {
130
srcAlpha = KoColorSpaceMaths<channels_type,quint8>::multiply(srcAlpha, *mask);
135
if (srcAlpha != NATIVE_OPACITY_TRANSPARENT) {
137
if (opacity != NATIVE_OPACITY_OPAQUE) {
138
srcAlpha = KoColorSpaceMaths<channels_type>::multiply(srcAlpha, opacity);
141
channels_type dstAlpha = dstN[_CSTraits::alpha_pos];
143
channels_type srcBlend;
145
if (dstAlpha == NATIVE_OPACITY_OPAQUE) {
63
const QBitArray & channelFlags) const {
65
qint32 srcInc = (srcstride == 0) ? 0 : _CSTraits::channels_nb;
66
bool allChannelFlags = channelFlags.isEmpty();
67
if (_CSTraits::alpha_pos == -1) {
69
qint32 pixelSize = _CSTraits::pixelSize;
71
// XXX: if cols == (dststride/dstPixelSize) == (srcstride/srcPixelSize) == maskstride/maskpixelsize)
72
// then don't loop through rows and cols, but composite everything in one go
74
const channels_type *srcN = reinterpret_cast<const channels_type *>(srcRowStart);
75
channels_type *dstN = reinterpret_cast<channels_type *>(dstRowStart);
76
const quint8 *mask = maskRowStart;
78
qint32 columns = cols;
83
// Don't blend dst with src if the mask is fully
87
if (*mask == OPACITY_TRANSPARENT_U8) {
90
srcN += _CSTraits::channels_nb;
91
dstN += _CSTraits::channels_nb;
97
_compositeOp::composeColorChannels(NATIVE_OPACITY_OPAQUE, srcN, dstN, pixelSize, allChannelFlags, channelFlags);
101
dstN += _CSTraits::channels_nb;
105
srcRowStart += srcstride;
106
dstRowStart += dststride;
108
maskRowStart += maskstride;
112
bool alphaLocked = false;
113
if (!channelFlags.isEmpty()) {
114
if (!channelFlags.testBit(_CSTraits::alpha_pos)) {
119
channels_type opacity = KoColorSpaceMaths<quint8, channels_type>::scaleToA(U8_opacity);
120
qint32 pixelSize = _CSTraits::pixelSize;
123
const channels_type *srcN = reinterpret_cast<const channels_type *>(srcRowStart);
124
channels_type *dstN = reinterpret_cast<channels_type *>(dstRowStart);
125
const quint8 *mask = maskRowStart;
127
qint32 columns = cols;
129
while (columns > 0) {
131
channels_type srcAlpha = _compositeOp::selectAlpha(srcN[_CSTraits::alpha_pos], dstN[_CSTraits::alpha_pos]);
133
// apply the alphamask
135
if (*mask != OPACITY_OPAQUE_U8) {
136
srcAlpha = KoColorSpaceMaths<channels_type, quint8>::multiply(srcAlpha, *mask);
141
if (srcAlpha != NATIVE_OPACITY_TRANSPARENT) {
143
if (opacity != NATIVE_OPACITY_OPAQUE) {
144
srcAlpha = KoColorSpaceMaths<channels_type>::multiply(srcAlpha, opacity);
147
channels_type dstAlpha = dstN[_CSTraits::alpha_pos];
149
channels_type srcBlend;
151
if (dstAlpha == NATIVE_OPACITY_OPAQUE) {
154
channels_type newAlpha = dstAlpha + KoColorSpaceMaths<channels_type>::multiply(NATIVE_OPACITY_OPAQUE - dstAlpha, srcAlpha);
155
if (!alphaLocked && !_alphaLocked) {
156
dstN[_CSTraits::alpha_pos] = newAlpha;
160
srcBlend = KoColorSpaceMaths<channels_type>::divide(srcAlpha, newAlpha);
146
162
srcBlend = srcAlpha;
148
channels_type newAlpha = dstAlpha + KoColorSpaceMaths<channels_type>::multiply(NATIVE_OPACITY_OPAQUE - dstAlpha, srcAlpha);
149
dstN[_CSTraits::alpha_pos] = newAlpha;
152
srcBlend = KoColorSpaceMaths<channels_type>::divide(srcAlpha, newAlpha);
157
_compositeOp::composeColorChannels( srcBlend, srcN, dstN, pixelSize, channelFlags );
162
dstN+=_CSTraits::channels_nb;
166
srcRowStart += srcstride;
167
dstRowStart += dststride;
169
maskRowStart += maskstride;
165
_compositeOp::composeColorChannels(srcBlend, srcN, dstN, pixelSize, allChannelFlags, channelFlags);
170
dstN += _CSTraits::channels_nb;
174
srcRowStart += srcstride;
175
dstRowStart += dststride;
177
maskRowStart += maskstride;