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 QColor color;
00605 emit notifyProgressStage(i18n("Anti-aliasing gradient..."), lastProgressPercent);
00606 Q_UINT8 * layerPointer = layer.bits();
00607 for (int y = starty; y <= endy; y++) {
00608 for (int x = startx; x <= endx; x++) {
00609
00610 double maxDistance = 0;
00611
00612 Q_UINT8 redThis = layerPointer[2];
00613 Q_UINT8 greenThis = layerPointer[1];
00614 Q_UINT8 blueThis = layerPointer[0];
00615 Q_UINT8 thisPixelOpacity = layerPointer[3];
00616
00617 for (int yOffset = -1; yOffset < 2; yOffset++) {
00618 for (int xOffset = -1; xOffset < 2; xOffset++) {
00619
00620 if (xOffset != 0 || yOffset != 0) {
00621 int sampleX = x + xOffset;
00622 int sampleY = y + yOffset;
00623
00624 if (sampleX >= startx && sampleX <= endx && sampleY >= starty && sampleY <= endy) {
00625 uint x = sampleX - startx;
00626 uint y = sampleY - starty;
00627 Q_UINT8 * pixelPos = layer.bits() + (y * width * 4) + (x * 4);
00628 Q_UINT8 red = *(pixelPos +2);
00629 Q_UINT8 green = *(pixelPos + 1);
00630 Q_UINT8 blue = *pixelPos;
00631 Q_UINT8 opacity = *(pixelPos + 3);
00632
00633 double dRed = (red * opacity - redThis * thisPixelOpacity) / 65535.0;
00634 double dGreen = (green * opacity - greenThis * thisPixelOpacity) / 65535.0;
00635 double dBlue = (blue * opacity - blueThis * thisPixelOpacity) / 65535.0;
00636
00637 #define SQRT_3 1.7320508
00638
00639 double distance =dRed * dRed + dGreen * dGreen + dBlue * dBlue;
00640
00641 if (distance > maxDistance) {
00642 maxDistance = distance;
00643 }
00644 }
00645 }
00646 }
00647 }
00648
00649 if (maxDistance > 3.*antiAliasThreshold*antiAliasThreshold) {
00650 const int numSamples = 4;
00651
00652 int totalRed = 0;
00653 int totalGreen = 0;
00654 int totalBlue = 0;
00655 int totalOpacity = 0;
00656
00657 for (int ySample = 0; ySample < numSamples; ySample++) {
00658 for (int xSample = 0; xSample < numSamples; xSample++) {
00659
00660 double sampleWidth = 1.0 / numSamples;
00661
00662 double sampleX = x - 0.5 + (sampleWidth / 2) + xSample * sampleWidth;
00663 double sampleY = y - 0.5 + (sampleWidth / 2) + ySample * sampleWidth;
00664
00665 double t = shapeStrategy->valueAt(sampleX, sampleY);
00666 t = repeatStrategy->valueAt(t);
00667
00668 if (reverseGradient) {
00669 t = 1 - t;
00670 }
00671
00672 Q_UINT8 opacity;
00673
00674 m_gradient->colorAt(t, &color, &opacity);
00675
00676 totalRed += color.red();
00677 totalGreen += color.green();
00678 totalBlue += color.blue();
00679 totalOpacity += opacity;
00680 }
00681 }
00682
00683 int red = totalRed / (numSamples * numSamples);
00684 int green = totalGreen / (numSamples * numSamples);
00685 int blue = totalBlue / (numSamples * numSamples);
00686 int opacity = totalOpacity / (numSamples * numSamples);
00687
00688 layer.setPixel(x - startx, y - starty, qRgba(red, green, blue, opacity));
00689 }
00690
00691 pixelsProcessed++;
00692
00693 int progressPercent = (pixelsProcessed * 100) / totalPixels;
00694
00695 if (progressPercent > lastProgressPercent) {
00696 emit notifyProgress(progressPercent);
00697 lastProgressPercent = progressPercent;
00698
00699 if (m_cancelRequested) {
00700 break;
00701 }
00702 }
00703 layerPointer += 4;
00704 }
00705
00706 if (m_cancelRequested) {
00707 break;
00708 }
00709 }
00710 }
00711
00712 if (!m_cancelRequested) {
00713 kdDebug() << "Have we got a selection? " << m_device->hasSelection() << endl;
00714 KisPaintDeviceSP dev = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(), "temporary device for gradient");
00715 dev->writeBytes(layer.bits(), startx, starty, width, height);
00716 bltSelection(startx, starty, m_compositeOp, dev, m_opacity, startx, starty, width, height);
00717 }
00718 delete shapeStrategy;
00719
00720 emit notifyProgressDone();
00721
00722 return !m_cancelRequested;
00723 }