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 Q_ASSERT(t >= 0 || t <= 1);
00146 Q_ASSERT(!m_segments.empty());
00147
00148 for(QValueVector<KisGradientSegment *>::const_iterator it = m_segments.begin(); it!= m_segments.end(); ++it)
00149 {
00150 if (t > (*it)->startOffset() - DBL_EPSILON && t < (*it)->endOffset() + DBL_EPSILON) {
00151 return *it;
00152 }
00153 }
00154
00155 return 0;
00156 }
00157
00158 void KisGradient::colorAt(double t, QColor *color, Q_UINT8 *opacity) const
00159 {
00160 const KisGradientSegment *segment = segmentAt(t);
00161 Q_ASSERT(segment != 0);
00162
00163 if (segment) {
00164 Color col = segment->colorAt(t);
00165 *color = col.color();
00166 *opacity = static_cast<Q_UINT8>(col.alpha() * OPACITY_OPAQUE + 0.5);
00167 }
00168 }
00169
00170 QImage KisGradient::generatePreview(int width, int height) const
00171 {
00172 QImage img(width, height, 32);
00173
00174 for (int y = 0; y < img.height(); y++) {
00175 for (int x = 0; x < img.width(); x++) {
00176
00177 int backgroundRed = 128 + 63 * ((x / 4 + y / 4) % 2);
00178 int backgroundGreen = backgroundRed;
00179 int backgroundBlue = backgroundRed;
00180
00181 QColor color;
00182 Q_UINT8 opacity;
00183 double t = static_cast<double>(x) / (img.width() - 1);
00184
00185 colorAt(t, &color, &opacity);
00186
00187 double alpha = static_cast<double>(opacity) / OPACITY_OPAQUE;
00188
00189 int red = static_cast<int>((1 - alpha) * backgroundRed + alpha * color.red() + 0.5);
00190 int green = static_cast<int>((1 - alpha) * backgroundGreen + alpha * color.green() + 0.5);
00191 int blue = static_cast<int>((1 - alpha) * backgroundBlue + alpha * color.blue() + 0.5);
00192
00193 img.setPixel(x, y, qRgb(red, green, blue));
00194 }
00195 }
00196
00197 return img;
00198 }
00199
00200 KisGradientSegment::KisGradientSegment(int interpolationType, int colorInterpolationType, double startOffset, double middleOffset, double endOffset, const Color& startColor, const Color& endColor)
00201 {
00202 m_interpolator = 0;
00203
00204 switch (interpolationType) {
00205 case INTERP_LINEAR:
00206 m_interpolator = LinearInterpolationStrategy::instance();
00207 break;
00208 case INTERP_CURVED:
00209 m_interpolator = CurvedInterpolationStrategy::instance();
00210 break;
00211 case INTERP_SINE:
00212 m_interpolator = SineInterpolationStrategy::instance();
00213 break;
00214 case INTERP_SPHERE_INCREASING:
00215 m_interpolator = SphereIncreasingInterpolationStrategy::instance();
00216 break;
00217 case INTERP_SPHERE_DECREASING:
00218 m_interpolator = SphereDecreasingInterpolationStrategy::instance();
00219 break;
00220 }
00221
00222 m_colorInterpolator = 0;
00223
00224 switch (colorInterpolationType) {
00225 case COLOR_INTERP_RGB:
00226 m_colorInterpolator = RGBColorInterpolationStrategy::instance();
00227 break;
00228 case COLOR_INTERP_HSV_CCW:
00229 m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance();
00230 break;
00231 case COLOR_INTERP_HSV_CW:
00232 m_colorInterpolator = HSVCWColorInterpolationStrategy::instance();
00233 break;
00234 }
00235
00236 if (startOffset < DBL_EPSILON) {
00237 m_startOffset = 0;
00238 }
00239 else
00240 if (startOffset > 1 - DBL_EPSILON) {
00241 m_startOffset = 1;
00242 }
00243 else {
00244 m_startOffset = startOffset;
00245 }
00246
00247 if (middleOffset < m_startOffset + DBL_EPSILON) {
00248 m_middleOffset = m_startOffset;
00249 }
00250 else
00251 if (middleOffset > 1 - DBL_EPSILON) {
00252 m_middleOffset = 1;
00253 }
00254 else {
00255 m_middleOffset = middleOffset;
00256 }
00257
00258 if (endOffset < m_middleOffset + DBL_EPSILON) {
00259 m_endOffset = m_middleOffset;
00260 }
00261 else
00262 if (endOffset > 1 - DBL_EPSILON) {
00263 m_endOffset = 1;
00264 }
00265 else {
00266 m_endOffset = endOffset;
00267 }
00268
00269 m_length = m_endOffset - m_startOffset;
00270
00271 if (m_length < DBL_EPSILON) {
00272 m_middleT = 0.5;
00273 }
00274 else {
00275 m_middleT = (m_middleOffset - m_startOffset) / m_length;
00276 }
00277
00278 m_startColor = startColor;
00279 m_endColor = endColor;
00280 }
00281
00282 const Color& KisGradientSegment::startColor() const
00283 {
00284 return m_startColor;
00285 }
00286
00287 const Color& KisGradientSegment::endColor() const
00288 {
00289 return m_endColor;
00290 }
00291
00292 double KisGradientSegment::startOffset() const
00293 {
00294 return m_startOffset;
00295 }
00296
00297 double KisGradientSegment::middleOffset() const
00298 {
00299 return m_middleOffset;
00300 }
00301
00302 double KisGradientSegment::endOffset() const
00303 {
00304 return m_endOffset;
00305 }
00306
00307 void KisGradientSegment::setStartOffset(double t)
00308 {
00309 m_startOffset = t;
00310 m_length = m_endOffset - m_startOffset;
00311
00312 if (m_length < DBL_EPSILON) {
00313 m_middleT = 0.5;
00314 }
00315 else {
00316 m_middleT = (m_middleOffset - m_startOffset) / m_length;
00317 }
00318 }
00319 void KisGradientSegment::setMiddleOffset(double t)
00320 {
00321 m_middleOffset = t;
00322
00323 if (m_length < DBL_EPSILON) {
00324 m_middleT = 0.5;
00325 }
00326 else {
00327 m_middleT = (m_middleOffset - m_startOffset) / m_length;
00328 }
00329 }
00330
00331 void KisGradientSegment::setEndOffset(double t)
00332 {
00333 m_endOffset = t;
00334 m_length = m_endOffset - m_startOffset;
00335
00336 if (m_length < DBL_EPSILON) {
00337 m_middleT = 0.5;
00338 }
00339 else {
00340 m_middleT = (m_middleOffset - m_startOffset) / m_length;
00341 }
00342 }
00343
00344 int KisGradientSegment::interpolation() const
00345 {
00346 return m_interpolator->type();
00347 }
00348
00349 void KisGradientSegment::setInterpolation(int interpolationType)
00350 {
00351 switch (interpolationType) {
00352 case INTERP_LINEAR:
00353 m_interpolator = LinearInterpolationStrategy::instance();
00354 break;
00355 case INTERP_CURVED:
00356 m_interpolator = CurvedInterpolationStrategy::instance();
00357 break;
00358 case INTERP_SINE:
00359 m_interpolator = SineInterpolationStrategy::instance();
00360 break;
00361 case INTERP_SPHERE_INCREASING:
00362 m_interpolator = SphereIncreasingInterpolationStrategy::instance();
00363 break;
00364 case INTERP_SPHERE_DECREASING:
00365 m_interpolator = SphereDecreasingInterpolationStrategy::instance();
00366 break;
00367 }
00368 }
00369
00370 int KisGradientSegment::colorInterpolation() const
00371 {
00372 return m_colorInterpolator->type();
00373 }
00374
00375 void KisGradientSegment::setColorInterpolation(int colorInterpolationType)
00376 {
00377 switch (colorInterpolationType) {
00378 case COLOR_INTERP_RGB:
00379 m_colorInterpolator = RGBColorInterpolationStrategy::instance();
00380 break;
00381 case COLOR_INTERP_HSV_CCW:
00382 m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance();
00383 break;
00384 case COLOR_INTERP_HSV_CW:
00385 m_colorInterpolator = HSVCWColorInterpolationStrategy::instance();
00386 break;
00387 }
00388 }
00389
00390 Color KisGradientSegment::colorAt(double t) const
00391 {
00392 Q_ASSERT(t > m_startOffset - DBL_EPSILON && t < m_endOffset + DBL_EPSILON);
00393
00394 double segmentT;
00395
00396 if (m_length < DBL_EPSILON) {
00397 segmentT = 0.5;
00398 }
00399 else {
00400 segmentT = (t - m_startOffset) / m_length;
00401 }
00402
00403 double colorT = m_interpolator->valueAt(segmentT, m_middleT);
00404
00405 Color color = m_colorInterpolator->colorAt(colorT, m_startColor, m_endColor);
00406
00407 return color;
00408 }
00409
00410 bool KisGradientSegment::isValid() const
00411 {
00412 if (m_interpolator == 0 || m_colorInterpolator ==0)
00413 return false;
00414 return true;
00415 }
00416
00417 KisGradientSegment::RGBColorInterpolationStrategy *KisGradientSegment::RGBColorInterpolationStrategy::instance()
00418 {
00419 if (m_instance == 0) {
00420 m_instance = new RGBColorInterpolationStrategy();
00421 Q_CHECK_PTR(m_instance);
00422 }
00423
00424 return m_instance;
00425 }
00426
00427 Color KisGradientSegment::RGBColorInterpolationStrategy::colorAt(double t, Color start, Color end) const
00428 {
00429 int startRed = start.color().red();
00430 int startGreen = start.color().green();
00431 int startBlue = start.color().blue();
00432 double startAlpha = start.alpha();
00433 int red = static_cast<int>(startRed + t * (end.color().red() - startRed) + 0.5);
00434 int green = static_cast<int>(startGreen + t * (end.color().green() - startGreen) + 0.5);
00435 int blue = static_cast<int>(startBlue + t * (end.color().blue() - startBlue) + 0.5);
00436 double alpha = startAlpha + t * (end.alpha() - startAlpha);
00437
00438 return Color(QColor(red, green, blue), alpha);
00439 }
00440
00441 KisGradientSegment::HSVCWColorInterpolationStrategy *KisGradientSegment::HSVCWColorInterpolationStrategy::instance()
00442 {
00443 if (m_instance == 0) {
00444 m_instance = new HSVCWColorInterpolationStrategy();
00445 Q_CHECK_PTR(m_instance);
00446 }
00447
00448 return m_instance;
00449 }
00450
00451 Color KisGradientSegment::HSVCWColorInterpolationStrategy::colorAt(double t, Color start, Color end) const
00452 {
00453 KoColor sc = KoColor(start.color());
00454 KoColor ec = KoColor(end.color());
00455
00456 int s = static_cast<int>(sc.S() + t * (ec.S() - sc.S()) + 0.5);
00457 int v = static_cast<int>(sc.V() + t * (ec.V() - sc.V()) + 0.5);
00458 int h;
00459
00460 if (ec.H() < sc.H()) {
00461 h = static_cast<int>(ec.H() + (1 - t) * (sc.H() - ec.H()) + 0.5);
00462 }
00463 else {
00464 h = static_cast<int>(ec.H() + (1 - t) * (360 - ec.H() + sc.H()) + 0.5);
00465
00466 if (h > 359) {
00467 h -= 360;
00468 }
00469 }
00470
00471 double alpha = start.alpha() + t * (end.alpha() - start.alpha());
00472
00473 return Color(KoColor(h, s, v, KoColor::csHSV).color(), alpha);
00474 }
00475
00476 KisGradientSegment::HSVCCWColorInterpolationStrategy *KisGradientSegment::HSVCCWColorInterpolationStrategy::instance()
00477 {
00478 if (m_instance == 0) {
00479 m_instance = new HSVCCWColorInterpolationStrategy();
00480 Q_CHECK_PTR(m_instance);
00481 }
00482
00483 return m_instance;
00484 }
00485
00486 Color KisGradientSegment::HSVCCWColorInterpolationStrategy::colorAt(double t, Color start, Color end) const
00487 {
00488 KoColor sc = KoColor(start.color());
00489 KoColor se = KoColor(end.color());
00490
00491 int s = static_cast<int>(sc.S() + t * (se.S() - sc.S()) + 0.5);
00492 int v = static_cast<int>(sc.V() + t * (se.V() - sc.V()) + 0.5);
00493 int h;
00494
00495 if (sc.H() < se.H()) {
00496 h = static_cast<int>(sc.H() + t * (se.H() - sc.H()) + 0.5);
00497 }
00498 else {
00499 h = static_cast<int>(sc.H() + t * (360 - sc.H() + se.H()) + 0.5);
00500
00501 if (h > 359) {
00502 h -= 360;
00503 }
00504 }
00505
00506 double alpha = start.alpha() + t * (end.alpha() - start.alpha());
00507
00508 return Color(KoColor(h, s, v, KoColor::csHSV).color(), alpha);
00509 }
00510
00511 KisGradientSegment::LinearInterpolationStrategy *KisGradientSegment::LinearInterpolationStrategy::instance()
00512 {
00513 if (m_instance == 0) {
00514 m_instance = new LinearInterpolationStrategy();
00515 Q_CHECK_PTR(m_instance);
00516 }
00517
00518 return m_instance;
00519 }
00520
00521 double KisGradientSegment::LinearInterpolationStrategy::calcValueAt(double t, double middle)
00522 {
00523 Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON);
00524 Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON);
00525
00526 double value = 0;
00527
00528 if (t <= middle) {
00529 if (middle < DBL_EPSILON) {
00530 value = 0;
00531 }
00532 else {
00533 value = (t / middle) * 0.5;
00534 }
00535 }
00536 else {
00537 if (middle > 1 - DBL_EPSILON) {
00538 value = 1;
00539 }
00540 else {
00541 value = ((t - middle) / (1 - middle)) * 0.5 + 0.5;
00542 }
00543 }
00544
00545 return value;
00546 }
00547
00548 double KisGradientSegment::LinearInterpolationStrategy::valueAt(double t, double middle) const
00549 {
00550 return calcValueAt(t, middle);
00551 }
00552
00553 KisGradientSegment::CurvedInterpolationStrategy::CurvedInterpolationStrategy()
00554 {
00555 m_logHalf = log(0.5);
00556 }
00557
00558 KisGradientSegment::CurvedInterpolationStrategy *KisGradientSegment::CurvedInterpolationStrategy::instance()
00559 {
00560 if (m_instance == 0) {
00561 m_instance = new CurvedInterpolationStrategy();
00562 Q_CHECK_PTR(m_instance);
00563 }
00564
00565 return m_instance;
00566 }
00567
00568 double KisGradientSegment::CurvedInterpolationStrategy::valueAt(double t, double middle) const
00569 {
00570 Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON);
00571 Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON);
00572
00573 double value = 0;
00574
00575 if (middle < DBL_EPSILON) {
00576 middle = DBL_EPSILON;
00577 }
00578
00579 value = pow(t, m_logHalf / log(middle));
00580
00581 return value;
00582 }
00583
00584 KisGradientSegment::SineInterpolationStrategy *KisGradientSegment::SineInterpolationStrategy::instance()
00585 {
00586 if (m_instance == 0) {
00587 m_instance = new SineInterpolationStrategy();
00588 Q_CHECK_PTR(m_instance);
00589 }
00590
00591 return m_instance;
00592 }
00593
00594 double KisGradientSegment::SineInterpolationStrategy::valueAt(double t, double middle) const
00595 {
00596 double lt = LinearInterpolationStrategy::calcValueAt(t, middle);
00597 double value = (sin(-M_PI_2 + M_PI * lt) + 1.0) / 2.0;
00598
00599 return value;
00600 }
00601
00602 KisGradientSegment::SphereIncreasingInterpolationStrategy *KisGradientSegment::SphereIncreasingInterpolationStrategy::instance()
00603 {
00604 if (m_instance == 0) {
00605 m_instance = new SphereIncreasingInterpolationStrategy();
00606 Q_CHECK_PTR(m_instance);
00607 }
00608
00609 return m_instance;
00610 }
00611
00612 double KisGradientSegment::SphereIncreasingInterpolationStrategy::valueAt(double t, double middle) const
00613 {
00614 double lt = LinearInterpolationStrategy::calcValueAt(t, middle) - 1;
00615 double value = sqrt(1 - lt * lt);
00616
00617 return value;
00618 }
00619
00620 KisGradientSegment::SphereDecreasingInterpolationStrategy *KisGradientSegment::SphereDecreasingInterpolationStrategy::instance()
00621 {
00622 if (m_instance == 0) {
00623 m_instance = new SphereDecreasingInterpolationStrategy();
00624 Q_CHECK_PTR(m_instance);
00625 }
00626
00627 return m_instance;
00628 }
00629
00630 double KisGradientSegment::SphereDecreasingInterpolationStrategy::valueAt(double t, double middle) const
00631 {
00632 double lt = LinearInterpolationStrategy::calcValueAt(t, middle);
00633 double value = 1 - sqrt(1 - lt * lt);
00634
00635 return value;
00636 }
00637
00638 #include "kis_gradient.moc"
00639