25#include "tqfontinfo.h"
26#include "tqfontmetrics.h"
34#include <tqpointarray.h>
42#include "kis_debug_areas.h"
43#include "kis_gradient.h"
45#include "kis_iterators_pixel.h"
47#include "kis_paint_device.h"
48#include "kis_pattern.h"
50#include "kis_colorspace.h"
53#include "kis_selection.h"
54#include "kis_gradient_painter.h"
55#include "kis_meta_registry.h"
56#include "kis_colorspace_factory_registry.h"
60 class GradientShapeStrategy {
62 GradientShapeStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd);
63 virtual ~GradientShapeStrategy() {}
65 virtual double valueAt(
double x,
double y)
const = 0;
68 KisPoint m_gradientVectorStart;
69 KisPoint m_gradientVectorEnd;
72 GradientShapeStrategy::GradientShapeStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd)
73 : m_gradientVectorStart(gradientVectorStart), m_gradientVectorEnd(gradientVectorEnd)
78 class LinearGradientStrategy :
public GradientShapeStrategy {
79 typedef GradientShapeStrategy super;
81 LinearGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd);
83 virtual double valueAt(
double x,
double y)
const;
86 double m_normalisedVectorX;
87 double m_normalisedVectorY;
88 double m_vectorLength;
91 LinearGradientStrategy::LinearGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd)
92 : super(gradientVectorStart, gradientVectorEnd)
94 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
95 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
97 m_vectorLength = sqrt((dx * dx) + (dy * dy));
99 if (m_vectorLength < DBL_EPSILON) {
100 m_normalisedVectorX = 0;
101 m_normalisedVectorY = 0;
104 m_normalisedVectorX = dx / m_vectorLength;
105 m_normalisedVectorY = dy / m_vectorLength;
109 double LinearGradientStrategy::valueAt(
double x,
double y)
const
111 double vx = x - m_gradientVectorStart.x();
112 double vy = y - m_gradientVectorStart.y();
115 double t = vx * m_normalisedVectorX + vy * m_normalisedVectorY;
117 if (m_vectorLength < DBL_EPSILON) {
129 class BiLinearGradientStrategy :
public LinearGradientStrategy {
130 typedef LinearGradientStrategy super;
132 BiLinearGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd);
134 virtual double valueAt(
double x,
double y)
const;
137 BiLinearGradientStrategy::BiLinearGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd)
138 : super(gradientVectorStart, gradientVectorEnd)
142 double BiLinearGradientStrategy::valueAt(
double x,
double y)
const
144 double t = super::valueAt(x, y);
147 if (t < -DBL_EPSILON) {
155 class RadialGradientStrategy :
public GradientShapeStrategy {
156 typedef GradientShapeStrategy super;
158 RadialGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd);
160 virtual double valueAt(
double x,
double y)
const;
166 RadialGradientStrategy::RadialGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd)
167 : super(gradientVectorStart, gradientVectorEnd)
169 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
170 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
172 m_radius = sqrt((dx * dx) + (dy * dy));
175 double RadialGradientStrategy::valueAt(
double x,
double y)
const
177 double dx = x - m_gradientVectorStart.x();
178 double dy = y - m_gradientVectorStart.y();
180 double distance = sqrt((dx * dx) + (dy * dy));
184 if (m_radius < DBL_EPSILON) {
188 t = distance / m_radius;
195 class SquareGradientStrategy :
public GradientShapeStrategy {
196 typedef GradientShapeStrategy super;
198 SquareGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd);
200 virtual double valueAt(
double x,
double y)
const;
203 double m_normalisedVectorX;
204 double m_normalisedVectorY;
205 double m_vectorLength;
208 SquareGradientStrategy::SquareGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd)
209 : super(gradientVectorStart, gradientVectorEnd)
211 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
212 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
214 m_vectorLength = sqrt((dx * dx) + (dy * dy));
216 if (m_vectorLength < DBL_EPSILON) {
217 m_normalisedVectorX = 0;
218 m_normalisedVectorY = 0;
221 m_normalisedVectorX = dx / m_vectorLength;
222 m_normalisedVectorY = dy / m_vectorLength;
226 double SquareGradientStrategy::valueAt(
double x,
double y)
const
228 double px = x - m_gradientVectorStart.x();
229 double py = y - m_gradientVectorStart.y();
231 double distance1 = 0;
232 double distance2 = 0;
234 if (m_vectorLength > DBL_EPSILON) {
241 distance1 = -m_normalisedVectorY * px + m_normalisedVectorX * py;
242 distance1 = fabs(distance1);
245 distance2 = -m_normalisedVectorY * -py + m_normalisedVectorX * px;
246 distance2 = fabs(distance2);
249 double t = TQMAX(distance1, distance2) / m_vectorLength;
255 class ConicalGradientStrategy :
public GradientShapeStrategy {
256 typedef GradientShapeStrategy super;
258 ConicalGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd);
260 virtual double valueAt(
double x,
double y)
const;
263 double m_vectorAngle;
266 ConicalGradientStrategy::ConicalGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd)
267 : super(gradientVectorStart, gradientVectorEnd)
269 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
270 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
273 m_vectorAngle = atan2(dy, dx) + M_PI;
276 double ConicalGradientStrategy::valueAt(
double x,
double y)
const
278 double px = x - m_gradientVectorStart.x();
279 double py = y - m_gradientVectorStart.y();
281 double angle = atan2(py, px) + M_PI;
283 angle -= m_vectorAngle;
289 double t = angle / (2 * M_PI);
295 class ConicalSymetricGradientStrategy :
public GradientShapeStrategy {
296 typedef GradientShapeStrategy super;
298 ConicalSymetricGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd);
300 virtual double valueAt(
double x,
double y)
const;
303 double m_vectorAngle;
306 ConicalSymetricGradientStrategy::ConicalSymetricGradientStrategy(
const KisPoint& gradientVectorStart,
const KisPoint& gradientVectorEnd)
307 : super(gradientVectorStart, gradientVectorEnd)
309 double dx = gradientVectorEnd.x() - gradientVectorStart.x();
310 double dy = gradientVectorEnd.y() - gradientVectorStart.y();
313 m_vectorAngle = atan2(dy, dx) + M_PI;
316 double ConicalSymetricGradientStrategy::valueAt(
double x,
double y)
const
318 double px = x - m_gradientVectorStart.x();
319 double py = y - m_gradientVectorStart.y();
321 double angle = atan2(py, px) + M_PI;
323 angle -= m_vectorAngle;
335 t = 1 - ((angle - M_PI) / M_PI);
342 class GradientRepeatStrategy {
344 GradientRepeatStrategy() {}
345 virtual ~GradientRepeatStrategy() {}
347 virtual double valueAt(
double t)
const = 0;
351 class GradientRepeatNoneStrategy :
public GradientRepeatStrategy {
353 static GradientRepeatNoneStrategy *instance();
355 virtual double valueAt(
double t)
const;
358 GradientRepeatNoneStrategy() {}
360 static GradientRepeatNoneStrategy *m_instance;
363 GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::m_instance = 0;
365 GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::instance()
367 if (m_instance == 0) {
368 m_instance =
new GradientRepeatNoneStrategy();
369 TQ_CHECK_PTR(m_instance);
376 double GradientRepeatNoneStrategy::valueAt(
double t)
const
380 if (t < DBL_EPSILON) {
384 if (t > 1 - DBL_EPSILON) {
392 class GradientRepeatForwardsStrategy :
public GradientRepeatStrategy {
394 static GradientRepeatForwardsStrategy *instance();
396 virtual double valueAt(
double t)
const;
399 GradientRepeatForwardsStrategy() {}
401 static GradientRepeatForwardsStrategy *m_instance;
404 GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::m_instance = 0;
406 GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::instance()
408 if (m_instance == 0) {
409 m_instance =
new GradientRepeatForwardsStrategy();
410 TQ_CHECK_PTR(m_instance);
417 double GradientRepeatForwardsStrategy::valueAt(
double t)
const
419 int i =
static_cast<int>(t);
421 if (t < DBL_EPSILON) {
425 double value = t - i;
431 class GradientRepeatAlternateStrategy :
public GradientRepeatStrategy {
433 static GradientRepeatAlternateStrategy *instance();
435 virtual double valueAt(
double t)
const;
438 GradientRepeatAlternateStrategy() {}
440 static GradientRepeatAlternateStrategy *m_instance;
443 GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::m_instance = 0;
445 GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::instance()
447 if (m_instance == 0) {
448 m_instance =
new GradientRepeatAlternateStrategy();
449 TQ_CHECK_PTR(m_instance);
456 double GradientRepeatAlternateStrategy::valueAt(
double t)
const
462 int i =
static_cast<int>(t);
464 double value = t - i;
474KisGradientPainter::KisGradientPainter()
480KisGradientPainter::KisGradientPainter(KisPaintDeviceSP device) : super(device), m_gradient(0)
484bool KisGradientPainter::paintGradient(
const KisPoint& gradientVectorStart,
486 enumGradientShape shape,
487 enumGradientRepeat repeat,
488 double antiAliasThreshold,
489 bool reverseGradient,
495 m_cancelRequested =
false;
497 if (!m_gradient)
return false;
499 GradientShapeStrategy *shapeStrategy = 0;
502 case GradientShapeLinear:
503 shapeStrategy =
new LinearGradientStrategy(gradientVectorStart, gradientVectorEnd);
505 case GradientShapeBiLinear:
506 shapeStrategy =
new BiLinearGradientStrategy(gradientVectorStart, gradientVectorEnd);
508 case GradientShapeRadial:
509 shapeStrategy =
new RadialGradientStrategy(gradientVectorStart, gradientVectorEnd);
511 case GradientShapeSquare:
512 shapeStrategy =
new SquareGradientStrategy(gradientVectorStart, gradientVectorEnd);
514 case GradientShapeConical:
515 shapeStrategy =
new ConicalGradientStrategy(gradientVectorStart, gradientVectorEnd);
517 case GradientShapeConicalSymetric:
518 shapeStrategy =
new ConicalSymetricGradientStrategy(gradientVectorStart, gradientVectorEnd);
521 TQ_CHECK_PTR(shapeStrategy);
523 GradientRepeatStrategy *repeatStrategy = 0;
526 case GradientRepeatNone:
527 repeatStrategy = GradientRepeatNoneStrategy::instance();
529 case GradientRepeatForwards:
530 repeatStrategy = GradientRepeatForwardsStrategy::instance();
532 case GradientRepeatAlternate:
533 repeatStrategy = GradientRepeatAlternateStrategy::instance();
536 Q_ASSERT(repeatStrategy != 0);
541 if( m_device->hasSelection() ) {
542 r = m_device->selection()->selectedExactRect();
549 TQ_INT32 endx = startx + width - 1;
550 TQ_INT32 endy = starty + height - 1;
552 TQImage layer (width, height, 32);
553 layer.setAlphaBuffer(
true);
555 int pixelsProcessed = 0;
556 int lastProgressPercent = 0;
558 emit notifyProgressStage(i18n(
"Rendering gradient..."), 0);
560 int totalPixels = width * height;
562 if (antiAliasThreshold < 1 - DBL_EPSILON) {
566 for (
int y = starty; y <= endy; y++) {
567 for (
int x = startx; x <= endx; x++) {
569 double t = shapeStrategy->valueAt( x, y);
570 t = repeatStrategy->valueAt(t);
572 if (reverseGradient) {
579 m_gradient->colorAt(t, &color, &
opacity);
581 layer.setPixel(x - startx, y - starty,
582 tqRgba(color.red(), color.green(), color.blue(),
opacity));
586 int progressPercent = (pixelsProcessed * 100) / totalPixels;
588 if (progressPercent > lastProgressPercent) {
589 emit notifyProgress(progressPercent);
590 lastProgressPercent = progressPercent;
592 if (m_cancelRequested) {
596 if (m_cancelRequested) {
602 if (!m_cancelRequested && antiAliasThreshold < 1 - DBL_EPSILON) {
605 emit notifyProgressStage(i18n(
"Anti-aliasing gradient..."), lastProgressPercent);
606 TQ_UINT8 * layerPointer = layer.bits();
607 for (
int y = starty; y <= endy; y++) {
608 for (
int x = startx; x <= endx; x++) {
610 double maxDistance = 0;
612 TQ_UINT8 redThis = layerPointer[2];
613 TQ_UINT8 greenThis = layerPointer[1];
614 TQ_UINT8 blueThis = layerPointer[0];
615 TQ_UINT8 thisPixelOpacity = layerPointer[3];
617 for (
int yOffset = -1; yOffset < 2; yOffset++) {
618 for (
int xOffset = -1; xOffset < 2; xOffset++) {
620 if (xOffset != 0 || yOffset != 0) {
621 int sampleX = x + xOffset;
622 int sampleY = y + yOffset;
624 if (sampleX >= startx && sampleX <= endx && sampleY >= starty && sampleY <= endy) {
625 uint x = sampleX - startx;
626 uint y = sampleY - starty;
627 TQ_UINT8 * pixelPos = layer.bits() + (y * width * 4) + (x * 4);
628 TQ_UINT8 red = *(pixelPos +2);
629 TQ_UINT8 green = *(pixelPos + 1);
630 TQ_UINT8 blue = *pixelPos;
631 TQ_UINT8
opacity = *(pixelPos + 3);
633 double dRed = (red *
opacity - redThis * thisPixelOpacity) / 65535.0;
634 double dGreen = (green *
opacity - greenThis * thisPixelOpacity) / 65535.0;
635 double dBlue = (blue *
opacity - blueThis * thisPixelOpacity) / 65535.0;
637 #define SQRT_3 1.7320508
639 double distance =dRed * dRed + dGreen * dGreen + dBlue * dBlue;
641 if (distance > maxDistance) {
642 maxDistance = distance;
649 if (maxDistance > 3.*antiAliasThreshold*antiAliasThreshold) {
650 const int numSamples = 4;
655 int totalOpacity = 0;
657 for (
int ySample = 0; ySample < numSamples; ySample++) {
658 for (
int xSample = 0; xSample < numSamples; xSample++) {
660 double sampleWidth = 1.0 / numSamples;
662 double sampleX = x - 0.5 + (sampleWidth / 2) + xSample * sampleWidth;
663 double sampleY = y - 0.5 + (sampleWidth / 2) + ySample * sampleWidth;
665 double t = shapeStrategy->valueAt(sampleX, sampleY);
666 t = repeatStrategy->valueAt(t);
668 if (reverseGradient) {
674 m_gradient->colorAt(t, &color, &
opacity);
676 totalRed += color.red();
677 totalGreen += color.green();
678 totalBlue += color.blue();
683 int red = totalRed / (numSamples * numSamples);
684 int green = totalGreen / (numSamples * numSamples);
685 int blue = totalBlue / (numSamples * numSamples);
686 int opacity = totalOpacity / (numSamples * numSamples);
688 layer.setPixel(x - startx, y - starty, tqRgba(red, green, blue,
opacity));
693 int progressPercent = (pixelsProcessed * 100) / totalPixels;
695 if (progressPercent > lastProgressPercent) {
696 emit notifyProgress(progressPercent);
697 lastProgressPercent = progressPercent;
699 if (m_cancelRequested) {
706 if (m_cancelRequested) {
712 if (!m_cancelRequested) {
713 kdDebug() <<
"Have we got a selection? " << m_device->hasSelection() << endl;
714 KisPaintDeviceSP dev =
new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(),
"temporary device for gradient");
715 dev->writeBytes(layer.bits(), startx, starty, width, height);
716 bltSelection(startx, starty, m_compositeOp, dev, m_opacity, startx, starty, width, height);
718 delete shapeStrategy;
720 emit notifyProgressDone();
722 return !m_cancelRequested;
TQ_UINT8 opacity() const
Returns the opacity that is used in painting.
void bltSelection(TQ_INT32 dx, TQ_INT32 dy, const KisCompositeOp &op, KisPaintDeviceSP src, KisSelectionSP selMask, TQ_UINT8 opacity, TQ_INT32 sx, TQ_INT32 sy, TQ_INT32 sw, TQ_INT32 sh)
A version of bitBlt that renders using an external selection mask, ignoring the src device's own sele...
A double-based point class that can return it's coordinates approximated to integers.