22#include <QDomDocument>
32#include <klocalizedstring.h>
77 Q_UNUSED(resourcesInterface);
79 QByteArray data = dev->readAll();
81 QTextStream fileContent(data, QIODevice::ReadOnly);
83 fileContent.setAutoDetectUnicode(
true);
85 QString header = fileContent.readLine();
87 if (header !=
"GIMP Gradient") {
91 QString nameDefinition = fileContent.readLine();
92 QString numSegmentsText;
94 if (nameDefinition.startsWith(
"Name: ")) {
95 QString nameText = nameDefinition.right(nameDefinition.length() - 6);
98 numSegmentsText = fileContent.readLine();
102 numSegmentsText = nameDefinition;
110 numSegments = numSegmentsText.toInt(&ok);
112 if (!ok || numSegments < 1) {
117 dbgPigment <<
"Number of segments = " << numSegments;
121 for (
int i = 0; i < numSegments; i++) {
123 QString segmentText = fileContent.readLine();
126 qreal leftOffset = values[0].toDouble();
127 qreal middleOffset = values[1].toDouble();
128 qreal rightOffset = values[2].toDouble();
130 qreal leftRed = values[3].toDouble();
131 qreal leftGreen = values[4].toDouble();
132 qreal leftBlue = values[5].toDouble();
133 qreal leftAlpha = values[6].toDouble();
135 qreal rightRed = values[7].toDouble();
136 qreal rightGreen = values[8].toDouble();
137 qreal rightBlue = values[9].toDouble();
138 qreal rightAlpha = values[10].toDouble();
140 int interpolationType = values[11].toInt();
141 int colorInterpolationType = values[12].toInt();
144 if (values.count() >= 15) {
151 std::array<quint16, 4> data;
152 data[2] =
static_cast<quint16
>(leftRed *
quint16_MAX + 0.5);
153 data[1] =
static_cast<quint16
>(leftGreen *
quint16_MAX + 0.5);
154 data[0] =
static_cast<quint16
>(leftBlue *
quint16_MAX + 0.5);
155 data[3] =
static_cast<quint16
>(leftAlpha *
quint16_MAX + 0.5);
157 KoColor leftColor(
reinterpret_cast<quint8 *
>(data.data()), rgbColorSpace);
159 data[2] =
static_cast<quint16
>(rightRed *
quint16_MAX + 0.5);
160 data[1] =
static_cast<quint16
>(rightGreen *
quint16_MAX + 0.5);
161 data[0] =
static_cast<quint16
>(rightBlue *
quint16_MAX + 0.5);
162 data[3] =
static_cast<quint16
>(rightAlpha *
quint16_MAX + 0.5);
164 KoColor rightColor(
reinterpret_cast<quint8 *
>(data.data()), rgbColorSpace);
169 Q_CHECK_PTR(segment);
171 if (!segment -> isValid()) {
191 QTextStream fileContent(dev);
193 fileContent <<
"GIMP Gradient\n";
194 fileContent <<
"Name: " <<
name() <<
"\n";
198 fileContent << QString::number(segment->
startOffset(),
'f') <<
" " << QString::number(segment->
middleOffset(),
'f') <<
" "
199 << QString::number(segment->
endOffset(),
'f') <<
" ";
203 fileContent << QString::number(startColor.redF(),
'f') <<
" " << QString::number(startColor.greenF(),
'f') <<
" "
204 << QString::number(startColor.blueF(),
'f') <<
" " << QString::number(startColor.alphaF(),
'f') <<
" ";
205 fileContent << QString::number(endColor.redF(),
'f') <<
" " << QString::number(endColor.greenF(),
'f') <<
" "
206 << QString::number(endColor.blueF(),
'f') <<
" " << QString::number(endColor.alphaF(),
'f') <<
" ";
210 fileContent << (int)segment->
startType() <<
" " << (int)segment->
endType() <<
"\n";
219 if (t < 0.0)
return 0;
220 if (t > 1.0)
return 0;
224 if (t > (*it)->startOffset() - DBL_EPSILON && t < (*it)->endOffset() + DBL_EPSILON) {
242 QGradient* gradient =
new QLinearGradient();
247 gradient->setColorAt(segment->
startOffset() , color);
249 gradient->setColorAt(segment->
endOffset() , color);
256 return QString(
".ggr");
261 gradientElt.setAttribute(
"type",
"segment");
263 QDomElement segmentElt = doc.createElement(
"segment");
264 QDomElement start = doc.createElement(
"start");
265 QDomElement end = doc.createElement(
"end");
271 startColor.
toXML(doc, start);
278 endColor.
toXML(doc, end);
281 segmentElt.appendChild(start);
282 segmentElt.appendChild(end);
283 gradientElt.appendChild(segmentElt);
290 QDomElement segmentElt = elt.firstChildElement(
"segment");
291 while (!segmentElt.isNull()) {
293 int colorInterpolation =
KisDomUtils::toInt(segmentElt.attribute(
"color-interpolation",
"0.0"));
297 QDomElement start = segmentElt.firstChildElement(
"start");
302 QDomElement end = segmentElt.firstChildElement(
"end");
307 gradient.
createSegment(interpolation, colorInterpolation, startOffset, endOffset, middleOffset, left, right, leftType, rightType);
308 segmentElt = segmentElt.nextSiblingElement(
"segment");
310 if (!gradient.
segments().isEmpty()) {
317 : m_start(start), m_end(end)
321 switch (interpolationType) {
341 switch (colorInterpolationType) {
527 switch (interpolationType) {
553 switch (colorInterpolationType) {
623 if (m_instance == 0) {
625 Q_CHECK_PTR(m_instance);
635 KoColor startDummy(_start, mixSpace);
636 KoColor endDummy(_end, mixSpace);
638 const std::array<quint8*, 2> colors = {{startDummy.
data(), endDummy.
data()}};
640 std::array<qint16, 2> colorWeights{};
641 colorWeights[0] = std::lround((1.0 - t) *
qint16_MAX);
642 colorWeights[1] =
qint16_MAX - colorWeights[0];
654 if (m_instance == 0) {
656 Q_CHECK_PTR(m_instance);
670 int s =
static_cast<int>(sc.saturation() + t * (ec.saturation() - sc.saturation()) + 0.5);
671 int v =
static_cast<int>(sc.value() + t * (ec.value() - sc.value()) + 0.5);
674 if (ec.hue() < sc.hue()) {
675 h =
static_cast<int>(ec.hue() + (1 - t) * (sc.hue() - ec.hue()) + 0.5);
677 h =
static_cast<int>(ec.hue() + (1 - t) * (360 - ec.hue() + sc.hue()) + 0.5);
684 qreal opacity{sc.alphaF() + t * (ec.alphaF() - sc.alphaF())};
687 result.setHsv(h, s,
v);
688 result.setAlphaF(opacity);
700 if (m_instance == 0) {
702 Q_CHECK_PTR(m_instance);
716 int s =
static_cast<int>(sc.saturation() + t * (se.saturation() - sc.saturation()) + 0.5);
717 int v =
static_cast<int>(sc.value() + t * (se.value() - sc.value()) + 0.5);
720 if (sc.hue() < se.hue()) {
721 h =
static_cast<int>(sc.hue() + t * (se.hue() - sc.hue()) + 0.5);
723 h =
static_cast<int>(sc.hue() + t * (360 - sc.hue() + se.hue()) + 0.5);
730 qreal opacity = sc.alphaF() + t * (se.alphaF() - sc.alphaF());
733 result.setHsv(h, s,
v);
734 result.setAlphaF(opacity);
740 if (m_instance == 0) {
742 Q_CHECK_PTR(m_instance);
750 Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON);
751 Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON);
756 if (middle < DBL_EPSILON) {
759 value = (t / middle) * 0.5;
762 if (middle > 1 - DBL_EPSILON) {
765 value = ((t - middle) / (1 - middle)) * 0.5 + 0.5;
774 return calcValueAt(t, middle);
779 m_logHalf = log(0.5);
784 if (m_instance == 0) {
786 Q_CHECK_PTR(m_instance);
794 Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON);
795 Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON);
799 if (middle < DBL_EPSILON) {
800 middle = DBL_EPSILON;
803 value = pow(t, m_logHalf / log(middle));
810 if (m_instance == 0) {
812 Q_CHECK_PTR(m_instance);
821 qreal
value = (sin(-M_PI_2 +
M_PI * lt) + 1.0) / 2.0;
828 if (m_instance == 0) {
830 Q_CHECK_PTR(m_instance);
839 qreal
value = sqrt(1 - lt * lt);
846 if (m_instance == 0) {
848 Q_CHECK_PTR(m_instance);
857 qreal
value = 1 - sqrt(1 - lt * lt);
870 ,
KoColor(leftColor, colorSpace())
871 ,
KoColor(rightColor, colorSpace())
888 handlePositions.push_back(m_segments[0]->
startOffset());
889 for (
int i = 0; i < m_segments.count(); i++) {
890 handlePositions.push_back(m_segments[i]->
endOffset());
892 return handlePositions;
899 for (
int i = 0; i < m_segments.count(); i++) {
900 middleHandlePositions.push_back(m_segments[i]->
middleOffset());
902 return middleHandlePositions;
908 if (it != m_segments.end()) {
909 if (it == m_segments.begin()) {
929 if (it != m_segments.end()) {
930 if (it + 1 == m_segments.end()) {
961 Q_ASSERT(segment != 0);
963 if (it != m_segments.end()) {
972 m_segments.insert(it, newSegment);
981 Q_ASSERT(segment != 0);
983 if (it != m_segments.end()) {
992 m_segments.insert(it, newSegment);
1000 Q_ASSERT(segment != 0);
1007 Q_ASSERT(segment != 0);
1008 if (m_segments.count() < 2)
1011 if (it != m_segments.end()) {
1012 double middlePositionPercentage;
1014 if (it == m_segments.begin()) {
1015 nextSegment = (*(it + 1));
1020 nextSegment = (*(it - 1));
1027 m_segments.erase(it);
1035 Q_ASSERT(segment != 0);
1036 if (m_segments.count() < 2)
1039 if (it != m_segments.end()) {
1040 double nextMiddlePositionPercentage, prevMiddlePositionPercentage;
1042 if (it == m_segments.begin()) {
1043 nextSegment = (*(it + 1));
1047 returnSegment = nextSegment;
1048 }
else if (it == m_segments.end() - 1) {
1049 prevSegment = (*(it - 1));
1053 returnSegment = prevSegment;
1055 prevSegment = (*(it - 1));
1056 nextSegment = (*(it + 1));
1064 returnSegment = prevSegment;
1068 m_segments.erase(it);
1069 return returnSegment;
1076 if (m_segments.count() < 2)
1088 for (
int i = 0; i < m_segments.count(); i++) {
1089 delete m_segments[i];
1096 segment->interpolation(),
1097 segment->colorInterpolation(),
1099 segment->startOffset(),
1100 segment->startColor().convertedTo(colorSpace()),
1101 segment->startType()
1104 segment->endOffset(),
1105 segment->endColor().convertedTo(colorSpace()),
1108 segment->middleOffset()
1110 m_segments.append(newSegment);
1112 if (!m_segments.isEmpty()) {
1123 for (
int i = 0; i < m_segments.count(); i++) {
1143 for (
auto it = m_segments.begin(); it != m_segments.end(); ++it) {
1144 if ((*it)->hasVariableColors()) {
1145 (*it)->setVariableColors(fgColor, bgColor);
1157 for (
auto it = m_segments.begin(); it != m_segments.end(); ++it) {
1158 if ((*it)->hasVariableColors()) {
1159 (*it)->setVariableColors(fgColor, bgColor);
float value(const T *src, size_t ch)
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
KoGradientSegmentEndpointType
@ BACKGROUND_TRANSPARENT_ENDPOINT
@ FOREGROUND_TRANSPARENT_ENDPOINT
@ INTERP_SPHERE_DECREASING
@ INTERP_SPHERE_INCREASING
PythonPluginManager * instance
virtual KoID colorDepthId() const =0
KoMixColorsOp * mixColorsOp
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
void toXML(QDomDocument &doc, QDomElement &colorElt) const
void setOpacity(quint8 alpha)
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
const KoColorSpace * colorSpace() const
return the current colorSpace
void toQColor(QColor *c) const
a convenience method for the above.
virtual int type() const =0
virtual void colorAt(KoColor &dst, qreal t, const KoColor &start, const KoColor &end) const =0
qreal valueAt(qreal t, qreal middle) const override
CurvedInterpolationStrategy()
static CurvedInterpolationStrategy * instance()
static CurvedInterpolationStrategy * m_instance
static HSVCCWColorInterpolationStrategy * instance()
static HSVCCWColorInterpolationStrategy * m_instance
void colorAt(KoColor &dst, qreal t, const KoColor &start, const KoColor &end) const override
HSVCCWColorInterpolationStrategy()
static HSVCWColorInterpolationStrategy * m_instance
HSVCWColorInterpolationStrategy()
static HSVCWColorInterpolationStrategy * instance()
void colorAt(KoColor &dst, qreal t, const KoColor &start, const KoColor &end) const override
virtual int type() const =0
virtual qreal valueAt(qreal t, qreal middle) const =0
qreal valueAt(qreal t, qreal middle) const override
static qreal calcValueAt(qreal t, qreal middle)
static LinearInterpolationStrategy * m_instance
static LinearInterpolationStrategy * instance()
RGBColorInterpolationStrategy()
void colorAt(KoColor &dst, qreal t, const KoColor &start, const KoColor &end) const override
static RGBColorInterpolationStrategy * m_instance
static RGBColorInterpolationStrategy * instance()
static SineInterpolationStrategy * instance()
static SineInterpolationStrategy * m_instance
qreal valueAt(qreal t, qreal middle) const override
static SphereDecreasingInterpolationStrategy * m_instance
qreal valueAt(qreal t, qreal middle) const override
static SphereDecreasingInterpolationStrategy * instance()
qreal valueAt(qreal t, qreal middle) const override
static SphereIncreasingInterpolationStrategy * m_instance
static SphereIncreasingInterpolationStrategy * instance()
ColorInterpolationStrategy * m_colorInterpolator
void setEndType(KoGradientSegmentEndpointType type)
int colorInterpolation() const
qreal startOffset() const
KoGradientSegment(int interpolationType, int colorInterpolationType, KoGradientSegmentEndpoint start, KoGradientSegmentEndpoint end, qreal middleOffset)
void setInterpolation(int interpolationType)
void setMiddleOffset(qreal t)
void setVariableColors(const KoColor &foreground, const KoColor &background)
void colorAt(KoColor &, qreal t) const
KoGradientSegmentEndpointType endType() const
InterpolationStrategy * m_interpolator
void setColorInterpolation(int colorInterpolationType)
int interpolation() const
KoGradientSegmentEndpointType startType() const
void setStartColor(const KoColor &color)
void setStartType(KoGradientSegmentEndpointType type)
KoGradientSegmentEndpoint m_end
KoGradientSegmentEndpoint m_start
void setStartOffset(qreal t)
void setEndColor(const KoColor &color)
const KoColor & startColor() const
void setEndOffset(qreal t)
const KoColor & endColor() const
qreal middleOffset() const
virtual void mixColors(const quint8 *const *colors, const qint16 *weights, int nColors, quint8 *dst, int weightSum=255) const =0
KoGradientSegment * removeSegment(KoGradientSegment *segment)
void createSegment(int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, const QColor &leftColor, const QColor &rightColor, KoGradientSegmentEndpointType leftType=COLOR_ENDPOINT, KoGradientSegmentEndpointType rightType=COLOR_ENDPOINT)
const QList< KoGradientSegment * > & segments() const
KoGradientSegment * collapseSegment(KoGradientSegment *segment)
void moveSegmentMiddleOffset(KoGradientSegment *segment, double t)
KoResourceSP clone() const override
QList< int > requiredCanvasResources() const override
~KoSegmentGradient() override
void toXML(QDomDocument &doc, QDomElement &gradientElt) const
toXML convert the gradient to xml.
static KoSegmentGradient fromXML(const QDomElement &elt)
fromXML get a segment gradient from xml.
void moveSegmentEndOffset(KoGradientSegment *segment, double t)
KoSegmentGradient(const QString &file=QString())
const QList< double > getMiddleHandlePositions() const
void bakeVariableColors(KoCanvasResourcesInterfaceSP canvasResourcesInterface) override
void duplicateSegment(KoGradientSegment *segment)
KoGradientSegment * segmentAt(qreal t) const
QList< KoGradientSegment * > m_segments
void setSegments(const QList< KoGradientSegment * > &segments)
void updateVariableColors(KoCanvasResourcesInterfaceSP canvasResourcesInterface) override
void moveSegmentStartOffset(KoGradientSegment *segment, double t)
void mirrorSegment(KoGradientSegment *segment)
void colorAt(KoColor &dst, qreal t) const override
reimplemented
QString defaultFileExtension() const override
reimplemented
bool loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) override
bool saveToDevice(QIODevice *dev) const override
void pushSegment(KoGradientSegment *segment)
QGradient * toQGradient() const override
reimplemented
const QList< double > getHandlePositions() const
void splitSegment(KoGradientSegment *segment)
bool removeSegmentPossible() const
const quint16 quint16_MAX
QSharedPointer< KoResource > KoResourceSP
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)
QString toString(const QString &value)
void setUtf8OnStream(QTextStream &stream)
@ BackgroundColor
The active background color selected for this canvas.
@ ForegroundColor
The active foreground color selected for this canvas.
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb16(const QString &profileName=QString())
KoGradientSegmentEndpointType type
void setValid(bool valid)
void setName(const QString &name)