File indexing completed on 2024-12-22 04:11:42

0001 /*
0002  * KDE. Krita Project.
0003  *
0004  * SPDX-FileCopyrightText: 2020 Deif Lou <ginoba@gmail.com>
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include <QList>
0010 
0011 #include <KoCanvasResourcesIds.h>
0012 #include <KoColorSpaceRegistry.h>
0013 
0014 #include "KisGradientConversion.h"
0015 
0016 namespace KisGradientConversion
0017 {
0018     QGradientStops toQGradientStops(KoAbstractGradientSP gradient,
0019                                     KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0020     {
0021         if (!gradient) {
0022             return QGradientStops();
0023         }
0024         if (gradient.dynamicCast<KoStopGradient>()) {
0025             return toQGradientStops(gradient.dynamicCast<KoStopGradient>(), canvasResourcesInterface);
0026         } else if (gradient.dynamicCast<KoSegmentGradient>()) {
0027             return toQGradientStops(gradient.dynamicCast<KoSegmentGradient>(), canvasResourcesInterface);
0028         }
0029         return QGradientStops();
0030     }
0031 
0032     QGradientStop toQGradientStop(const KoColor &color, KoGradientStopType type, qreal position,
0033                                   KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0034     {
0035         QGradientStop stop;
0036         stop.first = position;
0037 
0038         if (type == FOREGROUNDSTOP) {
0039             if (canvasResourcesInterface) {
0040                 canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>().toQColor(&stop.second);
0041                 return stop;
0042             }
0043         } else if (type == BACKGROUNDSTOP) {
0044             if (canvasResourcesInterface) {
0045                 canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>().toQColor(&stop.second);
0046                 return stop;
0047             }
0048         }
0049         
0050         color.toQColor(&stop.second);
0051         return stop;
0052     }
0053 
0054     QGradientStops toQGradientStops(KoStopGradientSP gradient,
0055                                     KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0056     {
0057         QGradientStops stops;
0058 
0059         if (!gradient) {
0060             return stops;
0061         }
0062 
0063         qreal lastStopPosition = -1.0;
0064         for (const KoGradientStop &stopGradientStop : gradient->stops()) {
0065             if (qFuzzyCompare(stopGradientStop.position, lastStopPosition)) {
0066                 stops << toQGradientStop(
0067                     stopGradientStop.color, stopGradientStop.type, stopGradientStop.position + 0.000001,
0068                     canvasResourcesInterface
0069                 );
0070                 lastStopPosition = stopGradientStop.position + 0.000001;
0071             } else {
0072                 stops << toQGradientStop(
0073                     stopGradientStop.color, stopGradientStop.type, stopGradientStop.position,
0074                     canvasResourcesInterface
0075                 );
0076                 lastStopPosition = stopGradientStop.position;
0077             }
0078         }
0079         return stops;
0080     }
0081 
0082     QGradientStop toQGradientStop(const KoColor &color, KoGradientSegmentEndpointType type, qreal offset,
0083                                   KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0084     {
0085         QGradientStop stop;
0086         stop.first = offset;
0087 
0088         if (type == FOREGROUND_ENDPOINT) {
0089             if (canvasResourcesInterface) {
0090                 canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>().toQColor(&stop.second);
0091                 return stop;
0092             }
0093         } else if (type == FOREGROUND_TRANSPARENT_ENDPOINT) {
0094             if (canvasResourcesInterface) {
0095                 canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>().toQColor(&stop.second);
0096                 stop.second.setAlpha(0);
0097                 return stop;
0098             }
0099         } else if (type == BACKGROUND_ENDPOINT) {
0100             if (canvasResourcesInterface) {
0101                 canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>().toQColor(&stop.second);
0102                 return stop;
0103             }
0104         } else if (type == BACKGROUND_TRANSPARENT_ENDPOINT) {
0105             if (canvasResourcesInterface) {
0106                 canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>().toQColor(&stop.second);
0107                 stop.second.setAlpha(0);
0108                 return stop;
0109             }
0110         }
0111         
0112         color.toQColor(&stop.second);
0113         return stop;
0114     }
0115 
0116     QGradientStops toQGradientStops(KoSegmentGradientSP gradient,
0117                                     KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0118     {
0119         QGradientStops stops;
0120 
0121         if (!gradient) {
0122             return stops;
0123         }
0124 
0125         QGradientStop lastStop;
0126         lastStop.first = -1.0;
0127 
0128         for (KoGradientSegment *segment : gradient->segments()) {
0129             QGradientStop stop;
0130             
0131             stop = toQGradientStop(
0132                 segment->startColor(), segment->startType(), segment->startOffset(),
0133                 canvasResourcesInterface
0134             );
0135             if (qFuzzyCompare(stop.first, lastStop.first)) {
0136                 if (stop.second != lastStop.second) {
0137                     stop.first = stop.first + 0.000001;
0138                     stops << stop;
0139                     lastStop = stop;
0140                 }
0141             } else {
0142                 stops << stop;
0143                 lastStop = stop;
0144             }
0145             
0146             stop = toQGradientStop(
0147                 segment->endColor(), segment->endType(), segment->endOffset(),
0148                 canvasResourcesInterface
0149             );
0150             if (qFuzzyCompare(stop.first, lastStop.first)) {
0151                 if (stop.second != lastStop.second) {
0152                     stop.first = stop.first + 0.000001;
0153                     stops << stop;
0154                     lastStop = stop;
0155                 }
0156             } else {
0157                 stops << stop;
0158                 lastStop = stop;
0159             }
0160         }
0161 
0162         return stops;
0163     }
0164     
0165     QGradient* toQGradient(KoAbstractGradientSP gradient, KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0166     {
0167         if (!gradient) {
0168             return nullptr;
0169         }
0170         if (gradient.dynamicCast<KoStopGradient>()) {
0171             return toQGradient(gradient.dynamicCast<KoStopGradient>(), canvasResourcesInterface);
0172         } else if (gradient.dynamicCast<KoSegmentGradient>()) {
0173             return toQGradient(gradient.dynamicCast<KoSegmentGradient>(), canvasResourcesInterface);
0174         }
0175         return nullptr;
0176     }
0177 
0178     QGradient* toQGradient(KoStopGradientSP gradient, KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0179     {
0180         if (!gradient) {
0181             return nullptr;
0182         }
0183         QGradient *qGradient = new QLinearGradient;
0184         qGradient->setStops(toQGradientStops(gradient, canvasResourcesInterface));
0185         return qGradient;
0186     }
0187 
0188     QGradient* toQGradient(KoSegmentGradientSP gradient, KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0189     {
0190         if (!gradient) {
0191             return nullptr;
0192         }
0193         QGradient *qGradient = new QLinearGradient;
0194         qGradient->setStops(toQGradientStops(gradient, canvasResourcesInterface));
0195         return qGradient;
0196     }
0197 
0198     KoAbstractGradientSP toAbstractGradient(const QGradientStops &gradient)
0199     {
0200         return toStopGradient(gradient).dynamicCast<KoAbstractGradient>();
0201     }
0202 
0203     KoAbstractGradientSP toAbstractGradient(const QGradient *gradient)
0204     {
0205         if (!gradient) {
0206             return nullptr;
0207         }
0208         return toStopGradient(gradient).dynamicCast<KoAbstractGradient>();
0209     }
0210 
0211     KoAbstractGradientSP toAbstractGradient(KoStopGradientSP gradient)
0212     {
0213         if (!gradient) {
0214             return nullptr;
0215         }
0216         return gradient->clone().dynamicCast<KoAbstractGradient>();
0217     }
0218 
0219     KoAbstractGradientSP toAbstractGradient(KoSegmentGradientSP gradient)
0220     {
0221         if (!gradient) {
0222             return nullptr;
0223         }
0224         return gradient->clone().dynamicCast<KoAbstractGradient>();
0225     }
0226 
0227     KoStopGradientSP toStopGradient(const QGradientStops &gradient)
0228     {
0229         KoStopGradientSP stopGradient(new KoStopGradient);
0230         QList<KoGradientStop> stops;
0231 
0232         for (const QGradientStop &qGradientStop : gradient) {
0233             KoGradientStop stop;
0234             stop.type = COLORSTOP;
0235             stop.position = qGradientStop.first;
0236             stop.color = KoColor(qGradientStop.second, stopGradient->colorSpace());
0237             stops << stop;
0238         }
0239 
0240         stopGradient->setStops(stops);
0241         stopGradient->setType(QGradient::LinearGradient);
0242         stopGradient->setValid(true);
0243 
0244         return stopGradient;
0245     }
0246 
0247     KoStopGradientSP toStopGradient(const QGradient *gradient)
0248     {
0249         if (!gradient || gradient->type() == QGradient::NoGradient) {
0250             return nullptr;
0251         }
0252         KoStopGradientSP stopGradient = toStopGradient(gradient->stops());
0253         stopGradient->setType(gradient->type());
0254         stopGradient->setSpread(gradient->spread());
0255         return stopGradient;
0256     }
0257 
0258     KoStopGradientSP toStopGradient(KoAbstractGradientSP gradient,
0259                                     KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0260     {
0261         if (!gradient) {
0262             return nullptr;
0263         }
0264         if (gradient.dynamicCast<KoStopGradient>()) {
0265             return gradient->clone().dynamicCast<KoStopGradient>();
0266         } else if (gradient.dynamicCast<KoSegmentGradient>()) {
0267             return toStopGradient(gradient.dynamicCast<KoSegmentGradient>(), canvasResourcesInterface);
0268         }
0269         return nullptr;
0270     }
0271 
0272     KoGradientStop toKoGradientStop(const KoColor &color, KoGradientSegmentEndpointType type, qreal offset,
0273                                     KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0274     {
0275         KoGradientStop stop;
0276     
0277         stop.position = offset;
0278 
0279         if (type == FOREGROUND_ENDPOINT) {
0280             stop.type = FOREGROUNDSTOP;
0281             stop.color = color;
0282         } else if (type == FOREGROUND_TRANSPARENT_ENDPOINT) {
0283             stop.type = COLORSTOP;
0284             if (canvasResourcesInterface) {
0285                 stop.color = canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>();
0286             } else {
0287                 stop.color = color;
0288             }
0289             stop.color.setOpacity(static_cast<quint8>(0));
0290         } else if (type == BACKGROUND_ENDPOINT) {
0291             stop.type = BACKGROUNDSTOP;
0292             stop.color = color;
0293         } else if (type == BACKGROUND_TRANSPARENT_ENDPOINT) {
0294             stop.type = COLORSTOP;
0295             if (canvasResourcesInterface) {
0296                 stop.color = canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>();
0297             } else {
0298                 stop.color = color;
0299             }
0300             stop.color.setOpacity(static_cast<quint8>(0));
0301         } else {
0302             stop.type = COLORSTOP;
0303             stop.color = color;
0304         }
0305 
0306         return stop;
0307     }
0308 
0309     KoStopGradientSP toStopGradient(KoSegmentGradientSP gradient, KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0310     {
0311         if (!gradient) {
0312             return nullptr;
0313         }
0314 
0315         KoStopGradientSP stopGradient(new KoStopGradient);
0316         QList<KoGradientStop> stops;
0317 
0318         KoGradientStop lastStop;
0319         lastStop.position = -1.0;
0320 
0321         for (KoGradientSegment *segment : gradient->segments()) {
0322             KoGradientStop stop;
0323             
0324             stop = toKoGradientStop(
0325                 segment->startColor(), segment->startType(), segment->startOffset(),
0326                 canvasResourcesInterface
0327             );
0328             stop.color.convertTo(stopGradient->colorSpace());
0329             if (!qFuzzyCompare(stop.position, lastStop.position) || stop.type != lastStop.type || stop.color != lastStop.color) {
0330                 stops << stop;
0331                 lastStop.type = stop.type;
0332                 lastStop.color = stop.color;
0333                 lastStop.position = stop.position;
0334             }
0335             
0336             stop = toKoGradientStop(
0337                 segment->endColor(), segment->endType(), segment->endOffset(),
0338                 canvasResourcesInterface
0339             );
0340             stop.color.convertTo(stopGradient->colorSpace());
0341             if (!qFuzzyCompare(stop.position, lastStop.position) || stop.type != lastStop.type || stop.color != lastStop.color) {
0342                 stops << stop;
0343                 lastStop.type = stop.type;
0344                 lastStop.color = stop.color;
0345                 lastStop.position = stop.position;
0346             }
0347         }
0348 
0349         stopGradient->setType(gradient->type());
0350         stopGradient->setSpread(gradient->spread());
0351         stopGradient->setStops(stops);
0352 
0353         stopGradient->setName(gradient->name());
0354         stopGradient->setFilename(gradient->filename());
0355         stopGradient->setValid(true);
0356 
0357         return stopGradient;
0358     }
0359 
0360     KoSegmentGradientSP toSegmentGradient(const QGradientStops &gradient)
0361     {
0362         KoSegmentGradientSP segmentGradient(new KoSegmentGradient);
0363         const QGradientStops &stops = gradient;
0364 
0365         for (int i = 0; i < stops.size() - 1; ++i) {
0366             if (qFuzzyCompare(stops[i].first, stops[i + 1].first)) {
0367                 continue;
0368             }
0369             segmentGradient->createSegment(
0370                 INTERP_LINEAR, COLOR_INTERP_RGB,
0371                 stops[i].first, stops[i + 1].first, (stops[i].first + stops[i + 1].first) / 2,
0372                 stops[i].second, stops[i + 1].second
0373             );
0374         }
0375 
0376         segmentGradient->setValid(true);
0377         
0378         return segmentGradient;
0379     }
0380 
0381     KoSegmentGradientSP toSegmentGradient(const QGradient *gradient)
0382     {
0383         if (!gradient || gradient->type() == QGradient::NoGradient) {
0384             return nullptr;
0385         }
0386         KoSegmentGradientSP segmentGradient = toSegmentGradient(gradient->stops());
0387         segmentGradient->setType(gradient->type());
0388         segmentGradient->setSpread(gradient->spread());
0389         return segmentGradient;
0390     }
0391 
0392     KoSegmentGradientSP toSegmentGradient(KoAbstractGradientSP gradient)
0393     {
0394         if (!gradient) {
0395             return nullptr;
0396         }
0397         if (gradient.dynamicCast<KoSegmentGradient>()) {
0398             return gradient->clone().dynamicCast<KoSegmentGradient>();
0399         } else if (gradient.dynamicCast<KoStopGradient>()) {
0400             return toSegmentGradient(gradient.dynamicCast<KoStopGradient>());
0401         }
0402         return nullptr;
0403     }
0404 
0405     KoSegmentGradientSP toSegmentGradient(KoStopGradientSP gradient)
0406     {
0407         if (!gradient) {
0408             return nullptr;
0409         }
0410 
0411         KoSegmentGradientSP segmentGradient(new KoSegmentGradient);
0412         QList<KoGradientStop> stops = gradient->stops();
0413 
0414         for (int i = 0; i < stops.size() - 1; ++i) {
0415             if (qFuzzyCompare(stops[i].position, stops[i + 1].position)) {
0416                 continue;
0417             }
0418 
0419             KoGradientSegmentEndpointType startType, endType;
0420             const KoGradientStopType startStopType = stops[i].type;
0421             const KoGradientStopType endStopType = stops[i + 1].type;
0422 
0423             if (startStopType == FOREGROUNDSTOP) {
0424                 startType = FOREGROUND_ENDPOINT;
0425             } else if (startStopType == BACKGROUNDSTOP) {
0426                 startType = BACKGROUND_ENDPOINT;
0427             } else {
0428                 startType = COLOR_ENDPOINT;
0429             }
0430 
0431             if (endStopType == FOREGROUNDSTOP) {
0432                 endType = FOREGROUND_ENDPOINT;
0433             } else if (endStopType == BACKGROUNDSTOP) {
0434                 endType = BACKGROUND_ENDPOINT;
0435             } else {
0436                 endType = COLOR_ENDPOINT;
0437             }
0438             
0439             segmentGradient->createSegment(
0440                 INTERP_LINEAR, COLOR_INTERP_RGB,
0441                 stops[i].position, stops[i + 1].position, (stops[i].position + stops[i + 1].position) / 2,
0442                 stops[i].color.toQColor(), stops[i + 1].color.toQColor(),
0443                 startType, endType
0444             );
0445         }
0446 
0447         segmentGradient->setType(gradient->type());
0448         segmentGradient->setSpread(gradient->spread());
0449 
0450         segmentGradient->setName(gradient->name());
0451         segmentGradient->setFilename(gradient->filename());
0452         segmentGradient->setValid(true);
0453 
0454         return segmentGradient;
0455     }
0456 }