5 #include "BlendingAlgorithms.h"
7 #include "TextureTile.h"
17 void OverpaintBlending::blend(
QImage *
const bottom, TextureTile
const *
const top )
const
21 Q_ASSERT( top->image() );
22 Q_ASSERT( bottom->
size() == top->image()->size() );
27 painter.drawImage( 0, 0, *top->image() );
30 void GrayscaleBlending::blend(
QImage *
const bottom, TextureTile
const *
const top )
const
34 Q_ASSERT( top->image() );
35 Q_ASSERT( bottom->
size() == top->image()->size() );
40 int const width = bottom->
width();
41 int const height = bottom->
height();
43 for (
int y = 0; y < height; ++y ) {
44 for (
int x = 0; x < width; ++x ) {
45 QRgb
const topPixel = topImagePremult.
pixel( x, y );
46 int const gray = qGray( topPixel );
47 QRgb
const grayPixel = qRgb( gray, gray, gray );
54 void InvertColorBlending::blend(
QImage *
const bottom, TextureTile
const *
const top )
const
58 Q_ASSERT( top->image() );
59 Q_ASSERT( bottom->
size() == top->image()->size() );
64 int const width = bottom->
width();
65 int const height = bottom->
height();
67 for (
int y = 0; y < height; ++y ) {
68 for (
int x = 0; x < width; ++x ) {
69 QRgb
const topPixel = topImagePremult.
pixel( x, y );
70 QRgb
const invertedPixel = qRgb( 255 - qRed(topPixel), 255 - qGreen(topPixel), 255 - qBlue(topPixel) );
71 bottom->
setPixel( x, y, invertedPixel );
76 void InvertHueBlending::blend(
QImage *
const bottom, TextureTile
const *
const top )
const
80 Q_ASSERT( top->image() );
81 Q_ASSERT( bottom->
size() == top->image()->size() );
86 int const width = bottom->
width();
87 int const height = bottom->
height();
89 for (
int y = 0; y < height; ++y ) {
90 for (
int x = 0; x < width; ++x ) {
91 QRgb
const topPixel = topImagePremult.
pixel( x, y );
92 QColor invertedColor(255 - qRed(topPixel), 255 - qGreen(topPixel), 255 - qBlue(topPixel));
93 int hue = invertedColor.hslHue();
94 int saturation = invertedColor.hslSaturation();
95 int lightness = invertedColor.lightness();
97 QRgb naturalInvertedPixel = naturalInvertedColor.
rgb();
98 bottom->
setPixel( x, y, naturalInvertedPixel );
106 void IndependentChannelBlending::blend(
QImage *
const bottom,
107 TextureTile
const *
const top )
const
109 QImage const *
const topImage = top->image();
110 Q_ASSERT( topImage );
111 Q_ASSERT( bottom->
size() == topImage->
size() );
114 int const width = bottom->
width();
115 int const height = bottom->
height();
117 for (
int y = 0; y < height; ++y ) {
118 for (
int x = 0; x < width; ++x ) {
119 QRgb
const bottomPixel = bottom->
pixel( x, y );
120 QRgb
const topPixel = topImagePremult.
pixel( x, y );
121 qreal
const resultRed = blendChannel( qRed( bottomPixel ) / 255.0,
122 qRed( topPixel ) / 255.0 );
123 qreal
const resultGreen = blendChannel( qGreen( bottomPixel ) / 255.0,
124 qGreen( topPixel ) / 255.0 );
125 qreal
const resultBlue = blendChannel( qBlue( bottomPixel ) / 255.0,
126 qBlue( topPixel ) / 255.0 );
127 bottom->
setPixel( x, y, qRgb( resultRed * 255.0,
129 resultBlue * 255.0 ));
137 qreal AllanonBlending::blendChannel( qreal
const bottomColorIntensity,
138 qreal
const topColorIntensity )
const
140 return ( bottomColorIntensity + topColorIntensity ) / 2.0;
143 qreal ArcusTangentBlending::blendChannel( qreal
const bottomColorIntensity,
144 qreal
const topColorIntensity )
const
146 return 2.0 * atan( topColorIntensity / bottomColorIntensity ) / M_PI;
149 qreal GeometricMeanBlending::blendChannel( qreal
const bottomColorIntensity,
150 qreal
const topColorIntensity )
const
152 return sqrt( bottomColorIntensity * topColorIntensity );
155 qreal LinearLightBlending::blendChannel( qreal
const bottomColorIntensity,
156 qreal
const topColorIntensity )
const
158 return qMin( qreal( 1.0 ),
159 qMax( qreal( 0.0 ), qreal( bottomColorIntensity + 2.0 * topColorIntensity - 1.0 )));
162 qreal OverlayBlending::blendChannel( qreal
const bottomColorIntensity,
163 qreal
const topColorIntensity )
const
165 if ( bottomColorIntensity < 0.5 )
166 return 2.0 * bottomColorIntensity * topColorIntensity;
168 return 1.0 - 2.0 * ( 1.0 - bottomColorIntensity ) * ( 1.0 - topColorIntensity );
171 qreal ParallelBlending::blendChannel( qreal
const bottomColorIntensity,
172 qreal
const topColorIntensity )
const
174 Q_UNUSED(bottomColorIntensity);
175 Q_UNUSED(topColorIntensity);
180 qreal TextureBlending::blendChannel( qreal
const bottomColorIntensity,
181 qreal
const topColorIntensity )
const
183 Q_UNUSED(bottomColorIntensity);
184 Q_UNUSED(topColorIntensity);
192 qreal ColorBurnBlending::blendChannel( qreal
const bottomColorIntensity,
193 qreal
const topColorIntensity )
const
195 Q_UNUSED(bottomColorIntensity);
196 Q_UNUSED(topColorIntensity);
198 return qMin( qreal( 1.0 ),
199 qMax( qreal( 0.0 ), qreal( 1.0 - ( 1.0 - bottomColorIntensity ) / topColorIntensity )));
202 qreal DarkBlending::blendChannel( qreal
const bottomColorIntensity,
203 qreal
const topColorIntensity )
const
205 return ( bottomColorIntensity + 1.0 - topColorIntensity ) * topColorIntensity;
208 qreal DarkenBlending::blendChannel( qreal
const bottomColorIntensity,
209 qreal
const topColorIntensity )
const
212 return bottomColorIntensity > topColorIntensity ? topColorIntensity : bottomColorIntensity;
215 qreal DivideBlending::blendChannel( qreal
const bottomColorIntensity,
216 qreal
const topColorIntensity )
const
218 return log1p( bottomColorIntensity / ( 1.0 - topColorIntensity ) / 8.0) / log(2.0);
221 qreal GammaDarkBlending::blendChannel( qreal
const bottomColorIntensity,
222 qreal
const topColorIntensity )
const
224 return pow( bottomColorIntensity, 1.0 / topColorIntensity );
227 qreal LinearBurnBlending::blendChannel( qreal
const bottomColorIntensity,
228 qreal
const topColorIntensity )
const
230 return qMax( qreal(0.0), bottomColorIntensity + topColorIntensity - qreal( 1.0 ) );
233 qreal MultiplyBlending::blendChannel( qreal
const bottomColorIntensity,
234 qreal
const topColorIntensity )
const
236 return bottomColorIntensity * topColorIntensity;
239 qreal SubtractiveBlending::blendChannel( qreal
const bottomColorIntensity,
240 qreal
const topColorIntensity )
const
242 return qMax( bottomColorIntensity - topColorIntensity, qreal(0.0) );
248 qreal AdditiveBlending::blendChannel( qreal
const bottomColorIntensity,
249 qreal
const topColorIntensity )
const
251 return qMin( topColorIntensity + bottomColorIntensity, qreal(1.0) );
254 qreal ColorDodgeBlending::blendChannel( qreal
const bottomColorIntensity,
255 qreal
const topColorIntensity )
const
257 return qMin( qreal( 1.0 ),
258 qMax( qreal( 0.0 ), qreal( bottomColorIntensity / ( 1.0 - topColorIntensity ))));
261 qreal GammaLightBlending::blendChannel( qreal
const bottomColorIntensity,
262 qreal
const topColorIntensity )
const
264 return pow( bottomColorIntensity, topColorIntensity );
267 qreal HardLightBlending::blendChannel( qreal
const bottomColorIntensity,
268 qreal
const topColorIntensity )
const
270 return topColorIntensity < 0.5
271 ? 2.0 * bottomColorIntensity * topColorIntensity
272 : 1.0 - 2.0 * ( 1.0 - bottomColorIntensity ) * ( 1.0 - topColorIntensity );
275 qreal LightBlending::blendChannel( qreal
const bottomColorIntensity,
276 qreal
const topColorIntensity )
const
278 return bottomColorIntensity * ( 1.0 - topColorIntensity ) + pow( topColorIntensity, 2 );
281 qreal LightenBlending::blendChannel( qreal
const bottomColorIntensity,
282 qreal
const topColorIntensity )
const
285 return bottomColorIntensity < topColorIntensity ? topColorIntensity : bottomColorIntensity;
288 qreal PinLightBlending::blendChannel( qreal
const bottomColorIntensity,
289 qreal
const topColorIntensity )
const
291 return qMax( qreal(0.0), qMax( qreal(2.0 + topColorIntensity - 1.0),
292 qMin( bottomColorIntensity, qreal(2.0 * topColorIntensity ))));
295 qreal ScreenBlending::blendChannel( qreal
const bottomColorIntensity,
296 qreal
const topColorIntensity )
const
298 return 1.0 - ( 1.0 - bottomColorIntensity ) * ( 1.0 - topColorIntensity );
301 qreal SoftLightBlending::blendChannel( qreal
const bottomColorIntensity,
302 qreal
const topColorIntensity )
const
304 return pow( bottomColorIntensity, pow( 2.0, ( 2.0 * ( 0.5 - topColorIntensity ))));
307 qreal VividLightBlending::blendChannel( qreal
const bottomColorIntensity,
308 qreal
const topColorIntensity )
const
310 return topColorIntensity < 0.5
311 ? qMin( qreal( 1.0 ),
312 qMax( qreal( 0.0 ), qreal( 1.0 - ( 1.0 - bottomColorIntensity ) / ( 2.0 * topColorIntensity ))))
313 : qMin( qreal( 1.0 ),
314 qMax( qreal( 0.0 ), qreal( bottomColorIntensity / ( 2.0 * ( 1.0 - topColorIntensity )))));
320 qreal AdditiveSubtractiveBlending::blendChannel( qreal
const bottomColorIntensity,
321 qreal
const topColorIntensity )
const
323 Q_UNUSED(bottomColorIntensity);
324 Q_UNUSED(topColorIntensity);
331 qreal BleachBlending::blendChannel( qreal
const bottomColorIntensity,
332 qreal
const topColorIntensity )
const
335 return 1.0 - ( 1.0 - bottomColorIntensity ) * ( 1.0 - topColorIntensity );
338 qreal DifferenceBlending::blendChannel( qreal
const bottomColorIntensity,
339 qreal
const topColorIntensity )
const
341 return qMax( qMin( qreal( 1.0 ), qreal( bottomColorIntensity - topColorIntensity + 0.5 )),
345 qreal EquivalenceBlending::blendChannel( qreal
const bottomColorIntensity,
346 qreal
const topColorIntensity )
const
348 return 1.0 - qAbs( bottomColorIntensity - topColorIntensity );
351 qreal HalfDifferenceBlending::blendChannel( qreal
const bottomColorIntensity,
352 qreal
const topColorIntensity )
const
354 return bottomColorIntensity + topColorIntensity
355 - 2.0 * ( bottomColorIntensity * topColorIntensity );
361 void CloudsBlending::blend(
QImage *
const bottom, TextureTile
const *
const top )
const
363 QImage const *
const topImage = top->image();
364 Q_ASSERT( topImage );
365 Q_ASSERT( bottom->
size() == topImage->
size() );
366 int const width = bottom->
width();
367 int const height = bottom->
height();
368 for (
int y = 0; y < height; ++y ) {
369 for (
int x = 0; x < width; ++x ) {
370 qreal
const c = qRed( topImage->
pixel( x, y )) / 255.0;
371 QRgb
const bottomPixel = bottom->
pixel( x, y );
372 int const bottomRed = qRed( bottomPixel );
373 int const bottomGreen = qGreen( bottomPixel );
374 int const bottomBlue = qBlue( bottomPixel );
375 bottom->
setPixel( x, y, qRgb((
int )( bottomRed + ( 255 - bottomRed ) * c ),
376 (
int )( bottomGreen + ( 255 - bottomGreen ) * c ),
377 (
int )( bottomBlue + ( 255 - bottomBlue ) * c )));