diff --git a/libs/libkis/Palette.cpp b/libs/libkis/Palette.cpp index 9972163f13..4e2044031e 100644 --- a/libs/libkis/Palette.cpp +++ b/libs/libkis/Palette.cpp @@ -1,164 +1,166 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Palette.h" #include #include struct Palette::Private { KoColorSet *palette {0}; }; Palette::Palette(Resource *resource): d(new Private()) { d->palette = dynamic_cast(resource->resource()); } Palette::~Palette() { delete d; } int Palette::numberOfEntries() const { if (!d->palette) return 0; return d->palette->nColors(); } int Palette::columnCount() { if (!d->palette) return 0; return d->palette->columnCount(); } void Palette::setColumnCount(int columns) { if (d->palette) d->palette->setColumnCount(columns); } QString Palette::comment() { if (!d->palette) return ""; return d->palette->comment(); } void Palette::setComment(QString comment) { if (!d->palette) return; return d->palette->setComment(comment); } QStringList Palette::groupNames() { if (!d->palette) return QStringList(); return d->palette->getGroupNames(); } bool Palette::addGroup(QString name) { if (!d->palette) return false; return d->palette->addGroup(name); } bool Palette::removeGroup(QString name, bool keepColors) { if (!d->palette) return false; return d->palette->removeGroup(name, keepColors); } int Palette::colorsCountTotal() { if (!d->palette) return 0; return d->palette->nColors(); } int Palette::colorsCountGroup(QString name) { if (!d->palette) return 0; return d->palette->nColorsGroup(name); } KoColorSetEntry Palette::colorSetEntryByIndex(int index) { /* if (!d->palette) return KoColorSetEntry(); return d->palette->getColorGlobal(index); */ return KoColorSetEntry(); } KoColorSetEntry Palette::colorSetEntryFromGroup(int index, const QString &groupName) { /* if (!d->palette) return KoColorSetEntry(); return d->palette->getColorGroup(index, groupName); */ return KoColorSetEntry(); } ManagedColor *Palette::colorForEntry(KoColorSetEntry entry) { if (!d->palette) return 0; ManagedColor *color = new ManagedColor(entry.color()); return color; } void Palette::addEntry(KoColorSetEntry entry, QString groupName) { d->palette->add(entry, groupName); } void Palette::removeEntry(int index, const QString &groupName) { // d->palette->removeAt(index, groupName); } +/* void Palette::insertEntry(int index, KoColorSetEntry entry, QString groupName) { d->palette->insertBefore(entry, index, groupName); } +*/ bool Palette::editEntry(int index, KoColorSetEntry entry, QString groupName) { // return d->palette->changeColorSetEntry(entry, groupName, index); return true; } bool Palette::changeGroupName(QString oldGroupName, QString newGroupName) { return d->palette->changeGroupName(oldGroupName, newGroupName); } bool Palette::moveGroup(const QString &groupName, const QString &groupNameInsertBefore) { return d->palette->moveGroup(groupName, groupNameInsertBefore); } bool Palette::save() { if (d->palette->filename().size()>0) { return d->palette->save(); } //if there's no filename the palette proly doesn't even exist... return false; } KoColorSet *Palette::colorSet() { return d->palette; } diff --git a/libs/libkis/Palette.h b/libs/libkis/Palette.h index 901fd60c5f..b028627198 100644 --- a/libs/libkis/Palette.h +++ b/libs/libkis/Palette.h @@ -1,204 +1,204 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef LIBKIS_PALETTE_H #define LIBKIS_PALETTE_H #include #include "kritalibkis_export.h" #include "libkis.h" #include "Resource.h" #include "KoColorSet.h" class ManagedColor; /** * @brief The Palette class * Palette is a resource object that stores organised color data. * It's purpose is to allow artists to save colors and store them. * * An example for printing all the palettes and the entries: * * @code import sys from krita import * resources = Application.resources("palette") for (k, v) in resources.items(): print(k) palette = Palette(v) for x in range(palette.numberOfEntries()): entry = palette.colorSetEntryByIndex(x) c = palette.colorForEntry(entry); print(x, entry.name(), entry.id(), entry.spotColor(), c.toQString()) * @endcode */ class KRITALIBKIS_EXPORT Palette : public QObject { public: Palette(Resource *resource); ~Palette() override; /** * @brief numberOfEntries * @return */ int numberOfEntries() const; /** * @brief columnCount * @return the amount of columns this palette is set to use. */ int columnCount(); /** * @brief setColumnCount * Set the amount of columns this palette should use. */ void setColumnCount(int columns); /** * @brief comment * @return the comment or description associated with the palette. */ QString comment(); /** * @brief setComment * set the comment or description associated with the palette. * @param comment */ void setComment(QString comment); /** * @brief groupNames * @return the list of group names. This is list is in the order these groups are in the file. */ QStringList groupNames(); /** * @brief addGroup * @param name of the new group * @return whether adding the group was successful. */ bool addGroup(QString name); /** * @brief removeGroup * @param name the name of the group to remove. * @param keepColors whether or not to delete all the colors inside, or to move them to the default group. * @return */ bool removeGroup(QString name, bool keepColors = true); /** * @brief colorsCountTotal * @return the total amount of entries in the whole group */ int colorsCountTotal(); /** * @brief colorsCountGroup * @param name of the group to check. Empty is the default group. * @return the amount of colors within that group. */ int colorsCountGroup(QString name); /** * @brief colorSetEntryByIndex * get the colorsetEntry from the global index. * @param index the global index * @return the colorset entry */ KoColorSetEntry colorSetEntryByIndex(int index); /** * @brief colorSetEntryFromGroup * @param index index in the group. * @param groupName the name of the group to get the color from. * @return the colorsetentry. */ KoColorSetEntry colorSetEntryFromGroup(int index, const QString &groupName); /** * @brief colorForEntry * special function to retrieve a ManagedColor object from the colorsetentry. * @param entry the entry * @return the ManagedColorObject */ ManagedColor *colorForEntry(KoColorSetEntry entry); /** * @brief addEntry * add an entry to a group. Gets appended to the end. * @param entry the entry * @param groupName the name of the group to add to. */ void addEntry(KoColorSetEntry entry, QString groupName = QString()); /** * @brief removeEntry * remove the entry at @param index from the group @param groupName. */ void removeEntry(int index, const QString &groupName); /** * @brief insertEntry * like addentry, but allows you to pick the index to insertBefore. * @param index * @param entry * @param groupName */ - void insertEntry(int index, KoColorSetEntry entry, QString groupName = QString()); + // void insertEntry(int index, KoColorSetEntry entry, QString groupName = QString()); /** * @brief editEntry * Changes the entry at @param index by replacing it with @param entry. * @param groupName the group at which the index is. * @return whether it was successful. */ bool editEntry (int index, KoColorSetEntry entry, QString groupName = QString()); /** * @brief changeGroupName * change the group name. * @param oldGroupName the old groupname to change. * @param newGroupName the new name to change it into. * @return whether successful. Reasons for failure include not knowing have oldGroupName */ bool changeGroupName(QString oldGroupName, QString newGroupName); /** * @brief moveGroup * move the group to before groupNameInsertBefore. * @param groupName group to move. * @param groupNameInsertBefore group to inset before. * @return whether successful. Reasons for failure include either group not existing. */ bool moveGroup(const QString &groupName, const QString &groupNameInsertBefore = QString()); /** * @brief save * save the palette * @return whether it was successful. */ bool save(); private: friend class PaletteView; struct Private; Private *const d; /** * @brief colorSet * @return gives qa KoColorSet object back */ KoColorSet *colorSet(); }; #endif // LIBKIS_PALETTE_H diff --git a/libs/pigment/CMakeLists.txt b/libs/pigment/CMakeLists.txt index 4eb080b0e2..aa7f9e103d 100644 --- a/libs/pigment/CMakeLists.txt +++ b/libs/pigment/CMakeLists.txt @@ -1,124 +1,125 @@ project(kritapigment) # we have to repeat platform specifics from top-level if (WIN32) include_directories(${CMAKE_SOURCE_DIR}/winquirks) add_definitions(-D_USE_MATH_DEFINES) add_definitions(-DNOMINMAX) set(WIN32_PLATFORM_NET_LIBS ws2_32.lib netapi32.lib) endif () include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/resources ${CMAKE_CURRENT_SOURCE_DIR}/compositeops) set(FILE_OPENEXR_SOURCES) set(LINK_OPENEXR_LIB) if(OPENEXR_FOUND) include_directories(SYSTEM ${OPENEXR_INCLUDE_DIR}) set(LINK_OPENEXR_LIB ${OPENEXR_LIBRARIES}) add_definitions(${OPENEXR_DEFINITIONS}) endif() set(LINK_VC_LIB) if(HAVE_VC) include_directories(SYSTEM ${Vc_INCLUDE_DIR}) set(LINK_VC_LIB ${Vc_LIBRARIES}) ko_compile_for_all_implementations_no_scalar(__per_arch_factory_objs compositeops/KoOptimizedCompositeOpFactoryPerArch.cpp) message("Following objects are generated from the per-arch lib") message("${__per_arch_factory_objs}") endif() add_subdirectory(tests) add_subdirectory(benchmarks) set(kritapigment_SRCS DebugPigment.cpp KoBasicHistogramProducers.cpp KoColor.cpp KoColorDisplayRendererInterface.cpp KoColorConversionAlphaTransformation.cpp KoColorConversionCache.cpp KoColorConversions.cpp KoColorConversionSystem.cpp KoColorConversionTransformation.cpp KoColorProofingConversionTransformation.cpp KoColorConversionTransformationFactory.cpp KoColorModelStandardIds.cpp KoColorProfile.cpp KoColorSpace.cpp KoColorSpaceEngine.cpp KoColorSpaceFactory.cpp KoColorSpaceMaths.cpp KoColorSpaceRegistry.cpp KoColorProfileStorage.cpp KoColorTransformation.cpp KoColorTransformationFactory.cpp KoColorTransformationFactoryRegistry.cpp KoCompositeColorTransformation.cpp KoCompositeOp.cpp KoCompositeOpRegistry.cpp KoCopyColorConversionTransformation.cpp KoFallBackColorTransformation.cpp KoHistogramProducer.cpp KoMultipleColorConversionTransformation.cpp KoUniqueNumberForIdServer.cpp colorspaces/KoAlphaColorSpace.cpp colorspaces/KoLabColorSpace.cpp colorspaces/KoRgbU16ColorSpace.cpp colorspaces/KoRgbU8ColorSpace.cpp colorspaces/KoSimpleColorSpaceEngine.cpp compositeops/KoOptimizedCompositeOpFactory.cpp compositeops/KoOptimizedCompositeOpFactoryPerArch_Scalar.cpp ${__per_arch_factory_objs} colorprofiles/KoDummyColorProfile.cpp resources/KoAbstractGradient.cpp resources/KoColorSet.cpp + resources/KoColorSet_p.cpp resources/KoColorSetEntry.cpp resources/KisSwatch.cpp resources/KisSwatchGroup.cpp resources/KoPattern.cpp resources/KoResource.cpp resources/KoMD5Generator.cpp resources/KoHashGeneratorProvider.cpp resources/KoStopGradient.cpp resources/KoSegmentGradient.cpp ) set (EXTRA_LIBRARIES ${LINK_OPENEXR_LIB} ${LINK_VC_LIB}) if(MSVC OR (WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")) # avoid "cannot open file 'LIBC.lib'" error set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:LIBC.LIB") endif() add_library(kritapigment SHARED ${kritapigment_SRCS}) generate_export_header(kritapigment) target_include_directories( kritapigment PUBLIC $ $ ) target_link_libraries( kritapigment PUBLIC kritaplugin kritastore kritaglobal ${EXTRA_LIBRARIES} KF5::I18n KF5::ConfigCore Qt5::Core Qt5::Gui Qt5::Xml ${WIN32_PLATFORM_NET_LIBS} ) set_target_properties(kritapigment PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritapigment ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/pigment/resources/KisSwatch.cpp b/libs/pigment/resources/KisSwatch.cpp index 5ec8a0565c..4c3994ad57 100644 --- a/libs/pigment/resources/KisSwatch.cpp +++ b/libs/pigment/resources/KisSwatch.cpp @@ -1,12 +1,33 @@ +/* This file is part of the KDE project + Copyright (c) 2005 Boudewijn Rempt + Copyright (c) 2016 L. E. Segovia + Copyright (c) 2018 Michael Zhou + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + */ + #include "KisSwatch.h" KisSwatch &KisSwatch::operator =(const KisSwatch &source) { if (&source == this) return *this; m_color = source.m_color; m_id = source.m_id; m_name = source.m_name; m_spotColor = source.m_spotColor; return *this; } diff --git a/libs/pigment/resources/KisSwatch.h b/libs/pigment/resources/KisSwatch.h index 491f54a659..fc4f1a1530 100644 --- a/libs/pigment/resources/KisSwatch.h +++ b/libs/pigment/resources/KisSwatch.h @@ -1,20 +1,41 @@ +/* This file is part of the KDE project + Copyright (c) 2005 Boudewijn Rempt + Copyright (c) 2016 L. E. Segovia + Copyright (c) 2018 Michael Zhou + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + */ + #ifndef KISSWATCH_H #define KISSWATCH_H #include #include class KRITAPIGMENT_EXPORT KisSwatch : public KoColorSetEntry { public: KisSwatch() : KoColorSetEntry() { } KisSwatch(const KoColor &color, const QString &name) : KoColorSetEntry(color, name) { } virtual ~KisSwatch() { } public: KisSwatch &operator =(const KisSwatch &source); }; #endif // KISSWATCH_H diff --git a/libs/pigment/resources/KisSwatchGroup.cpp b/libs/pigment/resources/KisSwatchGroup.cpp index 8d5c169a5b..c14af5e76c 100644 --- a/libs/pigment/resources/KisSwatchGroup.cpp +++ b/libs/pigment/resources/KisSwatchGroup.cpp @@ -1,75 +1,122 @@ +/* This file is part of the KDE project + Copyright (c) 2005 Boudewijn Rempt + Copyright (c) 2016 L. E. Segovia + Copyright (c) 2018 Michael Zhou + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + */ + #include "KisSwatchGroup.h" quint32 KisSwatchGroup::DEFAULT_N_COLUMN = 16; KisSwatchGroup::KisSwatchGroup() - : m_nColors(0) - , m_colorMatrix(DEFAULT_N_COLUMN) + : m_colorMatrix(DEFAULT_N_COLUMN) + , m_nColors(0) , m_nLastRowEntries(0) { } void KisSwatchGroup::setEntry(const KisSwatch &e, int x, int y) { Q_ASSERT(x < m_colorMatrix.size() && x >= 0 && y >= 0); if (!checkEntry(x, y)) { m_nColors++; } m_colorMatrix[x][y] = e; } bool KisSwatchGroup::checkEntry(int x, int y) const { if (x >= m_colorMatrix.size() || x < 0) { return false; } if (!m_colorMatrix[x].contains(y)) { return false; } return true; } bool KisSwatchGroup::removeEntry(int x, int y) { if (m_nColors == 0) { return false; } if (x >= m_colorMatrix.size() || x < 0) { return false; } // QMap::remove returns 1 if key found else 0 if (m_colorMatrix[x].remove(y)) { m_nColors -= 1; return true; } else { return false; } } void KisSwatchGroup::setNColumns(int nColumns) { Q_ASSERT(nColumns >= 0); - for (int i = nColumns; i < m_colorMatrix.size(); i++) { - m_nColors -= m_colorMatrix[i].size(); + Q_FOREACH (const Column &col, m_colorMatrix) { + m_nColors -= col.size(); } m_colorMatrix.resize(nColumns); } KisSwatch KisSwatchGroup::getEntry(int x, int y) const { Q_ASSERT(checkEntry(x, y)); return m_colorMatrix[x][y]; } int KisSwatchGroup::nRows() const { + /* + * shouldn't have too great a performance impact... + * add a heap to keep track of last row if there is one + */ + int res = 0; Q_FOREACH (const Column &c, m_colorMatrix) { if (c.empty()) { continue; } res = res > c.lastKey() ? res : c.lastKey(); } return res + 1; } + +void KisSwatchGroup::addEntry(const KisSwatch &e) +{ + if (nColumns() == 0) { + setNColumns(DEFAULT_N_COLUMN); + } + int maxY = nRows() - 1; + int y = maxY; + for (int x = m_colorMatrix.size() - 1; x >= 0; x--) { + if (checkEntry(x, maxY)) { + // if the last entry's at the rightmost column, + // add e to the leftmost column of the next row + if (++x == m_colorMatrix.size()) { + x = 0; + y++; + } + // else just add it to the right + setEntry(e, x, y); + } + } +} diff --git a/libs/pigment/resources/KisSwatchGroup.h b/libs/pigment/resources/KisSwatchGroup.h index 58e667d9f5..9454507766 100644 --- a/libs/pigment/resources/KisSwatchGroup.h +++ b/libs/pigment/resources/KisSwatchGroup.h @@ -1,49 +1,115 @@ +/* This file is part of the KDE project + Copyright (c) 2005 Boudewijn Rempt + Copyright (c) 2016 L. E. Segovia + Copyright (c) 2018 Michael Zhou + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + */ + #ifndef KISSWATCHGROUP_H #define KISSWATCHGROUP_H #include "kritapigment_export.h" #include #include // Used to keep track of the last row. Qt doesn't provide a priority queue... #include "KisSwatch.h" +/** + * @brief The KisSwatchGroup class stores a matrix of color swatches + * swatches can accessed using (x, y) coordinates. + * x is the column number from left to right and y is the row number from top + * to bottom. + * Both x and y start at 0 + * there could be empty entries, so the checkEntry(int, int) method must used + * whenever you want to get an entry from the matrix + */ class KRITAPIGMENT_EXPORT KisSwatchGroup { private: static quint32 DEFAULT_N_COLUMN; -public: +private: typedef QMap Column; public: KisSwatchGroup(); + void setName(const QString &name) { m_name = name; } QString name() const { return m_name; } + void setNColumns(int nColumns); int nColumns() const { return m_colorMatrix.size(); } + int nRows() const; int nColors() const { return m_nColors; } - const QVector &colors() const { return m_colorMatrix; } - /** - * @brief checkEntry checks if position x and y has an entry + * @brief checkEntry + * checks if position x and y has a valid entry + * both x and y start from 0 * @param x * @param y - * @return + * @return true if there is a valid entry at position (x, y) */ bool checkEntry(int x, int y) const; + /** + * @brief setEntry + * sets the entry at position (x, y) to be e + * @param e + * @param x + * @param y + */ void setEntry(const KisSwatch &e, int x, int y); - KisSwatch getEntry (int x, int y) const; + /** + * @brief getEntry + * used to get the swatch entry at position (x, y) + * there is an assertion to make sure that this position isn't empty, + * so checkEntry(int, int) must be used before this method to ensure + * a valid entry can be found + * @param x + * @param y + * @return the swatch entry at position (x, y) + */ + KisSwatch getEntry(int x, int y) const; + /** + * @brief removeEntry + * removes the entry at position (x, y) + * @param x + * @param y + * @return true if these is an entry at (x, y) + */ bool removeEntry(int x, int y); + /** + * @brief addEntry + * adds the entry e to the right of the rightmost entry in the last row + * if the rightmost entry in the last row is in the right most column, + * add e to the leftmost column of a new row + * + * when column is set to 0, resize number of columns to default + * @param e + */ + void addEntry(const KisSwatch &e); void clear() { m_colorMatrix.clear(); } private: QString m_name; QVector m_colorMatrix; - QMap m_nRows; int m_nColors; int m_nLastRowEntries; }; #endif // KISSWATCHGROUP_H diff --git a/libs/pigment/resources/KoColorSet.cpp b/libs/pigment/resources/KoColorSet.cpp index e663dcdcde..a8f8e625ac 100644 --- a/libs/pigment/resources/KoColorSet.cpp +++ b/libs/pigment/resources/KoColorSet.cpp @@ -1,1633 +1,483 @@ /* 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 License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include -#include // qFromLittleEndian -#include // qMax -#include -#include -#include #include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include #include #include #include -#include #include #include "KoColor.h" #include "KoColorSet.h" -#include "KoColorSetEntry.h" -#include "KoColorSetEntryGroup.h" -#include "KoColorProfile.h" -#include "KoColorSpaceRegistry.h" -#include "KoColorModelStandardIds.h" - -struct KoColorSet::Private { - KoColorSet::PaletteType paletteType; - QByteArray data; - QString comment; - qint32 columns; - 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) { - - QFileInfo fi(fileName); - - // .pal - if (ba.startsWith("RIFF") && ba.indexOf("PAL data", 8)) { - return KoColorSet::RIFF_PAL; - } - // .gpl - else if (ba.startsWith("GIMP Palette")) { - return KoColorSet::GPL; - } - // .pal - else if (ba.startsWith("JASC-PAL")) { - return KoColorSet::PSP_PAL; - } - else if (fi.suffix().toLower() == "aco") { - return KoColorSet::ACO; - } - else if (fi.suffix().toLower() == "act") { - return KoColorSet::ACT; - } - 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; -} +#include "KisSwatch.h" +#include "KoColorSet_p.h" KoColorSet::KoColorSet(const QString& filename) : KoResource(filename) - , d(new Private()) -{ -} - -KoColorSet::KoColorSet() - : KoResource(QString()) - , d(new Private()) + , d(new Private(this)) { - } /// Create an copied palette KoColorSet::KoColorSet(const KoColorSet& rhs) : QObject(0) , KoResource(QString()) - , d(new Private()) + , d(new Private(this)) { setFilename(rhs.filename()); d->comment = rhs.d->comment; - d->columns = rhs.d->columns; d->global = rhs.d->global; d->groupNames = rhs.d->groupNames; d->groups = rhs.d->groups; setValid(true); } KoColorSet::~KoColorSet() { } bool KoColorSet::load() { QFile file(filename()); if (file.size() == 0) return false; if (!file.open(QIODevice::ReadOnly)) { warnPigment << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&file); file.close(); return res; } bool KoColorSet::loadFromDevice(QIODevice *dev) { if (!dev->isOpen()) dev->open(QIODevice::ReadOnly); d->data = dev->readAll(); Q_ASSERT(d->data.size() != 0); - return init(); + return d->init(); } bool KoColorSet::save() { QFile file(filename()); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { return false; } saveToDevice(&file); file.close(); return true; } bool KoColorSet::saveToDevice(QIODevice *dev) const { bool res; switch(d->paletteType) { case GPL: - res = saveGpl(dev); + res = d->saveGpl(dev); break; default: - res = saveKpl(dev); + res = d->saveKpl(dev); } if (res) { KoResource::saveToDevice(dev); } return res; } -bool KoColorSet::init() -{ - d->global.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"; - return false; - } - if (d->data.isNull()) { - QFile file(filename()); - if (file.size() == 0) { - warnPigment << "Cannot load palette" << name() << "there is no data available"; - return false; - } - file.open(QIODevice::ReadOnly); - d->data = file.readAll(); - file.close(); - } - - bool res = false; - d->paletteType = detectFormat(filename(), d->data); - switch(d->paletteType) { - case GPL: - res = loadGpl(); - break; - case ACT: - res = loadAct(); - break; - case RIFF_PAL: - res = loadRiff(); - break; - case PSP_PAL: - res = loadPsp(); - break; - case ACO: - res = loadAco(); - break; - case XML: - res = loadXml(); - break; - case KPL: - res = loadKpl(); - break; - case SBZ: - res = loadSbz(); - break; - default: - res = false; - } - setValid(res); - - if (d->columns == 0) { - d->columns = 10; - } - - QImage img(d->columns * 4, d->global.nRows() * 4, QImage::Format_ARGB32); - QPainter gc(&img); - gc.fillRect(img.rect(), Qt::darkGray); - Q_FOREACH (const KoColorSetEntryGroup::Column &col, d->global.colors()) { - Q_FOREACH (const KoColorSetEntry &entry, col.values()) { - QColor c = entry.color().toQColor(); - gc.fillRect(entry.x() * 4, entry.y() * 4, 4, 4, c); - } - } - setImage(img); - - // save some memory - d->data.clear(); - return res; -} - -bool KoColorSet::saveGpl(QIODevice *dev) const -{ - QTextStream stream(dev); - stream << "GIMP Palette\nName: " << name() << "\nColumns: " << d->columns << "\n#\n"; - - for (int y = 0; y < d->global.nRows(); y++) { - for (int x = 0; x < d->columns; x++) { - bool colorPresent; - const KoColorSetEntry& entry = d->global.getEntry(x, y, colorPresent); - if (!colorPresent) { continue; } - 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; -} - quint32 KoColorSet::nColors() { return d->global.nColors(); } quint32 KoColorSet::nColorsGroup(QString groupName) { if (d->groups.contains(groupName)) { return d->groups[groupName].nColors(); } else if (groupName.isEmpty()) { return d->global.nColors(); } else { return 0; } } -quint32 KoColorSet::getIndexClosestColor(const KoColor color, bool useGivenColorSpace) +QString KoColorSet::closestColorName(const KoColor color, bool useGivenColorSpace) { - /* - quint32 closestIndex = 0; + int closestX = 0, closestY = 0; quint8 highestPercentage = 0; quint8 testPercentage = 0; KoColor compare = color; - for (quint32 i=0; i < nColors(); i++) { - KoColor entry = getColorGlobal(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; + QString res; + for (int x = 0; x < d->global.nColumns(); x++) { + for (int y = 0; y < rowCount(); y++ ) { + KisSwatch entry = getColorGlobal(x, y); + KoColor color = entry.color(); + if (useGivenColorSpace == true && compare.colorSpace() != color.colorSpace()) { + color.convertTo(compare.colorSpace()); + + } else if (compare.colorSpace() != color.colorSpace()) { + compare.convertTo(color.colorSpace()); + } + testPercentage = (255 - compare.colorSpace()->difference(compare.data(), color.data())); + if (testPercentage > highestPercentage) + { + res = entry.name(); + highestPercentage = testPercentage; + } } } - return closestIndex; - */ - return 0; -} - -QString KoColorSet::closestColorName(const KoColor color, bool useGivenColorSpace) -{ - /* - int i = getIndexClosestColor(color, useGivenColorSpace); - return getColorGlobal(i).name(); - */ - return QString(); -} - -void KoColorSet::add(KoColorSetEntry c, const QString &groupName) -{ - KoColorSetEntryGroup &modifiedGroup = - d->groups.contains(groupName) || d->groupNames.contains(groupName) - ? d->groups[groupName] : d->global; - if (c.x() == KoColorSetEntry::NULLPOSITON) { - c.setX(d->global.nColors() % d->columns); - c.setY(qMax(modifiedGroup.nRows(), modifiedGroup.nColors() / d->columns)); - } - modifiedGroup.setEntry(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; - */ - return 0; + return res; } -void KoColorSet::removeAt(quint32 x, quint32 y, QString groupName) +void KoColorSet::add(KisSwatch c, const QString &groupName) { - /* - if (d->groups.contains(groupName)){ - if ((quint32)d->groups.value(groupName).size()>x) { - d->groups[groupName].remove(x); - } - } else { - if ((quint32)d->colors.size()>x) { - d->colors.remove(x); - } - } - */ - if (x >= d->columns || x < 0) - return; - if (d->groups.contains(groupName)){ - d->groups[groupName].removeEntry(x, y); - } else { - d->global.removeEntry(x, y); - } + KisSwatchGroup &modifiedGroup = d->groups.contains(groupName) + ? d->groups[groupName] : d->groups[QString()]; + modifiedGroup.addEntry(c); } void KoColorSet::clear() { - d->global.clear(); d->groups.clear(); d->groupNames.clear(); } -KoColorSetEntry KoColorSet::getColorGlobal(quint32 x, quint32 y) +KisSwatch KoColorSet::getColorGlobal(quint32 x, quint32 y) { - KoColorSetEntry e; - QString groupName = findGroupByGlobalIndex(x, y); - e = getColorGroup(x, y, groupName); - return e; + KisSwatch e; + int yInGroup = y; + QString nameGroupFoundIn; + for (const QString &groupName : d->groupNames) { + if (yInGroup < d->groups[groupName].nRows()) { + nameGroupFoundIn = groupName; + break; + } else { + yInGroup -= d->groups[groupName].nRows(); + } + } + const KisSwatchGroup &groupFoundIn = nameGroupFoundIn == QString() + ? d->global : d->groups[nameGroupFoundIn]; + Q_ASSERT(groupFoundIn.checkEntry(x, yInGroup)); + return groupFoundIn.getEntry(x, yInGroup); } -KoColorSetEntry KoColorSet::getColorGroup(quint32 x, quint32 y, QString groupName) +KisSwatch KoColorSet::getColorGroup(quint32 x, quint32 y, QString groupName) { - KoColorSetEntry e; + KisSwatch e; bool entryFound; - if (d->groups.contains(groupName)) { - e = d->groups[groupName].getEntry(x, y, entryFound); - } else if (groupName.isEmpty()) { - e = d->global.getEntry(x, y, entryFound); + const KisSwatchGroup &sourceGroup = d->groups.contains(groupName) + ? d->groups[groupName] : d->groups[QString()]; + // warnPigment << "Color group "<< groupName <<" not found"; + entryFound = sourceGroup.checkEntry(x, y); + if (entryFound) { + e = sourceGroup.getEntry(x, y); } else { - warnPigment << "Color group "<< groupName <<" not found"; - } - if (!entryFound) { warnPigment << x << " " << y <<"doesn't exist in" << nColorsGroup(groupName); } return e; } -QString KoColorSet::findGroupByGlobalIndex(quint32 x, quint32 y) -{ - /* - *index = globalIndex; - QString groupName = QString(); - if ((quint32)d->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; - */ - return QString(); -} - -QString KoColorSet::findGroupByColorName(const QString &name, quint32 *x, quint32 *y) -{ - QString groupName = QString(); - Q_FOREACH (const KoColorSetEntryGroup::Column & col, d->global.colors()) { - Q_FOREACH (const KoColorSetEntry & entry, col.values()) { - if (entry.name() == name) { - *x = static_cast(entry.x()); - *y = static_cast(entry.y()); - return groupName; - } - } - } - QStringList groupNames = getGroupNames(); - Q_FOREACH (QString name, groupNames) { - Q_FOREACH (const KoColorSetEntryGroup::Column & col, d->groups[name].colors()) { - Q_FOREACH (const KoColorSetEntry & entry, col.values()) { - if (entry.name() == name) { - *x = static_cast(entry.x()); - *y = static_cast(entry.y()); - 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; - */ - return QString(); -} - QStringList KoColorSet::getGroupNames() { if (d->groupNames.size() != d->groups.size()) { warnPigment << "mismatch between groups and the groupnames list."; return QStringList(d->groups.keys()); } return d->groupNames; } bool KoColorSet::changeGroupName(QString oldGroupName, QString newGroupName) { if (d->groupNames.contains(oldGroupName)==false) { return false; } - KoColorSetEntryGroup tmp = d->groups.value(oldGroupName); + KisSwatchGroup tmp = d->groups.value(oldGroupName); d->groups.remove(oldGroupName); d->groups[newGroupName] = tmp; //rename the string in the stringlist; int index = d->groupNames.indexOf(oldGroupName); d->groupNames.replace(index, newGroupName); return true; } -bool KoColorSet::changeColorSetEntry(KoColorSetEntry entry, - QString groupName) -{ - if (!d->groupNames.contains(groupName)) { - return false; - } - if (groupName.isEmpty()) { - d->global.setEntry(entry); - } else { - d->groups[groupName].setEntry(entry); - } - return true; -} - void KoColorSet::setColumnCount(int columns) { - d->columns = columns; d->global.setNColumns(columns); - for (KoColorSetEntryGroup &g : d->groups.values()) { // Q_FOREACH doesn't accept non const refs + for (KisSwatchGroup &g : d->groups.values()) { // Q_FOREACH doesn't accept non const refs g.setNColumns(columns); } } int KoColorSet::columnCount() { - return d->columns; + return d->global.nColumns(); } QString KoColorSet::comment() { return d->comment; } void KoColorSet::setComment(QString comment) { d->comment = 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] = KoColorSetEntryGroup(); + d->groups[groupName] = KisSwatchGroup(); return true; } bool KoColorSet::moveGroup(const QString &groupName, const QString &groupNameInsertBefore) { if (d->groupNames.contains(groupName)==false || d->groupNames.contains(groupNameInsertBefore)==false) { return false; } d->groupNames.removeAt(d->groupNames.indexOf(groupName)); int index = d->groupNames.size(); if (groupNameInsertBefore!=QString()) { index = d->groupNames.indexOf(groupNameInsertBefore); } d->groupNames.insert(index, groupName); return true; } bool KoColorSet::removeGroup(const QString &groupName, bool keepColors) { if (!d->groups.contains(groupName)) { return false; } if (keepColors) { // put all colors directly below global - KoColorSetEntry newEntry; - Q_FOREACH (const KoColorSetEntryGroup::Column & col, d->groups[groupName].colors()) { - Q_FOREACH (const KoColorSetEntry & entry, col.values()) { - newEntry = entry; - newEntry.setY(entry.y() + d->global.nRows()); - d->global.setEntry(newEntry); + int startingRow = d->global.nRows(); + for (int x = 0; x < d->groups[groupName].nColumns(); x++) { + for (int y = 0; y < d->groups[groupName].nRows(); y++) { + if (d->groups[groupName].checkEntry(x, y)) { + d->global.setEntry(d->groups[groupName].getEntry(x, y), + x, + y + startingRow); + } } } } 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(".kpl"); } -bool KoColorSet::loadGpl() +int KoColorSet::rowCount() { - QString s = QString::fromUtf8(d->data.data(), d->data.count()); - - if (s.isEmpty() || s.isNull() || s.length() < 50) { - warnPigment << "Illegal Gimp palette file: " << filename(); - return false; - } - - quint32 index = 0; - - QStringList lines = s.split('\n', QString::SkipEmptyParts); - - if (lines.size() < 3) { - warnPigment << "Not enough lines in palette file: " << filename(); - return false; - } - - QString columns; - qint32 r, g, b; - KoColorSetEntry e; - - // Read name - - - if (!lines[0].startsWith("GIMP") || !lines[1].toLower().contains("name")) { - warnPigment << "Illegal Gimp palette file: " << filename(); - return false; - } - - setName(i18n(lines[1].split(":")[1].trimmed().toLatin1())); - - index = 2; - - // Read columns - if (lines[index].toLower().contains("columns")) { - columns = lines[index].split(":")[1].trimmed(); - d->columns = columns.toInt(); - index = 3; + int res = d->global.nRows(); + Q_FOREACH (QString name, d->groupNames) { + res += d->groups[name].nRows(); } + return res; +} - - for (qint32 i = index; i < lines.size(); i++) { - - if (lines[i].startsWith('#')) { - d->comment += lines[i].mid(1).trimmed() + ' '; - } else if (!lines[i].isEmpty()) { - QStringList a = lines[i].replace('\t', ' ').split(' ', QString::SkipEmptyParts); - - if (a.count() < 3) { - break; +/* +QString KoColorSet::findGroupByGlobalIndex(quint32 x, quint32 y) +{ + *index = globalIndex; + QString groupName = QString(); + if ((quint32)d->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; + } } - r = a[0].toInt(); - a.pop_front(); - g = a[0].toInt(); - a.pop_front(); - b = a[0].toInt(); - a.pop_front(); - - r = qBound(0, r, 255); - g = qBound(0, g, 255); - b = qBound(0, b, 255); - - e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); - - QString name = a.join(" "); - e.setName(name.isEmpty() ? i18n("Untitled") : name); - - add(e); } } - return true; -} - -bool KoColorSet::loadAct() -{ - QFileInfo info(filename()); - setName(info.baseName()); - KoColorSetEntry e; - for (int i = 0; i < d->data.size(); i += 3) { - quint8 r = d->data[i]; - quint8 g = d->data[i+1]; - quint8 b = d->data[i+2]; - e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); - add(e); - } - return true; -} - -struct RiffHeader { - quint32 riff; - quint32 size; - quint32 signature; - quint32 data; - quint32 datasize; - quint16 version; - quint16 colorcount; -}; - - -bool KoColorSet::loadRiff() -{ - // http://worms2d.info/Palette_file - QFileInfo info(filename()); - setName(info.baseName()); - KoColorSetEntry e; - - RiffHeader header; - memcpy(&header, d->data.constData(), sizeof(RiffHeader)); - header.colorcount = qFromBigEndian(header.colorcount); - - for (int i = sizeof(RiffHeader); - (i < (int)(sizeof(RiffHeader) + header.colorcount) && i < d->data.size()); - i += 4) { - quint8 r = d->data[i]; - quint8 g = d->data[i+1]; - quint8 b = d->data[i+2]; - e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); - add(e); - } - return true; -} - - -bool KoColorSet::loadPsp() -{ - QFileInfo info(filename()); - setName(info.baseName()); - KoColorSetEntry e; - qint32 r, g, b; - - QString s = QString::fromUtf8(d->data.data(), d->data.count()); - QStringList l = s.split('\n', QString::SkipEmptyParts); - if (l.size() < 4) return false; - if (l[0] != "JASC-PAL") return false; - if (l[1] != "0100") return false; - - int entries = l[2].toInt(); - - for (int i = 0; i < entries; ++i) { - - QStringList a = l[i + 3].replace('\t', ' ').split(' ', QString::SkipEmptyParts); - - if (a.count() != 3) { - continue; - } - - r = a[0].toInt(); - a.pop_front(); - g = a[0].toInt(); - a.pop_front(); - b = a[0].toInt(); - a.pop_front(); - - r = qBound(0, r, 255); - g = qBound(0, g, 255); - b = qBound(0, b, 255); - - e.setColor(KoColor(QColor(r, g, b), - KoColorSpaceRegistry::instance()->rgb8())); - - QString name = a.join(" "); - e.setName(name.isEmpty() ? i18n("Untitled") : name); - - add(e); - } - return true; + return groupName; + return QString(); } -void scribusParseColor(KoColorSet *set, QXmlStreamReader *xml) +QString KoColorSet::findGroupByColorName(const QString &name, quint32 *x, quint32 *y) { - KoColorSetEntry colorEntry; - // It's a color, retrieve it - QXmlStreamAttributes colorProperties = xml->attributes(); - - QStringRef colorName = colorProperties.value("NAME"); - colorEntry.setName(colorName.isEmpty() || colorName.isNull() ? i18n("Untitled") : colorName.toString()); - - // RGB or CMYK? - if (colorProperties.hasAttribute("RGB")) { - dbgPigment << "Color " << colorProperties.value("NAME") << ", RGB " << colorProperties.value("RGB"); - - KoColor currentColor(KoColorSpaceRegistry::instance()->rgb8()); - QStringRef colorValue = colorProperties.value("RGB"); - - if (colorValue.length() != 7 && colorValue.at(0) != '#') { // Color is a hexadecimal number - xml->raiseError("Invalid rgb8 color (malformed): " + colorValue); - return; - } else { - bool rgbOk; - quint32 rgb = colorValue.mid(1).toUInt(&rgbOk, 16); - if (!rgbOk) { - xml->raiseError("Invalid rgb8 color (unable to convert): " + colorValue); - return; - } - - quint8 r = rgb >> 16 & 0xff; - quint8 g = rgb >> 8 & 0xff; - quint8 b = rgb & 0xff; - - dbgPigment << "Color parsed: "<< r << g << b; - - currentColor.data()[0] = r; - currentColor.data()[1] = g; - currentColor.data()[2] = b; - currentColor.setOpacity(OPACITY_OPAQUE_U8); - colorEntry.setColor(currentColor); - - set->add(colorEntry); - - while(xml->readNextStartElement()) { - //ignore - these are all unknown or the /> element tag - xml->skipCurrentElement(); + QString groupName = QString(); + Q_FOREACH (const KisSwatchGroup::Column & col, d->global.colors()) { + Q_FOREACH (const KisSwatch & entry, col.values()) { + if (entry.name() == name) { + *x = static_cast(entry.x()); + *y = static_cast(entry.y()); + return groupName; } - return; } } - else if (colorProperties.hasAttribute("CMYK")) { - dbgPigment << "Color " << colorProperties.value("NAME") << ", CMYK " << colorProperties.value("CMYK"); - - KoColor currentColor(KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Integer8BitsColorDepthID.id(), QString())); - - QStringRef colorValue = colorProperties.value("CMYK"); - if (colorValue.length() != 9 && colorValue.at(0) != '#') { // Color is a hexadecimal number - 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); - return; - } - - quint8 c = cmyk >> 24 & 0xff; - quint8 m = cmyk >> 16 & 0xff; - quint8 y = cmyk >> 8 & 0xff; - quint8 k = cmyk & 0xff; - - dbgPigment << "Color parsed: "<< c << m << y << k; - - currentColor.data()[0] = c; - currentColor.data()[1] = m; - currentColor.data()[2] = y; - currentColor.data()[3] = k; - currentColor.setOpacity(OPACITY_OPAQUE_U8); - colorEntry.setColor(currentColor); - - set->add(colorEntry); - - while(xml->readNextStartElement()) { - //ignore - these are all unknown or the /> element tag - xml->skipCurrentElement(); + QStringList groupNames = getGroupNames(); + Q_FOREACH (QString name, groupNames) { + Q_FOREACH (const KisSwatchGroup::Column & col, d->groups[name].colors()) { + Q_FOREACH (const KisSwatch & entry, col.values()) { + if (entry.name() == name) { + *x = static_cast(entry.x()); + *y = static_cast(entry.y()); + return groupName; + } } - return; } } - else { - xml->raiseError("Unknown color space for color " + colorEntry.name()); - } -} - -bool loadScribusXmlPalette(KoColorSet *set, QXmlStreamReader *xml) -{ - - //1. Get name - QXmlStreamAttributes paletteProperties = xml->attributes(); - QStringRef paletteName = paletteProperties.value("Name"); - dbgPigment << "Processed name of palette:" << paletteName; - set->setName(paletteName.toString()); - - //2. Inside the SCRIBUSCOLORS, there are lots of colors. Retrieve them - - while(xml->readNextStartElement()) { - QStringRef currentElement = xml->name(); - if(QStringRef::compare(currentElement, "COLOR", Qt::CaseInsensitive) == 0) { - scribusParseColor(set, xml); - } - else { - xml->skipCurrentElement(); - } - } - - if(xml->hasError()) { - return false; - } - - return true; + return groupName; } -bool KoColorSet::loadXml() { - bool res = false; - - QXmlStreamReader *xml = new QXmlStreamReader(d->data); - - if (xml->readNextStartElement()) { - QStringRef paletteId = xml->name(); - if (QStringRef::compare(paletteId, "SCRIBUSCOLORS", Qt::CaseInsensitive) == 0) { // Scribus - dbgPigment << "XML palette: " << filename() << ", Scribus format"; - res = loadScribusXmlPalette(this, xml); - } - else { - // Unknown XML format - xml->raiseError("Unknown XML palette format. Expected SCRIBUSCOLORS, found " + paletteId); +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; } } - - // If there is any error (it should be returned through the stream) - if (xml->hasError() || !res) { - warnPigment << "Illegal XML palette:" << filename(); - warnPigment << "Error (line"<< xml->lineNumber() << ", column" << xml->columnNumber() << "):" << xml->errorString(); - return false; - } - else { - dbgPigment << "XML palette parsed successfully:" << filename(); - return true; - } -} - -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 KoColorSetEntryGroup::Column &col, d->global.colors()) { - Q_FOREACH(const KoColorSetEntry &entry, col.values()) { - // 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 KoColorSetEntryGroup::Column &col, d->groups[groupName].colors()) { - Q_FOREACH(const KoColorSetEntry &entry, col.values()) { - - // 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); - } + 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; } } - - 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(); + return groupName; + return QString(); } -bool KoColorSet::loadKpl() +const KisSwatchGroup &KoColorSet::getGroupByName(const QString &groupName, bool &success) const { - 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 (groupName.isEmpty()) { + success = true; + return d->global; } - - { - 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.setColor(KoColor::fromXML(c.firstChildElement(), colorDepthId)); - entry.setName(c.attribute("name")); - entry.setId(c.attribute("id")); - entry.setSpotColor(c.attribute("spot", "false") == "true" ? true : false); - d->global.setEntry(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.setColor(KoColor::fromXML(cg.firstChildElement(), colorDepthId)); - entry.setName(cg.attribute("name")); - entry.setId(cg.attribute("id")); - entry.setSpotColor(cg.attribute("spot", "false") == "true" ? true : false); - add(entry, groupName); - - cg = cg.nextSiblingElement("ColorSetEntry"); - - } - g = g.nextSiblingElement("Group"); - } - + if (d->groupNames.contains(groupName)) { + success = true; + return d->groups[groupName]; } - - - buf.close(); - return true; -} - -quint16 readShort(QIODevice *io) { - quint16 val; - quint64 read = io->read((char*)&val, 2); - if (read != 2) return false; - return qFromBigEndian(val); + success = false; + return d->global; } -bool KoColorSet::loadAco() +bool KoColorSet::changeColorSetEntry(KisSwatch entry, + QString groupName) { - QFileInfo info(filename()); - setName(info.baseName()); - - QBuffer buf(&d->data); - buf.open(QBuffer::ReadOnly); - - quint16 version = readShort(&buf); - quint16 numColors = readShort(&buf); - KoColorSetEntry e; - - if (version == 1 && buf.size() > 4+numColors*10) { - buf.seek(4+numColors*10); - version = readShort(&buf); - numColors = readShort(&buf); + if (!d->groupNames.contains(groupName)) { + return false; } - - const quint16 quint16_MAX = 65535; - - for (int i = 0; i < numColors && !buf.atEnd(); ++i) { - - quint16 colorSpace = readShort(&buf); - quint16 ch1 = readShort(&buf); - quint16 ch2 = readShort(&buf); - quint16 ch3 = readShort(&buf); - quint16 ch4 = readShort(&buf); - - bool skip = false; - if (colorSpace == 0) { // RGB - const KoColorProfile *srgb = KoColorSpaceRegistry::instance()->rgb8()->profile(); - KoColor c(KoColorSpaceRegistry::instance()->rgb16(srgb)); - reinterpret_cast(c.data())[0] = ch3; - reinterpret_cast(c.data())[1] = ch2; - reinterpret_cast(c.data())[2] = ch1; - c.setOpacity(OPACITY_OPAQUE_U8); - e.setColor(c); - } - else if (colorSpace == 1) { // HSB - QColor qc; - qc.setHsvF(ch1 / 65536.0, ch2 / 65536.0, ch3 / 65536.0); - KoColor c(qc, KoColorSpaceRegistry::instance()->rgb16()); - c.setOpacity(OPACITY_OPAQUE_U8); - e.setColor(c); - } - else if (colorSpace == 2) { // CMYK - KoColor c(KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Integer16BitsColorDepthID.id(), QString())); - reinterpret_cast(c.data())[0] = quint16_MAX - ch1; - reinterpret_cast(c.data())[1] = quint16_MAX - ch2; - reinterpret_cast(c.data())[2] = quint16_MAX - ch3; - reinterpret_cast(c.data())[3] = quint16_MAX - ch4; - c.setOpacity(OPACITY_OPAQUE_U8); - e.setColor(c); - } - else if (colorSpace == 7) { // LAB - KoColor c = KoColor(KoColorSpaceRegistry::instance()->lab16()); - reinterpret_cast(c.data())[0] = ch3; - reinterpret_cast(c.data())[1] = ch2; - reinterpret_cast(c.data())[2] = ch1; - c.setOpacity(OPACITY_OPAQUE_U8); - e.setColor(c); - } - else if (colorSpace == 8) { // GRAY - KoColor c(KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer16BitsColorDepthID.id(), QString())); - reinterpret_cast(c.data())[0] = ch1 * (quint16_MAX / 10000); - c.setOpacity(OPACITY_OPAQUE_U8); - e.setColor(c); - } - else { - warnPigment << "Unsupported colorspace in palette" << filename() << "(" << colorSpace << ")"; - skip = true; - } - if (version == 2) { - quint16 v2 = readShort(&buf); //this isn't a version, it's a marker and needs to be skipped. - Q_UNUSED(v2); - quint16 size = readShort(&buf) -1; //then comes the length - if (size>0) { - QByteArray ba = buf.read(size*2); - if (ba.size() == size*2) { - QTextCodec *Utf16Codec = QTextCodec::codecForName("UTF-16BE"); - e.setName(Utf16Codec->toUnicode(ba)); - } else { - warnPigment << "Version 2 name block is the wrong size" << filename(); - } - } - v2 = readShort(&buf); //end marker also needs to be skipped. - Q_UNUSED(v2); - } - if (!skip) { - add(e); - } + if (groupName.isEmpty()) { + d->global.setEntry(entry); + } else { + d->groups[groupName].setEntry(entry); } 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; - } +quint32 KoColorSet::getIndexClosestColor(const KoColor color, bool useGivenColorSpace) +{ + quint32 closestIndex = 0; + quint8 highestPercentage = 0; + quint8 testPercentage = 0; + KoColor compare = color; + for (quint32 i=0; i < nColors(); i++) { + KoColor entry = getColorGlobal(i).color(); + if (useGivenColorSpace == true && compare.colorSpace() != entry.colorSpace()) { + entry.convertTo(compare.colorSpace()); - // 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; + } else if(compare.colorSpace()!=entry.colorSpace()) { + compare.convertTo(entry.colorSpace()); } - - // 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")) + testPercentage = (255 - compare.colorSpace()->difference(compare.data(), entry.data())); + if (testPercentage>highestPercentage) { - KoColorSetEntry currentEntry; - // Set if color is spot - currentEntry.setSpotColor(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 - currentEntry.setId(colorId.text()); - currentEntry.setName(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() << ")"; - } - - KoColor c(KoColorSpaceRegistry::instance()->colorSpace(LABAColorModelID.id(), Float32BitsColorDepthID.id(), QString())); - reinterpret_cast(c.data())[0] = l; - reinterpret_cast(c.data())[1] = a; - reinterpret_cast(c.data())[2] = b; - c.setOpacity(OPACITY_OPAQUE_F); - firstDefinition = true; - currentEntry.setColor(c); - 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() << ")"; - } - - KoColor c(KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), srgb)); - reinterpret_cast(c.data())[0] = r; - reinterpret_cast(c.data())[1] = g; - reinterpret_cast(c.data())[2] = b; - c.setOpacity(OPACITY_OPAQUE_F); - currentEntry.setColor(c); - 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() << ")"; - } - - KoColor c(KoColorSpaceRegistry::instance()->colorSpace(XYZAColorModelID.id(), Float32BitsColorDepthID.id(), QString())); - reinterpret_cast(c.data())[0] = x; - reinterpret_cast(c.data())[1] = y; - reinterpret_cast(c.data())[2] = z; - c.setOpacity(OPACITY_OPAQUE_F); - currentEntry.setColor(c); - 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); - } - } - - KoColor color(colorSpace); - reinterpret_cast(color.data())[0] = c; - reinterpret_cast(color.data())[1] = m; - reinterpret_cast(color.data())[2] = y; - reinterpret_cast(color.data())[3] = k; - color.setOpacity(OPACITY_OPAQUE_F); - currentEntry.setColor(color); - 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); - } - } - - KoColor c(colorSpace); - reinterpret_cast(c.data())[0] = g; - c.setOpacity(OPACITY_OPAQUE_F); - currentEntry.setColor(c); - 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); - } - } - - KoColor c(colorSpace); - reinterpret_cast(c.data())[0] = r; - reinterpret_cast(c.data())[1] = g; - reinterpret_cast(c.data())[2] = b; - c.setOpacity(OPACITY_OPAQUE_F); - currentEntry.setColor(c); - firstDefinition = true; - } - else { - warnPigment << "Color space not implemented:" << model << "(line" << colorValueE.lineNumber() << ", column "<< colorValueE.columnNumber() << ")"; - } - } - if (firstDefinition) { - materialsBook.insert(currentEntry.id(), currentEntry); - } - 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"); - } - } + closestIndex = i; + highestPercentage = testPercentage; } - // End palette } - - buf.close(); - return true; + return closestIndex; } -const KoColorSetEntryGroup &KoColorSet::getGroupByName (const QString &groupName, bool &success) const +void KoColorSet::removeAt(quint32 x, quint32 y, QString groupName) { - if (groupName.isEmpty()) { - success = true; - return d->global; + if (d->groups.contains(groupName)){ + if ((quint32)d->groups.value(groupName).size()>x) { + d->groups[groupName].remove(x); + } + } else { + if ((quint32)d->colors.size()>x) { + d->colors.remove(x); + } } - if (d->groupNames.contains(groupName)) { - success = true; - return d->groups[groupName]; + if (x >= d->columns || x < 0) + return; + if (d->groups.contains(groupName)){ + d->groups[groupName].removeEntry(x, y); + } else { + d->global.removeEntry(x, y); } - success = false; - return d->global; } -int KoColorSet::rowCount() +quint32 KoColorSet::insertBefore(const KisSwatch &c, qint32 index, const QString &groupName) { - int res = d->global.nRows(); - Q_FOREACH (QString name, d->groupNames) { - res += d->groups[name].nRows(); + 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 res; + return newIndex; + return 0; } +*/ diff --git a/libs/pigment/resources/KoColorSet.h b/libs/pigment/resources/KoColorSet.h index 23fac07d96..2892147a02 100644 --- a/libs/pigment/resources/KoColorSet.h +++ b/libs/pigment/resources/KoColorSet.h @@ -1,228 +1,206 @@ /* 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 License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KOCOLORSET #define KOCOLORSET #include #include #include #include #include #include "KoColor.h" -#include "KoColorSetEntry.h" -#include "KoColorSetEntryGroup.h" +#include "KisSwatch.h" +#include "KisSwatchGroup.h" /** * Open Gimp, Photoshop or RIFF palette files. This is a straight port * from the Gimp. */ class KRITAPIGMENT_EXPORT KoColorSet : public QObject, public KoResource { Q_OBJECT public: enum PaletteType { UNKNOWN = 0, GPL, // GIMP RIFF_PAL, // RIFF ACT, // Photoshop binary PSP_PAL, // PaintShop Pro ACO, // Photoshop Swatches 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, a Photoshop palette, * a Krita palette, * a Scribus palette or a SwatchBooker palette. */ - explicit KoColorSet(const QString &filename); - - /// Create an empty color set - KoColorSet(); + explicit KoColorSet(const QString &filename = QString()); /// Explicit copy constructor (KoResource copy constructor is private) KoColorSet(const KoColorSet& rhs); ~KoColorSet() override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; QString defaultFileExtension() const override; void setColumnCount(int columns); int columnCount(); int rowCount(); /** * @brief comment * @return the comment. */ QString comment(); void setComment(QString comment); public: /** * @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(KoColorSetEntry, const 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 x, quint32 y, QString groupName = QString()); + void add(KisSwatch, const 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 x, quint32 y); + KisSwatch getColorGlobal(quint32 x, quint32 y); /** * @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 x, quint32 y, QString groupName = QString()); + KisSwatch getColorGroup(quint32 x, quint32 y, QString groupName = QString()); - QString findGroupByGlobalIndex(quint32 x, quint32 y); - QString findGroupByColorName(const QString &name, quint32 *x, quint32 *y); - QString findGroupByID(const QString &id,quint32 *index); /** * @brief getGroupNames * @return returns a list of group names, excluding the unsorted group. */ QStringList getGroupNames(); - /** - * @brief getGroupByName - * @param groupName - * @param if success - * @return group found - */ - const KoColorSetEntryGroup &getGroupByName(const QString &groupName, bool &success) const; - bool changeGroupName(QString oldGroupName, QString newGroupName); - bool changeColorSetEntry(KoColorSetEntry entry, QString groupName); - /** * @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 moveGroup * Move a group in the internal stringlist. * @param groupName the groupname to move. * @param groupNameInsertBefore the groupname to insert before. Empty means it will be added to the end. * @return */ bool moveGroup(const QString &groupName, const QString &groupNameInsertBefore = QString()); /** * @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(); + /** + * @brief closestColorName + * convenience function to get the name of the closest match. + * @param color + * @param useGivenColorSpace + * @return + */ + QString closestColorName(KoColor color, bool useGivenColorSpace = true); + + /* + * No one seems to be using these methods... + */ + // QString findGroupByGlobalIndex(quint32 x, quint32 y); + // QString findGroupByColorName(const QString &name, quint32 *x, quint32 *y); + // QString findGroupByID(const QString &id,quint32 *index); + // void removeAt(quint32 x, quint32 y, QString groupName = QString()); + /** + * @brief getGroupByName + * @param groupName + * @param if success + * @return group found + */ + // const KisSwatchGroup &getGroupByName(const QString &groupName, bool &success) const; + // bool changeColorSetEntry(KisSwatch entry, QString groupName); /** * @brief getIndexClosestColor * function that matches the color to all colors in the colorset, and returns the index * of the closest match. * @param color the color you wish to compare. * @param useGivenColorSpace whether to use the color space of the color given * when the two colors' colorspaces don't match. Else it'll use the entry's colorspace. * @return returns the int of the closest match. */ - quint32 getIndexClosestColor(KoColor color, bool useGivenColorSpace = true); - + // quint32 getIndexClosestColor(KoColor color, bool useGivenColorSpace = true); /** - * @brief closestColorName - * convenience function to get the name of the closest match. - * @param color - * @param useGivenColorSpace - * @return + * @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. */ - QString closestColorName(KoColor color, bool useGivenColorSpace = true); - -private: - + // quint32 insertBefore(const KisSwatch &, qint32 index, const QString &groupName = QString()); - 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; +private: + class Private; const QScopedPointer d; }; #endif // KOCOLORSET diff --git a/libs/pigment/resources/KoColorSetEntryGroup.cpp b/libs/pigment/resources/KoColorSetEntryGroup.cpp deleted file mode 100644 index 64aab4594d..0000000000 --- a/libs/pigment/resources/KoColorSetEntryGroup.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "KoColorSetEntryGroup.h" - -KoColorSetEntry KoColorSetEntryGroup::NULLENTRY = KoColorSetEntry(); - -KoColorSetEntryGroup::KoColorSetEntryGroup() - : m_nColors(0) - , m_nLastRowEntries(0) -{ - m_nRows[0] = 0; -} - -void KoColorSetEntryGroup::setEntry(KoColorSetEntry e) -{ - Q_ASSERT(e.x() <= m_colors.size() && e.x() >= 0); - if (e.y() >= m_nRows.lastKey() - 1) { - m_nRows[e.y() + 1] = 0; - if (!m_colors[e.x()].contains(e.y())) { - m_nLastRowEntries++; - } - } - m_colors[e.x()][e.y()] = e; - m_nColors++; -} - -void KoColorSetEntryGroup::removeEntry(int x, int y) -{ - Q_ASSERT(x <= m_colors.size() && x >= 0); - m_nColors -= m_colors[x].remove(y); // remove returns 1 if target found, else 0 - if (y == m_nRows.lastKey() - 1) { - m_nLastRowEntries--; - } - if (m_nLastRowEntries == 0) { - m_nRows.remove(m_nRows.lastKey()); - } -} - -void KoColorSetEntryGroup::setNColumns(int nColumns) -{ - m_colors.resize(nColumns); -} - -KoColorSetEntry KoColorSetEntryGroup::getEntry (int x, int y, bool &success) const -{ - Q_ASSERT(x >= 0 && x <= m_colors.size()); - if (m_colors[x].contains(y)) { - success = true; - return m_colors[x][y]; - } else { - success = false; - return NULLENTRY; - } -} diff --git a/libs/pigment/resources/KoColorSetEntryGroup.h b/libs/pigment/resources/KoColorSetEntryGroup.h deleted file mode 100644 index b4615c4a09..0000000000 --- a/libs/pigment/resources/KoColorSetEntryGroup.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef KOCOLORSETENTRYGROUP_H -#define KOCOLORSETENTRYGROUP_H - -#include "kritapigment_export.h" -#include -#include -#include // Used to keep track of the last row. Qt doesn't provide a priority queue... -#include "KoColorSetEntry.h" - -class KoColorSet; - -class KRITAPIGMENT_EXPORT KoColorSetEntryGroup -{ - static KoColorSetEntry NULLENTRY; -public: - typedef QHash Column; - -public: - KoColorSetEntryGroup(); - int nColors() const { return m_nColors; } - int nRows() const { return m_nRows.lastKey(); } // last is the largest - void setNColors(int n) { m_nColors = n; } - void setEntry(KoColorSetEntry e); - void setNColumns(int nColumns); - const QVector &colors() const { return m_colors; } - void removeEntry(int x, int y); - void clear() { m_colors.clear(); } - KoColorSetEntry getEntry (int x, int y, bool &success) const; - -private: - QVector m_colors; - int m_nColors; - QMap m_nRows; - int m_nLastRowEntries; - -friend class KoColorSet; -}; - -#endif // KOCOLORSETENTRYGROUP_H diff --git a/libs/pigment/resources/KoColorSet.cpp b/libs/pigment/resources/KoColorSet_p.cpp similarity index 68% copy from libs/pigment/resources/KoColorSet.cpp copy to libs/pigment/resources/KoColorSet_p.cpp index e663dcdcde..e28d9a5ee0 100644 --- a/libs/pigment/resources/KoColorSet.cpp +++ b/libs/pigment/resources/KoColorSet_p.cpp @@ -1,1633 +1,1137 @@ -/* 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 - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include - -#include -#include // qFromLittleEndian -#include // qMax - -#include -#include -#include -#include -#include #include +#include #include #include -#include #include #include #include +#include +#include +#include +#include +#include #include +#include +#include // qFromLittleEndian #include -#include -#include -#include - -#include -#include #include -#include -#include "KoColor.h" -#include "KoColorSet.h" -#include "KoColorSetEntry.h" -#include "KoColorSetEntryGroup.h" -#include "KoColorProfile.h" -#include "KoColorSpaceRegistry.h" -#include "KoColorModelStandardIds.h" - -struct KoColorSet::Private { - KoColorSet::PaletteType paletteType; - QByteArray data; - QString comment; - qint32 columns; - 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) { +#include +#include +#include +#include +#include +#include +#include +#include "KoColorSet_p.h" + +QString KoColorSet::Private::GLOBAL_GROUP_NAME = QString(); + +KoColorSet::PaletteType detectFormat(const QString &fileName, const QByteArray &ba) +{ QFileInfo fi(fileName); // .pal if (ba.startsWith("RIFF") && ba.indexOf("PAL data", 8)) { return KoColorSet::RIFF_PAL; } // .gpl else if (ba.startsWith("GIMP Palette")) { return KoColorSet::GPL; } // .pal else if (ba.startsWith("JASC-PAL")) { return KoColorSet::PSP_PAL; } else if (fi.suffix().toLower() == "aco") { return KoColorSet::ACO; } else if (fi.suffix().toLower() == "act") { return KoColorSet::ACT; } 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; } -KoColorSet::KoColorSet(const QString& filename) - : KoResource(filename) - , d(new Private()) +void scribusParseColor(KoColorSet *set, QXmlStreamReader *xml) { -} + KisSwatch colorEntry; + // It's a color, retrieve it + QXmlStreamAttributes colorProperties = xml->attributes(); -KoColorSet::KoColorSet() - : KoResource(QString()) - , d(new Private()) -{ + QStringRef colorName = colorProperties.value("NAME"); + colorEntry.setName(colorName.isEmpty() || colorName.isNull() ? i18n("Untitled") : colorName.toString()); -} + // RGB or CMYK? + if (colorProperties.hasAttribute("RGB")) { + dbgPigment << "Color " << colorProperties.value("NAME") << ", RGB " << colorProperties.value("RGB"); -/// Create an copied palette -KoColorSet::KoColorSet(const KoColorSet& rhs) - : QObject(0) - , KoResource(QString()) - , d(new Private()) -{ - setFilename(rhs.filename()); - d->comment = rhs.d->comment; - d->columns = rhs.d->columns; - d->global = rhs.d->global; - d->groupNames = rhs.d->groupNames; - d->groups = rhs.d->groups; - setValid(true); -} + KoColor currentColor(KoColorSpaceRegistry::instance()->rgb8()); + QStringRef colorValue = colorProperties.value("RGB"); -KoColorSet::~KoColorSet() -{ -} + if (colorValue.length() != 7 && colorValue.at(0) != '#') { // Color is a hexadecimal number + xml->raiseError("Invalid rgb8 color (malformed): " + colorValue); + return; + } else { + bool rgbOk; + quint32 rgb = colorValue.mid(1).toUInt(&rgbOk, 16); + if (!rgbOk) { + xml->raiseError("Invalid rgb8 color (unable to convert): " + colorValue); + return; + } -bool KoColorSet::load() -{ - QFile file(filename()); - if (file.size() == 0) return false; - if (!file.open(QIODevice::ReadOnly)) { - warnPigment << "Can't open file " << filename(); - return false; + quint8 r = rgb >> 16 & 0xff; + quint8 g = rgb >> 8 & 0xff; + quint8 b = rgb & 0xff; + + dbgPigment << "Color parsed: "<< r << g << b; + + currentColor.data()[0] = r; + currentColor.data()[1] = g; + currentColor.data()[2] = b; + currentColor.setOpacity(OPACITY_OPAQUE_U8); + colorEntry.setColor(currentColor); + + set->add(colorEntry); + + while(xml->readNextStartElement()) { + //ignore - these are all unknown or the /> element tag + xml->skipCurrentElement(); + } + return; + } } - bool res = loadFromDevice(&file); - file.close(); - return res; -} + else if (colorProperties.hasAttribute("CMYK")) { + dbgPigment << "Color " << colorProperties.value("NAME") << ", CMYK " << colorProperties.value("CMYK"); -bool KoColorSet::loadFromDevice(QIODevice *dev) -{ - if (!dev->isOpen()) dev->open(QIODevice::ReadOnly); + KoColor currentColor(KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Integer8BitsColorDepthID.id(), QString())); - d->data = dev->readAll(); + QStringRef colorValue = colorProperties.value("CMYK"); + if (colorValue.length() != 9 && colorValue.at(0) != '#') { // Color is a hexadecimal number + 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); + return; + } - Q_ASSERT(d->data.size() != 0); + quint8 c = cmyk >> 24 & 0xff; + quint8 m = cmyk >> 16 & 0xff; + quint8 y = cmyk >> 8 & 0xff; + quint8 k = cmyk & 0xff; - return init(); -} + dbgPigment << "Color parsed: "<< c << m << y << k; + currentColor.data()[0] = c; + currentColor.data()[1] = m; + currentColor.data()[2] = y; + currentColor.data()[3] = k; + currentColor.setOpacity(OPACITY_OPAQUE_U8); + colorEntry.setColor(currentColor); + + set->add(colorEntry); + + while(xml->readNextStartElement()) { + //ignore - these are all unknown or the /> element tag + xml->skipCurrentElement(); + } + return; + } + } + else { + xml->raiseError("Unknown color space for color " + colorEntry.name()); + } +} -bool KoColorSet::save() +bool loadScribusXmlPalette(KoColorSet *set, QXmlStreamReader *xml) { - QFile file(filename()); - if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + + //1. Get name + QXmlStreamAttributes paletteProperties = xml->attributes(); + QStringRef paletteName = paletteProperties.value("Name"); + dbgPigment << "Processed name of palette:" << paletteName; + set->setName(paletteName.toString()); + + //2. Inside the SCRIBUSCOLORS, there are lots of colors. Retrieve them + + while(xml->readNextStartElement()) { + QStringRef currentElement = xml->name(); + if(QStringRef::compare(currentElement, "COLOR", Qt::CaseInsensitive) == 0) { + scribusParseColor(set, xml); + } + else { + xml->skipCurrentElement(); + } + } + + if(xml->hasError()) { return false; } - saveToDevice(&file); - file.close(); + return true; } -bool KoColorSet::saveToDevice(QIODevice *dev) const +quint16 readShort(QIODevice *io) { + quint16 val; + quint64 read = io->read((char*)&val, 2); + if (read != 2) return false; + return qFromBigEndian(val); +} + + +KoColorSet::Private::Private(KoColorSet *a_colorSet) + : colorSet(a_colorSet) + , global(groups[GLOBAL_GROUP_NAME]) { - bool res; - switch(d->paletteType) { - case GPL: - res = saveGpl(dev); - break; - default: - res = saveKpl(dev); - } - if (res) { - KoResource::saveToDevice(dev); - } - return res; + } -bool KoColorSet::init() +bool KoColorSet::Private::init() { - d->global.clear(); // just in case this is a reload (eg by KoEditColorSetDialog), - d->groups.clear(); - d->groupNames.clear(); + // global.clear(); // just in case this is a reload (eg by KoEditColorSetDialog), + groups.clear(); + groupNames.clear(); - if (filename().isNull()) { - warnPigment << "Cannot load palette" << name() << "there is no filename set"; + if (colorSet->filename().isNull()) { + warnPigment << "Cannot load palette" << colorSet->name() << "there is no filename set"; return false; } - if (d->data.isNull()) { - QFile file(filename()); + if (data.isNull()) { + QFile file(colorSet->filename()); if (file.size() == 0) { - warnPigment << "Cannot load palette" << name() << "there is no data available"; + warnPigment << "Cannot load palette" << colorSet->name() << "there is no data available"; return false; } file.open(QIODevice::ReadOnly); - d->data = file.readAll(); + data = file.readAll(); file.close(); } bool res = false; - d->paletteType = detectFormat(filename(), d->data); - switch(d->paletteType) { + paletteType = detectFormat(colorSet->filename(), data); + switch(paletteType) { case GPL: res = loadGpl(); break; case ACT: res = loadAct(); break; case RIFF_PAL: res = loadRiff(); break; case PSP_PAL: res = loadPsp(); break; case ACO: res = loadAco(); break; case XML: res = loadXml(); break; case KPL: res = loadKpl(); break; case SBZ: res = loadSbz(); break; default: res = false; } - setValid(res); + colorSet->setValid(res); - if (d->columns == 0) { - d->columns = 10; - } - - QImage img(d->columns * 4, d->global.nRows() * 4, QImage::Format_ARGB32); + QImage img(global.nColumns() * 4, global.nRows() * 4, QImage::Format_ARGB32); QPainter gc(&img); gc.fillRect(img.rect(), Qt::darkGray); - Q_FOREACH (const KoColorSetEntryGroup::Column &col, d->global.colors()) { - Q_FOREACH (const KoColorSetEntry &entry, col.values()) { - QColor c = entry.color().toQColor(); - gc.fillRect(entry.x() * 4, entry.y() * 4, 4, 4, c); + for (int x = 0; x < global.nColumns(); x++) { + for (int y = 0; y < global.nRows(); y++) { + QColor c = global.getEntry(x, y).color().toQColor(); + gc.fillRect(x * 4, y * 4, 4, 4, c); } } - setImage(img); + colorSet->setImage(img); // save some memory - d->data.clear(); + data.clear(); return res; } -bool KoColorSet::saveGpl(QIODevice *dev) const +bool KoColorSet::Private::saveGpl(QIODevice *dev) const { QTextStream stream(dev); - stream << "GIMP Palette\nName: " << name() << "\nColumns: " << d->columns << "\n#\n"; + int columns = 0; + stream << "GIMP Palette\nName: " << colorSet->name() << "\nColumns: " << columns << "\n#\n"; - for (int y = 0; y < d->global.nRows(); y++) { - for (int x = 0; x < d->columns; x++) { - bool colorPresent; - const KoColorSetEntry& entry = d->global.getEntry(x, y, colorPresent); - if (!colorPresent) { continue; } + for (int y = 0; y < global.nRows(); y++) { + for (int x = 0; x < columns; x++) { + if (!global.checkEntry(x, y)) { + continue; + } + const KisSwatch& entry = global.getEntry(x, y); 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; } -quint32 KoColorSet::nColors() -{ - return d->global.nColors(); -} - -quint32 KoColorSet::nColorsGroup(QString groupName) -{ - if (d->groups.contains(groupName)) { - return d->groups[groupName].nColors(); - } else if (groupName.isEmpty()) { - return d->global.nColors(); - } 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; i < nColors(); i++) { - KoColor entry = getColorGlobal(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; - */ - return 0; -} - -QString KoColorSet::closestColorName(const KoColor color, bool useGivenColorSpace) -{ - /* - int i = getIndexClosestColor(color, useGivenColorSpace); - return getColorGlobal(i).name(); - */ - return QString(); -} - -void KoColorSet::add(KoColorSetEntry c, const QString &groupName) -{ - KoColorSetEntryGroup &modifiedGroup = - d->groups.contains(groupName) || d->groupNames.contains(groupName) - ? d->groups[groupName] : d->global; - if (c.x() == KoColorSetEntry::NULLPOSITON) { - c.setX(d->global.nColors() % d->columns); - c.setY(qMax(modifiedGroup.nRows(), modifiedGroup.nColors() / d->columns)); - } - modifiedGroup.setEntry(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; - */ - return 0; -} - -void KoColorSet::removeAt(quint32 x, quint32 y, QString groupName) -{ - /* - if (d->groups.contains(groupName)){ - if ((quint32)d->groups.value(groupName).size()>x) { - d->groups[groupName].remove(x); - } - } else { - if ((quint32)d->colors.size()>x) { - d->colors.remove(x); - } - } - */ - if (x >= d->columns || x < 0) - return; - if (d->groups.contains(groupName)){ - d->groups[groupName].removeEntry(x, y); - } else { - d->global.removeEntry(x, y); - } -} - -void KoColorSet::clear() -{ - d->global.clear(); - d->groups.clear(); - d->groupNames.clear(); -} - -KoColorSetEntry KoColorSet::getColorGlobal(quint32 x, quint32 y) -{ - KoColorSetEntry e; - QString groupName = findGroupByGlobalIndex(x, y); - e = getColorGroup(x, y, groupName); - return e; -} - -KoColorSetEntry KoColorSet::getColorGroup(quint32 x, quint32 y, QString groupName) -{ - KoColorSetEntry e; - bool entryFound; - if (d->groups.contains(groupName)) { - e = d->groups[groupName].getEntry(x, y, entryFound); - } else if (groupName.isEmpty()) { - e = d->global.getEntry(x, y, entryFound); - } else { - warnPigment << "Color group "<< groupName <<" not found"; - } - if (!entryFound) { - warnPigment << x << " " << y <<"doesn't exist in" << nColorsGroup(groupName); - } - return e; -} - -QString KoColorSet::findGroupByGlobalIndex(quint32 x, quint32 y) -{ - /* - *index = globalIndex; - QString groupName = QString(); - if ((quint32)d->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; - */ - return QString(); -} - -QString KoColorSet::findGroupByColorName(const QString &name, quint32 *x, quint32 *y) -{ - QString groupName = QString(); - Q_FOREACH (const KoColorSetEntryGroup::Column & col, d->global.colors()) { - Q_FOREACH (const KoColorSetEntry & entry, col.values()) { - if (entry.name() == name) { - *x = static_cast(entry.x()); - *y = static_cast(entry.y()); - return groupName; - } - } - } - QStringList groupNames = getGroupNames(); - Q_FOREACH (QString name, groupNames) { - Q_FOREACH (const KoColorSetEntryGroup::Column & col, d->groups[name].colors()) { - Q_FOREACH (const KoColorSetEntry & entry, col.values()) { - if (entry.name() == name) { - *x = static_cast(entry.x()); - *y = static_cast(entry.y()); - 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; - */ - return QString(); -} - -QStringList KoColorSet::getGroupNames() -{ - if (d->groupNames.size() != d->groups.size()) { - warnPigment << "mismatch between groups and the groupnames list."; - return QStringList(d->groups.keys()); - } - return d->groupNames; -} - -bool KoColorSet::changeGroupName(QString oldGroupName, QString newGroupName) -{ - if (d->groupNames.contains(oldGroupName)==false) { - return false; - } - KoColorSetEntryGroup tmp = d->groups.value(oldGroupName); - d->groups.remove(oldGroupName); - d->groups[newGroupName] = tmp; - //rename the string in the stringlist; - int index = d->groupNames.indexOf(oldGroupName); - d->groupNames.replace(index, newGroupName); - return true; -} - -bool KoColorSet::changeColorSetEntry(KoColorSetEntry entry, - QString groupName) -{ - if (!d->groupNames.contains(groupName)) { - return false; - } - if (groupName.isEmpty()) { - d->global.setEntry(entry); - } else { - d->groups[groupName].setEntry(entry); - } - return true; -} - -void KoColorSet::setColumnCount(int columns) -{ - d->columns = columns; - d->global.setNColumns(columns); - for (KoColorSetEntryGroup &g : d->groups.values()) { // Q_FOREACH doesn't accept non const refs - g.setNColumns(columns); - } -} - -int KoColorSet::columnCount() -{ - return d->columns; -} - -QString KoColorSet::comment() -{ - return d->comment; -} - -void KoColorSet::setComment(QString comment) -{ - d->comment = 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] = KoColorSetEntryGroup(); - return true; -} - -bool KoColorSet::moveGroup(const QString &groupName, const QString &groupNameInsertBefore) -{ - if (d->groupNames.contains(groupName)==false || d->groupNames.contains(groupNameInsertBefore)==false) { - return false; - } - d->groupNames.removeAt(d->groupNames.indexOf(groupName)); - int index = d->groupNames.size(); - if (groupNameInsertBefore!=QString()) { - index = d->groupNames.indexOf(groupNameInsertBefore); - } - d->groupNames.insert(index, groupName); - return true; -} - -bool KoColorSet::removeGroup(const QString &groupName, bool keepColors) -{ - if (!d->groups.contains(groupName)) { - return false; - } - - if (keepColors) { - // put all colors directly below global - KoColorSetEntry newEntry; - Q_FOREACH (const KoColorSetEntryGroup::Column & col, d->groups[groupName].colors()) { - Q_FOREACH (const KoColorSetEntry & entry, col.values()) { - newEntry = entry; - newEntry.setY(entry.y() + d->global.nRows()); - d->global.setEntry(newEntry); - } - } - } - - 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(".kpl"); -} - - -bool KoColorSet::loadGpl() +bool KoColorSet::Private::loadGpl() { - QString s = QString::fromUtf8(d->data.data(), d->data.count()); + QString s = QString::fromUtf8(data.data(), data.count()); if (s.isEmpty() || s.isNull() || s.length() < 50) { - warnPigment << "Illegal Gimp palette file: " << filename(); + warnPigment << "Illegal Gimp palette file: " << colorSet->filename(); return false; } quint32 index = 0; QStringList lines = s.split('\n', QString::SkipEmptyParts); if (lines.size() < 3) { - warnPigment << "Not enough lines in palette file: " << filename(); + warnPigment << "Not enough lines in palette file: " << colorSet->filename(); return false; } - QString columns; + QString columnsText; qint32 r, g, b; - KoColorSetEntry e; + KisSwatch e; // Read name - - if (!lines[0].startsWith("GIMP") || !lines[1].toLower().contains("name")) { - warnPigment << "Illegal Gimp palette file: " << filename(); + warnPigment << "Illegal Gimp palette file: " << colorSet->filename(); return false; } - setName(i18n(lines[1].split(":")[1].trimmed().toLatin1())); + colorSet->setName(i18n(lines[1].split(":")[1].trimmed().toLatin1())); index = 2; // Read columns + int columns = 0; if (lines[index].toLower().contains("columns")) { - columns = lines[index].split(":")[1].trimmed(); - d->columns = columns.toInt(); + columnsText = lines[index].split(":")[1].trimmed(); + columns = columnsText.toInt(); + global.setNColumns(columns); index = 3; } + int x = 0, y = 0; for (qint32 i = index; i < lines.size(); i++) { - if (lines[i].startsWith('#')) { - d->comment += lines[i].mid(1).trimmed() + ' '; + comment += lines[i].mid(1).trimmed() + ' '; } else if (!lines[i].isEmpty()) { QStringList a = lines[i].replace('\t', ' ').split(' ', QString::SkipEmptyParts); - if (a.count() < 3) { - break; - } - - r = a[0].toInt(); - a.pop_front(); - g = a[0].toInt(); - a.pop_front(); - b = a[0].toInt(); - a.pop_front(); - - r = qBound(0, r, 255); - g = qBound(0, g, 255); - b = qBound(0, b, 255); - - e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); - - QString name = a.join(" "); - e.setName(name.isEmpty() ? i18n("Untitled") : name); - - add(e); - } - } - return true; -} - -bool KoColorSet::loadAct() -{ - QFileInfo info(filename()); - setName(info.baseName()); - KoColorSetEntry e; - for (int i = 0; i < d->data.size(); i += 3) { - quint8 r = d->data[i]; - quint8 g = d->data[i+1]; - quint8 b = d->data[i+2]; - e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); - add(e); - } - return true; -} - -struct RiffHeader { - quint32 riff; - quint32 size; - quint32 signature; - quint32 data; - quint32 datasize; - quint16 version; - quint16 colorcount; -}; - - -bool KoColorSet::loadRiff() -{ - // http://worms2d.info/Palette_file - QFileInfo info(filename()); - setName(info.baseName()); - KoColorSetEntry e; - - RiffHeader header; - memcpy(&header, d->data.constData(), sizeof(RiffHeader)); - header.colorcount = qFromBigEndian(header.colorcount); - - for (int i = sizeof(RiffHeader); - (i < (int)(sizeof(RiffHeader) + header.colorcount) && i < d->data.size()); - i += 4) { - quint8 r = d->data[i]; - quint8 g = d->data[i+1]; - quint8 b = d->data[i+2]; - e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); - add(e); - } - return true; -} - - -bool KoColorSet::loadPsp() -{ - QFileInfo info(filename()); - setName(info.baseName()); - KoColorSetEntry e; - qint32 r, g, b; - - QString s = QString::fromUtf8(d->data.data(), d->data.count()); - QStringList l = s.split('\n', QString::SkipEmptyParts); - if (l.size() < 4) return false; - if (l[0] != "JASC-PAL") return false; - if (l[1] != "0100") return false; - - int entries = l[2].toInt(); - - for (int i = 0; i < entries; ++i) { - - QStringList a = l[i + 3].replace('\t', ' ').split(' ', QString::SkipEmptyParts); - - if (a.count() != 3) { - continue; - } - - r = a[0].toInt(); - a.pop_front(); - g = a[0].toInt(); - a.pop_front(); - b = a[0].toInt(); - a.pop_front(); - - r = qBound(0, r, 255); - g = qBound(0, g, 255); - b = qBound(0, b, 255); - - e.setColor(KoColor(QColor(r, g, b), - KoColorSpaceRegistry::instance()->rgb8())); - - QString name = a.join(" "); - e.setName(name.isEmpty() ? i18n("Untitled") : name); - - add(e); - } - return true; -} - -void scribusParseColor(KoColorSet *set, QXmlStreamReader *xml) -{ - KoColorSetEntry colorEntry; - // It's a color, retrieve it - QXmlStreamAttributes colorProperties = xml->attributes(); - - QStringRef colorName = colorProperties.value("NAME"); - colorEntry.setName(colorName.isEmpty() || colorName.isNull() ? i18n("Untitled") : colorName.toString()); - - // RGB or CMYK? - if (colorProperties.hasAttribute("RGB")) { - dbgPigment << "Color " << colorProperties.value("NAME") << ", RGB " << colorProperties.value("RGB"); - - KoColor currentColor(KoColorSpaceRegistry::instance()->rgb8()); - QStringRef colorValue = colorProperties.value("RGB"); - - if (colorValue.length() != 7 && colorValue.at(0) != '#') { // Color is a hexadecimal number - xml->raiseError("Invalid rgb8 color (malformed): " + colorValue); - return; - } else { - bool rgbOk; - quint32 rgb = colorValue.mid(1).toUInt(&rgbOk, 16); - if (!rgbOk) { - xml->raiseError("Invalid rgb8 color (unable to convert): " + colorValue); - return; - } - - quint8 r = rgb >> 16 & 0xff; - quint8 g = rgb >> 8 & 0xff; - quint8 b = rgb & 0xff; - - dbgPigment << "Color parsed: "<< r << g << b; - - currentColor.data()[0] = r; - currentColor.data()[1] = g; - currentColor.data()[2] = b; - currentColor.setOpacity(OPACITY_OPAQUE_U8); - colorEntry.setColor(currentColor); - - set->add(colorEntry); - - while(xml->readNextStartElement()) { - //ignore - these are all unknown or the /> element tag - xml->skipCurrentElement(); - } - return; - } - } - else if (colorProperties.hasAttribute("CMYK")) { - dbgPigment << "Color " << colorProperties.value("NAME") << ", CMYK " << colorProperties.value("CMYK"); - - KoColor currentColor(KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Integer8BitsColorDepthID.id(), QString())); - - QStringRef colorValue = colorProperties.value("CMYK"); - if (colorValue.length() != 9 && colorValue.at(0) != '#') { // Color is a hexadecimal number - 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); - return; - } - - quint8 c = cmyk >> 24 & 0xff; - quint8 m = cmyk >> 16 & 0xff; - quint8 y = cmyk >> 8 & 0xff; - quint8 k = cmyk & 0xff; - - dbgPigment << "Color parsed: "<< c << m << y << k; - - currentColor.data()[0] = c; - currentColor.data()[1] = m; - currentColor.data()[2] = y; - currentColor.data()[3] = k; - currentColor.setOpacity(OPACITY_OPAQUE_U8); - colorEntry.setColor(currentColor); - - set->add(colorEntry); - - while(xml->readNextStartElement()) { - //ignore - these are all unknown or the /> element tag - xml->skipCurrentElement(); + if (a.count() < 3) { + break; } - return; - } - } - else { - xml->raiseError("Unknown color space for color " + colorEntry.name()); - } -} -bool loadScribusXmlPalette(KoColorSet *set, QXmlStreamReader *xml) -{ + r = qBound(0, a[0].toInt(), 255); + g = qBound(0, a[1].toInt(), 255); + b = qBound(0, a[2].toInt(), 255); - //1. Get name - QXmlStreamAttributes paletteProperties = xml->attributes(); - QStringRef paletteName = paletteProperties.value("Name"); - dbgPigment << "Processed name of palette:" << paletteName; - set->setName(paletteName.toString()); + e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); - //2. Inside the SCRIBUSCOLORS, there are lots of colors. Retrieve them + QString name = a.join(" "); + e.setName(name.isEmpty() ? i18n("Untitled") : name); - while(xml->readNextStartElement()) { - QStringRef currentElement = xml->name(); - if(QStringRef::compare(currentElement, "COLOR", Qt::CaseInsensitive) == 0) { - scribusParseColor(set, xml); - } - else { - xml->skipCurrentElement(); + global.addEntry(e); } } + return true; +} - if(xml->hasError()) { - return false; +bool KoColorSet::Private::loadAct() +{ + QFileInfo info(colorSet->filename()); + colorSet->setName(info.baseName()); + KisSwatch e; + for (int i = 0; i < data.size(); i += 3) { + quint8 r = data[i]; + quint8 g = data[i+1]; + quint8 b = data[i+2]; + e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); + global.addEntry(e); } - return true; } -bool KoColorSet::loadXml() { - bool res = false; - - QXmlStreamReader *xml = new QXmlStreamReader(d->data); +bool KoColorSet::Private::loadRiff() +{ + // http://worms2d.info/Palette_file + QFileInfo info(colorSet->filename()); + colorSet->setName(info.baseName()); + KisSwatch e; - if (xml->readNextStartElement()) { - QStringRef paletteId = xml->name(); - if (QStringRef::compare(paletteId, "SCRIBUSCOLORS", Qt::CaseInsensitive) == 0) { // Scribus - dbgPigment << "XML palette: " << filename() << ", Scribus format"; - res = loadScribusXmlPalette(this, xml); - } - else { - // Unknown XML format - xml->raiseError("Unknown XML palette format. Expected SCRIBUSCOLORS, found " + paletteId); - } - } + RiffHeader header; + memcpy(&header, data.constData(), sizeof(RiffHeader)); + header.colorcount = qFromBigEndian(header.colorcount); - // If there is any error (it should be returned through the stream) - if (xml->hasError() || !res) { - warnPigment << "Illegal XML palette:" << filename(); - warnPigment << "Error (line"<< xml->lineNumber() << ", column" << xml->columnNumber() << "):" << xml->errorString(); - return false; - } - else { - dbgPigment << "XML palette parsed successfully:" << filename(); - return true; + for (int i = sizeof(RiffHeader); + (i < (int)(sizeof(RiffHeader) + header.colorcount) && i < data.size()); + i += 4) { + quint8 r = data[i]; + quint8 g = data[i+1]; + quint8 b = data[i+2]; + e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); + global.addEntry(e); } + return true; } -bool KoColorSet::saveKpl(QIODevice *dev) const + +bool KoColorSet::Private::loadPsp() { - QScopedPointer store(KoStore::createStore(dev, KoStore::Write, "application/x-krita-palette", KoStore::Zip)); - if (!store || store->bad()) return false; + QFileInfo info(colorSet->filename()); + colorSet->setName(info.baseName()); + KisSwatch e; + qint32 r, g, b; - QSet profiles; - QMap profileMap; + QString s = QString::fromUtf8(data.data(), data.count()); + QStringList l = s.split('\n', QString::SkipEmptyParts); + if (l.size() < 4) return false; + if (l[0] != "JASC-PAL") return false; + if (l[1] != "0100") return false; - { - 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 KoColorSetEntryGroup::Column &col, d->global.colors()) { - Q_FOREACH(const KoColorSetEntry &entry, col.values()) { - // 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 KoColorSetEntryGroup::Column &col, d->groups[groupName].colors()) { - Q_FOREACH(const KoColorSetEntry &entry, col.values()) { + int entries = l[2].toInt(); - // 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); - } - } + for (int i = 0; i < entries; ++i) { + + QStringList a = l[i + 3].replace('\t', ' ').split(' ', QString::SkipEmptyParts); + + if (a.count() != 3) { + continue; } - 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; } - } + r = qBound(0, a[0].toInt(), 255); + g = qBound(0, a[1].toInt(), 255); + b = qBound(0, a[2].toInt(), 255); - QDomDocument doc; - QDomElement profileElement = doc.createElement("Profiles"); + e.setColor(KoColor(QColor(r, g, b), + KoColorSpaceRegistry::instance()->rgb8())); - 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); + QString name = a.join(" "); + e.setName(name.isEmpty() ? i18n("Untitled") : name); + global.addEntry(e); } - 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(); + return true; } -bool KoColorSet::loadKpl() +bool KoColorSet::Private::loadKpl() { - QBuffer buf(&d->data); + QBuffer buf(&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(); + colorSet->setName(e.attribute("name")); + colorSet->setColumnCount(e.attribute("columns").toInt()); + comment = e.attribute("comment"); QDomElement c = e.firstChildElement("ColorSetEntry"); while (!c.isNull()) { QString colorDepthId = c.attribute("bitdepth", Integer8BitsColorDepthID.id()); - KoColorSetEntry entry; + KisSwatch entry; entry.setColor(KoColor::fromXML(c.firstChildElement(), colorDepthId)); entry.setName(c.attribute("name")); entry.setId(c.attribute("id")); entry.setSpotColor(c.attribute("spot", "false") == "true" ? true : false); - d->global.setEntry(entry); + global.addEntry(entry); c = c.nextSiblingElement("ColorSetEntry"); - } QDomElement g = e.firstChildElement("Group"); while (!g.isNull()) { QString groupName = g.attribute("name"); - addGroup(groupName); + colorSet->addGroup(groupName); QDomElement cg = g.firstChildElement("ColorSetEntry"); while (!cg.isNull()) { QString colorDepthId = cg.attribute("bitdepth", Integer8BitsColorDepthID.id()); - KoColorSetEntry entry; - + KisSwatch entry; entry.setColor(KoColor::fromXML(cg.firstChildElement(), colorDepthId)); entry.setName(cg.attribute("name")); entry.setId(cg.attribute("id")); entry.setSpotColor(cg.attribute("spot", "false") == "true" ? true : false); - add(entry, groupName); + groups[groupName].addEntry(entry); 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); - if (read != 2) return false; - return qFromBigEndian(val); -} - -bool KoColorSet::loadAco() +bool KoColorSet::Private::loadAco() { - QFileInfo info(filename()); - setName(info.baseName()); + QFileInfo info(colorSet->filename()); + colorSet->setName(info.baseName()); - QBuffer buf(&d->data); + QBuffer buf(&data); buf.open(QBuffer::ReadOnly); quint16 version = readShort(&buf); quint16 numColors = readShort(&buf); - KoColorSetEntry e; + KisSwatch e; if (version == 1 && buf.size() > 4+numColors*10) { buf.seek(4+numColors*10); version = readShort(&buf); numColors = readShort(&buf); } const quint16 quint16_MAX = 65535; for (int i = 0; i < numColors && !buf.atEnd(); ++i) { quint16 colorSpace = readShort(&buf); quint16 ch1 = readShort(&buf); quint16 ch2 = readShort(&buf); quint16 ch3 = readShort(&buf); quint16 ch4 = readShort(&buf); bool skip = false; if (colorSpace == 0) { // RGB const KoColorProfile *srgb = KoColorSpaceRegistry::instance()->rgb8()->profile(); KoColor c(KoColorSpaceRegistry::instance()->rgb16(srgb)); reinterpret_cast(c.data())[0] = ch3; reinterpret_cast(c.data())[1] = ch2; reinterpret_cast(c.data())[2] = ch1; c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else if (colorSpace == 1) { // HSB QColor qc; qc.setHsvF(ch1 / 65536.0, ch2 / 65536.0, ch3 / 65536.0); KoColor c(qc, KoColorSpaceRegistry::instance()->rgb16()); c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else if (colorSpace == 2) { // CMYK KoColor c(KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Integer16BitsColorDepthID.id(), QString())); reinterpret_cast(c.data())[0] = quint16_MAX - ch1; reinterpret_cast(c.data())[1] = quint16_MAX - ch2; reinterpret_cast(c.data())[2] = quint16_MAX - ch3; reinterpret_cast(c.data())[3] = quint16_MAX - ch4; c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else if (colorSpace == 7) { // LAB KoColor c = KoColor(KoColorSpaceRegistry::instance()->lab16()); reinterpret_cast(c.data())[0] = ch3; reinterpret_cast(c.data())[1] = ch2; reinterpret_cast(c.data())[2] = ch1; c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else if (colorSpace == 8) { // GRAY KoColor c(KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer16BitsColorDepthID.id(), QString())); reinterpret_cast(c.data())[0] = ch1 * (quint16_MAX / 10000); c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else { - warnPigment << "Unsupported colorspace in palette" << filename() << "(" << colorSpace << ")"; + warnPigment << "Unsupported colorspace in palette" << colorSet->filename() << "(" << colorSpace << ")"; skip = true; } if (version == 2) { quint16 v2 = readShort(&buf); //this isn't a version, it's a marker and needs to be skipped. Q_UNUSED(v2); quint16 size = readShort(&buf) -1; //then comes the length if (size>0) { QByteArray ba = buf.read(size*2); if (ba.size() == size*2) { QTextCodec *Utf16Codec = QTextCodec::codecForName("UTF-16BE"); e.setName(Utf16Codec->toUnicode(ba)); } else { - warnPigment << "Version 2 name block is the wrong size" << filename(); + warnPigment << "Version 2 name block is the wrong size" << colorSet->filename(); } } v2 = readShort(&buf); //end marker also needs to be skipped. Q_UNUSED(v2); } if (!skip) { - add(e); + global.addEntry(e); } } return true; } -bool KoColorSet::loadSbz() { - QBuffer buf(&d->data); +bool KoColorSet::Private::loadSbz() { + QBuffer buf(&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"; + dbgPigment << "XML palette: " << colorSet->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 << "Illegal XML palette:" << colorSet->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(); + colorSet->setName(colorName); + dbgPigment << "Processed name of palette:" << colorSet->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 materialsBook; QHash fileColorSpaces; // Color processing for(; !colorElement.isNull(); colorElement = colorElement.nextSiblingElement("color")) { - KoColorSetEntry currentEntry; + KisSwatch currentEntry; // Set if color is spot currentEntry.setSpotColor(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 currentEntry.setId(colorId.text()); currentEntry.setName(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() << ")"; } KoColor c(KoColorSpaceRegistry::instance()->colorSpace(LABAColorModelID.id(), Float32BitsColorDepthID.id(), QString())); reinterpret_cast(c.data())[0] = l; reinterpret_cast(c.data())[1] = a; reinterpret_cast(c.data())[2] = b; c.setOpacity(OPACITY_OPAQUE_F); firstDefinition = true; currentEntry.setColor(c); 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() << ")"; } KoColor c(KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), srgb)); reinterpret_cast(c.data())[0] = r; reinterpret_cast(c.data())[1] = g; reinterpret_cast(c.data())[2] = b; c.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(c); 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() << ")"; } KoColor c(KoColorSpaceRegistry::instance()->colorSpace(XYZAColorModelID.id(), Float32BitsColorDepthID.id(), QString())); reinterpret_cast(c.data())[0] = x; reinterpret_cast(c.data())[1] = y; reinterpret_cast(c.data())[2] = z; c.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(c); 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); } } KoColor color(colorSpace); reinterpret_cast(color.data())[0] = c; reinterpret_cast(color.data())[1] = m; reinterpret_cast(color.data())[2] = y; reinterpret_cast(color.data())[3] = k; color.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(color); 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); } } KoColor c(colorSpace); reinterpret_cast(c.data())[0] = g; c.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(c); 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); } } KoColor c(colorSpace); reinterpret_cast(c.data())[0] = r; reinterpret_cast(c.data())[1] = g; reinterpret_cast(c.data())[2] = b; c.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(c); firstDefinition = true; } else { warnPigment << "Color space not implemented:" << model << "(line" << colorValueE.lineNumber() << ", column "<< colorValueE.columnNumber() << ")"; } } if (firstDefinition) { materialsBook.insert(currentEntry.id(), currentEntry); } 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)); + global.addEntry(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); + groups[currentGroupName].addEntry(materialsBook.value(id)); } 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; } -const KoColorSetEntryGroup &KoColorSet::getGroupByName (const QString &groupName, bool &success) const -{ - if (groupName.isEmpty()) { - success = true; - return d->global; +bool KoColorSet::Private::loadXml() { + bool res = false; + + QXmlStreamReader *xml = new QXmlStreamReader(data); + + if (xml->readNextStartElement()) { + QStringRef paletteId = xml->name(); + if (QStringRef::compare(paletteId, "SCRIBUSCOLORS", Qt::CaseInsensitive) == 0) { // Scribus + dbgPigment << "XML palette: " << colorSet->filename() << ", Scribus format"; + res = loadScribusXmlPalette(colorSet, xml); + } + else { + // Unknown XML format + xml->raiseError("Unknown XML palette format. Expected SCRIBUSCOLORS, found " + paletteId); + } + } + + // If there is any error (it should be returned through the stream) + if (xml->hasError() || !res) { + warnPigment << "Illegal XML palette:" << colorSet->filename(); + warnPigment << "Error (line"<< xml->lineNumber() << ", column" << xml->columnNumber() << "):" << xml->errorString(); + return false; } - if (d->groupNames.contains(groupName)) { - success = true; - return d->groups[groupName]; + else { + dbgPigment << "XML palette parsed successfully:" << colorSet->filename(); + return true; } - success = false; - return d->global; } -int KoColorSet::rowCount() +bool KoColorSet::Private::saveKpl(QIODevice *dev) const { - int res = d->global.nRows(); - Q_FOREACH (QString name, d->groupNames) { - res += d->groups[name].nRows(); + 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", colorSet->name()); + root.setAttribute("comment", comment); + root.setAttribute("columns", global.nColumns()); + for (int x = 0; x < global.nColumns(); x++) { + for (int y = 0; y < global.nRows(); y++) { + // 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, groupNames) { + QDomElement gl = doc.createElement("Group"); + gl.setAttribute("name", groupName); + root.appendChild(gl); + for (int x = 0; x < groups[groupName].nColumns(); x++) { + for (int y = 0; y < groups[groupName].nRows(); y++) { + // 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; } } - return res; + + 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(); } diff --git a/libs/pigment/resources/KoColorSet_p.h b/libs/pigment/resources/KoColorSet_p.h new file mode 100644 index 0000000000..00e7c37e0f --- /dev/null +++ b/libs/pigment/resources/KoColorSet_p.h @@ -0,0 +1,60 @@ +#ifndef KOCOLORSET_P_H +#define KOCOLORSET_P_H + +#include +#include + +#include +#include + +#include "KoColorSet.h" + +struct RiffHeader { + quint32 riff; + quint32 size; + quint32 signature; + quint32 data; + quint32 datasize; + quint16 version; + quint16 colorcount; +}; + +KoColorSet::PaletteType detectFormat(const QString &fileName, const QByteArray &ba); +void scribusParseColor(KoColorSet *set, QXmlStreamReader *xml); +bool loadScribusXmlPalette(KoColorSet *set, QXmlStreamReader *xml); + +class KoColorSet::Private +{ +public: + Private(KoColorSet *a_colorSet); + +public: + 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(); + +public: + KoColorSet *colorSet; + KoColorSet::PaletteType paletteType; + QByteArray data; + QString comment; + QStringList groupNames; //names of the groups, this is used to determine the order they are in. + QHash groups; //grouped colors. + KisSwatchGroup &global; + +public: + static QString GLOBAL_GROUP_NAME; +}; + +#endif // KOCOLORSET_P_H diff --git a/libs/pigment/tests/TestKoColorSet.h b/libs/pigment/tests/TestKoColorSet.h index 5676b896f8..6e508828a6 100644 --- a/libs/pigment/tests/TestKoColorSet.h +++ b/libs/pigment/tests/TestKoColorSet.h @@ -1,17 +1,18 @@ #ifndef TESTKOCOLORSET_H #define TESTKOCOLORSET_H #include +#include + class TestKoColorSet : public QObject { Q_OBJECT public: explicit TestKoColorSet(QObject *parent = nullptr); -signals: - -public slots: +private Q_SLOTS: +private: }; -#endif // TESTKOCOLORSET_H \ No newline at end of file +#endif // TESTKOCOLORSET_H diff --git a/libs/widgets/CMakeLists.txt b/libs/widgets/CMakeLists.txt index 8df921ae88..a94757e40b 100644 --- a/libs/widgets/CMakeLists.txt +++ b/libs/widgets/CMakeLists.txt @@ -1,153 +1,154 @@ add_subdirectory( tests ) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(kritawidgets_LIB_SRCS KoGradientEditWidget.cpp KoVBox.cpp KoDialog.cpp KoZoomWidget.cpp KoTagToolButton.cpp KoTagChooserWidget.cpp KoTagFilterWidget.cpp KoResourceTaggingManager.cpp KoResourceItemChooserContextMenu.cpp KoAspectButton.cpp KoPagePreviewWidget.cpp KoSliderCombo.cpp KoColorPopupButton.cpp KoConfigAuthorPage.cpp KoUnitDoubleSpinBox.cpp KoZoomAction.cpp KoZoomController.cpp KoZoomInput.cpp KoZoomHandler.cpp KoZoomMode.cpp KoDpi.cpp KoColorPatch.cpp KoColorPopupAction.cpp KoColorSetWidget.cpp KoColorSlider.cpp KoEditColorSetDialog.cpp KoTriangleColorSelector.cpp KoResourcePopupAction.cpp KoIconToolTip.cpp KoResourceItemChooser.cpp KoResourceItemChooserSync.cpp KoResourceSelector.cpp KoResourceModel.cpp KoResourceItemDelegate.cpp KoResourceItemView.cpp KoResourceTagStore.cpp KoRuler.cpp KoItemToolTip.cpp KoCheckerBoardPainter.cpp KoResourceServerAdapter.cpp KoResourceServerProvider.cpp KoLineStyleSelector.cpp KoLineStyleItemDelegate.cpp KoLineStyleModel.cpp KoResourceFiltering.cpp KoTitledTabWidget.cpp KoToolBoxButton.cpp KoToolBox.cpp KoToolBoxDocker.cpp KoToolBoxFactory.cpp KoToolDocker.cpp KisPaletteModel.cpp kis_palette_delegate.cpp kis_palette_view.cpp KoPageLayoutWidget.cpp KoPageLayoutDialog.cpp KoShadowConfigWidget.cpp KoMarkerSelector.cpp KoMarkerModel.cpp KoMarkerItemDelegate.cpp KoDocumentInfoDlg.cpp KoTableView.cpp WidgetsDebug.cpp kis_file_name_requester.cpp kis_double_parse_spin_box.cpp kis_double_parse_unit_spin_box.cpp kis_int_parse_spin_box.cpp KisColorSelectorInterface.cpp KoAnchorSelectionWidget.cpp squeezedcombobox.cpp KisGradientSlider.cpp KisGradientSliderWidget.cpp kis_color_input.cpp # classes used by internal color selector kis_spinbox_color_selector.cpp KisVisualColorSelector.cpp KisVisualColorSelectorShape.cpp KisVisualEllipticalSelectorShape.cpp KisVisualRectangleSelectorShape.cpp KisVisualTriangleSelectorShape.cpp KisScreenColorPickerBase.cpp KisDlgInternalColorSelector.cpp KisPaletteListWidget.cpp KisPaletteListWidget_p.cpp KisPaletteModel.cpp kis_palette_delegate.cpp kis_palette_view.cpp kis_popup_button.cc kis_color_button.cpp KisScreenColorPickerBase.cpp KisColorsetChooser.cpp ) ki18n_wrap_ui( kritawidgets_LIB_SRCS KoConfigAuthorPage.ui koDocumentInfoAboutWidget.ui koDocumentInfoAuthorWidget.ui KoEditColorSet.ui wdg_file_name_requester.ui KoPageLayoutWidget.ui KoShadowConfigWidget.ui WdgDlgInternalColorSelector.ui + WdgPaletteListWidget.ui ) add_library(kritawidgets SHARED ${kritawidgets_LIB_SRCS}) generate_export_header(kritawidgets BASE_NAME kritawidgets) target_link_libraries(kritawidgets kritaodf kritaglobal kritaflake kritapigment kritawidgetutils Qt5::PrintSupport KF5::CoreAddons KF5::ConfigGui KF5::GuiAddons KF5::WidgetsAddons KF5::ConfigCore KF5::Completion ) if(X11_FOUND) target_link_libraries(kritawidgets Qt5::X11Extras ${X11_LIBRARIES}) endif() set_target_properties(kritawidgets PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritawidgets ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/widgets/KisColorsetChooser.cpp b/libs/widgets/KisColorsetChooser.cpp index e805854e59..88740ab5dd 100644 --- a/libs/widgets/KisColorsetChooser.cpp +++ b/libs/widgets/KisColorsetChooser.cpp @@ -1,162 +1,169 @@ /* This file is part of the KDE project * Copyright (C) 2013 Sven Langkamp * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisColorsetChooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_int_parse_spin_box.h" class ColorSetDelegate : public QAbstractItemDelegate { public: ColorSetDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} ~ColorSetDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } }; void ColorSetDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { + /* painter->save(); if (! index.isValid()) return; KoResource* resource = static_cast(index.internalPointer()); KoColorSet* colorSet = static_cast(resource); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); painter->setPen(option.palette.highlightedText().color()); } else { painter->setBrush(option.palette.text().color()); } painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, colorSet->name()); int size = 7; - 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->getColorGlobal(i).color().toQColor()); + for (quint32 x = 0; x < colorSet->columnCount(); x++) { + for (quint32 y = 0; y < colorSet->rowCount(); y++) { + QRect rect(option.rect.x() + x * size, + option.rect.y() + option.rect.height() - size, + size, + size); + painter->fillRect(rect, colorSet->getColorGlobal(x, y).color().toQColor()); + } } painter->restore(); + */ } KisColorsetChooser::KisColorsetChooser(QWidget* parent): QWidget(parent) { KoResourceServer * rserver = KoResourceServerProvider::instance()->paletteServer(); QSharedPointer adapter(new KoResourceServerAdapter(rserver)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->setItemDelegate(new ColorSetDelegate(this)); m_itemChooser->showTaggingBar(true); m_itemChooser->setFixedSize(250, 250); m_itemChooser->setRowHeight(30); m_itemChooser->setColumnCount(1); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); KConfigGroup cfg = KSharedConfig::openConfig()->group(""); m_itemChooser->configureKineticScrolling(cfg.readEntry("KineticScrollingGesture", 0), cfg.readEntry("KineticScrollingSensitivity", 75), cfg.readEntry("KineticScrollingScrollbar", true)); QPushButton* saveButton = new QPushButton(i18n("Save")); connect(saveButton, SIGNAL(clicked(bool)), this, SLOT(slotSave())); m_nameEdit = new QLineEdit(this); m_nameEdit->setPlaceholderText(i18n("Insert name")); m_nameEdit->setClearButtonEnabled(true); m_columnEdit = new KisIntParseSpinBox(this); m_columnEdit->setRange(1, 30); m_columnEdit->setValue(10); QGridLayout* layout = new QGridLayout(this); layout->addWidget(m_itemChooser, 0, 0, 1, 3); layout->setColumnStretch(1, 1); layout->addWidget(saveButton, 2, 2, 1, 1); layout->addWidget(m_nameEdit, 1, 1, 1, 2); layout->addWidget(new QLabel(i18n("Name:"), this), 1, 0, 1, 1); layout->addWidget(m_columnEdit, 2, 1, 1, 1); layout->addWidget(new QLabel(i18n("Columns:"), this), 2, 0, 1, 1); } KisColorsetChooser::~KisColorsetChooser() { } void KisColorsetChooser::resourceSelected(KoResource* resource) { emit paletteSelected(static_cast(resource)); } void KisColorsetChooser::slotSave() { KoResourceServer * rserver = KoResourceServerProvider::instance()->paletteServer(); KoColorSet* colorset = new KoColorSet(); colorset->setValid(true); QString saveLocation = rserver->saveLocation(); QString name = m_nameEdit->text(); int columns = m_columnEdit->value(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Palette"); } QFileInfo fileInfo(saveLocation + name + colorset->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + colorset->defaultFileExtension()); i++; } colorset->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Palette %1", i); } colorset->setName(name); colorset->setColumnCount(columns); rserver->addResource(colorset); } diff --git a/libs/widgets/KoEditColorSetDialog.cpp b/libs/widgets/KoEditColorSetDialog.cpp index 82d6163bef..7105f07c28 100644 --- a/libs/widgets/KoEditColorSetDialog.cpp +++ b/libs/widgets/KoEditColorSetDialog.cpp @@ -1,246 +1,246 @@ /* This file is part of the KDE project * Copyright (C) 2007 Fredy Yanardi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoEditColorSetDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include // debug #include #include "kis_palette_view.h" #include "KisPaletteModel.h" KoEditColorSetWidget::KoEditColorSetWidget(const QList &palettes, const QString &activePalette, QWidget *parent) : QWidget(parent), m_colorSets(palettes), m_gridLayout(0), m_activeColorSet(0), m_initialColorSetCount(palettes.count()), m_activeColorSetRequested(false) { widget.setupUi(this); foreach (KoColorSet *colorSet, m_colorSets) { widget.selector->addItem(colorSet->name()); } connect(widget.selector, SIGNAL(currentIndexChanged(int)), this, SLOT(setActiveColorSet(int))); // A widget that shows all colors from active palette // FIXME no need to handcode the QScrollArea if designer can add QScrollArea (Qt 4.4?) m_scrollArea = new QScrollArea(widget.patchesFrame); int index = 0; foreach (KoColorSet *set, m_colorSets) { if (set->name() == activePalette) { m_activeColorSet = set; index = widget.selector->findText(set->name()); widget.selector->setCurrentIndex(index); } } if (!m_activeColorSet && !palettes.isEmpty()) { m_activeColorSet = palettes.first(); index = widget.selector->findText(m_activeColorSet->name()); } int columns = 16; if(m_activeColorSet) { columns = m_activeColorSet->columnCount(); if (columns==0){ columns = 16; } } m_scrollArea->setMinimumWidth(columns*(12+2)); QHBoxLayout *layout = new QHBoxLayout(); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(m_scrollArea); widget.patchesFrame->setLayout(layout); widget.add->setIcon(koIcon("list-add")); widget.remove->setIcon(koIcon("list-remove")); widget.open->setIcon(koIcon("document-open")); widget.save->setIcon(koIcon("document-save")); setEnabled(m_activeColorSet != 0); setActiveColorSet(index); widget.remove->setEnabled(false); // initially no color selected connect(widget.add, SIGNAL(clicked()), this, SLOT(addColor())); connect(widget.remove, SIGNAL(clicked()), this, SLOT(removeColor())); connect(widget.open, SIGNAL(clicked()), this, SLOT(open())); connect(widget.save, SIGNAL(clicked()), this, SLOT(save())); } KoEditColorSetWidget::~KoEditColorSetWidget() { // only delete new color sets uint colorSetCount = m_colorSets.count(); for( uint i = m_initialColorSetCount; i < colorSetCount; ++i ) { KoColorSet * cs = m_colorSets[i]; // if the active color set was requested by activeColorSet() // the caller takes ownership and then we do not delete it here if( cs == m_activeColorSet && m_activeColorSetRequested ) continue; delete cs; } } void KoEditColorSetWidget::setActiveColorSet(int index) { if (m_gridLayout) { qDeleteAll(m_gridLayout->children()); delete m_gridLayout; } QWidget *wdg = new QWidget(m_scrollArea); m_gridLayout = new QGridLayout(); m_gridLayout->setMargin(0); m_gridLayout->setSpacing(2); 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;} KisPaletteView *paletteView = new KisPaletteView(this); KisPaletteModel *paletteModel = new KisPaletteModel(paletteView); QSharedPointer colorSet(new KoColorSet()); // paletteModel->setDisplayRenderer(displayRenderer); paletteModel->setColorSet(colorSet.data()); paletteView->setPaletteModel(paletteModel); m_gridLayout->addWidget(paletteView); /* for (quint32 i = 0; i < m_activeColorSet->nColors(); i++) { KoColorPatch *patch = new KoColorPatch(widget.patchesFrame); 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); } */ } m_scrollArea->setMinimumWidth(columns*(12+2)); wdg->setLayout(m_gridLayout); m_scrollArea->setWidget(wdg); } void KoEditColorSetWidget::setTextLabel(KoColorPatch *patch) { widget.colorName->setText(patch->toolTip()); widget.remove->setEnabled(true); } void KoEditColorSetWidget::addColor() { QColor color; color = QColorDialog::getColor(color); if (color.isValid()) { - KoColorSetEntry newEntry( + KisSwatch newEntry( KoColor(color, KoColorSpaceRegistry::instance()->rgb8()), QInputDialog::getText(this, i18n("Add Color To Palette"), i18n("Color name:"))); KoColorPatch *patch = new KoColorPatch(widget.patchesFrame); patch->setColor(newEntry.color()); patch->setToolTip(newEntry.name()); connect(patch, SIGNAL(triggered(KoColorPatch *)), this, SLOT(setTextLabel(KoColorPatch *))); Q_ASSERT(m_gridLayout); Q_ASSERT(m_activeColorSet); m_gridLayout->addWidget(patch, m_activeColorSet->nColors()/m_activeColorSet->columnCount(), m_activeColorSet->nColors()%m_activeColorSet->columnCount()); m_activeColorSet->add(newEntry); } } void KoEditColorSetWidget::removeColor() { Q_ASSERT(m_activeColorSet); /* 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; } } */ } void KoEditColorSetWidget::open() { Q_ASSERT(m_activeColorSet); KoFileDialog dialog(this, KoFileDialog::OpenFile, "OpenColorSet"); dialog.setDefaultDir(m_activeColorSet->filename()); dialog.setMimeTypeFilters(QStringList() << "application/x-gimp-color-palette"); QString fileName = dialog.filename(); KoColorSet *colorSet = new KoColorSet(fileName); colorSet->load(); m_colorSets.append(colorSet); widget.selector->addItem(colorSet->name()); widget.selector->setCurrentIndex(widget.selector->count() - 1); } void KoEditColorSetWidget::save() { Q_ASSERT(m_activeColorSet); if (!m_activeColorSet->save()) KMessageBox::error(0, i18n("Cannot write to palette file %1. Maybe it is read-only. ", m_activeColorSet->filename()), i18n("Palette")); } KoColorSet *KoEditColorSetWidget::activeColorSet() { m_activeColorSetRequested = true; return m_activeColorSet; } KoEditColorSetDialog::KoEditColorSetDialog(const QList &palettes, const QString &activePalette, QWidget *parent) : KoDialog(parent) { ui = new KoEditColorSetWidget(palettes, activePalette, this); setMainWidget(ui); setCaption(i18n("Add/Remove Colors")); enableButton(KoDialog::Ok, ui->isEnabled()); } KoEditColorSetDialog::~KoEditColorSetDialog() { delete ui; } KoColorSet *KoEditColorSetDialog::activeColorSet() { return ui->activeColorSet(); } diff --git a/plugins/dockers/palettedocker/palettedocker_dock.cpp b/plugins/dockers/palettedocker/palettedocker_dock.cpp index 6b1732a485..a885562912 100644 --- a/plugins/dockers/palettedocker/palettedocker_dock.cpp +++ b/plugins/dockers/palettedocker/palettedocker_dock.cpp @@ -1,306 +1,306 @@ /* * Copyright (c) 2013 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "palettedocker_dock.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisPaletteModel.h" #include "ui_wdgpalettedock.h" #include "kis_palette_delegate.h" #include "kis_palette_view.h" -#include +#include PaletteDockerDock::PaletteDockerDock( ) : QDockWidget(i18n("Palette")) , m_wdgPaletteDock(new Ui_WdgPaletteDock()) , m_currentColorSet(0) , m_resourceProvider(0) , m_canvas(0) { QWidget* mainWidget = new QWidget(this); setWidget(mainWidget); m_wdgPaletteDock->setupUi(mainWidget); m_wdgPaletteDock->bnAdd->setIcon(KisIconUtils::loadIcon("list-add")); m_wdgPaletteDock->bnAdd->setIconSize(QSize(16, 16)); m_wdgPaletteDock->bnRemove->setIcon(KisIconUtils::loadIcon("edit-delete")); m_wdgPaletteDock->bnRemove->setIconSize(QSize(16, 16)); m_wdgPaletteDock->bnAdd->setEnabled(false); m_wdgPaletteDock->bnRemove->setEnabled(false); m_wdgPaletteDock->bnAddDialog->setVisible(false); m_wdgPaletteDock->bnAddGroup->setIcon(KisIconUtils::loadIcon("groupLayer")); m_wdgPaletteDock->bnAddGroup->setIconSize(QSize(16, 16)); m_model = new KisPaletteModel(this); m_wdgPaletteDock->paletteView->setPaletteModel(m_model); connect(m_wdgPaletteDock->bnAdd, SIGNAL(clicked(bool)), this, SLOT(addColorForeground())); connect(m_wdgPaletteDock->bnRemove, SIGNAL(clicked(bool)), this, SLOT(removeColor())); connect(m_wdgPaletteDock->bnAddGroup, SIGNAL(clicked(bool)), m_wdgPaletteDock->paletteView, SLOT(addGroupWithDialog())); connect(m_wdgPaletteDock->paletteView, SIGNAL(entrySelected(KoColorSetEntry)), this, SLOT(entrySelected(KoColorSetEntry))); connect(m_wdgPaletteDock->paletteView, SIGNAL(entrySelectedBackGround(KoColorSetEntry)), this, SLOT(entrySelectedBack(KoColorSetEntry))); KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); m_serverAdapter = QSharedPointer(new KoResourceServerAdapter(rServer)); m_serverAdapter->connectToResourceServer(); rServer->addObserver(this); - m_paletteChooser = new KisColorsetChooser(this); + m_paletteChooser = new KisPaletteListWidget(this); connect(m_paletteChooser, SIGNAL(paletteSelected(KoColorSet*)), this, SLOT(setColorSet(KoColorSet*))); m_wdgPaletteDock->bnColorSets->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); m_wdgPaletteDock->bnColorSets->setToolTip(i18n("Choose palette")); m_wdgPaletteDock->bnColorSets->setPopupWidget(m_paletteChooser); connect(m_wdgPaletteDock->cmbNameList, SIGNAL(currentIndexChanged(int)), this, SLOT(setColorFromNameList(int))); KisConfig cfg; QString defaultPalette = cfg.defaultPalette(); KoColorSet* defaultColorSet = rServer->resourceByName(defaultPalette); if (defaultColorSet) { setColorSet(defaultColorSet); } } PaletteDockerDock::~PaletteDockerDock() { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); rServer->removeObserver(this); if (m_currentColorSet) { KisConfig cfg; cfg.setDefaultPalette(m_currentColorSet->name()); } delete m_wdgPaletteDock->paletteView->itemDelegate(); delete m_wdgPaletteDock; } void PaletteDockerDock::setMainWindow(KisViewManager* kisview) { m_resourceProvider = kisview->resourceProvider(); connect(m_resourceProvider, SIGNAL(sigSavingWorkspace(KisWorkspaceResource*)), SLOT(saveToWorkspace(KisWorkspaceResource*))); connect(m_resourceProvider, SIGNAL(sigLoadingWorkspace(KisWorkspaceResource*)), SLOT(loadFromWorkspace(KisWorkspaceResource*))); connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)),m_wdgPaletteDock->paletteView, SLOT(trySelectClosestColor(KoColor))); kisview->nodeManager()->disconnect(m_model); } void PaletteDockerDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); if (canvas) { KisCanvas2 *cv = qobject_cast(canvas); m_model->setDisplayRenderer(cv->displayColorConverter()->displayRendererInterface()); } m_canvas = static_cast(canvas); } void PaletteDockerDock::unsetCanvas() { setEnabled(false); m_model->setDisplayRenderer(0); m_canvas = 0; } void PaletteDockerDock::unsetResourceServer() { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); rServer->removeObserver(this); } void PaletteDockerDock::removingResource(KoColorSet *resource) { if (resource == m_currentColorSet) { setColorSet(0); } } void PaletteDockerDock::resourceChanged(KoColorSet *resource) { setColorSet(resource); } void PaletteDockerDock::setColorSet(KoColorSet* colorSet) { m_model->setColorSet(colorSet); m_wdgPaletteDock->paletteView->updateView(); m_wdgPaletteDock->paletteView->updateRows(); m_wdgPaletteDock->cmbNameList->clear(); /* if (colorSet && colorSet->nColors()>0) { for (quint32 i = 0; i< colorSet->nColors(); i++) { KoColorSetEntry entry = colorSet->getColorGlobal(i); QPixmap colorSquare = QPixmap(32, 32); if (entry.spotColor()) { QImage img = QImage(32, 32, QImage::Format_ARGB32); QPainter circlePainter; img.fill(Qt::transparent); circlePainter.begin(&img); QBrush brush = QBrush(Qt::SolidPattern); brush.setColor(entry.color().toQColor()); circlePainter.setBrush(brush); QPen pen = circlePainter.pen(); pen.setColor(Qt::transparent); pen.setWidth(0); circlePainter.setPen(pen); circlePainter.drawEllipse(0, 0, 32, 32); circlePainter.end(); colorSquare = QPixmap::fromImage(img); } else { colorSquare.fill(entry.color().toQColor()); } QString name = entry.name(); if (!entry.id().isEmpty()){ name = entry.id() + " - " + entry.name(); } m_wdgPaletteDock->cmbNameList->addSqueezedItem(QIcon(colorSquare), name); } } */ QCompleter *completer = new QCompleter(m_wdgPaletteDock->cmbNameList->model()); completer->setCompletionMode(QCompleter::PopupCompletion); completer->setCaseSensitivity(Qt::CaseInsensitive); completer->setFilterMode(Qt::MatchContains); m_wdgPaletteDock->cmbNameList->setCompleter(completer); if (colorSet && colorSet->removable()) { m_wdgPaletteDock->bnAdd->setEnabled(true); m_wdgPaletteDock->bnRemove->setEnabled(true); } else { m_wdgPaletteDock->bnAdd->setEnabled(false); m_wdgPaletteDock->bnRemove->setEnabled(false); } m_currentColorSet = colorSet; } void PaletteDockerDock::setColorFromNameList(int index) { if (m_model && m_currentColorSet) { // entrySelected(m_currentColorSet->getColorGlobal(index)); m_wdgPaletteDock->paletteView->blockSignals(true); m_wdgPaletteDock->cmbNameList->blockSignals(true); m_wdgPaletteDock->cmbNameList->setCurrentIndex(index); m_wdgPaletteDock->paletteView->selectionModel()->clearSelection(); m_wdgPaletteDock->paletteView->selectionModel()->setCurrentIndex(m_model->indexFromId(index), QItemSelectionModel::Select); m_wdgPaletteDock->paletteView->blockSignals(false); m_wdgPaletteDock->cmbNameList->blockSignals(false); } } void PaletteDockerDock::addColorForeground() { if (m_resourceProvider) { //setup dialog m_wdgPaletteDock->paletteView->addEntryWithDialog(m_resourceProvider->fgColor()); } } void PaletteDockerDock::removeColor() { QModelIndex index = m_wdgPaletteDock->paletteView->currentIndex(); if (!index.isValid()) { return; } m_wdgPaletteDock->paletteView->removeEntryWithDialog(index); } void PaletteDockerDock::entrySelected(KoColorSetEntry entry) { if (m_wdgPaletteDock->paletteView->currentIndex().isValid()) { quint32 index = m_model->idFromIndex(m_wdgPaletteDock->paletteView->currentIndex()); m_wdgPaletteDock->cmbNameList->setCurrentIndex(index); } if (m_resourceProvider) { m_resourceProvider->setFGColor(entry.color()); } if (m_currentColorSet->removable()) { m_wdgPaletteDock->bnRemove->setEnabled(true); } } void PaletteDockerDock::entrySelectedBack(KoColorSetEntry entry) { if (m_wdgPaletteDock->paletteView->currentIndex().isValid()) { quint32 index = m_model->idFromIndex(m_wdgPaletteDock->paletteView->currentIndex()); m_wdgPaletteDock->cmbNameList->setCurrentIndex(index); } if (m_resourceProvider) { m_resourceProvider->setBGColor(entry.color()); } if (m_currentColorSet->removable()) { m_wdgPaletteDock->bnRemove->setEnabled(true); } } void PaletteDockerDock::saveToWorkspace(KisWorkspaceResource* workspace) { if (m_currentColorSet) { workspace->setProperty("palette", m_currentColorSet->name()); } } void PaletteDockerDock::loadFromWorkspace(KisWorkspaceResource* workspace) { if (workspace->hasProperty("palette")) { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); KoColorSet* colorSet = rServer->resourceByName(workspace->getString("palette")); if (colorSet) { setColorSet(colorSet); } } }