diff --git a/libs/image/kis_properties_configuration.cc b/libs/image/kis_properties_configuration.cc --- a/libs/image/kis_properties_configuration.cc +++ b/libs/image/kis_properties_configuration.cc @@ -255,7 +255,7 @@ QDomDocument doc; doc.setContent(v.toString()); QDomElement e = doc.documentElement().firstChild().toElement(); - return KoColor::fromXML(e, Integer16BitsColorDepthID.id(), QHash()); + return KoColor::fromXML(e, Integer16BitsColorDepthID.id()); } } else { return color; diff --git a/libs/image/recorder/kis_recorded_paint_action.cpp b/libs/image/recorder/kis_recorded_paint_action.cpp --- a/libs/image/recorder/kis_recorded_paint_action.cpp +++ b/libs/image/recorder/kis_recorded_paint_action.cpp @@ -437,7 +437,7 @@ KoColor bC; if (!colorElt.isNull()) { - bC = KoColor::fromXML(colorElt.firstChildElement(), Integer8BitsColorDepthID.id(), QHash()); + bC = KoColor::fromXML(colorElt.firstChildElement(), Integer8BitsColorDepthID.id()); bC.setOpacity(quint8(255)); dbgImage << elementName << " color : " << bC.toQColor(); } else { diff --git a/libs/koplugin/KisMimeDatabase.cpp b/libs/koplugin/KisMimeDatabase.cpp --- a/libs/koplugin/KisMimeDatabase.cpp +++ b/libs/koplugin/KisMimeDatabase.cpp @@ -206,7 +206,7 @@ mimeType.mimeType = "application/x-gimp-color-palette"; mimeType.description = i18nc("description of a file type", "Color Palette"); - mimeType.suffixes = QStringList() << "*.gpl" << "*.pal" << "*.act" << "*.aco" << "*.colors" << "*.xml"; + mimeType.suffixes = QStringList() << "*.gpl" << "*.pal" << "*.act" << "*.aco" << "*.colors" << "*.xml" << "*.sbz"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-opencolorio-configuration"; diff --git a/libs/pigment/CMakeLists.txt b/libs/pigment/CMakeLists.txt --- a/libs/pigment/CMakeLists.txt +++ b/libs/pigment/CMakeLists.txt @@ -105,6 +105,7 @@ target_link_libraries( kritapigment PUBLIC kritaplugin + kritastore ${EXTRA_LIBRARIES} KF5::I18n KF5::ConfigCore diff --git a/libs/pigment/KoColor.h b/libs/pigment/KoColor.h --- a/libs/pigment/KoColor.h +++ b/libs/pigment/KoColor.h @@ -111,7 +111,6 @@ quint8 opacityU8() const; qreal opacityF() const; -// what about making the next two methods static factory methods? /// Convenient function for converting from a QColor void fromQColor(const QColor& c) const; @@ -152,12 +151,10 @@ * a preferred bit depth for creating the KoColor object (if that * bit depth isn't available, this function will randomly select * an other bit depth) - * @param profileAliases alias between the profile name specified by the "space" - * attribute and the profile name used inside pigment * @return the unserialize color, or an empty color object if the function failed * to unserialize the color */ - static KoColor fromXML(const QDomElement& elt, const QString & bitDepthId, const QHash & aliases); + static KoColor fromXML(const QDomElement& elt, const QString & bitDepthId); static QString toQString(const KoColor &color); diff --git a/libs/pigment/KoColor.cpp b/libs/pigment/KoColor.cpp --- a/libs/pigment/KoColor.cpp +++ b/libs/pigment/KoColor.cpp @@ -283,7 +283,7 @@ return d->colorSpace->opacityF(d->data); } -KoColor KoColor::fromXML(const QDomElement& elt, const QString & bitDepthId, const QHash & aliases) +KoColor KoColor::fromXML(const QDomElement& elt, const QString & bitDepthId) { QString modelId; if (elt.tagName() == "CMYK") { @@ -304,10 +304,6 @@ QString profileName; if (elt.tagName() != "sRGB") { profileName = elt.attribute("space", ""); - const QHash::ConstIterator it = aliases.find(profileName); - if (it != aliases.end()) { - profileName = it.value(); - } if (!KoColorSpaceRegistry::instance()->profileByName(profileName)) { profileName.clear(); } diff --git a/libs/pigment/resources/KoColorSet.h b/libs/pigment/resources/KoColorSet.h --- a/libs/pigment/resources/KoColorSet.h +++ b/libs/pigment/resources/KoColorSet.h @@ -1,5 +1,6 @@ /* This file is part of the KDE project Copyright (c) 2005 Boudewijn Rempt + Copyright (c) 2016 L. E. Segovia This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -58,13 +59,16 @@ ACT, // Photoshop binary PSP_PAL, // PaintShop Pro ACO, // Photoshop Swatches - XML // XML palette (Scribus) + XML, // XML palette (Scribus) + KPL, // KoColor-based XML palette + SBZ // SwatchBooker }; /** * Load a color set from a file. This can be a Gimp - * palette, a RIFF palette or a Photoshop palette. + * palette, a RIFF palette, a Photoshop palette, + * a Scribus palette or a SwatchBooker palette. */ explicit KoColorSet(const QString &filename); @@ -85,14 +89,84 @@ void setColumnCount(int columns); int columnCount(); + /** + * @brief comment + * @return the comment. + */ + QString comment(); public: - void add(const KoColorSetEntry &); - void remove(const KoColorSetEntry &); - void removeAt(quint32 index); - KoColorSetEntry getColor(quint32 index); - qint32 nColors(); + /** + * @brief add Add a color to the palette. + * @param groupName color to add the group to. If empty, it will be added to the unsorted. + */ + void add(const KoColorSetEntry &, QString groupName = QString()); + + /** + * @brief insertBefore insert color before index into group. + * @param index + * @param groupName name of the group that the color goes into. + * @return new index of index after the prepending. + */ + quint32 insertBefore(const KoColorSetEntry &, qint32 index, const QString &groupName = QString()); + + void removeAt(quint32 index, QString groupName = QString()); + + /** + * @brief getColorGlobal + * A function for getting a color based on a global index. Useful for itterating through all color entries. + * @param globalIndex the global index over the whole palette. + * @return the entry. + */ + KoColorSetEntry getColorGlobal(quint32 globalIndex); + /** + * @brief getColorGroup + * A function for getting the color from a specific group. + * @param groupName the name of the group, will give unosrted when not defined. + * @param index the index within the group. + * @return the entry + */ + KoColorSetEntry getColorGroup(quint32 index, QString groupName = QString()); + + QString findGroupByGlobalIndex(quint32 globalIndex, quint32 *index); + QString findGroupByColorName(const QString &name, quint32 *index); + QString findGroupByID(const QString &id,quint32 *index); + + /** + * @brief getGroupNames + * @return returns a list of group names, excluding the unsorted group. + */ + QStringList getGroupNames(); + + /** + * @brief nColorsGroup + * @param groupName string name of the group, when not specified, returns unsorted colors. + * @return the amount of colors in this group. + */ + quint32 nColorsGroup(QString groupName = QString()); + /** + * @brief nColors + * @return total colors in palette. + */ + quint32 nColors(); + + /** + * @brief addGroup + * Adds a new group. + * @param groupName the name of the new group. When not specified, this will fail. + * @return whether thegroup was made. + */ + bool addGroup(const QString &groupName); + /** + * @brief removeGroup + * Remove a group from the KoColorSet + * @param groupName the name of the group you want to remove. + * @param keepColors Whether you wish to keep the colorsetentries. These will be added to the unsorted. + * @return whether it could find the group to remove. + */ + bool removeGroup(const QString &groupName, bool keepColors = true); + void clear(); /** @@ -104,7 +178,7 @@ * when the two colors' colorspaces don't match. Else it'll use the entry's colorspace. * @return returns the int of the closest match. */ - qint32 getIndexClosestColor(KoColor color, bool useGivenColorSpace = true); + quint32 getIndexClosestColor(KoColor color, bool useGivenColorSpace = true); /** * @brief closestColorName @@ -120,12 +194,20 @@ bool init(); + bool saveGpl(QIODevice *dev) const; bool loadGpl(); + bool loadAct(); bool loadRiff(); bool loadPsp(); bool loadAco(); bool loadXml(); + bool loadSbz(); + + bool saveKpl(QIODevice *dev) const; + bool loadKpl(); + + struct Private; const QScopedPointer d; diff --git a/libs/pigment/resources/KoColorSet.cpp b/libs/pigment/resources/KoColorSet.cpp --- a/libs/pigment/resources/KoColorSet.cpp +++ b/libs/pigment/resources/KoColorSet.cpp @@ -1,5 +1,6 @@ /* This file is part of the KDE project Copyright (c) 2005 Boudewijn Rempt + Copyright (c) 2016 L. E. Segovia This library is free software; you can redistribute it and/or @@ -30,23 +31,33 @@ #include #include #include +#include +#include +#include #include #include +#include +#include +#include #include #include +#include #include "KoColor.h" +#include "KoColorProfile.h" #include "KoColorSpaceRegistry.h" #include "KoColorModelStandardIds.h" struct KoColorSet::Private { + KoColorSet::PaletteType paletteType; QByteArray data; - QString name; QString comment; qint32 columns; - QVector colors; + QVector colors; //ungrouped colors + QStringList groupNames; //names of the groups, this is used to determine the order they are in. + QMap> groups; //grouped colors. }; KoColorSet::PaletteType detectFormat(const QString &fileName, const QByteArray &ba) { @@ -74,7 +85,12 @@ else if (fi.suffix().toLower() == "xml") { return KoColorSet::XML; } - + else if (fi.suffix().toLower() == "kpl") { + return KoColorSet::KPL; + } + else if (fi.suffix().toLower() == "sbz") { + return KoColorSet::SBZ; + } return KoColorSet::UNKNOWN; } @@ -100,10 +116,11 @@ , d(new Private()) { setFilename(rhs.filename()); - d->name = rhs.d->name; d->comment = rhs.d->comment; d->columns = rhs.d->columns; d->colors = rhs.d->colors; + d->groupNames = rhs.d->groupNames; + d->groups = rhs.d->groups; setValid(true); } @@ -147,65 +164,27 @@ return true; } -qint32 KoColorSet::nColors() -{ - return d->colors.count(); -} - -qint32 KoColorSet::getIndexClosestColor(KoColor color, bool useGivenColorSpace) -{ - qint32 closestIndex = 0; - quint8 highestPercentage = 0; - quint8 testPercentage = 0; - KoColor compare = color; - for (qint32 i=0; icolors.at(i).color; - if (useGivenColorSpace==true && compare.colorSpace()!=entry.colorSpace()) { - entry.convertTo(compare.colorSpace()); - - } else if(compare.colorSpace()!=entry.colorSpace()) { - compare.convertTo(entry.colorSpace()); - } - testPercentage = (255 - compare.colorSpace()->difference(compare.data(), entry.data())); - if (testPercentage>highestPercentage) - { - closestIndex = i; - highestPercentage = testPercentage; - } - } - return closestIndex; -} - -QString KoColorSet::closestColorName(KoColor color, bool useGivenColorSpace) -{ - int i = getIndexClosestColor(color, useGivenColorSpace); - QString name = d->colors.at(i).name; - return name; -} - bool KoColorSet::saveToDevice(QIODevice *dev) const { - QTextStream stream(dev); - stream << "GIMP Palette\nName: " << name() << "\nColumns: " << d->columns << "\n#\n"; - - for (int i = 0; i < d->colors.size(); i++) { - const KoColorSetEntry& entry = d->colors.at(i); - QColor c = entry.color.toQColor(); - stream << c.red() << " " << c.green() << " " << c.blue() << "\t"; - if (entry.name.isEmpty()) - stream << "Untitled\n"; - else - stream << entry.name << "\n"; + bool res; + switch(d->paletteType) { + case GPL: + res = saveGpl(dev); + break; + default: + res = saveKpl(dev); } - - KoResource::saveToDevice(dev); - - return true; + if (res) { + KoResource::saveToDevice(dev); + } + return res; } bool KoColorSet::init() { d->colors.clear(); // just in case this is a reload (eg by KoEditColorSetDialog), + d->groups.clear(); + d->groupNames.clear(); if (filename().isNull()) { warnPigment << "Cannot load palette" << name() << "there is no filename set"; @@ -223,8 +202,8 @@ } bool res = false; - PaletteType paletteType = detectFormat(filename(), d->data); - switch(paletteType) { + d->paletteType = detectFormat(filename(), d->data); + switch(d->paletteType) { case GPL: res = loadGpl(); break; @@ -243,6 +222,12 @@ case XML: res = loadXml(); break; + case KPL: + res = loadKpl(); + break; + case SBZ: + res = loadSbz(); + break; default: res = false; } @@ -275,35 +260,214 @@ return res; } -void KoColorSet::add(const KoColorSetEntry & c) +bool KoColorSet::saveGpl(QIODevice *dev) const { - d->colors.push_back(c); + QTextStream stream(dev); + stream << "GIMP Palette\nName: " << name() << "\nColumns: " << d->columns << "\n#\n"; + + for (int i = 0; i < d->colors.size(); i++) { + const KoColorSetEntry& entry = d->colors.at(i); + QColor c = entry.color.toQColor(); + stream << c.red() << " " << c.green() << " " << c.blue() << "\t"; + if (entry.name.isEmpty()) + stream << "Untitled\n"; + else + stream << entry.name << "\n"; + } + + return true; } -void KoColorSet::remove(const KoColorSetEntry & c) +quint32 KoColorSet::nColors() { - for (auto it = d->colors.begin(); it != d->colors.end(); /*noop*/) { - if ((*it) == c) { - it = d->colors.erase(it); - return; + quint32 total = d->colors.count(); + if (!d->groups.empty()) { + Q_FOREACH (const QVector &group, d->groups.values()) { + total += group.size(); } - ++it; } + return total; } -void KoColorSet::removeAt(quint32 index) +quint32 KoColorSet::nColorsGroup(QString groupName) { + if (d->groups.contains(groupName)) { + return d->groups.value(groupName).size(); + } else if (groupName.isEmpty()){ + return d->colors.size(); + } else { + return 0; + } +} + +quint32 KoColorSet::getIndexClosestColor(const KoColor color, bool useGivenColorSpace) +{ + quint32 closestIndex = 0; + quint8 highestPercentage = 0; + quint8 testPercentage = 0; + KoColor compare = color; + for (quint32 i=0; idifference(compare.data(), entry.data())); + if (testPercentage>highestPercentage) + { + closestIndex = i; + highestPercentage = testPercentage; + } + } + return closestIndex; +} + +QString KoColorSet::closestColorName(const KoColor color, bool useGivenColorSpace) +{ + int i = getIndexClosestColor(color, useGivenColorSpace); + QString name = d->colors.at(i).name; + return name; +} + +void KoColorSet::add(const KoColorSetEntry & c, QString groupName) +{ + if (d->groups.contains(groupName) || d->groupNames.contains(groupName)) { + d->groups[groupName].push_back(c); + } else { + d->colors.push_back(c); + } +} + +quint32 KoColorSet::insertBefore(const KoColorSetEntry &c, qint32 index, const QString &groupName) +{ + quint32 newIndex = index; + if (d->groups.contains(groupName)) { + d->groups[groupName].insert(index, c); + } else if (groupName.isEmpty()){ + d->colors.insert(index, c);; + } else { + warnPigment << "Couldn't find group to insert to"; + } + return newIndex; +} + +void KoColorSet::removeAt(quint32 index, QString groupName) { - d->colors.remove(index); + if (d->groups.contains(groupName)){ + if ((quint32)d->groups.value(groupName).size()>index) { + d->groups[groupName].remove(index); + } + } else { + if ((quint32)d->colors.size()>index) { + d->colors.remove(index); + } + } } void KoColorSet::clear() { d->colors.clear(); + d->groups.clear(); } -KoColorSetEntry KoColorSet::getColor(quint32 index) +KoColorSetEntry KoColorSet::getColorGlobal(quint32 index) { - return d->colors[index]; + KoColorSetEntry e; + quint32 groupIndex = index; + QString groupName = findGroupByGlobalIndex(index, &groupIndex); + e = getColorGroup(groupIndex, groupName); + return e; +} + +KoColorSetEntry KoColorSet::getColorGroup(quint32 index, QString groupName) +{ + KoColorSetEntry e; + if (d->groups.contains(groupName) && index<(quint32)d->groups.value(groupName).size()) { + e = d->groups.value(groupName).at(index); + } else if (groupName == QString() && index<(quint32)d->colors.size()) { + e = d->colors.at(index); + } else { + warnPigment << "Color group "<colors.size()<=*index) { + *index -= (quint32)d->colors.size(); + if (!d->groups.empty() || !d->groupNames.empty()) { + QStringList groupNames = getGroupNames(); + Q_FOREACH (QString name, groupNames) { + quint32 size = (quint32)d->groups.value(name).size(); + if (size<=*index) { + *index -= size; + } else { + groupName = name; + return groupName; + } + } + + } + } + return groupName; +} + +QString KoColorSet::findGroupByColorName(const QString &name, quint32 *index) +{ + *index = 0; + QString groupName = QString(); + for (int i = 0; icolors.size(); i++) { + if(d->colors.at(i).name == name) { + *index = (quint32)i; + return groupName; + } + } + QStringList groupNames = getGroupNames(); + Q_FOREACH (QString name, groupNames) { + for (int i=0; igroups[name].size(); i++) { + if(d->groups[name].at(i).name == name) { + *index = (quint32)i; + groupName = name; + return groupName; + } + } + } + return groupName; +} + +QString KoColorSet::findGroupByID(const QString &id, quint32 *index) { + *index = 0; + QString groupName = QString(); + for (int i = 0; icolors.size(); i++) { + if(d->colors.at(i).id == id) { + *index = (quint32)i; + return groupName; + } + } + QStringList groupNames = getGroupNames(); + Q_FOREACH (QString name, groupNames) { + for (int i=0; igroups[name].size(); i++) { + if(d->groups[name].at(i).id == id) { + *index = (quint32)i; + groupName = name; + return groupName; + } + } + } + return groupName; +} + +QStringList KoColorSet::getGroupNames() +{ + if (d->groupNames.size()groups.size()) { + warnPigment << "mismatch between groups and the groupnames list."; + return QStringList(d->groups.keys()); + } + return d->groupNames; } void KoColorSet::setColumnCount(int columns) @@ -316,9 +480,44 @@ return d->columns; } +QString KoColorSet::comment() +{ + return d->comment; +} + +bool KoColorSet::addGroup(const QString &groupName) +{ + if (d->groups.contains(groupName) || d->groupNames.contains(groupName)) { + return false; + } + d->groupNames.append(groupName); + d->groups[groupName]; + return true; +} + +bool KoColorSet::removeGroup(const QString &groupName, bool keepColors) +{ + if (!d->groups.contains(groupName)) { + return false; + } + if (keepColors) { + for (int i = 0; igroups.value(groupName).size(); i++) { + d->colors.append(d->groups.value(groupName).at(i)); + } + } + for(int n = 0; ngroupNames.size(); n++) { + if (d->groupNames.at(n) == groupName) { + d->groupNames.removeAt(n); + } + } + + d->groups.remove(groupName); + return true; +} + QString KoColorSet::defaultFileExtension() const { - return QString(".gpl"); + return QString(".kpl"); } @@ -548,14 +747,14 @@ colorValue = colorProperties.value("CMYK"); if (colorValue.length() != 9 && colorValue.at(0) != '#') { // Color is a hexadecimal number - xml->raiseError("Invalid cmyk color (malformed): " + colorValue); + xml->raiseError("Invalid cmyk color (malformed): " % colorValue); return; } else { bool cmykOk; quint32 cmyk = colorValue.mid(1).toUInt(&cmykOk, 16); // cmyk uses the full 32 bits if (!cmykOk) { - xml->raiseError("Invalid cmyk color (unable to convert): " + colorValue); + xml->raiseError("Invalid cmyk color (unable to convert): " % colorValue); return; } @@ -643,6 +842,194 @@ } } +bool KoColorSet::saveKpl(QIODevice *dev) const +{ + QScopedPointer store(KoStore::createStore(dev, KoStore::Write, "application/x-krita-palette", KoStore::Zip)); + if (!store || store->bad()) return false; + + QSet profiles; + QMap profileMap; + + { + QDomDocument doc; + QDomElement root = doc.createElement("Colorset"); + root.setAttribute("version", "1.0"); + root.setAttribute("name", name()); + root.setAttribute("comment", d->comment); + root.setAttribute("columns", d->columns); + Q_FOREACH(const KoColorSetEntry &entry, d->colors) { + + // Only save non-builtin profiles.= + const KoColorProfile *profile = entry.color.colorSpace()->profile(); + if (!profile->fileName().isEmpty()) { + profiles << profile; + profileMap[profile] = entry.color.colorSpace(); + } + QDomElement el = doc.createElement("ColorSetEntry"); + el.setAttribute("name", entry.name); + el.setAttribute("id", entry.id); + el.setAttribute("spot", entry.spotColor ? "true" : "false"); + el.setAttribute("bitdepth", entry.color.colorSpace()->colorDepthId().id()); + entry.color.toXML(doc, el); + root.appendChild(el); + } + Q_FOREACH(const QString &groupName, d->groupNames) { + QDomElement gl = doc.createElement("Group"); + gl.setAttribute("name", groupName); + root.appendChild(gl); + Q_FOREACH(const KoColorSetEntry &entry, d->groups.value(groupName)) { + + // Only save non-builtin profiles.= + const KoColorProfile *profile = entry.color.colorSpace()->profile(); + if (!profile->fileName().isEmpty()) { + profiles << profile; + profileMap[profile] = entry.color.colorSpace(); + } + QDomElement el = doc.createElement("ColorSetEntry"); + el.setAttribute("name", entry.name); + el.setAttribute("id", entry.id); + el.setAttribute("spot", entry.spotColor ? "true" : "false"); + el.setAttribute("bitdepth", entry.color.colorSpace()->colorDepthId().id()); + entry.color.toXML(doc, el); + gl.appendChild(el); + } + } + + doc.appendChild(root); + if (!store->open("colorset.xml")) { return false; } + QByteArray ba = doc.toByteArray(); + if (store->write(ba) != ba.size()) { return false; } + if (!store->close()) { return false; } + } + + QDomDocument doc; + QDomElement profileElement = doc.createElement("Profiles"); + + Q_FOREACH(const KoColorProfile *profile, profiles) { + QString fn = QFileInfo(profile->fileName()).fileName(); + if (!store->open(fn)) { return false; } + QByteArray profileRawData = profile->rawData(); + if (!store->write(profileRawData)) { return false; } + if (!store->close()) { return false; } + QDomElement el = doc.createElement("Profile"); + el.setAttribute("filename", fn); + el.setAttribute("name", profile->name()); + el.setAttribute("colorModelId", profileMap[profile]->colorModelId().id()); + el.setAttribute("colorDepthId", profileMap[profile]->colorDepthId().id()); + profileElement.appendChild(el); + + } + doc.appendChild(profileElement); + if (!store->open("profiles.xml")) { return false; } + QByteArray ba = doc.toByteArray(); + if (store->write(ba) != ba.size()) { return false; } + if (!store->close()) { return false; } + + return store->finalize(); +} + +bool KoColorSet::loadKpl() +{ + QBuffer buf(&d->data); + buf.open(QBuffer::ReadOnly); + + QScopedPointer store(KoStore::createStore(&buf, KoStore::Read, "application/x-krita-palette", KoStore::Zip)); + if (!store || store->bad()) return false; + + if (store->hasFile("profiles.xml")) { + + if (!store->open("profiles.xml")) { return false; } + QByteArray data; + data.resize(store->size()); + QByteArray ba = store->read(store->size()); + store->close(); + + QDomDocument doc; + doc.setContent(ba); + QDomElement e = doc.documentElement(); + QDomElement c = e.firstChildElement("Profiles"); + while (!c.isNull()) { + + QString name = c.attribute("name"); + QString filename = c.attribute("filename"); + QString colorModelId = c.attribute("colorModelId"); + QString colorDepthId = c.attribute("colorDepthId"); + if (!KoColorSpaceRegistry::instance()->profileByName(name)) { + store->open(filename); + QByteArray data; + data.resize(store->size()); + data = store->read(store->size()); + store->close(); + + const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(colorModelId, colorDepthId, data); + if (profile && profile->valid()) { + KoColorSpaceRegistry::instance()->addProfile(profile); + } + } + + c = c.nextSiblingElement(); + + } + } + + { + if (!store->open("colorset.xml")) { return false; } + QByteArray data; + data.resize(store->size()); + QByteArray ba = store->read(store->size()); + store->close(); + + QDomDocument doc; + doc.setContent(ba); + QDomElement e = doc.documentElement(); + setName(e.attribute("name")); + d->comment = e.attribute("comment"); + d->columns = e.attribute("columns").toInt(); + + QDomElement c = e.firstChildElement("ColorSetEntry"); + while (!c.isNull()) { + QString colorDepthId = c.attribute("bitdepth", Integer8BitsColorDepthID.id()); + KoColorSetEntry entry; + + + entry.color = KoColor::fromXML(c.firstChildElement(), colorDepthId); + entry.name = c.attribute("name"); + entry.id = c.attribute("id"); + entry.spotColor = c.attribute("spot", "false") == "true" ? true : false; + d->colors << entry; + + c = c.nextSiblingElement("ColorSetEntry"); + + } + QDomElement g = e.firstChildElement("Group"); + while (!g.isNull()) { + QString groupName = g.attribute("name"); + addGroup(groupName); + QDomElement cg = g.firstChildElement("ColorSetEntry"); + while (!cg.isNull()) { + QString colorDepthId = cg.attribute("bitdepth", Integer8BitsColorDepthID.id()); + KoColorSetEntry entry; + + + entry.color = KoColor::fromXML(cg.firstChildElement(), colorDepthId); + entry.name = cg.attribute("name"); + entry.id = cg.attribute("id"); + entry.spotColor = cg.attribute("spot", "false") == "true" ? true : false; + add(entry, groupName); + + cg = cg.nextSiblingElement("ColorSetEntry"); + + } + g = g.nextSiblingElement("Group"); + } + + } + + + buf.close(); + return true; +} + quint16 readShort(QIODevice *io) { quint16 val; quint64 read = io->read((char*)&val, 2); @@ -680,7 +1067,8 @@ bool skip = false; if (colorSpace == 0) { // RGB - e.color = KoColor(KoColorSpaceRegistry::instance()->rgb16()); + const KoColorProfile *srgb = KoColorSpaceRegistry::instance()->rgb8()->profile(); + e.color = KoColor(KoColorSpaceRegistry::instance()->rgb16(srgb)); reinterpret_cast(e.color.data())[0] = ch3; reinterpret_cast(e.color.data())[1] = ch2; reinterpret_cast(e.color.data())[2] = ch1; @@ -740,3 +1128,385 @@ return true; } +bool KoColorSet::loadSbz() { + QBuffer buf(&d->data); + buf.open(QBuffer::ReadOnly); + + // &buf is a subclass of QIODevice + QScopedPointer store(KoStore::createStore(&buf, KoStore::Read, "application/x-swatchbook", KoStore::Zip)); + if (!store || store->bad()) return false; + + if (store->hasFile("swatchbook.xml")) { // Try opening... + + if (!store->open("swatchbook.xml")) { return false; } + QByteArray data; + data.resize(store->size()); + QByteArray ba = store->read(store->size()); + store->close(); + + dbgPigment << "XML palette: " << filename() << ", SwatchBooker format"; + + QDomDocument doc; + int errorLine, errorColumn; + QString errorMessage; + bool status = doc.setContent(ba, &errorMessage, &errorLine, &errorColumn); + if (!status) { + warnPigment << "Illegal XML palette:" << filename(); + warnPigment << "Error (line" << errorLine << ", column" << errorColumn << "):" << errorMessage; + return false; + } + + QDomElement e = doc.documentElement(); // SwatchBook + + // Start reading properties... + QDomElement metadata = e.firstChildElement("metadata"); + + if (e.isNull()) { + warnPigment << "Palette metadata not found"; + return false; + } + + QDomElement title = metadata.firstChildElement("dc:title"); + QString colorName = title.text(); + colorName = colorName.isEmpty() ? i18n("Untitled") : colorName; + setName(colorName); + dbgPigment << "Processed name of palette:" << name(); + // End reading properties + + // Now read colors... + QDomElement materials = e.firstChildElement("materials"); + if (materials.isNull()) { + warnPigment << "Materials (color definitions) not found"; + return false; + } + // This one has lots of "color" elements + QDomElement colorElement = materials.firstChildElement("color"); + if (colorElement.isNull()) { + warnPigment << "Color definitions not found (line" << materials.lineNumber() << ", column" << materials.columnNumber() << ")"; + return false; + } + + // Also read the swatch book... + QDomElement book = e.firstChildElement("book"); + if (book.isNull()) { + warnPigment << "Palette book (swatch composition) not found (line" << e.lineNumber() << ", column" << e.columnNumber() << ")"; + return false; + } + // Which has lots of "swatch"es (todo: support groups) + QDomElement swatch = book.firstChildElement(); + if (swatch.isNull()) { + warnPigment << "Swatches/groups definition not found (line" << book.lineNumber() << ", column" << book.columnNumber() << ")"; + return false; + } + + // We'll store colors here, and as we process swatches + // we'll add them to the palette + QHash materialsBook; + QHash fileColorSpaces; + + // Color processing + for(; !colorElement.isNull(); colorElement = colorElement.nextSiblingElement("color")) + { + KoColorSetEntry currentColor; + // Set if color is spot + currentColor.spotColor = colorElement.attribute("usage") == "spot"; + + // inside contains id and name + // one or more define the color + QDomElement currentColorMetadata = colorElement.firstChildElement("metadata"); + QDomNodeList currentColorValues = colorElement.elementsByTagName("values"); + // Get color name + QDomElement colorTitle = currentColorMetadata.firstChildElement("dc:title"); + QDomElement colorId = currentColorMetadata.firstChildElement("dc:identifier"); + // Is there an id? (we need that at the very least for identifying a color) + if (colorId.text().isEmpty()) { + warnPigment << "Unidentified color (line" << colorId.lineNumber()<< ", column" << colorId.columnNumber() << ")"; + return false; + } + if (materialsBook.contains(colorId.text())) { + warnPigment << "Duplicated color definition (line" << colorId.lineNumber()<< ", column" << colorId.columnNumber() << ")"; + return false; + } + + // Get a valid color name + currentColor.id = colorId.text(); + currentColor.name = colorTitle.text().isEmpty() ? colorId.text() : colorTitle.text(); + + // Get a valid color definition + if (currentColorValues.isEmpty()) { + warnPigment << "Color definitions not found (line" << colorElement.lineNumber() << ", column" << colorElement.columnNumber() << ")"; + return false; + } + + bool firstDefinition = false; + const KoColorProfile *srgb = KoColorSpaceRegistry::instance()->rgb8()->profile(); + // Priority: Lab, otherwise the first definition found + for(int j = 0; j < currentColorValues.size(); j++) { + QDomNode colorValue = currentColorValues.at(j); + QDomElement colorValueE = colorValue.toElement(); + QString model = colorValueE.attribute("model", QString()); + + // sRGB,RGB,HSV,HSL,CMY,CMYK,nCLR: 0 -> 1 + // YIQ: Y 0 -> 1 : IQ -0.5 -> 0.5 + // Lab: L 0 -> 100 : ab -128 -> 127 + // XYZ: 0 -> ~100 + if (model == "Lab") { + QStringList lab = colorValueE.text().split(" "); + if (lab.length() != 3) { + warnPigment << "Invalid Lab color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + float l = lab.at(0).toFloat(&status); + float a = lab.at(1).toFloat(&status); + float b = lab.at(2).toFloat(&status); + if (!status) { + warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + + currentColor.color = KoColor(KoColorSpaceRegistry::instance()->colorSpace(LABAColorModelID.id(), Float32BitsColorDepthID.id(), QString())); + reinterpret_cast(currentColor.color.data())[0] = l; + reinterpret_cast(currentColor.color.data())[1] = a; + reinterpret_cast(currentColor.color.data())[2] = b; + currentColor.color.setOpacity(OPACITY_OPAQUE_F); + firstDefinition = true; + break; // Immediately add this one + } + else if (model == "sRGB" && !firstDefinition) { + QStringList rgb = colorValueE.text().split(" "); + if (rgb.length() != 3) { + warnPigment << "Invalid sRGB color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + float r = rgb.at(0).toFloat(&status); + float g = rgb.at(1).toFloat(&status); + float b = rgb.at(2).toFloat(&status); + if (!status) { + warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + + currentColor.color = KoColor(KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), srgb)); + reinterpret_cast(currentColor.color.data())[0] = r; + reinterpret_cast(currentColor.color.data())[1] = g; + reinterpret_cast(currentColor.color.data())[2] = b; + currentColor.color.setOpacity(OPACITY_OPAQUE_F); + firstDefinition = true; + } + else if (model == "XYZ" && !firstDefinition) { + QStringList xyz = colorValueE.text().split(" "); + if (xyz.length() != 3) { + warnPigment << "Invalid XYZ color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + float x = xyz.at(0).toFloat(&status); + float y = xyz.at(1).toFloat(&status); + float z = xyz.at(2).toFloat(&status); + if (!status) { + warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + + currentColor.color = KoColor(KoColorSpaceRegistry::instance()->colorSpace(XYZAColorModelID.id(), Float32BitsColorDepthID.id(), QString())); + reinterpret_cast(currentColor.color.data())[0] = x; + reinterpret_cast(currentColor.color.data())[1] = y; + reinterpret_cast(currentColor.color.data())[2] = z; + currentColor.color.setOpacity(OPACITY_OPAQUE_F); + firstDefinition = true; + } + // The following color spaces admit an ICC profile (in SwatchBooker) + else if (model == "CMYK" && !firstDefinition) { + QStringList cmyk = colorValueE.text().split(" "); + if (cmyk.length() != 4) { + warnPigment << "Invalid CMYK color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + float c = cmyk.at(0).toFloat(&status); + float m = cmyk.at(1).toFloat(&status); + float y = cmyk.at(2).toFloat(&status); + float k = cmyk.at(3).toFloat(&status); + if (!status) { + warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + + QString space = colorValueE.attribute("space"); + const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), QString()); + + if (!space.isEmpty()) { + // Try loading the profile and add it to the registry + if (!fileColorSpaces.contains(space)) { + store->enterDirectory("profiles"); + store->open(space); + QByteArray data; + data.resize(store->size()); + data = store->read(store->size()); + store->close(); + + const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), data); + if (profile && profile->valid()) { + KoColorSpaceRegistry::instance()->addProfile(profile); + colorSpace = KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), profile); + fileColorSpaces.insert(space, colorSpace); + } + } + else { + colorSpace = fileColorSpaces.value(space); + } + } + + currentColor.color = KoColor(colorSpace); + reinterpret_cast(currentColor.color.data())[0] = c; + reinterpret_cast(currentColor.color.data())[1] = m; + reinterpret_cast(currentColor.color.data())[2] = y; + reinterpret_cast(currentColor.color.data())[3] = k; + currentColor.color.setOpacity(OPACITY_OPAQUE_F); + firstDefinition = true; + } + else if (model == "GRAY" && !firstDefinition) { + QString gray = colorValueE.text(); + + float g = gray.toFloat(&status); + if (!status) { + warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + + QString space = colorValueE.attribute("space"); + const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Float32BitsColorDepthID.id(), QString()); + + if (!space.isEmpty()) { + // Try loading the profile and add it to the registry + if (!fileColorSpaces.contains(space)) { + store->enterDirectory("profiles"); + store->open(space); + QByteArray data; + data.resize(store->size()); + data = store->read(store->size()); + store->close(); + + const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), data); + if (profile && profile->valid()) { + KoColorSpaceRegistry::instance()->addProfile(profile); + colorSpace = KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), profile); + fileColorSpaces.insert(space, colorSpace); + } + } + else { + colorSpace = fileColorSpaces.value(space); + } + } + + currentColor.color = KoColor(colorSpace); + reinterpret_cast(currentColor.color.data())[0] = g; + currentColor.color.setOpacity(OPACITY_OPAQUE_F); + firstDefinition = true; + } + else if (model == "RGB" && !firstDefinition) { + QStringList rgb = colorValueE.text().split(" "); + if (rgb.length() != 3) { + warnPigment << "Invalid RGB color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + float r = rgb.at(0).toFloat(&status); + float g = rgb.at(1).toFloat(&status); + float b = rgb.at(2).toFloat(&status); + if (!status) { + warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; + } + + QString space = colorValueE.attribute("space"); + const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), srgb); + + if (!space.isEmpty()) { + // Try loading the profile and add it to the registry + if (!fileColorSpaces.contains(space)) { + store->enterDirectory("profiles"); + store->open(space); + QByteArray data; + data.resize(store->size()); + data = store->read(store->size()); + store->close(); + + const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), data); + if (profile && profile->valid()) { + KoColorSpaceRegistry::instance()->addProfile(profile); + colorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), profile); + fileColorSpaces.insert(space, colorSpace); + } + } + else { + colorSpace = fileColorSpaces.value(space); + } + } + + currentColor.color = KoColor(colorSpace); + reinterpret_cast(currentColor.color.data())[0] = r; + reinterpret_cast(currentColor.color.data())[1] = g; + reinterpret_cast(currentColor.color.data())[2] = b; + currentColor.color.setOpacity(OPACITY_OPAQUE_F); + firstDefinition = true; + } + else { + warnPigment << "Color space not implemented:" << model << "(line" << colorValueE.lineNumber() << ", column "<< colorValueE.columnNumber() << ")"; + } + } + if (firstDefinition) { + materialsBook.insert(currentColor.id, currentColor); + } + else { + warnPigment << "No supported color spaces for the current color (line" << colorElement.lineNumber() << ", column "<< colorElement.columnNumber() << ")"; + return false; + } + } + // End colors + // Now decide which ones will go into the palette + + for(;!swatch.isNull(); swatch = swatch.nextSiblingElement()) { + QString type = swatch.tagName(); + if (type.isEmpty() || type.isNull()) { + warnPigment << "Invalid swatch/group definition (no id) (line" << swatch.lineNumber() << ", column" << swatch.columnNumber() << ")"; + return false; + } + else if (type == "swatch") { + QString id = swatch.attribute("material"); + if (id.isEmpty() || id.isNull()) { + warnPigment << "Invalid swatch definition (no material id) (line" << swatch.lineNumber() << ", column" << swatch.columnNumber() << ")"; + return false; + } + if (materialsBook.contains(id)) { + add(materialsBook.value(id)); + } + else { + warnPigment << "Invalid swatch definition (material not found) (line" << swatch.lineNumber() << ", column" << swatch.columnNumber() << ")"; + return false; + } + } + else if (type == "group") { + QDomElement groupMetadata = swatch.firstChildElement("metadata"); + if (groupMetadata.isNull()) { + warnPigment << "Invalid group definition (missing metadata) (line" << groupMetadata.lineNumber() << ", column" << groupMetadata.columnNumber() << ")"; + return false; + } + QDomElement groupTitle = metadata.firstChildElement("dc:title"); + if (groupTitle.isNull()) { + warnPigment << "Invalid group definition (missing title) (line" << groupTitle.lineNumber() << ", column" << groupTitle.columnNumber() << ")"; + return false; + } + QString currentGroupName = groupTitle.text(); + + QDomElement groupSwatch = swatch.firstChildElement("swatch"); + + while(!groupSwatch.isNull()) { + QString id = groupSwatch.attribute("material"); + if (id.isEmpty() || id.isNull()) { + warnPigment << "Invalid swatch definition (no material id) (line" << groupSwatch.lineNumber() << ", column" << groupSwatch.columnNumber() << ")"; + return false; + } + if (materialsBook.contains(id)) { + add(materialsBook.value(id), currentGroupName); + } + else { + warnPigment << "Invalid swatch definition (material not found) (line" << groupSwatch.lineNumber() << ", column" << groupSwatch.columnNumber() << ")"; + return false; + } + groupSwatch = groupSwatch.nextSiblingElement("swatch"); + } + } + } + // End palette + } + + buf.close(); + return true; +} diff --git a/libs/pigment/tests/TestKoColor.cpp b/libs/pigment/tests/TestKoColor.cpp --- a/libs/pigment/tests/TestKoColor.cpp +++ b/libs/pigment/tests/TestKoColor.cpp @@ -49,7 +49,7 @@ kc.toXML(doc, elt); doc.appendChild(elt); dbgPigment << doc.toString(); - KoColor kcu = KoColor::fromXML(elt.firstChildElement(), depthId.id(), QHash()); + KoColor kcu = KoColor::fromXML(elt.firstChildElement(), depthId.id()); QVERIFY2(*(kc.colorSpace()) == *(kcu.colorSpace()), QString("Not identical color space (colorModelId = %1 depthId = %2) != (colorModelId = %3 depthId = %4) ") .arg(kc.colorSpace()->colorModelId().id()) diff --git a/libs/store/KoStore.h b/libs/store/KoStore.h --- a/libs/store/KoStore.h +++ b/libs/store/KoStore.h @@ -225,27 +225,6 @@ bool hasFile(const QString &fileName) const; /** - * Imports a local file into a store - * @param fileName file on hard disk - * @param destName file in the store - */ - bool addLocalFile(const QString &fileName, const QString &destName); - - /** - * Imports data into a store - * @param buffer data - * @param destName file in the store - */ - bool addDataToFile(QByteArray &buffer, const QString &destName); - - /** - * Extracts a file out of the store - * @param sourceName file in the store - * @param fileName file on a disk - */ - bool extractFile(const QString &sourceName, const QString &fileName); - - /** * Extracts a file out of the store to a buffer * @param sourceName file in the store * @param data memory buffer diff --git a/libs/store/KoStore.cpp b/libs/store/KoStore.cpp --- a/libs/store/KoStore.cpp +++ b/libs/store/KoStore.cpp @@ -320,77 +320,6 @@ enterDirectory(d->directoryStack.pop()); } -bool KoStore::addLocalFile(const QString &fileName, const QString &destName) -{ - QFileInfo fi(fileName); - uint size = fi.size(); - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly)) { - return false; - } - - if (!open(destName)) { - return false; - } - - QByteArray data; - data.resize(8 * 1024); - - uint total = 0; - for (int block = 0; (block = file.read(data.data(), data.size())) > 0; total += block) { - data.resize(block); - if (write(data) != block) - return false; - data.resize(8*1024); - } - Q_ASSERT(total == size); - if (total != size) { - warnStore << "Did not write enough bytes. Expected: " << size << ", wrote" << total; - return false; - } - - close(); - file.close(); - - return true; -} - -bool KoStore::addDataToFile(QByteArray &buffer, const QString &destName) -{ - QBuffer file(&buffer); - if (!file.open(QIODevice::ReadOnly)) { - return false; - } - - if (!open(destName)) { - return false; - } - - QByteArray data; - data.resize(8 * 1024); - - uint total = 0; - for (int block = 0; (block = file.read(data.data(), data.size())) > 0; total += block) { - data.resize(block); - if (write(data) != block) - return false; - data.resize(8*1024); - } - - close(); - file.close(); - - return true; -} - -bool KoStore::extractFile(const QString &srcName, const QString &fileName) -{ - Q_D(KoStore); - QFile file(fileName); - return d->extractFile(srcName, file); -} - - bool KoStore::extractFile(const QString &srcName, QByteArray &data) { Q_D(KoStore); diff --git a/libs/ui/KisColorsetChooser.cpp b/libs/ui/KisColorsetChooser.cpp --- a/libs/ui/KisColorsetChooser.cpp +++ b/libs/ui/KisColorsetChooser.cpp @@ -76,9 +76,9 @@ painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, colorSet->name()); int size = 7; - for (int i = 0; i < colorSet->nColors() && i*size < option.rect.width(); i++) { + for (quint32 i = 0; i < colorSet->nColors() && i*size < (quint32)option.rect.width(); i++) { QRect rect(option.rect.x() + i*size, option.rect.y() + option.rect.height() - size, size, size); - painter->fillRect(rect, colorSet->getColor(i).color.toQColor()); + painter->fillRect(rect, colorSet->getColorGlobal(i).color.toQColor()); } painter->restore(); diff --git a/libs/ui/KisPaletteModel.cpp b/libs/ui/KisPaletteModel.cpp --- a/libs/ui/KisPaletteModel.cpp +++ b/libs/ui/KisPaletteModel.cpp @@ -60,14 +60,14 @@ QVariant KisPaletteModel::data(const QModelIndex& index, int role) const { if (m_colorSet) { - int i = index.row()*columnCount()+index.column(); + quint32 i = (quint32)(index.row()*columnCount()+index.column()); if (i < m_colorSet->nColors()) { switch (role) { case Qt::DisplayRole: { - return m_colorSet->getColor(i).name; + return m_colorSet->getColorGlobal(i).name; } case Qt::BackgroundRole: { - QColor color = m_displayRenderer->toQColor(m_colorSet->getColor(i).color); + QColor color = m_displayRenderer->toQColor(m_colorSet->getColorGlobal(i).color); return QBrush(color); } } @@ -104,7 +104,7 @@ QModelIndex KisPaletteModel::index(int row, int column, const QModelIndex& parent) const { int index = row*columnCount()+column; - if (m_colorSet && index < m_colorSet->nColors()) { + if (m_colorSet && (quint32)index < m_colorSet->nColors()) { return QAbstractTableModel::index(row, column, parent); } return QModelIndex(); diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc --- a/libs/ui/kis_config.cc +++ b/libs/ui/kis_config.cc @@ -1810,12 +1810,12 @@ if (!m_cfg.readEntry(name).isNull()) { doc.setContent(m_cfg.readEntry(name)); QDomElement e = doc.documentElement().firstChild().toElement(); - return KoColor::fromXML(e, Integer16BitsColorDepthID.id(), QHash()); + return KoColor::fromXML(e, Integer16BitsColorDepthID.id()); } else { QString blackColor = "\n\n \n\n"; doc.setContent(blackColor); QDomElement e = doc.documentElement().firstChild().toElement(); - return KoColor::fromXML(e, Integer16BitsColorDepthID.id(), QHash()); + return KoColor::fromXML(e, Integer16BitsColorDepthID.id()); } return color; diff --git a/libs/widgets/KoColorSetWidget.cpp b/libs/widgets/KoColorSetWidget.cpp --- a/libs/widgets/KoColorSetWidget.cpp +++ b/libs/widgets/KoColorSetWidget.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -49,41 +51,84 @@ { delete colorSetContainer; colorSetContainer = new QWidget(); - colorSetLayout = new QGridLayout(); + colorSetLayout = new QVBoxLayout(); colorSetLayout->setMargin(3); colorSetLayout->setSpacing(0); // otherwise the use can click where there is none colorSetContainer->setBackgroundRole(QPalette::Dark); + int patchSize = 12; + int columns = 16; if (colorSet) { columns = colorSet->columnCount(); } - for(int i = 0; isetColumnMinimumWidth(i, 12); - } - colorSetContainer->setMinimumWidth(columns*12+6); + colorSetContainer->setMinimumWidth(columns*patchSize+6); colorSetContainer->setLayout(colorSetLayout); patchWidgetList.clear(); colornames.clear(); colorNameCmb->clear(); + QWidget *defaultGroupContainer = new QWidget(); + QGridLayout *colorGroupLayout = new QGridLayout(); + for(int i = 0; isetColumnMinimumWidth(i, patchSize); + } + defaultGroupContainer->setMinimumWidth(columns*patchSize); + defaultGroupContainer->setMaximumWidth(columns*patchSize); + colorGroupLayout->setSpacing(0); + colorGroupLayout->setMargin(0); + defaultGroupContainer->setLayout(colorGroupLayout); if (colorSet) { - for( int i = 0, p= 0; i < colorSet->nColors(); i++) { + for( quint32 i = 0, p= 0; i < colorSet->nColorsGroup(); i++) { KoColorPatch *patch = new KoColorPatch(colorSetContainer); patch->setFrameStyle(QFrame::Plain | QFrame::Box); patch->setLineWidth(1); - patch->setColor(colorSet->getColor(i).color); - patch->setToolTip(colorSet->getColor(i).name); + KoColorSetEntry c = colorSet->getColorGlobal(i); + patch->setColor(c.color); + patch->setToolTip(c.name); connect(patch, SIGNAL(triggered(KoColorPatch *)), thePublic, SLOT(colorTriggered(KoColorPatch *))); - colorSetLayout->addWidget(patch, p/columns, p%columns); + colorGroupLayout->addWidget(patch, p/columns, p%columns); patch->setDisplayRenderer(displayRenderer); patchWidgetList.append(patch); - colornames.append(colorSet->getColor(i).name); + colornames.append(c.name); QPixmap colorsquare = QPixmap(12,12); - colorsquare.fill(colorSet->getColor(i).color.toQColor()); - colorNameCmb->addItem(QIcon(colorsquare), colorSet->getColor(i).name); + colorsquare.fill(c.color.toQColor()); + colorNameCmb->addItem(QIcon(colorsquare), c.name); ++p; } + colorSetLayout->addWidget(defaultGroupContainer); + Q_FOREACH(QString groupName, colorSet->getGroupNames()) { + QGroupBox *groupbox = new QGroupBox(); + groupbox->setTitle(groupName); + QGridLayout *groupLayout = new QGridLayout(); + for(int i = 0; isetColumnMinimumWidth(i, patchSize); + } + groupLayout->setSpacing(0); + groupLayout->setMargin(0); + groupbox->setMinimumWidth(columns*patchSize); + groupbox->setMaximumWidth(columns*patchSize); + groupbox->setLayout(groupLayout); + groupbox->setFlat(true); + for( quint32 i = 0, p= 0; i < colorSet->nColorsGroup(groupName); i++) { + KoColorPatch *patch = new KoColorPatch(colorSetContainer); + patch->setFrameStyle(QFrame::Plain | QFrame::Box); + patch->setLineWidth(1); + KoColorSetEntry c = colorSet->getColorGroup(i, groupName); + patch->setColor(c.color); + patch->setToolTip(c.name); + connect(patch, SIGNAL(triggered(KoColorPatch *)), thePublic, SLOT(colorTriggered(KoColorPatch *))); + groupLayout->addWidget(patch, p/columns, p%columns); + patch->setDisplayRenderer(displayRenderer); + patchWidgetList.append(patch); + colornames.append(c.name); + QPixmap colorsquare = QPixmap(12,12); + colorsquare.fill(c.color.toQColor()); + colorNameCmb->addItem(QIcon(colorsquare), c.name); + ++p; + } + colorSetLayout->addWidget(groupbox); + } } scrollArea->setWidget(colorSetContainer); @@ -106,7 +151,7 @@ QString savePath = srv->saveLocation(); do { - fileInfo.setFile( savePath + QString("%1.gpl").arg( i++, 4, 10, QChar('0') ) ); + fileInfo.setFile(savePath + QString("%1.%2").arg(i++, 4, 10, QChar('0')).arg(colorSet->defaultFileExtension())); } while (fileInfo.exists()); diff --git a/libs/widgets/KoColorSetWidget_p.h b/libs/widgets/KoColorSetWidget_p.h --- a/libs/widgets/KoColorSetWidget_p.h +++ b/libs/widgets/KoColorSetWidget_p.h @@ -55,7 +55,7 @@ bool firstShowOfContainer; QWidget *colorSetContainer; QScrollArea *scrollArea; - QGridLayout *colorSetLayout; + QVBoxLayout *colorSetLayout; QHBoxLayout *recentsLayout; KoColorPatch *recentPatches[6]; QToolButton *addRemoveButton; diff --git a/libs/widgets/KoEditColorSetDialog.cpp b/libs/widgets/KoEditColorSetDialog.cpp --- a/libs/widgets/KoEditColorSetDialog.cpp +++ b/libs/widgets/KoEditColorSetDialog.cpp @@ -49,7 +49,7 @@ { widget.setupUi(this); foreach (KoColorSet *colorSet, m_colorSets) { - colorSet->load(); + //colorSet->load(); resources are loaded at startup... widget.selector->addItem(colorSet->name()); } connect(widget.selector, SIGNAL(currentIndexChanged(int)), this, SLOT(setActiveColorSet(int))); @@ -117,6 +117,7 @@ void KoEditColorSetWidget::setActiveColorSet(int index) { if (m_gridLayout) { + qDeleteAll(m_gridLayout->children()); delete m_gridLayout; m_activePatch = 0; } @@ -129,14 +130,16 @@ m_activeColorSet = m_colorSets.value(index); setEnabled(m_activeColorSet != 0); int columns = 16; + if (m_activeColorSet) { columns = m_activeColorSet->columnCount(); if (columns==0){columns=16;} widget.remove->setEnabled(false); - for (int i = 0; i < m_activeColorSet->nColors(); i++) { + for (quint32 i = 0; i < m_activeColorSet->nColors(); i++) { KoColorPatch *patch = new KoColorPatch(widget.patchesFrame); - patch->setColor(m_activeColorSet->getColor(i).color); - patch->setToolTip(m_activeColorSet->getColor(i).name); + KoColorSetEntry c = m_activeColorSet->getColorGlobal(i); + patch->setColor(c.color); + patch->setToolTip(c.name); connect(patch, SIGNAL(triggered(KoColorPatch *)), this, SLOT(setTextLabel(KoColorPatch *))); m_gridLayout->addWidget(patch, i/columns, i%columns); } @@ -183,9 +186,10 @@ void KoEditColorSetWidget::removeColor() { Q_ASSERT(m_activeColorSet); - for (int i = 0; i < m_activeColorSet->nColors(); i++) { - if (m_activePatch->color() == m_activeColorSet->getColor(i).color) { - m_activeColorSet->remove(m_activeColorSet->getColor(i)); + for (quint32 i = 0; i < m_activeColorSet->nColors(); i++) { + KoColorSetEntry c = m_activeColorSet->getColorGlobal(i); + if (m_activePatch->color() == c.color) { + m_activeColorSet->removeAt(i); setActiveColorSet(widget.selector->currentIndex()); break; } diff --git a/libs/widgets/KoResourceServerProvider.cpp b/libs/widgets/KoResourceServerProvider.cpp --- a/libs/widgets/KoResourceServerProvider.cpp +++ b/libs/widgets/KoResourceServerProvider.cpp @@ -190,7 +190,7 @@ // d->gradientThread->barrier(); // } - d->paletteServer = new KoResourceServerSimpleConstruction("ko_palettes", "*.gpl:*.pal:*.act:*.aco:*.css:*.colors;*.xml"); + d->paletteServer = new KoResourceServerSimpleConstruction("ko_palettes", "*.kpl:*.gpl:*.pal:*.act:*.aco:*.css:*.colors:*.xml:*.sbz"); if (!QFileInfo(d->paletteServer->saveLocation()).exists()) { QDir().mkpath(d->paletteServer->saveLocation()); } diff --git a/plugins/dockers/palettedocker/palettedocker_dock.cpp b/plugins/dockers/palettedocker/palettedocker_dock.cpp --- a/plugins/dockers/palettedocker/palettedocker_dock.cpp +++ b/plugins/dockers/palettedocker/palettedocker_dock.cpp @@ -222,10 +222,16 @@ return; } - int i = index.row()*m_model->columnCount()+index.column(); + quint32 i = (quint32)(index.row()*m_model->columnCount()+index.column()); if (i < m_currentColorSet->nColors()) { - KoColorSetEntry entry = m_currentColorSet->getColor(i); - m_wdgPaletteDock->lblColorName->setText(entry.name); + KoColorSetEntry entry = m_currentColorSet->getColorGlobal(i); + quint32 li = 0; + QString groupName = m_currentColorSet->findGroupByGlobalIndex(i, &li); + if (groupName != QString()) { + groupName = groupName+" - "; + } + m_wdgPaletteDock->lblColorName->setText(groupName+entry.name); + qDebug()<<"The index of the currently selected color within its group is: "<setFGColor(entry.color); } diff --git a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp --- a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp +++ b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp @@ -78,7 +78,7 @@ const int pixelSize = device->colorSpace()->pixelSize(); do { grey = device->colorSpace()->intensity8(it.oldRawData()); - outColor = gradientCache->getColor((quint32)grey).color; + outColor = gradientCache->getColorGlobal((quint32)grey).color; outColor.setOpacity(qMin(KoColor(it.oldRawData(), device->colorSpace()).opacityF(), outColor.opacityF())); outColor.convertTo(device->colorSpace()); memcpy(it.rawData(), outColor.data(), pixelSize); diff --git a/plugins/impex/libkra/kis_kra_loader.cpp b/plugins/impex/libkra/kis_kra_loader.cpp --- a/plugins/impex/libkra/kis_kra_loader.cpp +++ b/plugins/impex/libkra/kis_kra_loader.cpp @@ -316,7 +316,7 @@ QDomDocument dom; KoXml::asQDomElement(dom, e); QDomElement eq = dom.firstChildElement(); - proofingConfig->warningColor = KoColor::fromXML(eq.firstChildElement(), Integer8BitsColorDepthID.id(), QHash()); + proofingConfig->warningColor = KoColor::fromXML(eq.firstChildElement(), Integer8BitsColorDepthID.id()); } if (e.tagName().toLower() == "animation") { diff --git a/plugins/paintops/libpaintop/kis_dynamic_sensor.cc b/plugins/paintops/libpaintop/kis_dynamic_sensor.cc --- a/plugins/paintops/libpaintop/kis_dynamic_sensor.cc +++ b/plugins/paintops/libpaintop/kis_dynamic_sensor.cc @@ -275,7 +275,7 @@ case PERSPECTIVE: return i18n("Near"); case TANGENTIAL_PRESSURE: - case PRESSURE_IN: + case PRESSURE_IN: return i18n("High"); default: return i18n("1.0"); @@ -404,7 +404,6 @@ void KisDynamicSensor::fromXML(const QDomElement& e) { - Q_UNUSED(e); Q_ASSERT(e.attribute("id", "") == id(sensorType())); m_customCurve = false; QDomElement curve_elt = e.firstChildElement("curve"); diff --git a/plugins/tools/tool_lazybrush/kis_tool_lazy_brush_options_widget.cpp b/plugins/tools/tool_lazybrush/kis_tool_lazy_brush_options_widget.cpp --- a/plugins/tools/tool_lazybrush/kis_tool_lazy_brush_options_widget.cpp +++ b/plugins/tools/tool_lazybrush/kis_tool_lazy_brush_options_widget.cpp @@ -125,8 +125,8 @@ const int i = m_d->colorModel->idFromIndex(index); - if (i >= 0 && i < m_d->colorSet.nColors()) { - KoColorSetEntry entry = m_d->colorSet.getColor(i); + if (i >= 0 && i < (int)m_d->colorSet.nColors()) { + KoColorSetEntry entry = m_d->colorSet.getColorGlobal(i); m_d->provider->setFGColor(entry.color); } @@ -139,10 +139,10 @@ { int selectedIndex = -1; - for (int i = 0; i < m_d->colorSet.nColors(); i++) { - KoColorSetEntry entry = m_d->colorSet.getColor(i); + for (quint32 i = 0; i < m_d->colorSet.nColors(); i++) { + KoColorSetEntry entry = m_d->colorSet.getColorGlobal(i); if (entry.color == color) { - selectedIndex = i; + selectedIndex = (int)i; break; } } @@ -241,8 +241,8 @@ KisColorizeMask::KeyStrokeColors colors; - for (int i = 0; i < m_d->colorSet.nColors(); i++) { - colors.colors << m_d->colorSet.getColor(i).color; + for (quint32 i = 0; i < m_d->colorSet.nColors(); i++) { + colors.colors << m_d->colorSet.getColorGlobal(i).color; } colors.transparentIndex = value ? activeIndex : -1; @@ -261,7 +261,7 @@ KIS_ASSERT_RECOVER_RETURN(activeIndex >= 0); - const KoColor color = m_d->colorSet.getColor(activeIndex).color; + const KoColor color = m_d->colorSet.getColorGlobal((quint32)activeIndex).color; m_d->activeMask->removeKeyStroke(color); }