17#include <QDomDocument>
19#include <QDomNodeList>
23#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
31#include <QXmlStreamReader>
32#include <QXmlStreamAttributes>
34#include <QRegularExpression>
35#include <QRegularExpressionMatch>
38#include <klocalizedstring.h>
66 buffer.open(QBuffer::ReadOnly);
67 QTextStream stream(&buffer);
71 while (stream.readLineInto(&line)) {
124 QPair<int, int> pos = modifiedGroup->addSwatch(
m_swatch);
138 modifiedGroup->removeSwatch(
m_x,
m_y);
155 ,
m_swatch(group->getSwatch(column, row))
345 for (
const KisSwatchGroup::SwatchInfo &info :
m_oldGroup->infoList()) {
346 globalGroup->setSwatch(info.swatch,
366 for (
const KisSwatchGroup::SwatchInfo &info : globalGroup->infoList()) {
368 globalGroup->removeSwatch(info.column,
524 switch(paletteType) {
576 d->paletteType = rhs.
d->paletteType;
577 d->data = rhs.
d->data;
578 d->comment = rhs.
d->comment;
579 d->swatchGroups = rhs.
d->swatchGroups;
593 Q_UNUSED(resourcesInterface);
595 if (!dev->isOpen()) dev->open(QIODevice::ReadOnly);
597 d->data = dev->readAll();
599 Q_ASSERT(
d->data.size() != 0);
607 switch(
d->paletteType) {
609 res =
d->saveGpl(dev);
612 res =
d->saveKpl(dev);
624 buf.open(QIODevice::ReadOnly);
630 return d->paletteType;
639 d->undoStack.push(cmd);
645 if (
d->isLocked)
return;
649 d->undoStack.push(cmd);
655 if (
d->isLocked)
return;
658 d->undoStack.push(cmd);
663 if (
d->isLocked)
return;
667 d->undoStack.push(cmd);
678 if (group->name().isEmpty()) {
679 rowInGroup = (int)row - titleRow;
682 rowInGroup = (int)row - (titleRow + 1);
685 Q_ASSERT((
isGroupTitleRow(titleRow) && titleRow > 0) || titleRow == 0);
686 Q_ASSERT(rowInGroup < group->
rowCount());
688 return group->getSwatch(column, rowInGroup);
696 if (group->name() == groupName) {
697 if (group->checkSwatchExists(column, row)) {
698 swatch = group->getSwatch(column, row);
710 groupNames << group->name();
719 idx += group->rowCount();
732 if (groupName.isEmpty())
return 0;
736 if (group->name() == groupName) {
739 row += group->rowCount();
754 for (
int i = rowNumber; i > -1; i--) {
777 if (!groupName.isEmpty()) {
796 if (
d->undoStack.canUndo()) {
806 if (!
swatchGroupNames().contains(oldGroupName) || (oldGroupName == newGroupName) ||
d->isLocked)
return;
809 d->undoStack.push(cmd);
814 if (
d->isLocked || (columns ==
d->columns))
return;
818 d->undoStack.push(cmd);
823 Q_ASSERT(
d->swatchGroups.size() > 0);
825 return d->swatchGroups.first()->columnCount();
835 if (
d->isLocked ||
comment ==
d->comment)
return;
839 d->undoStack.push(cmd);
848 d->undoStack.push(cmd);
854 if (!groupNames.contains(groupName)
855 || !groupNames.contains(groupNameInsertBefore)
856 ||
d->isLocked)
return;
860 d->undoStack.push(cmd);
871 d->undoStack.push(cmd);
876 return (
d->paletteType ==
GPL) ?
".gpl" :
".kpl";
881 return &
d->undoStack;
898 res += group->rowCount();
905 return rowCount() +
d->swatchGroups.size() - 1;
929 if (group->name() ==
name) {
946 int groupRowCount = group->rowCount();
955 bool hit = (currentRow <= row && row < currentRow + groupRowCount);
961 currentRow += group->rowCount();
976 Q_ASSERT(
d->swatchGroups.size() > 0);
978 return d->swatchGroups.first();
983 KisSwatchGroup::SwatchInfo closestSwatch;
985 quint8 highestPercentage = 0;
986 quint8 testPercentage = 0;
989 for (
const KisSwatchGroup::SwatchInfo &currInfo : group->infoList()) {
990 KoColor color = currInfo.swatch.color();
998 if (testPercentage > highestPercentage)
1000 highestPercentage = testPercentage;
1001 closestSwatch = currInfo;
1005 return closestSwatch;
1014 int lastRowInGroup = 0;
1015 for (
const KisSwatchGroup::SwatchInfo &info : group->infoList()) {
1016 lastRowInGroup = qMax(lastRowInGroup, info.row);
1018 rows += (lastRowInGroup + 1);
1021 QImage img(
d->global()->columnCount() * 4, rows * 4, QImage::Format_ARGB32);
1023 gc.fillRect(img.rect(), Qt::darkGray);
1027 int lastRowGroup = 0;
1028 for (
const KisSwatchGroup::SwatchInfo &info : group->infoList()) {
1029 QColor c = info.swatch.color().toQColor();
1030 gc.fillRect(info.column * 4, (lastRow + info.row) * 4, 4, 4, c);
1031 lastRowGroup = qMax(lastRowGroup, info.row);
1033 lastRow += (lastRowGroup + 1);
1042 : colorSet(a_colorSet)
1053 QFileInfo fi(fileName);
1056 if (ba.startsWith(
"RIFF") && ba.indexOf(
"PAL data", 8)) {
1060 else if (ba.startsWith(
"GIMP Palette")) {
1064 else if (ba.startsWith(
"JASC-PAL")) {
1067 else if (ba.contains(
"krita/x-colorset") || ba.contains(
"application/x-krita-palette")) {
1070 else if (fi.suffix().toLower() ==
"aco") {
1073 else if (fi.suffix().toLower() ==
"act") {
1076 else if (fi.suffix().toLower() ==
"xml") {
1079 else if (fi.suffix().toLower() ==
"sbz") {
1082 else if (fi.suffix().toLower() ==
"ase" || ba.startsWith(
"ASEF")) {
1085 else if (fi.suffix().toLower() ==
"acb" || ba.startsWith(
"8BCB")) {
1088 else if (fi.suffix().toLower() ==
"css") {
1098 QXmlStreamAttributes colorProperties = xml->attributes();
1099 auto colorName = colorProperties.value(
"NAME");
1100 colorEntry.
setName(colorName.isEmpty() || colorName.isNull() ? i18n(
"Untitled") : colorName.toString());
1103 if (colorProperties.hasAttribute(
"RGB")) {
1104 dbgPigment <<
"Color " << colorProperties.value(
"NAME") <<
", RGB " << colorProperties.value(
"RGB");
1107 auto colorValue = colorProperties.value(
"RGB");
1109 if (colorValue.length() != 7 && colorValue.at(0) !=
'#') {
1110 xml->raiseError(
"Invalid rgb8 color (malformed): " + colorValue);
1114 quint32 rgb = colorValue.mid(1).toUInt(&rgbOk, 16);
1116 xml->raiseError(
"Invalid rgb8 color (unable to convert): " + colorValue);
1120 quint8 r = rgb >> 16 & 0xff;
1121 quint8 g = rgb >> 8 & 0xff;
1122 quint8 b = rgb & 0xff;
1124 dbgPigment <<
"Color parsed: "<< r << g << b;
1126 currentColor.
data()[0] = r;
1127 currentColor.
data()[1] = g;
1128 currentColor.
data()[2] = b;
1134 while(xml->readNextStartElement()) {
1136 xml->skipCurrentElement();
1141 else if (colorProperties.hasAttribute(
"CMYK")) {
1142 dbgPigment <<
"Color " << colorProperties.value(
"NAME") <<
", CMYK " << colorProperties.value(
"CMYK");
1145 auto colorValue = colorProperties.value(
"CMYK");
1147 if (colorValue.length() != 9 && colorValue.at(0) !=
'#') {
1148 xml->raiseError(
"Invalid cmyk color (malformed): " % colorValue);
1153 quint32 cmyk = colorValue.mid(1).toUInt(&cmykOk, 16);
1155 xml->raiseError(
"Invalid cmyk color (unable to convert): " % colorValue);
1159 quint8 c = cmyk >> 24 & 0xff;
1160 quint8 m = cmyk >> 16 & 0xff;
1161 quint8 y = cmyk >> 8 & 0xff;
1162 quint8 k = cmyk & 0xff;
1164 dbgPigment <<
"Color parsed: "<< c << m << y << k;
1166 currentColor.
data()[0] = c;
1167 currentColor.
data()[1] = m;
1168 currentColor.
data()[2] = y;
1169 currentColor.
data()[3] = k;
1175 while(xml->readNextStartElement()) {
1177 xml->skipCurrentElement();
1183 xml->raiseError(
"Unknown color space for color " + colorEntry.
name());
1191 QXmlStreamAttributes paletteProperties = xml->attributes();
1192 auto paletteName = paletteProperties.value(
"Name");
1193 dbgPigment <<
"Processed name of palette:" << paletteName;
1194 set->
setName(paletteName.toString());
1198 while(xml->readNextStartElement()) {
1199 auto currentElement = xml->name();
1200 if (currentElement.compare(QString(
"COLOR"), Qt::CaseInsensitive) == 0) {
1201 scribusParseColor(set, xml);
1204 xml->skipCurrentElement();
1208 if(xml->hasError()) {
1218 quint64 read = io->read((
char*)&val, 1);
1219 if (read != 1)
return false;
1225 quint64 read = io->read((
char*)&val, 2);
1226 if (read != 2)
return false;
1227 return qFromBigEndian(val);
1233 quint64 read = io->read((
char*)&val, 4);
1234 if (read != 4)
return false;
1235 return qFromBigEndian(val);
1241 quint64 read = io->read((
char*)&val, 4);
1242 if (read != 4)
return false;
1243 return qFromBigEndian(val);
1253 size = readShort(io)-1;
1256 QByteArray ba = io->read(size*2);
1257 if (ba.size() ==
int(size)*2) {
1258 QTextCodec *Utf16Codec = QTextCodec::codecForName(
"UTF-16BE");
1259 unicode = Utf16Codec->toUnicode(ba);
1261 warnPigment <<
"Unicode name block is the wrong size" << colorSet->filename();
1267 return unicode.trimmed();
1273 swatchGroups.clear();
1276 swatchGroups.append(globalGroup);
1279 if (colorSet->filename().isNull()) {
1280 warnPigment <<
"Cannot load palette" << colorSet->name() <<
"there is no filename set";
1283 if (data.isNull()) {
1284 QFile file(colorSet->filename());
1285 if (file.size() == 0) {
1286 warnPigment <<
"Cannot load palette" << colorSet->name() <<
"there is no data available";
1289 file.open(QIODevice::ReadOnly);
1290 data = file.readAll();
1295 paletteType = detectFormat(colorSet->filename(), data);
1334 int rowCount = global()->colorCount() / global()->columnCount();
1340 colorSet->setValid(res);
1341 colorSet->updateThumbnail();
1351 Q_ASSERT(dev->isOpen());
1352 Q_ASSERT(dev->isWritable());
1354 QTextStream stream(dev);
1356 stream <<
"GIMP Palette\nName: " << colorSet->name() <<
"\nColumns: " << colorSet->columnCount() <<
"\n#\n";
1359 for (
int y = 0; y < global->rowCount(); y++) {
1360 for (
int x = 0; x < colorSet->columnCount(); x++) {
1361 if (!global->checkSwatchExists(x, y)) {
1364 const KisSwatch& entry = global->getSwatch(x, y);
1366 stream << c.red() <<
" " << c.green() <<
" " << c.blue() <<
"\t";
1367 if (entry.
name().isEmpty())
1368 stream <<
"Untitled\n";
1370 stream << entry.
name() <<
"\n";
1379 if (data.isEmpty() || data.isNull() || data.length() < 50) {
1380 warnPigment <<
"Illegal Gimp palette file: " << colorSet->filename();
1388 if (lines.size() < 3) {
1389 warnPigment <<
"Not enough lines in palette file: " << colorSet->filename();
1393 QString columnsText;
1398 if (!lines[0].startsWith(
"GIMP") || !lines[1].toLower().contains(
"name")) {
1399 warnPigment <<
"Illegal Gimp palette file: " << colorSet->filename();
1404 colorSet->
setName(lines[1].split(
":")[1].trimmed());
1410 if (lines[index].toLower().contains(
"columns")) {
1411 columnsText = lines[index].split(
":")[1].trimmed();
1412 columns = columnsText.toInt();
1414 warnPigment <<
"Refusing to set unreasonable number of columns (" << columns <<
") in GIMP Palette file " << colorSet->filename() <<
" - using maximum number of allowed columns instead";
1418 global()->setColumnCount(columns);
1424 for (qint32 i = index; i < lines.size(); i++) {
1425 if (lines[i].startsWith(
'#')) {
1426 comment += lines[i].mid(1).trimmed() +
' ';
1427 }
else if (!lines[i].isEmpty()) {
1428 QStringList a = lines[i].replace(
'\t',
' ').split(
' ', Qt::SkipEmptyParts);
1430 if (a.count() < 3) {
1434 r = qBound(0, a[0].toInt(), 255);
1435 g = qBound(0, a[1].toInt(), 255);
1436 b = qBound(0, a[2].toInt(), 255);
1440 for (
int i = 0; i != 3; i++) {
1443 QString
name = a.join(
" ");
1446 global()->addSwatch(swatch);
1454 QFileInfo info(colorSet->filename());
1455 colorSet->setName(info.completeBaseName());
1457 int numOfTriplets = int(data.size() / 3);
1458 for (
int i = 0; i < numOfTriplets * 3; i += 3) {
1460 quint8 g = data[i+1];
1461 quint8 b = data[i+2];
1463 global()->addSwatch(swatch);
1471 QFileInfo info(colorSet->filename());
1472 colorSet->setName(info.completeBaseName());
1476 memcpy(&header, data.constData(),
sizeof(
RiffHeader));
1483 quint8 g = data[i+1];
1484 quint8 b = data[i+2];
1486 colorSet->getGlobalGroup()->addSwatch(swatch);
1494 QFileInfo info(colorSet->filename());
1495 colorSet->setName(info.completeBaseName());
1500 if (l.size() < 4)
return false;
1501 if (l[0] !=
"JASC-PAL")
return false;
1502 if (l[1] !=
"0100")
return false;
1504 int entries = l[2].toInt();
1508 for (
int i = 0; i < entries; ++i) {
1510 QStringList a = l[i + 3].replace(
'\t',
' ').split(
' ', Qt::SkipEmptyParts);
1512 if (a.count() != 3) {
1516 r = qBound(0, a[0].toInt(), 255);
1517 g = qBound(0, a[1].toInt(), 255);
1518 b = qBound(0, a[2].toInt(), 255);
1523 QString
name = a.join(
" ");
1526 global->addSwatch(swatch);
1533 QFileInfo info(colorSet->filename());
1534 colorSet->setName(info.completeBaseName());
1536 QString text = readAllLinesSafe(&data).join(
"").replace(
"\t",
"").replace(
" ",
"");
1538 QRegularExpression re(
"/\\*.*?\\*/");
1545 QRegularExpression
palette(
"(.*?){(?:[^:;]+:[^;]+;)*?color:(.*?)(?:;.*?)*?}");
1547 QRegularExpressionMatchIterator colors =
palette.globalMatch(text);
1549 if (!colors.hasNext()) {
1550 warnPigment <<
"No color found in CSS palette : " << colorSet->filename();
1554 while (colors.hasNext()) {
1555 QRegularExpressionMatch match = colors.next();
1556 QString colorInfo = match.captured();
1557 QString colorName = match.captured(1);
1558 QString colorValue = match.captured(2);
1560 if (!colorInfo.startsWith(
".") || colorValue.isEmpty()) {
1561 warnPigment <<
"Illegal CSS palette syntax : " << colorInfo;
1567 colorName.remove(
".");
1570 if (colorValue.startsWith(
"rgb")) {
1573 if (colorValue.startsWith(
"rgba")) {
1574 colorValue.remove(
"rgba(").remove(
")");
1575 color = colorValue.split(
",");
1577 if (color.size() != 4) {
1578 warnPigment <<
"Invalid RGBA color definition : " << colorInfo;
1582 int alpha = color[3].toFloat() * 255;
1584 if (alpha < 0 || alpha > 255) {
1585 warnPigment <<
"Invalid alpha parameter : " << colorInfo;
1590 colorValue.remove(
"rgb(").remove(
")");
1592 color = colorValue.split(
",");
1594 if (color.size() != 3) {
1595 warnPigment <<
"Invalid RGB color definition : " << colorInfo;
1602 for (
int i = 0; i < 3; i++) {
1603 if (color[i].endsWith(
"%")) {
1604 color[i].replace(
"%",
"");
1605 rgb[i] = color[i].toFloat() / 100 * 255 ;
1608 rgb[i] = color[i].toInt();
1612 qColor = QColor(rgb[0], rgb[1], rgb[2]);
1614 else if (colorValue.startsWith(
"hsl")) {
1617 if (colorValue.startsWith(
"hsla")) {
1618 colorValue.remove(
"hsla(").remove(
")").replace(
"%",
"");
1619 color = colorValue.split(
",");
1620 if (color.size() != 4) {
1621 warnPigment <<
"Invalid HSLA color definition : " << colorInfo;
1625 float alpha = color[3].toFloat();
1627 if (alpha < 0.0 || alpha > 1.0) {
1628 warnPigment <<
"Invalid alpha parameter : " << colorInfo;
1634 colorValue.remove(
"hsl(").remove(
")").replace(
"%",
"");
1635 color = colorValue.split(
",");
1636 if (color.size() != 3) {
1637 warnPigment <<
"Invalid HSL color definition : " << colorInfo;
1642 float hue = color[0].toFloat() / 359;
1643 float saturation = color[1].toFloat() / 100;
1644 float lightness = color[2].toFloat() / 100;
1646 if (hue < 0.0 || hue > 1.0) {
1647 warnPigment <<
"Invalid hue parameter : " << colorInfo;
1651 if (saturation < 0.0 || saturation > 1.0) {
1652 warnPigment <<
"Invalid saturation parameter : " << colorInfo;
1656 if (lightness < 0.0 || lightness > 1.0) {
1657 warnPigment <<
"Invalid lightness parameter : " << colorInfo;
1661 qColor = QColor::fromHslF(hue, saturation, lightness);
1664 else if (colorValue.startsWith(
"#")) {
1665 if (colorValue.size() == 9) {
1668 colorValue.truncate(7);
1671 qColor = QColor(colorValue);
1674 warnPigment <<
"Unknown color declaration : " << colorInfo;
1678 if (!qColor.isValid()) {
1679 warnPigment <<
"Invalid color definition : " << colorInfo;
1685 global()->addSwatch(swatch);
1692 const QString &path,
1693 const QString &modelId,
1694 const QString &colorDepthId)
1696 if (!store->open(path)) {
1700 QByteArray bytes = store->read(store->size());
1705 if (!profile || !profile->
valid()) {
1715 if (!store->open(
"profiles.xml")) {
1719 QByteArray bytes = store->read(store->size());
1723 if(!doc.setContent(bytes)) {
1727 QDomElement root = doc.documentElement();
1740 loadColorProfile(store,
filename, colorModelId, colorDepthId);
1749 if (!store->open(
"colorset.xml")) {
1753 QByteArray bytes = store->read(store->size());
1757 if (!doc.setContent(bytes)) {
1761 QDomElement root = doc.documentElement();
1768 warnPigment <<
"Refusing to set unreasonable number of columns (" << desiredColumnCount
1769 <<
") in KPL palette file " << colorSet->filename()
1770 <<
" - setting maximum allowed column count instead.";
1773 colorSet->setColumnCount(desiredColumnCount);
1776 loadKplGroup(doc, root, colorSet->getGlobalGroup(),
version);
1782 colorSet->addGroup(groupName);
1783 loadKplGroup(doc, g, colorSet->getGroup(groupName),
version);
1792 buf.open(QBuffer::ReadOnly);
1794 QScopedPointer<KoStore> store(
1796 "application/x-krita-palette",
1798 if (!store || store->bad()) {
1802 if (store->hasFile(
"profiles.xml") && !loadKplProfiles(store)) {
1806 if (!loadKplColorset(store)) {
1816 QFileInfo info(colorSet->filename());
1817 colorSet->setName(info.completeBaseName());
1820 buf.open(QBuffer::ReadOnly);
1822 quint16
version = readShort(&buf);
1823 quint16 numColors = readShort(&buf);
1826 if (
version == 1 && buf.size() > 4+numColors*10) {
1827 buf.seek(4+numColors*10);
1829 numColors = readShort(&buf);
1836 for (
int i = 0; i < numColors && !buf.atEnd(); ++i) {
1838 quint16 colorSpace = readShort(&buf);
1839 quint16 ch1 = readShort(&buf);
1840 quint16 ch2 = readShort(&buf);
1841 quint16 ch3 = readShort(&buf);
1842 quint16 ch4 = readShort(&buf);
1845 if (colorSpace == 0) {
1848 reinterpret_cast<quint16*
>(c.
data())[0] = ch3;
1849 reinterpret_cast<quint16*
>(c.
data())[1] = ch2;
1850 reinterpret_cast<quint16*
>(c.
data())[2] = ch1;
1854 else if (colorSpace == 1) {
1856 qc.setHsvF(ch1 / 65536.0, ch2 / 65536.0, ch3 / 65536.0);
1861 else if (colorSpace == 2) {
1870 else if (colorSpace == 7) {
1872 reinterpret_cast<quint16*
>(c.
data())[0] = ch3;
1873 reinterpret_cast<quint16*
>(c.
data())[1] = ch2;
1874 reinterpret_cast<quint16*
>(c.
data())[2] = ch1;
1878 else if (colorSpace == 8) {
1880 reinterpret_cast<quint16*
>(c.
data())[0] = ch1 * (
quint16_MAX / 10000);
1885 warnPigment <<
"Unsupported colorspace in palette" << colorSet->filename() <<
"(" << colorSpace <<
")";
1890 QString
name = readUnicodeString(&buf,
true);
1894 group->addSwatch(swatch);
1902 if (!store->open(
"swatchbook.xml")) {
1906 QByteArray bytes = store->read(store->size());
1909 dbgPigment <<
"XML palette: " << colorSet->filename() <<
", SwatchBooker format";
1912#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
1913 int errorLine, errorColumn;
1914 QString errorMessage;
1915 if (!doc.setContent(bytes, &errorMessage, &errorLine, &errorColumn)) {
1916 warnPigment <<
"Illegal XML palette:" << colorSet->filename();
1918 <<
", column" << errorColumn
1919 <<
"):" << errorMessage;
1921 QDomDocument::ParseResult result = doc.setContent(bytes);
1923 warnPigment <<
"Illegal XML palette:" << colorSet->filename();
1925 <<
", column" << result.errorColumn
1926 <<
"):" << result.errorMessage;
1931 QDomElement root = doc.documentElement();
1934 QDomElement
metadata = root.firstChildElement(
"metadata");
1940 QDomElement title =
metadata.firstChildElement(
"dc:title");
1941 QString colorName = title.text();
1942 colorName = colorName.isEmpty() ? i18n(
"Untitled") : colorName;
1943 colorSet->setName(colorName);
1944 dbgPigment <<
"Processed name of palette:" << colorSet->name();
1948 QDomElement book = root.firstChildElement(
"book");
1949 if (book.isNull()) {
1950 warnPigment <<
"Palette book (swatch composition) not found (line" << root.lineNumber()
1951 <<
", column" << root.columnNumber()
1957 QDomElement swatch = book.firstChildElement();
1958 if (swatch.isNull()) {
1959 warnPigment <<
"Swatches/groups definition not found (line" << book.lineNumber()
1960 <<
", column" << book.columnNumber()
1966 QDomElement materials = root.firstChildElement(
"materials");
1967 if (materials.isNull()) {
1968 warnPigment <<
"Materials (color definitions) not found";
1973 if (materials.firstChildElement(
"color").isNull()) {
1974 warnPigment <<
"Color definitions not found (line" << materials.lineNumber()
1975 <<
", column" << materials.columnNumber()
1982 QHash<QString, KisSwatch> materialsBook;
1983 QHash<QString, const KoColorSpace*> fileColorSpaces;
1986 store->enterDirectory(
"profiles");
1987 for (QDomElement colorElement = materials.firstChildElement(
"color");
1988 !colorElement.isNull();
1989 colorElement = colorElement.nextSiblingElement(
"color")) {
1992 currentEntry.
setSpotColor(colorElement.attribute(
"usage") ==
"spot");
1996 QDomElement currentColorMetadata = colorElement.firstChildElement(
"metadata");
1998 QDomElement colorTitle = currentColorMetadata.firstChildElement(
"dc:title");
1999 QDomElement colorId = currentColorMetadata.firstChildElement(
"dc:identifier");
2001 if (colorId.text().isEmpty()) {
2002 warnPigment <<
"Unidentified color (line" << colorId.lineNumber()
2003 <<
", column" << colorId.columnNumber()
2008 if (materialsBook.contains(colorId.text())) {
2009 warnPigment <<
"Duplicated color definition (line" << colorId.lineNumber()
2010 <<
", column" << colorId.columnNumber()
2016 currentEntry.
setId(colorId.text());
2017 currentEntry.
setName(colorTitle.text().isEmpty() ? colorId.text() : colorTitle.text());
2020 if (colorElement.firstChildElement(
"values").isNull()) {
2021 warnPigment <<
"Color definitions not found (line" << colorElement.lineNumber()
2022 <<
", column" << colorElement.columnNumber()
2028 bool firstDefinition =
false;
2032 for (QDomElement colorValueE = colorElement.firstChildElement(
"values");
2033 !colorValueE.isNull();
2034 colorValueE = colorValueE.nextSiblingElement(
"values")) {
2035 QString model = colorValueE.attribute(
"model");
2039 if (model ==
"Lab") {
2041 }
else if (model ==
"sRGB") {
2044 }
else if (model ==
"XYZ") {
2046 }
else if (model ==
"CMYK") {
2048 }
else if (model ==
"GRAY") {
2050 }
else if (model ==
"RGB") {
2053 warnPigment <<
"Color space not implemented:" << model
2054 <<
"(line" << colorValueE.lineNumber()
2055 <<
", column "<< colorValueE.columnNumber()
2064 QString space = colorValueE.attribute(
"space");
2065 if (!space.isEmpty()) {
2066 if (fileColorSpaces.contains(space)) {
2067 colorSpace = fileColorSpaces.value(space);
2070 profile = loadColorProfile(store, space, modelId, colorDepthId);
2072 colorSpace = colorSpaceRegistry->
colorSpace(modelId, colorDepthId, profile);
2073 fileColorSpaces.insert(space, colorSpace);
2085 for (
const QString &str : colorValueE.text().split(
" ")) {
2086 float channelValue = str.toFloat(&status);
2088 warnPigment <<
"Invalid float definition (line" << colorValueE.lineNumber()
2089 <<
", column" << colorValueE.columnNumber()
2095 channels.append(channelValue);
2101 firstDefinition =
true;
2103 if (model ==
"Lab") {
2108 if (firstDefinition) {
2109 materialsBook.insert(currentEntry.
id(), currentEntry);
2111 warnPigment <<
"No supported color spaces for the current color (line" << colorElement.lineNumber()
2112 <<
", column "<< colorElement.columnNumber()
2118 store->leaveDirectory();
2123 for(; !swatch.isNull(); swatch = swatch.nextSiblingElement()) {
2124 QString type = swatch.tagName();
2125 if (type.isEmpty() || type.isNull()) {
2126 warnPigment <<
"Invalid swatch/group definition (no id) (line" << swatch.lineNumber()
2127 <<
", column" << swatch.columnNumber()
2130 }
else if (type ==
"swatch") {
2131 QString
id = swatch.attribute(
"material");
2132 if (
id.isEmpty() ||
id.isNull()) {
2133 warnPigment <<
"Invalid swatch definition (no material id) (line" << swatch.lineNumber()
2134 <<
", column" << swatch.columnNumber()
2139 if (materialsBook.contains(
id)) {
2140 global->addSwatch(materialsBook.value(
id));
2142 warnPigment <<
"Invalid swatch definition (material not found) (line" << swatch.lineNumber()
2143 <<
", column" << swatch.columnNumber()
2147 }
else if (type ==
"group") {
2148 QDomElement groupMetadata = swatch.firstChildElement(
"metadata");
2149 if (groupMetadata.isNull()) {
2150 warnPigment <<
"Invalid group definition (missing metadata) (line" << groupMetadata.lineNumber()
2151 <<
", column" << groupMetadata.columnNumber()
2155 QDomElement groupTitle =
metadata.firstChildElement(
"dc:title");
2156 if (groupTitle.isNull()) {
2157 warnPigment <<
"Invalid group definition (missing title) (line" << groupTitle.lineNumber()
2158 <<
", column" << groupTitle.columnNumber()
2162 QString currentGroupName = groupTitle.text();
2163 colorSet->addGroup(currentGroupName);
2165 for (QDomElement groupSwatch = swatch.firstChildElement(
"swatch");
2166 !groupSwatch.isNull();
2167 groupSwatch = groupSwatch.nextSiblingElement(
"swatch")) {
2168 QString
id = groupSwatch.attribute(
"material");
2169 if (
id.isEmpty() ||
id.isNull()) {
2170 warnPigment <<
"Invalid swatch definition (no material id) (line" << groupSwatch.lineNumber()
2171 <<
", column" << groupSwatch.columnNumber()
2176 if (materialsBook.contains(
id)) {
2177 colorSet->getGroup(currentGroupName)->addSwatch(materialsBook.value(
id));
2179 warnPigment <<
"Invalid swatch definition (material not found) (line" << groupSwatch.lineNumber()
2180 <<
", column" << groupSwatch.columnNumber()
2194 buf.open(QBuffer::ReadOnly);
2197 QScopedPointer<KoStore> store(
2199 "application/x-swatchbook",
2201 if (!store || store->bad()) {
2205 if (store->hasFile(
"swatchbook.xml") && !loadSbzSwatchbook(store)) {
2215 QFileInfo info(colorSet->filename());
2216 colorSet->setName(info.completeBaseName());
2219 buf.open(QBuffer::ReadOnly);
2223 quint16
version = readShort(&buf);
2224 quint16 version2 = readShort(&buf);
2230 qint32 numBlocks = readInt(&buf);
2232 QByteArray groupStart(
"\xC0\x01");
2233 QByteArray groupEnd(
"\xC0\x02");
2234 QByteArray swatchSig(
"\x00\x01");
2236 bool inGroup =
false;
2238 for (qint32 i = 0; i < numBlocks; i++) {
2239 QByteArray blockType;
2240 blockType = buf.read(2);
2241 qint32 blockSize = readInt(&buf);
2242 qint64 pos = buf.pos();
2244 if (blockType == groupStart) {
2245 groupName = readUnicodeString(&buf);
2246 colorSet->addGroup(groupName);
2249 else if (blockType == groupEnd) {
2250 int colorCount = colorSet->getGroup(groupName)->colorCount();
2251 int columns = colorSet->columnCount();
2256 colorSet->getGroup(groupName)->setRowCount(rows);
2261 swatch.
setName(readUnicodeString(&buf).trimmed());
2262 QByteArray colorModel;
2264 colorModel = buf.read(4);
2265 if (colorModel ==
"RGB ") {
2266 QDomElement elt = doc.createElement(
"sRGB");
2268 elt.setAttribute(
"r", readFloat(&buf));
2269 elt.setAttribute(
"g", readFloat(&buf));
2270 elt.setAttribute(
"b", readFloat(&buf));
2274 }
else if (colorModel ==
"CMYK") {
2275 QDomElement elt = doc.createElement(
"CMYK");
2277 elt.setAttribute(
"c", readFloat(&buf));
2278 elt.setAttribute(
"m", readFloat(&buf));
2279 elt.setAttribute(
"y", readFloat(&buf));
2280 elt.setAttribute(
"k", readFloat(&buf));
2282 elt.setAttribute(
"space",
"U.S. Web Coated (SWOP) v2");
2286 }
else if (colorModel ==
"LAB ") {
2287 QDomElement elt = doc.createElement(
"Lab");
2289 elt.setAttribute(
"L", readFloat(&buf)*100.0);
2290 elt.setAttribute(
"a", readFloat(&buf));
2291 elt.setAttribute(
"b", readFloat(&buf));
2295 }
else if (colorModel ==
"GRAY") {
2296 QDomElement elt = doc.createElement(
"Gray");
2298 elt.setAttribute(
"g", readFloat(&buf));
2303 qint16 type = readShort(&buf);
2308 colorSet->addSwatch(swatch, groupName);
2310 colorSet->addSwatch(swatch);
2313 buf.seek(pos + qint64(blockSize));
2321 QFileInfo info(colorSet->filename());
2324 buf.open(QBuffer::ReadOnly);
2328 quint16
version = readShort(&buf);
2329 quint16 bookID = readShort(&buf);
2337 for (
int i = 0; i< 4; i++) {
2339 QString metadataString = readUnicodeString(&buf,
true);
2340 if (metadataString.startsWith(
"\"")) {
2341 metadataString = metadataString.remove(0, 1);
2343 if (metadataString.endsWith(
"\"")) {
2344 metadataString.chop(1);
2346 if (metadataString.startsWith(
"$$$/")) {
2347 if (metadataString.contains(
"=")) {
2348 metadataString = metadataString.split(
"=").last();
2350 metadataString = QString();
2356 colorSet->setName(title);
2359 QString description =
metadata.at(3);
2360 colorSet->setComment(description);
2362 quint16 numColors = readShort(&buf);
2363 quint16 numColumns = readShort(&buf);
2364 numColumns = numColumns > 0 ? numColumns : 8;
2365 colorSet->setColumnCount(numColumns);
2366 quint16 numKeyColorPage = readShort(&buf);
2367 Q_UNUSED(numKeyColorPage);
2368 quint16 colorType = readShort(&buf);
2371 if (colorType == 2) {
2372 QString profileName =
"U.S. Web Coated (SWOP) v2";
2374 }
else if (colorType == 7) {
2378 for (quint16 i = 0; i < numColors; i++) {
2382 name << readUnicodeString(&buf,
true);
2387 swatch.
setId(QString::fromLatin1(key));
2389 quint8 c1 = readByte(&buf);
2390 quint8 c2 = readByte(&buf);
2391 quint8 c3 = readByte(&buf);
2393 if (colorType == 0) {
2397 }
else if (colorType == 2) {
2398 quint8 c4 = readByte(&buf);
2403 }
else if (colorType == 7) {
2410 colorSet->addSwatch(swatch);
2419 QXmlStreamReader *xml =
new QXmlStreamReader(data);
2421 if (xml->readNextStartElement()) {
2422 auto paletteId = xml->name();
2423 if (paletteId.compare(QString(
"SCRIBUSCOLORS"), Qt::CaseInsensitive) == 0) {
2424 dbgPigment <<
"XML palette: " << colorSet->filename() <<
", Scribus format";
2425 res = loadScribusXmlPalette(colorSet, xml);
2429 xml->raiseError(
"Unknown XML palette format. Expected SCRIBUSCOLORS, found " + paletteId);
2434 if (xml->hasError() || !res) {
2435 warnPigment <<
"Illegal XML palette:" << colorSet->filename();
2436 warnPigment <<
"Error (line"<< xml->lineNumber() <<
", column" << xml->columnNumber() <<
"):" << xml->errorString();
2440 dbgPigment <<
"XML palette parsed successfully:" << colorSet->filename();
2448 if (!store || store->bad()) {
2449 qWarning() <<
"saveKpl could not create store";
2453 QSet<const KoColorSpace *> colorSpaces;
2470 root.appendChild(gl);
2471 saveKplGroup(doc, gl, group, colorSpaces);
2474 doc.appendChild(root);
2475 if (!store->open(
"colorset.xml")) {
return false; }
2476 QByteArray ba = doc.toByteArray();
2477 if (store->write(ba) != ba.size()) {
return false; }
2478 if (!store->close()) {
return false; }
2482 QDomElement profileElement = doc.createElement(
"Profiles");
2485 QString fn = QFileInfo(colorSpace->profile()->fileName()).fileName();
2486 if (!store->open(fn)) { qWarning() <<
"Could not open the store for profiles directory";
return false; }
2487 QByteArray profileRawData = colorSpace->profile()->rawData();
2488 if (!store->write(profileRawData)) { qWarning() <<
"Could not write the profiles data into the store";
return false; }
2489 if (!store->close()) { qWarning() <<
"Could not close the store for profiles directory";
return false; }
2495 profileElement.appendChild(el);
2498 doc.appendChild(profileElement);
2500 if (!store->open(
"profiles.xml")) { qWarning() <<
"Could not open profiles.xml";
return false; }
2501 QByteArray ba = doc.toByteArray();
2503 int bytesWritten = store->write(ba);
2504 if (bytesWritten != ba.size()) { qWarning() <<
"Bytes written is wrong" << ba.size();
return false; }
2506 if (!store->close()) { qWarning() <<
"Could not close the store";
return false; }
2508 bool r = store->finalize();
2509 if (!r) { qWarning() <<
"Could not finalize the store"; }
2514 QDomElement &groupEle,
2516 QSet<const KoColorSpace *> &colorSetSet)
const
2520 for (
const KisSwatchGroup::SwatchInfo &info : group->infoList()) {
2521 const KoColorProfile *profile = info.swatch.color().colorSpace()->profile();
2523 if (!profile->
fileName().isEmpty()) {
2524 bool alreadyIncluded =
false;
2525 Q_FOREACH(
const KoColorSpace* colorSpace, colorSetSet) {
2527 alreadyIncluded =
true;
2531 if(!alreadyIncluded) {
2532 colorSetSet.insert(info.swatch.color().colorSpace());
2540 info.swatch.color().toXML(doc, swatchEle);
2545 swatchEle.appendChild(positionEle);
2547 groupEle.appendChild(swatchEle);
2557 group->setColumnCount(colorSet->columnCount());
2559 for (QDomElement swatchEle = parentEle.firstChildElement(
KPL_SWATCH_TAG);
2560 !swatchEle.isNull();
2565 if (
version ==
"1.0" && swatchEle.firstChildElement().tagName() ==
"Lab") {
2569 QDomElement el = swatchEle.firstChildElement();
2571 el.setAttribute(
"L", L*100.0);
2574 ab = (0.5 - ab) * 2 * -128.0;
2576 ab = (ab - 0.5) * 2 * 127.0;
2578 el.setAttribute(
"a", ab);
2582 ab = (0.5 - ab) * 2 * -128.0;
2584 ab = (ab - 0.5) * 2 * 127.0;
2586 el.setAttribute(
"b", ab);
2595 if (!positionEle.isNull()) {
2598 if (columnNumber < 0 ||
2599 columnNumber >= colorSet->columnCount() ||
2603 <<
"of palette" << colorSet->name()
2604 <<
"has invalid position.";
2607 group->setSwatch(swatch, columnNumber, rowNumber);
2609 group->addSwatch(swatch);
2614 && group->colorCount() > 0
2615 && group->columnCount() > 0
2616 && (group->colorCount() / (group->columnCount()) + 1) < 20) {
2617 group->setRowCount((group->colorCount() / group->columnCount()) + 1);
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID XYZAColorModelID("XYZA", ki18n("XYZ/Alpha"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
const KoID LABAColorModelID("LABA", ki18n("L*a*b*/Alpha"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
const int MAXIMUM_ALLOWED_COLUMNS
const qreal OPACITY_OPAQUE_F
const quint8 OPACITY_OPAQUE_U8
void setUndoLimit(int limit)
The KisSwatchGroup class stores a matrix of color swatches swatches can accessed using (x,...
void setSpotColor(bool spotColor)
void setColor(const KoColor &color)
void setId(const QString &id)
void setName(const QString &name)
bool saveKpl(QIODevice *dev) const
KoColorSet::PaletteType detectFormat(const QString &fileName, const QByteArray &ba)
bool loadSbzSwatchbook(QScopedPointer< KoStore > &store)
quint8 readByte(QIODevice *io)
const KoColorProfile * loadColorProfile(QScopedPointer< KoStore > &store, const QString &path, const QString &modelId, const QString &colorDepthId)
bool loadKplColorset(QScopedPointer< KoStore > &store)
Private(KoColorSet *a_colorSet)
void scribusParseColor(KoColorSet *set, QXmlStreamReader *xml)
bool loadKplProfiles(QScopedPointer< KoStore > &store)
float readFloat(QIODevice *io)
void saveKplGroup(QDomDocument &doc, QDomElement &groupEle, const KisSwatchGroupSP group, QSet< const KoColorSpace * > &colorSetSet) const
bool saveGpl(QIODevice *dev) const
bool loadScribusXmlPalette(KoColorSet *set, QXmlStreamReader *xml)
quint16 readShort(QIODevice *io)
QList< KisSwatchGroupSP > swatchGroups
QString readUnicodeString(QIODevice *io, bool sizeIsInt=false)
void loadKplGroup(const QDomDocument &doc, const QDomElement &parentElement, KisSwatchGroupSP group, QString version)
qint32 readInt(QIODevice *io)
static const QString KPL_COLOR_DEPTH_ID_ATTR
static const QString KPL_SWATCH_TAG
int rowNumberInGroup(int rowNumber) const
rowNumberInGroup calculates the row number in the group from the global rownumber
KoColorSet(const QString &filename=QString())
static const QString KPL_SWATCH_ROW_ATTR
int rowCountWithTitles() const
friend struct SetColumnCountCommand
static const QString KPL_COLOR_MODEL_ID_ATTR
void setColumnCount(int columns)
void removeGroup(const QString &groupName, bool keepColors=true)
removeGroup Remove a group from the KoColorSet
KUndo2Stack * undoStack() const
static const QString KPL_SWATCH_COL_ATTR
static const QString KPL_PALETTE_PROFILE_TAG
static const QString KPL_PALETTE_COMMENT_ATTR
static const QString KPL_PALETTE_NAME_ATTR
void canUndoChanged(bool canUndo)
friend struct MoveGroupCommand
KisSwatchGroup::SwatchInfo getClosestSwatchInfo(KoColor compare, bool useGivenColorSpace=true) const
getIndexClosestColor function that matches the color to all colors in the colorset,...
void setLocked(bool lock)
bool isGroupTitleRow(int row) const
isGroupRow checks whether the current row is a group title
int startRowForGroup(const QString &groupName) const
rowForNamedGroup returns the row the group's title is on
void updateThumbnail() override
updateThumbnail updates the thumbnail for this resource. Reimplement if your thumbnail is something e...
bool saveToDevice(QIODevice *dev) const override
static const QString KPL_SWATCH_POS_TAG
static const QString KPL_PALETTE_READONLY_ATTR
bool fromByteArray(QByteArray &data, KisResourcesInterfaceSP resourcesInterface)
friend struct AddSwatchCommand
KisSwatchGroupSP getGlobalGroup() const
getGlobalGroup
friend struct SetPaletteTypeCommand
void setPaletteType(PaletteType paletteType)
static const QString KPL_PALETTE_COLUMN_COUNT_ATTR
const QScopedPointer< Private > d
quint32 slotCount() const
static const QString KPL_GROUP_TAG
static const QString GLOBAL_GROUP_NAME
KisSwatch getColorGlobal(quint32 column, quint32 row) const
getColorGlobal A function for getting a color based on a global index. Useful for iterating through a...
QStringList swatchGroupNames() const
getGroupNames
void addSwatch(const KisSwatch &swatch, const QString &groupName=GLOBAL_GROUP_NAME, int column=-1, int row=-1)
Add a color to the palette.
static const QString KPL_GROUP_NAME_ATTR
static const QString KPL_PALETTE_TAG
friend struct ClearCommand
KisSwatchGroupSP getGroup(const QString &name) const
getGroup
KisSwatch getSwatchFromGroup(quint32 column, quint32 row, QString groupName=KoColorSet::GLOBAL_GROUP_NAME) const
getColorGroup A function for getting the color from a specific group.
static const QString KPL_VERSION_ATTR
friend struct SetCommentCommand
friend struct AddGroupCommand
static const QString KPL_GROUP_ROW_COUNT_ATTR
void notifySwatchChanged(const QString &groupName, int column, int row)
friend struct RemoveGroupCommand
static const QString KPL_SWATCH_BITDEPTH_ATTR
static const QString KPL_PALETTE_FILENAME_ATTR
void moveGroup(const QString &groupName, const QString &groupNameInsertBefore=GLOBAL_GROUP_NAME)
moveGroup Move a group in the internal stringlist.
void clear()
clears the complete colorset
void setComment(QString comment)
bool loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) override
void canRedoChanged(bool canRedo)
void addGroup(const QString &groupName, int columnCount=KisSwatchGroup::DEFAULT_COLUMN_COUNT, int rowCount=KisSwatchGroup::DEFAULT_ROW_COUNT)
addGroup Adds a new group.
friend struct ChangeGroupNameCommand
KoResourceSP clone() const override
friend struct RemoveSwatchCommand
void removeSwatch(int column, int row, KisSwatchGroupSP group)
remove the swatch from the given group at column and row
static const QString KPL_SWATCH_SPOT_ATTR
quint32 colorCount() const
PaletteType paletteType() const
void entryChanged(int column, int row)
static const QString KPL_SWATCH_NAME_ATTR
void layoutAboutToChange()
void changeGroupName(const QString &oldGroupName, const QString &newGroupName)
changeGroupName
QString defaultFileExtension() const override
static const QString KPL_SWATCH_ID_ATTR
virtual quint8 difference(const quint8 *src1, const quint8 *src2) const =0
virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector< float > &values) const =0
virtual const KoColorProfile * profile() const =0
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
void setOpacity(quint8 alpha)
const KoColorSpace * colorSpace() const
return the current colorSpace
void toQColor(QColor *c) const
a convenience method for the above.
static KoStore * createStore(const QString &fileName, Mode mode, const QByteArray &appIdentification=QByteArray(), Backend backend=Auto, bool writeMimetype=true)
const quint16 quint16_MAX
QSharedPointer< KoResource > KoResourceSP
double toDouble(const QString &str, bool *ok=nullptr)
void setUtf8OnStream(QTextStream &stream)
rgba palette[MAX_PALETTE]
AddGroupCommand(KoColorSet *colorSet, QString groupName, int columnCount, int rowCount)
void undo() override
revert the actions done in redo
void redo() override
redo the command
void undo() override
revert the actions done in redo
~AddSwatchCommand() override
AddSwatchCommand(KoColorSet *colorSet, const KisSwatch &swatch, const QString &groupName, int column, int row)
void redo() override
redo the command
~ChangeGroupNameCommand() override
void undo() override
revert the actions done in redo
ChangeGroupNameCommand(KoColorSet *colorSet, QString oldGroupName, const QString &newGroupName)
void redo() override
redo the command
ClearCommand(KoColorSet *colorSet)
void undo() override
revert the actions done in redo
KoColorSet * m_OldColorSet
void redo() override
redo the command
virtual bool valid() const =0
const KoColorProfile * profileByName(const QString &name) const
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)
void addProfile(KoColorProfile *profile)
void setName(const QString &name)
void setFilename(const QString &filename)
void setDirty(bool value)
Mark the preset as modified but not saved.
void setImage(const QImage &image)
QMap< QString, QVariant > metadata
KoResourceSignature signature() const
MoveGroupCommand(KoColorSet *colorSet, QString groupName, const QString &groupNameInsertBefore)
QString m_groupNameInsertBefore
void redo() override
redo the command
void undo() override
revert the actions done in redo
RemoveGroupCommand(KoColorSet *colorSet, QString groupName, bool keepColors=true)
void redo() override
redo the command
void undo() override
revert the actions done in redo
KisSwatchGroupSP m_oldGroup
void undo() override
revert the actions done in redo
void redo() override
redo the command
RemoveSwatchCommand(KoColorSet *colorSet, int column, int row, KisSwatchGroupSP group)
void redo() override
redo the command
SetColumnCountCommand(KoColorSet *colorSet, int columnCount)
void undo() override
revert the actions done in redo
void undo() override
revert the actions done in redo
KoColorSet::PaletteType m_paletteType
QString suffix(KoColorSet::PaletteType paletteType) const
SetPaletteTypeCommand(KoColorSet *colorSet, const KoColorSet::PaletteType &paletteType)
void redo() override
redo the command
KoColorSet::PaletteType m_oldPaletteType