00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdlib.h>
00020 #include <string.h>
00021 #include <cfloat>
00022
00023 #include "qbrush.h"
00024 #include "qcolor.h"
00025 #include "qfontinfo.h"
00026 #include "qfontmetrics.h"
00027 #include "qpen.h"
00028 #include "qregion.h"
00029 #include "qwmatrix.h"
00030 #include <qimage.h>
00031 #include <qmap.h>
00032 #include <qpainter.h>
00033 #include <qpixmap.h>
00034 #include <qpointarray.h>
00035 #include <qrect.h>
00036 #include <qstring.h>
00037
00038 #include <kdebug.h>
00039 #include <klocale.h>
00040
00041 #include "kis_brush.h"
00042 #include "kis_debug_areas.h"
00043 #include "kis_gradient.h"
00044 #include "kis_image.h"
00045 #include "kis_iterators_pixel.h"
00046 #include "kis_layer.h"
00047 #include "kis_paint_device.h"
00048 #include "kis_pattern.h"
00049 #include "kis_rect.h"
00050 #include "kis_colorspace.h"
00051 #include "kis_types.h"
00052 #include "kis_vec.h"
00053 #include "kis_selection.h"
00054 #include "kis_gradient_painter.h"
00055 #include "kis_meta_registry.h"
00056 #include "kis_colorspace_factory_registry.h"
00057
00058 namespace {
00059
00060 class GradientShapeStrategy {
00061 public:
00062 GradientShapeStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd);
00063 virtual ~GradientShapeStrategy() {}
00064
00065 virtual double valueAt(double x, double y) const = 0;
00066
00067 protected:
00068 KisPoint m_gradientVectorStart;
00069 KisPoint m_gradientVectorEnd;
00070 };
00071
00072 GradientShapeStrategy::GradientShapeStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd)
00073 : m_gradientVectorStart(gradientVectorStart), m_gradientVectorEnd(gradientVectorEnd)
00074 {
00075 }
00076
00077
00078 class LinearGradientStrategy : public GradientShapeStrategy {
00079 typedef GradientShapeStrategy super;
00080 public:
00081 LinearGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd);
00082
00083 virtual double valueAt(double x, double y) const;
00084
00085 protected:
00086 double m_normalisedVectorX;
00087 double m_normalisedVectorY;
00088 double m_vectorLength;
00089 };
00090
00091 LinearGradientStrategy::LinearGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd)
00092 : super(gradientVectorStart, gradientVectorEnd)
00093 {
00094 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
00095 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
00096
00097 m_vectorLength = sqrt((dx * dx) + (dy * dy));
00098
00099 if (m_vectorLength < DBL_EPSILON) {
00100 m_normalisedVectorX = 0;
00101 m_normalisedVectorY = 0;
00102 }
00103 else {
00104 m_normalisedVectorX = dx / m_vectorLength;
00105 m_normalisedVectorY = dy / m_vectorLength;
00106 }
00107 }
00108
00109 double LinearGradientStrategy::valueAt(double x, double y) const
00110 {
00111 double vx = x - m_gradientVectorStart.x();
00112 double vy = y - m_gradientVectorStart.y();
00113
00114
00115 double t = vx * m_normalisedVectorX + vy * m_normalisedVectorY;
00116
00117 if (m_vectorLength < DBL_EPSILON) {
00118 t = 0;
00119 }
00120 else {
00121
00122 t /= m_vectorLength;
00123 }
00124
00125 return t;
00126 }
00127
00128
00129 class BiLinearGradientStrategy : public LinearGradientStrategy {
00130 typedef LinearGradientStrategy super;
00131 public:
00132 BiLinearGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd);
00133
00134 virtual double valueAt(double x, double y) const;
00135 };
00136
00137 BiLinearGradientStrategy::BiLinearGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd)
00138 : super(gradientVectorStart, gradientVectorEnd)
00139 {
00140 }
00141
00142 double BiLinearGradientStrategy::valueAt(double x, double y) const
00143 {
00144 double t = super::valueAt(x, y);
00145
00146
00147 if (t < -DBL_EPSILON) {
00148 t = -t;
00149 }
00150
00151 return t;
00152 }
00153
00154
00155 class RadialGradientStrategy : public GradientShapeStrategy {
00156 typedef GradientShapeStrategy super;
00157 public:
00158 RadialGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd);
00159
00160 virtual double valueAt(double x, double y) const;
00161
00162 protected:
00163 double m_radius;
00164 };
00165
00166 RadialGradientStrategy::RadialGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd)
00167 : super(gradientVectorStart, gradientVectorEnd)
00168 {
00169 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
00170 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
00171
00172 m_radius = sqrt((dx * dx) + (dy * dy));
00173 }
00174
00175 double RadialGradientStrategy::valueAt(double x, double y) const
00176 {
00177 double dx = x - m_gradientVectorStart.x();
00178 double dy = y - m_gradientVectorStart.y();
00179
00180 double distance = sqrt((dx * dx) + (dy * dy));
00181
00182 double t;
00183
00184 if (m_radius < DBL_EPSILON) {
00185 t = 0;
00186 }
00187 else {
00188 t = distance / m_radius;
00189 }
00190
00191 return t;
00192 }
00193
00194
00195 class SquareGradientStrategy : public GradientShapeStrategy {
00196 typedef GradientShapeStrategy super;
00197 public:
00198 SquareGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd);
00199
00200 virtual double valueAt(double x, double y) const;
00201
00202 protected:
00203 double m_normalisedVectorX;
00204 double m_normalisedVectorY;
00205 double m_vectorLength;
00206 };
00207
00208 SquareGradientStrategy::SquareGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd)
00209 : super(gradientVectorStart, gradientVectorEnd)
00210 {
00211 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
00212 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
00213
00214 m_vectorLength = sqrt((dx * dx) + (dy * dy));
00215
00216 if (m_vectorLength < DBL_EPSILON) {
00217 m_normalisedVectorX = 0;
00218 m_normalisedVectorY = 0;
00219 }
00220 else {
00221 m_normalisedVectorX = dx / m_vectorLength;
00222 m_normalisedVectorY = dy / m_vectorLength;
00223 }
00224 }
00225
00226 double SquareGradientStrategy::valueAt(double x, double y) const
00227 {
00228 double px = x - m_gradientVectorStart.x();
00229 double py = y - m_gradientVectorStart.y();
00230
00231 double distance1 = 0;
00232 double distance2 = 0;
00233
00234 if (m_vectorLength > DBL_EPSILON) {
00235
00236
00237
00238
00239
00240
00241 distance1 = -m_normalisedVectorY * px + m_normalisedVectorX * py;
00242 distance1 = fabs(distance1);
00243
00244
00245 distance2 = -m_normalisedVectorY * -py + m_normalisedVectorX * px;
00246 distance2 = fabs(distance2);
00247 }
00248
00249 double t = QMAX(distance1, distance2) / m_vectorLength;
00250
00251 return t;
00252 }
00253
00254
00255 class ConicalGradientStrategy : public GradientShapeStrategy {
00256 typedef GradientShapeStrategy super;
00257 public:
00258 ConicalGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd);
00259
00260 virtual double valueAt(double x, double y) const;
00261
00262 protected:
00263 double m_vectorAngle;
00264 };
00265
00266 ConicalGradientStrategy::ConicalGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd)
00267 : super(gradientVectorStart, gradientVectorEnd)
00268 {
00269 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
00270 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
00271
00272
00273 m_vectorAngle = atan2(dy, dx) + M_PI;
00274 }
00275
00276 double ConicalGradientStrategy::valueAt(double x, double y) const
00277 {
00278 double px = x - m_gradientVectorStart.x();
00279 double py = y - m_gradientVectorStart.y();
00280
00281 double angle = atan2(py, px) + M_PI;
00282
00283 angle -= m_vectorAngle;
00284
00285 if (angle < 0) {
00286 angle += 2 * M_PI;
00287 }
00288
00289 double t = angle / (2 * M_PI);
00290
00291 return t;
00292 }
00293
00294
00295 class ConicalSymetricGradientStrategy : public GradientShapeStrategy {
00296 typedef GradientShapeStrategy super;
00297 public:
00298 ConicalSymetricGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd);
00299
00300 virtual double valueAt(double x, double y) const;
00301
00302 protected:
00303 double m_vectorAngle;
00304 };
00305
00306 ConicalSymetricGradientStrategy::ConicalSymetricGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd)
00307 : super(gradientVectorStart, gradientVectorEnd)
00308 {
00309 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
00310 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
00311
00312
00313 m_vectorAngle = atan2(dy, dx) + M_PI;
00314 }
00315
00316 double ConicalSymetricGradientStrategy::valueAt(double x, double y) const
00317 {
00318 double px = x - m_gradientVectorStart.x();
00319 double py = y - m_gradientVectorStart.y();
00320
00321 double angle = atan2(py, px) + M_PI;
00322
00323 angle -= m_vectorAngle;
00324
00325 if (angle < 0) {
00326 angle += 2 * M_PI;
00327 }
00328
00329 double t;
00330
00331 if (angle < M_PI) {
00332 t = angle / M_PI;
00333 }
00334 else {
00335 t = 1 - ((angle - M_PI) / M_PI);
00336 }
00337
00338 return t;
00339 }
00340
00341
00342 class GradientRepeatStrategy {
00343 public:
00344 GradientRepeatStrategy() {}
00345 virtual ~GradientRepeatStrategy() {}
00346
00347 virtual double valueAt(double t) const = 0;
00348 };
00349
00350
00351 class GradientRepeatNoneStrategy : public GradientRepeatStrategy {
00352 public:
00353 static GradientRepeatNoneStrategy *instance();
00354
00355 virtual double valueAt(double t) const;
00356
00357 private:
00358 GradientRepeatNoneStrategy() {}
00359
00360 static GradientRepeatNoneStrategy *m_instance;
00361 };
00362
00363 GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::m_instance = 0;
00364
00365 GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::instance()
00366 {
00367 if (m_instance == 0) {
00368 m_instance = new GradientRepeatNoneStrategy();
00369 Q_CHECK_PTR(m_instance);
00370 }
00371
00372 return m_instance;
00373 }
00374
00375
00376 double GradientRepeatNoneStrategy::valueAt(double t) const
00377 {
00378 double value = t;
00379
00380 if (t < DBL_EPSILON) {
00381 value = 0;
00382 }
00383 else
00384 if (t > 1 - DBL_EPSILON) {
00385 value = 1;
00386 }
00387
00388 return value;
00389 }
00390
00391
00392 class GradientRepeatForwardsStrategy : public GradientRepeatStrategy {
00393 public:
00394 static GradientRepeatForwardsStrategy *instance();
00395
00396 virtual double valueAt(double t) const;
00397
00398 private:
00399 GradientRepeatForwardsStrategy() {}
00400
00401 static GradientRepeatForwardsStrategy *m_instance;
00402 };
00403
00404 GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::m_instance = 0;
00405
00406 GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::instance()
00407 {
00408 if (m_instance == 0) {
00409 m_instance = new GradientRepeatForwardsStrategy();
00410 Q_CHECK_PTR(m_instance);
00411 }
00412
00413 return m_instance;
00414 }
00415
00416
00417 double GradientRepeatForwardsStrategy::valueAt(double t) const
00418 {
00419 int i = static_cast<int>(t);
00420
00421 if (t < DBL_EPSILON) {
00422 i--;
00423 }
00424
00425 double value = t - i;
00426
00427 return value;
00428 }
00429
00430
00431 class GradientRepeatAlternateStrategy : public GradientRepeatStrategy {
00432 public:
00433 static GradientRepeatAlternateStrategy *instance();
00434
00435 virtual double valueAt(double t) const;
00436
00437 private:
00438 GradientRepeatAlternateStrategy() {}
00439
00440 static GradientRepeatAlternateStrategy *m_instance;
00441 };
00442
00443 GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::m_instance = 0;
00444
00445 GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::instance()
00446 {
00447 if (m_instance == 0) {
00448 m_instance = new GradientRepeatAlternateStrategy();
00449 Q_CHECK_PTR(m_instance);
00450 }
00451
00452 return m_instance;
00453 }
00454
00455
00456 double GradientRepeatAlternateStrategy::valueAt(double t) const
00457 {
00458 if (t < 0) {
00459 t = -t;
00460 }
00461
00462 int i = static_cast<int>(t);
00463
00464 double value = t - i;
00465
00466 if (i % 2 == 1) {
00467 value = 1 - value;
00468 }
00469
00470 return value;
00471 }
00472 }
00473
00474 KisGradientPainter::KisGradientPainter()
00475 : super()
00476 {
00477 m_gradient = 0;
00478 }
00479
00480 KisGradientPainter::KisGradientPainter(KisPaintDeviceSP device) : super(device), m_gradient(0)
00481 {
00482 }
00483
00484 bool KisGradientPainter::paintGradient(const KisPoint& gradientVectorStart,
00485 const KisPoint& gradientVectorEnd,
00486 enumGradientShape shape,
00487 enumGradientRepeat repeat,
00488 double antiAliasThreshold,
00489 bool reverseGradient,
00490 Q_INT32 startx,
00491 Q_INT32 starty,
00492 Q_INT32 width,
00493 Q_INT32 height)
00494 {
00495 m_cancelRequested = false;
00496
00497 if (!m_gradient) return false;
00498
00499 GradientShapeStrategy *shapeStrategy = 0;
00500
00501 switch (shape) {
00502 case GradientShapeLinear:
00503 shapeStrategy = new LinearGradientStrategy(gradientVectorStart, gradientVectorEnd);
00504 break;
00505 case GradientShapeBiLinear:
00506 shapeStrategy = new BiLinearGradientStrategy(gradientVectorStart, gradientVectorEnd);
00507 break;
00508 case GradientShapeRadial:
00509 shapeStrategy = new RadialGradientStrategy(gradientVectorStart, gradientVectorEnd);
00510 break;
00511 case GradientShapeSquare:
00512 shapeStrategy = new SquareGradientStrategy(gradientVectorStart, gradientVectorEnd);
00513 break;
00514 case GradientShapeConical:
00515 shapeStrategy = new ConicalGradientStrategy(gradientVectorStart, gradientVectorEnd);
00516 break;
00517 case GradientShapeConicalSymetric:
00518 shapeStrategy = new ConicalSymetricGradientStrategy(gradientVectorStart, gradientVectorEnd);
00519 break;
00520 }
00521 Q_CHECK_PTR(shapeStrategy);
00522
00523 GradientRepeatStrategy *repeatStrategy = 0;
00524
00525 switch (repeat) {
00526 case GradientRepeatNone:
00527 repeatStrategy = GradientRepeatNoneStrategy::instance();
00528 break;
00529 case GradientRepeatForwards:
00530 repeatStrategy = GradientRepeatForwardsStrategy::instance();
00531 break;
00532 case GradientRepeatAlternate:
00533 repeatStrategy = GradientRepeatAlternateStrategy::instance();
00534 break;
00535 }
00536 Q_ASSERT(repeatStrategy != 0);
00537
00538
00539
00540 QRect r;
00541 if( m_device->hasSelection() ) {
00542 r = m_device->selection()->selectedExactRect();
00543 startx = r.x();
00544 starty = r.y();
00545 width = r.width();
00546 height = r.height();
00547 }
00548
00549 Q_INT32 endx = startx + width - 1;
00550 Q_INT32 endy = starty + height - 1;
00551
00552 QImage layer (width, height, 32);
00553 layer.setAlphaBuffer(true);
00554
00555 int pixelsProcessed = 0;
00556 int lastProgressPercent = 0;
00557
00558 emit notifyProgressStage(i18n("Rendering gradient..."), 0);
00559
00560 int totalPixels = width * height;
00561
00562 if (antiAliasThreshold < 1 - DBL_EPSILON) {
00563 totalPixels *= 2;
00564 }
00565
00566 for (int y = starty; y <= endy; y++) {
00567 for (int x = startx; x <= endx; x++) {
00568
00569 double t = shapeStrategy->valueAt( x, y);
00570 t = repeatStrategy->valueAt(t);
00571
00572 if (reverseGradient) {
00573 t = 1 - t;
00574 }
00575
00576 QColor color;
00577 Q_UINT8 opacity;
00578
00579 m_gradient->colorAt(t, &color, &opacity);
00580
00581 layer.setPixel(x - startx, y - starty,
00582 qRgba(color.red(), color.green(), color.blue(), opacity));
00583
00584 pixelsProcessed++;
00585
00586 int progressPercent = (pixelsProcessed * 100) / totalPixels;
00587
00588 if (progressPercent > lastProgressPercent) {
00589 emit notifyProgress(progressPercent);
00590 lastProgressPercent = progressPercent;
00591
00592 if (m_cancelRequested) {
00593 break;
00594 }
00595 }
00596 if (m_cancelRequested) {
00597 break;
00598 }
00599 }
00600 }
00601
00602 if (!m_cancelRequested && antiAliasThreshold < 1 - DBL_EPSILON) {
00603
00604 emit notifyProgressStage(i18n("Anti-aliasing gradient..."), lastProgressPercent);
00605 Q_UINT8 * layerPointer = layer.bits();
00606 for (int y = starty; y <= endy; y++) {
00607 for (int x = startx; x <= endx; x++) {
00608
00609 double maxDistance = 0;
00610
00611 QColor thisPixel(layerPointer[2], layerPointer[1], layerPointer[0]);
00612 Q_UINT8 thisPixelOpacity = layerPointer[3];
00613
00614 for (int yOffset = -1; yOffset < 2; yOffset++) {
00615 for (int xOffset = -1; xOffset < 2; xOffset++) {
00616
00617 if (xOffset != 0 || yOffset != 0) {
00618 int sampleX = x + xOffset;
00619 int sampleY = y + yOffset;
00620
00621 if (sampleX >= startx && sampleX <= endx && sampleY >= starty && sampleY <= endy) {
00622 uint x = sampleX - startx;
00623 uint y = sampleY - starty;
00624 Q_UINT8 * pixelPos = layer.bits() + (y * width * 4) + (x * 4);
00625 QColor color(*(pixelPos +2), *(pixelPos + 1), *pixelPos);
00626 Q_UINT8 opacity = *(pixelPos + 3);
00627
00628 double dRed = (color.red() * opacity - thisPixel.red() * thisPixelOpacity) / 65535.0;
00629 double dGreen = (color.green() * opacity - thisPixel.green() * thisPixelOpacity) / 65535.0;
00630 double dBlue = (color.blue() * opacity - thisPixel.blue() * thisPixelOpacity) / 65535.0;
00631
00632 #define SQRT_3 1.7320508
00633
00634 double distance = sqrt(dRed * dRed + dGreen * dGreen + dBlue * dBlue) / SQRT_3;
00635
00636 if (distance > maxDistance) {
00637 maxDistance = distance;
00638 }
00639 }
00640 }
00641 }
00642 }
00643
00644 if (maxDistance > antiAliasThreshold) {
00645 const int numSamples = 4;
00646
00647 int totalRed = 0;
00648 int totalGreen = 0;
00649 int totalBlue = 0;
00650 int totalOpacity = 0;
00651
00652 for (int ySample = 0; ySample < numSamples; ySample++) {
00653 for (int xSample = 0; xSample < numSamples; xSample++) {
00654
00655 double sampleWidth = 1.0 / numSamples;
00656
00657 double sampleX = x - 0.5 + (sampleWidth / 2) + xSample * sampleWidth;
00658 double sampleY = y - 0.5 + (sampleWidth / 2) + ySample * sampleWidth;
00659
00660 double t = shapeStrategy->valueAt(sampleX, sampleY);
00661 t = repeatStrategy->valueAt(t);
00662
00663 if (reverseGradient) {
00664 t = 1 - t;
00665 }
00666
00667 QColor color;
00668 Q_UINT8 opacity;
00669
00670 m_gradient->colorAt(t, &color, &opacity);
00671
00672 totalRed += color.red();
00673 totalGreen += color.green();
00674 totalBlue += color.blue();
00675 totalOpacity += opacity;
00676 }
00677 }
00678
00679 int red = totalRed / (numSamples * numSamples);
00680 int green = totalGreen / (numSamples * numSamples);
00681 int blue = totalBlue / (numSamples * numSamples);
00682 int opacity = totalOpacity / (numSamples * numSamples);
00683
00684 layer.setPixel(x - startx, y - starty, qRgba(red, green, blue, opacity));
00685 }
00686
00687 pixelsProcessed++;
00688
00689 int progressPercent = (pixelsProcessed * 100) / totalPixels;
00690
00691 if (progressPercent > lastProgressPercent) {
00692 emit notifyProgress(progressPercent);
00693 lastProgressPercent = progressPercent;
00694
00695 if (m_cancelRequested) {
00696 break;
00697 }
00698 }
00699 layerPointer += 4;
00700 }
00701
00702 if (m_cancelRequested) {
00703 break;
00704 }
00705 }
00706 }
00707
00708 if (!m_cancelRequested) {
00709 kdDebug() << "Have we got a selection? " << m_device->hasSelection() << endl;
00710 KisPaintDeviceSP dev = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(), "temporary device for gradient");
00711 dev->writeBytes(layer.bits(), startx, starty, width, height);
00712 bltSelection(startx, starty, m_compositeOp, dev, m_opacity, startx, starty, width, height);
00713 }
00714 delete shapeStrategy;
00715
00716 emit notifyProgressDone();
00717
00718 return !m_cancelRequested;
00719 }