00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <cfloat>
00026 #include <cmath>
00027
00028 #include <qimage.h>
00029 #include <qtextstream.h>
00030 #include <qfile.h>
00031
00032 #include <koColor.h>
00033 #include <kogradientmanager.h>
00034
00035 #include <kdebug.h>
00036 #include <klocale.h>
00037
00038 #include "kis_gradient.h"
00039
00040 #define PREVIEW_WIDTH 64
00041 #define PREVIEW_HEIGHT 64
00042
00043 KisGradientSegment::RGBColorInterpolationStrategy *KisGradientSegment::RGBColorInterpolationStrategy::m_instance = 0;
00044 KisGradientSegment::HSVCWColorInterpolationStrategy *KisGradientSegment::HSVCWColorInterpolationStrategy::m_instance = 0;
00045 KisGradientSegment::HSVCCWColorInterpolationStrategy *KisGradientSegment::HSVCCWColorInterpolationStrategy::m_instance = 0;
00046
00047 KisGradientSegment::LinearInterpolationStrategy *KisGradientSegment::LinearInterpolationStrategy::m_instance = 0;
00048 KisGradientSegment::CurvedInterpolationStrategy *KisGradientSegment::CurvedInterpolationStrategy::m_instance = 0;
00049 KisGradientSegment::SineInterpolationStrategy *KisGradientSegment::SineInterpolationStrategy::m_instance = 0;
00050 KisGradientSegment::SphereIncreasingInterpolationStrategy *KisGradientSegment::SphereIncreasingInterpolationStrategy::m_instance = 0;
00051 KisGradientSegment::SphereDecreasingInterpolationStrategy *KisGradientSegment::SphereDecreasingInterpolationStrategy::m_instance = 0;
00052
00053 KisGradient::KisGradient(const QString& file) : super(file)
00054 {
00055 }
00056
00057 KisGradient::~KisGradient()
00058 {
00059 for (uint i = 0; i < m_segments.count(); i++) {
00060 delete m_segments[i];
00061 m_segments[i] = 0;
00062 }
00063 }
00064
00065 bool KisGradient::load()
00066 {
00067 return init();
00068 }
00069
00070 bool KisGradient::save()
00071 {
00072 return false;
00073 }
00074
00075 QImage KisGradient::img()
00076 {
00077 return m_img;
00078 }
00079
00080 bool KisGradient::init()
00081 {
00082 KoGradientManager gradLoader;
00083 KoGradient* grad = gradLoader.loadGradient(filename());
00084
00085 if( !grad )
00086 return false;
00087
00088 m_segments.clear();
00089
00090 if( grad->colorStops.count() > 1 ) {
00091 KoColorStop *colstop;
00092 for(colstop = grad->colorStops.first(); colstop; colstop = grad->colorStops.next()) {
00093 KoColorStop *colstopNext = grad->colorStops.next();
00094
00095 if(colstopNext) {
00096 KoColor leftRgb((int)(colstop->color1 * 255 + 0.5), (int)(colstop->color2 * 255 + 0.5), (int)(colstop->color3 * 255 + 0.5));
00097 KoColor rightRgb((int)(colstopNext->color1 * 255 + 0.5), (int)(colstopNext->color2 * 255 + 0.5), (int)(colstopNext->color3 * 255 + 0.5));
00098
00099 double midp = colstop->midpoint;
00100 midp = colstop->offset + ((colstopNext->offset - colstop->offset) * midp);
00101
00102 Color leftColor(leftRgb.color(), colstop->opacity);
00103 Color rightColor(rightRgb.color(), colstopNext->opacity);
00104
00105 KisGradientSegment *segment = new KisGradientSegment(colstop->interpolation, colstop->colorType, colstop->offset, midp, colstopNext->offset, leftColor, rightColor);
00106 Q_CHECK_PTR(segment);
00107
00108 if ( !segment->isValid() ) {
00109 delete segment;
00110 return false;
00111 }
00112
00113 m_segments.push_back(segment);
00114 grad->colorStops.prev();
00115 }
00116 else {
00117 grad->colorStops.prev();
00118 break;
00119 }
00120 }
00121 }
00122 else
00123 return false;
00124
00125 if (!m_segments.isEmpty()) {
00126 m_img = generatePreview(PREVIEW_WIDTH, PREVIEW_HEIGHT);
00127 setValid(true);
00128 return true;
00129 }
00130 else {
00131 return false;
00132 }
00133 }
00134
00135 void KisGradient::setImage(const QImage& img)
00136 {
00137 m_img = img;
00138 m_img.detach();
00139
00140 setValid(true);
00141 }
00142
00143 KisGradientSegment *KisGradient::segmentAt(double t) const
00144 {
00145 if (t < DBL_EPSILON) {
00146 t = 0;
00147 }
00148 else
00149 if (t > 1 - DBL_EPSILON) {
00150 t = 1;
00151 }
00152
00153 Q_ASSERT(m_segments.count() != 0);
00154
00155 KisGradientSegment *segment = 0;
00156
00157 for (uint i = 0; i < m_segments.count(); i++) {
00158 if (t > m_segments[i]->startOffset() - DBL_EPSILON && t < m_segments[i]->endOffset() + DBL_EPSILON) {
00159 segment = m_segments[i];
00160 break;
00161 }
00162 }
00163
00164 return segment;
00165 }
00166
00167 void KisGradient::colorAt(double t, QColor *color, Q_UINT8 *opacity) const
00168 {
00169 const KisGradientSegment *segment = segmentAt(t);
00170 Q_ASSERT(segment != 0);
00171
00172 if (segment) {
00173 Color col = segment->colorAt(t);
00174 *color = col.color();
00175 *opacity = static_cast<Q_UINT8>(col.alpha() * OPACITY_OPAQUE + 0.5);
00176 }
00177 }
00178
00179 QImage KisGradient::generatePreview(int width, int height) const
00180 {
00181 QImage img(width, height, 32);
00182
00183 for (int y = 0; y < img.height(); y++) {
00184 for (int x = 0; x < img.width(); x++) {
00185
00186 int backgroundRed = 128 + 63 * ((x / 4 + y / 4) % 2);
00187 int backgroundGreen = backgroundRed;
00188 int backgroundBlue = backgroundRed;
00189
00190 QColor color;
00191 Q_UINT8 opacity;
00192 double t = static_cast<double>(x) / (img.width() - 1);
00193
00194 colorAt(t, &color, &opacity);
00195
00196 double alpha = static_cast<double>(opacity) / OPACITY_OPAQUE;
00197
00198 int red = static_cast<int>((1 - alpha) * backgroundRed + alpha * color.red() + 0.5);
00199 int green = static_cast<int>((1 - alpha) * backgroundGreen + alpha * color.green() + 0.5);
00200 int blue = static_cast<int>((1 - alpha) * backgroundBlue + alpha * color.blue() + 0.5);
00201
00202 img.setPixel(x, y, qRgb(red, green, blue));
00203 }
00204 }
00205
00206 return img;
00207 }
00208
00209 KisGradientSegment::KisGradientSegment(int interpolationType, int colorInterpolationType, double startOffset, double middleOffset, double endOffset, const Color& startColor, const Color& endColor)
00210 {
00211 m_interpolator = 0;
00212
00213 switch (interpolationType) {
00214 case INTERP_LINEAR:
00215 m_interpolator = LinearInterpolationStrategy::instance();
00216 break;
00217 case INTERP_CURVED:
00218 m_interpolator = CurvedInterpolationStrategy::instance();
00219 break;
00220 case INTERP_SINE:
00221 m_interpolator = SineInterpolationStrategy::instance();
00222 break;
00223 case INTERP_SPHERE_INCREASING:
00224 m_interpolator = SphereIncreasingInterpolationStrategy::instance();
00225 break;
00226 case INTERP_SPHERE_DECREASING:
00227 m_interpolator = SphereDecreasingInterpolationStrategy::instance();
00228 break;
00229 }
00230
00231 m_colorInterpolator = 0;
00232
00233 switch (colorInterpolationType) {
00234 case COLOR_INTERP_RGB:
00235 m_colorInterpolator = RGBColorInterpolationStrategy::instance();
00236 break;
00237 case COLOR_INTERP_HSV_CCW:
00238 m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance();
00239 break;
00240 case COLOR_INTERP_HSV_CW:
00241 m_colorInterpolator = HSVCWColorInterpolationStrategy::instance();
00242 break;
00243 }
00244
00245 if (startOffset < DBL_EPSILON) {
00246 m_startOffset = 0;
00247 }
00248 else
00249 if (startOffset > 1 - DBL_EPSILON) {
00250 m_startOffset = 1;
00251 }
00252 else {
00253 m_startOffset = startOffset;
00254 }
00255
00256 if (middleOffset < m_startOffset + DBL_EPSILON) {
00257 m_middleOffset = m_startOffset;
00258 }
00259 else
00260 if (middleOffset > 1 - DBL_EPSILON) {
00261 m_middleOffset = 1;
00262 }
00263 else {
00264 m_middleOffset = middleOffset;
00265 }
00266
00267 if (endOffset < m_middleOffset + DBL_EPSILON) {
00268 m_endOffset = m_middleOffset;
00269 }
00270 else
00271 if (endOffset > 1 - DBL_EPSILON) {
00272 m_endOffset = 1;
00273 }
00274 else {
00275 m_endOffset = endOffset;
00276 }
00277
00278 m_length = m_endOffset - m_startOffset;
00279
00280 if (m_length < DBL_EPSILON) {
00281 m_middleT = 0.5;
00282 }
00283 else {
00284 m_middleT = (m_middleOffset - m_startOffset) / m_length;
00285 }
00286
00287 m_startColor = startColor;
00288 m_endColor = endColor;
00289 }
00290
00291 const Color& KisGradientSegment::startColor() const
00292 {
00293 return m_startColor;
00294 }
00295
00296 const Color& KisGradientSegment::endColor() const
00297 {
00298 return m_endColor;
00299 }
00300
00301 double KisGradientSegment::startOffset() const
00302 {
00303 return m_startOffset;
00304 }
00305
00306 double KisGradientSegment::middleOffset() const
00307 {
00308 return m_middleOffset;
00309 }
00310
00311 double KisGradientSegment::endOffset() const
00312 {
00313 return m_endOffset;
00314 }
00315
00316 void KisGradientSegment::setStartOffset(double t)
00317 {
00318 m_startOffset = t;
00319 m_length = m_endOffset - m_startOffset;
00320
00321 if (m_length < DBL_EPSILON) {
00322 m_middleT = 0.5;
00323 }
00324 else {
00325 m_middleT = (m_middleOffset - m_startOffset) / m_length;
00326 }
00327 }
00328 void KisGradientSegment::setMiddleOffset(double t)
00329 {
00330 m_middleOffset = t;
00331
00332 if (m_length < DBL_EPSILON) {
00333 m_middleT = 0.5;
00334 }
00335 else {
00336 m_middleT = (m_middleOffset - m_startOffset) / m_length;
00337 }
00338 }
00339
00340 void KisGradientSegment::setEndOffset(double t)
00341 {
00342 m_endOffset = t;
00343 m_length = m_endOffset - m_startOffset;
00344
00345 if (m_length < DBL_EPSILON) {
00346 m_middleT = 0.5;
00347 }
00348 else {
00349 m_middleT = (m_middleOffset - m_startOffset) / m_length;
00350 }
00351 }
00352
00353 int KisGradientSegment::interpolation() const
00354 {
00355 return m_interpolator->type();
00356 }
00357
00358 void KisGradientSegment::setInterpolation(int interpolationType)
00359 {
00360 switch (interpolationType) {
00361 case INTERP_LINEAR:
00362 m_interpolator = LinearInterpolationStrategy::instance();
00363 break;
00364 case INTERP_CURVED:
00365 m_interpolator = CurvedInterpolationStrategy::instance();
00366 break;
00367 case INTERP_SINE:
00368 m_interpolator = SineInterpolationStrategy::instance();
00369 break;
00370 case INTERP_SPHERE_INCREASING:
00371 m_interpolator = SphereIncreasingInterpolationStrategy::instance();
00372 break;
00373 case INTERP_SPHERE_DECREASING:
00374 m_interpolator = SphereDecreasingInterpolationStrategy::instance();
00375 break;
00376 }
00377 }
00378
00379 int KisGradientSegment::colorInterpolation() const
00380 {
00381 return m_colorInterpolator->type();
00382 }
00383
00384 void KisGradientSegment::setColorInterpolation(int colorInterpolationType)
00385 {
00386 switch (colorInterpolationType) {
00387 case COLOR_INTERP_RGB:
00388 m_colorInterpolator = RGBColorInterpolationStrategy::instance();
00389 break;
00390 case COLOR_INTERP_HSV_CCW:
00391 m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance();
00392 break;
00393 case COLOR_INTERP_HSV_CW:
00394 m_colorInterpolator = HSVCWColorInterpolationStrategy::instance();
00395 break;
00396 }
00397 }
00398
00399 Color KisGradientSegment::colorAt(double t) const
00400 {
00401 Q_ASSERT(t > m_startOffset - DBL_EPSILON && t < m_endOffset + DBL_EPSILON);
00402
00403 double segmentT;
00404
00405 if (m_length < DBL_EPSILON) {
00406 segmentT = 0.5;
00407 }
00408 else {
00409 segmentT = (t - m_startOffset) / m_length;
00410 }
00411
00412 double colorT = m_interpolator->valueAt(segmentT, m_middleT);
00413
00414 Color color = m_colorInterpolator->colorAt(colorT, m_startColor, m_endColor);
00415
00416 return color;
00417 }
00418
00419 bool KisGradientSegment::isValid() const
00420 {
00421 if (m_interpolator == 0 || m_colorInterpolator ==0)
00422 return false;
00423 return true;
00424 }
00425
00426 KisGradientSegment::RGBColorInterpolationStrategy *KisGradientSegment::RGBColorInterpolationStrategy::instance()
00427 {
00428 if (m_instance == 0) {
00429 m_instance = new RGBColorInterpolationStrategy();
00430 Q_CHECK_PTR(m_instance);
00431 }
00432
00433 return m_instance;
00434 }
00435
00436 Color KisGradientSegment::RGBColorInterpolationStrategy::colorAt(double t, Color start, Color end) const
00437 {
00438 int red = static_cast<int>(start.color().red() + t * (end.color().red() - start.color().red()) + 0.5);
00439 int green = static_cast<int>(start.color().green() + t * (end.color().green() - start.color().green()) + 0.5);
00440 int blue = static_cast<int>(start.color().blue() + t * (end.color().blue() - start.color().blue()) + 0.5);
00441 double alpha = start.alpha() + t * (end.alpha() - start.alpha());
00442
00443 return Color(QColor(red, green, blue), alpha);
00444 }
00445
00446 KisGradientSegment::HSVCWColorInterpolationStrategy *KisGradientSegment::HSVCWColorInterpolationStrategy::instance()
00447 {
00448 if (m_instance == 0) {
00449 m_instance = new HSVCWColorInterpolationStrategy();
00450 Q_CHECK_PTR(m_instance);
00451 }
00452
00453 return m_instance;
00454 }
00455
00456 Color KisGradientSegment::HSVCWColorInterpolationStrategy::colorAt(double t, Color start, Color end) const
00457 {
00458 KoColor sc = KoColor(start.color());
00459 KoColor ec = KoColor(end.color());
00460
00461 int s = static_cast<int>(sc.S() + t * (ec.S() - sc.S()) + 0.5);
00462 int v = static_cast<int>(sc.V() + t * (ec.V() - sc.V()) + 0.5);
00463 int h;
00464
00465 if (ec.H() < sc.H()) {
00466 h = static_cast<int>(ec.H() + (1 - t) * (sc.H() - ec.H()) + 0.5);
00467 }
00468 else {
00469 h = static_cast<int>(ec.H() + (1 - t) * (360 - ec.H() + sc.H()) + 0.5);
00470
00471 if (h > 359) {
00472 h -= 360;
00473 }
00474 }
00475
00476 double alpha = start.alpha() + t * (end.alpha() - start.alpha());
00477
00478 return Color(KoColor(h, s, v, KoColor::csHSV).color(), alpha);
00479 }
00480
00481 KisGradientSegment::HSVCCWColorInterpolationStrategy *KisGradientSegment::HSVCCWColorInterpolationStrategy::instance()
00482 {
00483 if (m_instance == 0) {
00484 m_instance = new HSVCCWColorInterpolationStrategy();
00485 Q_CHECK_PTR(m_instance);
00486 }
00487
00488 return m_instance;
00489 }
00490
00491 Color KisGradientSegment::HSVCCWColorInterpolationStrategy::colorAt(double t, Color start, Color end) const
00492 {
00493 KoColor sc = KoColor(start.color());
00494 KoColor se = KoColor(end.color());
00495
00496 int s = static_cast<int>(sc.S() + t * (se.S() - sc.S()) + 0.5);
00497 int v = static_cast<int>(sc.V() + t * (se.V() - sc.V()) + 0.5);
00498 int h;
00499
00500 if (sc.H() < se.H()) {
00501 h = static_cast<int>(sc.H() + t * (se.H() - sc.H()) + 0.5);
00502 }
00503 else {
00504 h = static_cast<int>(sc.H() + t * (360 - sc.H() + se.H()) + 0.5);
00505
00506 if (h > 359) {
00507 h -= 360;
00508 }
00509 }
00510
00511 double alpha = start.alpha() + t * (end.alpha() - start.alpha());
00512
00513 return Color(KoColor(h, s, v, KoColor::csHSV).color(), alpha);
00514 }
00515
00516 KisGradientSegment::LinearInterpolationStrategy *KisGradientSegment::LinearInterpolationStrategy::instance()
00517 {
00518 if (m_instance == 0) {
00519 m_instance = new LinearInterpolationStrategy();
00520 Q_CHECK_PTR(m_instance);
00521 }
00522
00523 return m_instance;
00524 }
00525
00526 double KisGradientSegment::LinearInterpolationStrategy::calcValueAt(double t, double middle)
00527 {
00528 Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON);
00529 Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON);
00530
00531 double value = 0;
00532
00533 if (t <= middle) {
00534 if (middle < DBL_EPSILON) {
00535 value = 0;
00536 }
00537 else {
00538 value = (t / middle) * 0.5;
00539 }
00540 }
00541 else {
00542 if (middle > 1 - DBL_EPSILON) {
00543 value = 1;
00544 }
00545 else {
00546 value = ((t - middle) / (1 - middle)) * 0.5 + 0.5;
00547 }
00548 }
00549
00550 return value;
00551 }
00552
00553 double KisGradientSegment::LinearInterpolationStrategy::valueAt(double t, double middle) const
00554 {
00555 return calcValueAt(t, middle);
00556 }
00557
00558 KisGradientSegment::CurvedInterpolationStrategy::CurvedInterpolationStrategy()
00559 {
00560 m_logHalf = log(0.5);
00561 }
00562
00563 KisGradientSegment::CurvedInterpolationStrategy *KisGradientSegment::CurvedInterpolationStrategy::instance()
00564 {
00565 if (m_instance == 0) {
00566 m_instance = new CurvedInterpolationStrategy();
00567 Q_CHECK_PTR(m_instance);
00568 }
00569
00570 return m_instance;
00571 }
00572
00573 double KisGradientSegment::CurvedInterpolationStrategy::valueAt(double t, double middle) const
00574 {
00575 Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON);
00576 Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON);
00577
00578 double value = 0;
00579
00580 if (middle < DBL_EPSILON) {
00581 middle = DBL_EPSILON;
00582 }
00583
00584 value = pow(t, m_logHalf / log(middle));
00585
00586 return value;
00587 }
00588
00589 KisGradientSegment::SineInterpolationStrategy *KisGradientSegment::SineInterpolationStrategy::instance()
00590 {
00591 if (m_instance == 0) {
00592 m_instance = new SineInterpolationStrategy();
00593 Q_CHECK_PTR(m_instance);
00594 }
00595
00596 return m_instance;
00597 }
00598
00599 double KisGradientSegment::SineInterpolationStrategy::valueAt(double t, double middle) const
00600 {
00601 double lt = LinearInterpolationStrategy::calcValueAt(t, middle);
00602 double value = (sin(-M_PI_2 + M_PI * lt) + 1.0) / 2.0;
00603
00604 return value;
00605 }
00606
00607 KisGradientSegment::SphereIncreasingInterpolationStrategy *KisGradientSegment::SphereIncreasingInterpolationStrategy::instance()
00608 {
00609 if (m_instance == 0) {
00610 m_instance = new SphereIncreasingInterpolationStrategy();
00611 Q_CHECK_PTR(m_instance);
00612 }
00613
00614 return m_instance;
00615 }
00616
00617 double KisGradientSegment::SphereIncreasingInterpolationStrategy::valueAt(double t, double middle) const
00618 {
00619 double lt = LinearInterpolationStrategy::calcValueAt(t, middle) - 1;
00620 double value = sqrt(1 - lt * lt);
00621
00622 return value;
00623 }
00624
00625 KisGradientSegment::SphereDecreasingInterpolationStrategy *KisGradientSegment::SphereDecreasingInterpolationStrategy::instance()
00626 {
00627 if (m_instance == 0) {
00628 m_instance = new SphereDecreasingInterpolationStrategy();
00629 Q_CHECK_PTR(m_instance);
00630 }
00631
00632 return m_instance;
00633 }
00634
00635 double KisGradientSegment::SphereDecreasingInterpolationStrategy::valueAt(double t, double middle) const
00636 {
00637 double lt = LinearInterpolationStrategy::calcValueAt(t, middle);
00638 double value = 1 - sqrt(1 - lt * lt);
00639
00640 return value;
00641 }
00642
00643 #include "kis_gradient.moc"
00644