diff --git a/libs/libkis/CMakeLists.txt b/libs/libkis/CMakeLists.txt index 34903a1e9f..538fd12bda 100644 --- a/libs/libkis/CMakeLists.txt +++ b/libs/libkis/CMakeLists.txt @@ -1,35 +1,36 @@ set(kritalibkis_LIB_SRCS Action.cpp Canvas.cpp Channel.cpp DockWidget.cpp DockWidgetFactoryBase.cpp Document.cpp Filter.cpp InfoObject.cpp Krita.cpp + ManagedColor.cpp Node.cpp Notifier.cpp PresetChooser Palette.cpp Resource.cpp Selection.cpp View.cpp Extension.cpp Window.cpp ) add_library(kritalibkis SHARED ${kritalibkis_LIB_SRCS} ) generate_export_header(kritalibkis) target_link_libraries(kritalibkis kritaui kritaimage kritaversion) target_link_libraries(kritalibkis LINK_INTERFACE_LIBRARIES kritaimage kritaui) set_target_properties(kritalibkis PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritalibkis ${INSTALL_TARGETS_DEFAULT_ARGS}) add_subdirectory(tests) diff --git a/libs/libkis/Canvas.cpp b/libs/libkis/Canvas.cpp index 378d38bf2d..0bbddf9979 100644 --- a/libs/libkis/Canvas.cpp +++ b/libs/libkis/Canvas.cpp @@ -1,136 +1,142 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * 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 "Canvas.h" #include #include #include #include #include #include #include #include struct Canvas::Private { Private() {} KisCanvas2 *canvas; }; Canvas::Canvas(KoCanvasBase *canvas, QObject *parent) : QObject(parent) , d(new Private) { d->canvas = static_cast(canvas); } Canvas::~Canvas() { delete d; } bool Canvas::operator==(const Canvas &other) const { return (d->canvas == other.d->canvas); } bool Canvas::operator!=(const Canvas &other) const { return !(operator==(other)); } qreal Canvas::zoomLevel() const { if (!d->canvas) return 1.0; return d->canvas->imageView()->zoomManager()->zoom(); } void Canvas::setZoomLevel(qreal value) { if (!d->canvas) return; d->canvas->imageView()->zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, value); } void Canvas::resetZoom() { if (!d->canvas) return; d->canvas->imageView()->zoomManager()->zoomTo100(); } void Canvas::resetRotation() { if (!d->canvas) return; d->canvas->imageView()->canvasController()->resetCanvasRotation(); } qreal Canvas::rotation() const { if (!d->canvas) return 0; return d->canvas->imageView()->canvasController()->rotation(); } void Canvas::setRotation(qreal angle) { if (!d->canvas) return; d->canvas->imageView()->canvasController()->rotateCanvas(angle); } bool Canvas::mirror() const { if (!d->canvas) return false; return d->canvas->imageView()->canvasIsMirrored(); } void Canvas::setMirror(bool value) { if (!d->canvas) return; d->canvas->imageView()->canvasController()->mirrorCanvas(value); } View *Canvas::view() const { if (!d->canvas) return 0; View *view = new View(d->canvas->imageView()); return view; } +KisDisplayColorConverter *Canvas::displayColorConverter() const +{ + if (!d->canvas) return 0; + return d->canvas->displayColorConverter(); +} + bool Canvas::wrapAroundMode() const { if (!d->canvas) return false; return d->canvas->imageView()->canvasController()->wrapAroundMode(); } void Canvas::setWrapAroundMode(bool enable) { if (!d->canvas) return; d->canvas->imageView()->canvasController()->slotToggleWrapAroundMode(enable); } bool Canvas::levelOfDetailMode() const { if (!d->canvas) return false; return d->canvas->imageView()->canvasController()->levelOfDetailMode(); } void Canvas::setLevelOfDetailMode(bool enable) { if (!d->canvas) return; return d->canvas->imageView()->canvasController()->slotToggleLevelOfDetailMode(enable); } diff --git a/libs/libkis/Canvas.h b/libs/libkis/Canvas.h index 151b66446f..c014545fde 100644 --- a/libs/libkis/Canvas.h +++ b/libs/libkis/Canvas.h @@ -1,119 +1,125 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * 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_CANVAS_H #define LIBKIS_CANVAS_H #include #include "kritalibkis_export.h" #include "libkis.h" class KoCanvasBase; +class KisDisplayColorConverter; /** * Canvas wraps the canvas inside a view on an image/document. * It is responsible for the view parameters of the document: * zoom, rotation, mirror, wraparound and instant preview. */ class KRITALIBKIS_EXPORT Canvas : public QObject { Q_OBJECT public: explicit Canvas(KoCanvasBase *canvas, QObject *parent = 0); ~Canvas() override; bool operator==(const Canvas &other) const; bool operator!=(const Canvas &other) const; - + public Q_SLOTS: /** * @return the current zoomlevel. 1.0 is 100%. */ qreal zoomLevel() const; /** * @brief setZoomLevel set the zoomlevel to the given @param value. 1.0 is 100%. */ void setZoomLevel(qreal value); /** * @brief resetZoom set the zoomlevel to 100% */ void resetZoom(); /** * @return the rotation of the canvas in degrees. */ qreal rotation() const; /** * @brief setRotation set the rotation of the canvas to the given @param angle in degrees. */ void setRotation(qreal angle); /** * @brief resetRotation reset the canvas rotation. */ void resetRotation(); /** * @return return true if the canvas is mirrored, false otherwise. */ bool mirror() const; /** * @brief setMirror turn the canvas mirroring on or off depending on @param value */ void setMirror(bool value); /** * @return true if the canvas is in wraparound mode, false if not. Only when OpenGL is enabled, * is wraparound mode available. */ bool wrapAroundMode() const; /** * @brief setWrapAroundMode set wraparound mode to @param enable */ void setWrapAroundMode(bool enable); /** * @return true if the canvas is in Instant Preview mode, false if not. Only when OpenGL is enabled, * is Instant Preview mode available. */ bool levelOfDetailMode() const; /** * @brief setLevelOfDetailMode sets Instant Preview to @param enable */ void setLevelOfDetailMode(bool enable); /** * @return the view that holds this canvas */ View *view() const; private: + + friend class ManagedColor; + + KisDisplayColorConverter *displayColorConverter() const; + struct Private; Private *const d; }; #endif // LIBKIS_CANVAS_H diff --git a/libs/libkis/ManagedColor.cpp b/libs/libkis/ManagedColor.cpp new file mode 100644 index 0000000000..d6a68786c5 --- /dev/null +++ b/libs/libkis/ManagedColor.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2017 Boudewijn Rempt + * + * 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 "ManagedColor.h" +#include +#include +#include +#include + +#include +#include + +#include + +#include + +struct ManagedColor::Private { + KoColor color; +}; + + + +ManagedColor::ManagedColor(QObject *parent) + : QObject(parent) + , d(new Private()) +{ + // Default black rgb color +} + +ManagedColor::ManagedColor(const QString &colorModel, const QString &colorDepth, const QString &colorProfile, QObject *parent) + : QObject(parent) + , d(new Private()) +{ + const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, colorProfile); + if (colorSpace) { + d->color = KoColor(colorSpace); + } +} + + +ManagedColor::ManagedColor(KoColor color, QObject *parent) + : QObject(parent) + , d(new Private()) +{ + d->color = color; +} + +ManagedColor::~ManagedColor() +{ +} + +bool ManagedColor::operator==(const ManagedColor &other) const +{ + return d->color == other.d->color; +} + +QColor ManagedColor::colorForCanvas(Canvas *canvas) const +{ + KisDisplayColorConverter *converter = canvas->displayColorConverter(); + return converter->toQColor(d->color); +} + +QString ManagedColor::colorDepth() const +{ + return d->color.colorSpace()->colorDepthId().id(); +} + +QString ManagedColor::colorModel() const +{ + return d->color.colorSpace()->colorModelId().id(); +} + +QString ManagedColor::colorProfile() const +{ + return d->color.colorSpace()->profile()->name(); +} + +bool ManagedColor::setColorProfile(const QString &colorProfile) +{ + const KoColorProfile *profile = KoColorSpaceRegistry::instance()->profileByName(colorProfile); + if (!profile) return false; + d->color.setProfile(profile); + return true; +} + +bool ManagedColor::setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile) +{ + const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, colorProfile); + if (!colorSpace) return false; + d->color.convertTo(colorSpace); + return true; +} + +QVector ManagedColor::components() const +{ + QVector values(d->color.colorSpace()->channelCount()); + d->color.colorSpace()->normalisedChannelsValue(d->color.data(), values); + return values; +} + +void ManagedColor::setComponents(const QVector &values) +{ + d->color.colorSpace()->fromNormalisedChannelsValue(d->color.data(), values); +} + +QString ManagedColor::toXML() const +{ + QDomDocument doc; + QDomElement root = doc.createElement("Color"); + root.setAttribute("bitdepth", colorDepth()); + doc.appendChild(root); + d->color.toXML(doc, root); + return doc.toString(); +} + +void ManagedColor::fromXML(const QString &xml) +{ + QDomDocument doc; + doc.setContent(xml); + QDomElement e = doc.documentElement(); + QDomElement c = e.firstChildElement("Color"); + KoColor kc; + if (!c.isNull()) { + QString colorDepthId = c.attribute("bitdepth", Integer8BitsColorDepthID.id()); + d->color = KoColor::fromXML(c, colorDepthId); + } + +} + +QString ManagedColor::toQString() +{ + return KoColor::toQString(d->color); +} diff --git a/libs/libkis/ManagedColor.h b/libs/libkis/ManagedColor.h new file mode 100644 index 0000000000..11a306e702 --- /dev/null +++ b/libs/libkis/ManagedColor.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2017 Boudewijn Rempt + * + * 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. + */ + +#ifndef MANAGEDCOLOR_H +#define MANAGEDCOLOR_H + +#include +#include +#include + +#include "kritalibkis_export.h" +#include "libkis.h" + +class KoColor; + +/** + * @brief The ManagedColor class ... + */ +class KRITALIBKIS_EXPORT ManagedColor : public QObject +{ + Q_OBJECT +public: + explicit ManagedColor(QObject *parent = 0); + ManagedColor(const QString &colorModel, const QString &colorDepth, const QString &colorProfile, QObject *parent = 0); + ManagedColor(KoColor color, QObject *parent = 0); + ~ManagedColor() override; + + bool operator==(const ManagedColor &other) const; + + QColor colorForCanvas(Canvas *canvas) const; + /** + * colorDepth A string describing the color depth of the image: + *
    + *
  • U8: unsigned 8 bits integer, the most common type
  • + *
  • U16: unsigned 16 bits integer
  • + *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • + *
  • F32: 32 bits floating point
  • + *
+ * @return the color depth. + */ + QString colorDepth() const; + + /** + * @brief colorModel retrieve the current color model of this document: + *
    + *
  • A: Alpha mask
  • + *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • + *
  • XYZA: XYZ with alpha channel
  • + *
  • LABA: LAB with alpha channel
  • + *
  • CMYKA: CMYK with alpha channel
  • + *
  • GRAYA: Gray with alpha channel
  • + *
  • YCbCrA: YCbCr with alpha channel
  • + *
+ * @return the internal color model string. + */ + QString colorModel() const; + + /** + * @return the name of the current color profile + */ + QString colorProfile() const; + + /** + * @brief setColorProfile set the color profile of the image to the given profile. The profile has to + * be registered with krita and be compatible with the current color model and depth; the image data + * is not converted. + * @param colorProfile + * @return false if the colorProfile name does not correspond to to a registered profile or if assigning + * the profile failed. + */ + bool setColorProfile(const QString &colorProfile); + + /** + * @brief setColorSpace convert the nodes and the image to the given colorspace. The conversion is + * done with Perceptual as intent, High Quality and No LCMS Optimizations as flags and no blackpoint + * compensation. + * + * @param colorModel A string describing the color model of the image: + *
    + *
  • A: Alpha mask
  • + *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • + *
  • XYZA: XYZ with alpha channel
  • + *
  • LABA: LAB with alpha channel
  • + *
  • CMYKA: CMYK with alpha channel
  • + *
  • GRAYA: Gray with alpha channel
  • + *
  • YCbCrA: YCbCr with alpha channel
  • + *
+ * @param colorDepth A string describing the color depth of the image: + *
    + *
  • U8: unsigned 8 bits integer, the most common type
  • + *
  • U16: unsigned 16 bits integer
  • + *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • + *
  • F32: 32 bits floating point
  • + *
+ * @param colorProfile a valid color profile for this color model and color depth combination. + * @return false the combination of these arguments does not correspond to a colorspace. + */ + bool setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile); + + /** + * @brief components + * @return + */ + QVector components() const; + + /** + * @brief setComponents + * @param values + */ + void setComponents(const QVector &values); + + /** + * Serialize this color following Create's swatch color specification available + * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format + */ + QString toXML() const; + + /** + * Unserialize a color following Create's swatch color specification available + * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format + * + * @param XXX + * + * @return the unserialized color, or an empty color object if the function failed + * to unserialize the color + */ + void fromXML(const QString &xml); + + /** + * @brief toQString create a user-visible string of the channel names and the channel values + * @param color the color to create the string from + * @return a string that can be used to display the values of this color to the user. + */ + QString toQString(); + + +private: + struct Private; + const QScopedPointer d; + +}; + +#endif // MANAGEDCOLOR_H diff --git a/libs/libkis/Palette.cpp b/libs/libkis/Palette.cpp index 0dd31c105c..50b0b658d3 100644 --- a/libs/libkis/Palette.cpp +++ b/libs/libkis/Palette.cpp @@ -1,63 +1,68 @@ /* * 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 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::columnCount() { return d->palette->columnCount(); } void Palette::setColumnCount(int columns) { d->palette->setColumnCount(columns); } QString Palette::comment() { return d->palette->comment(); } QStringList Palette::groupNames() { return d->palette->getGroupNames(); } bool Palette::addGroup(QString name) { return d->palette->addGroup(name); } bool Palette::removeGroup(QString name, bool keepColors) { return d->palette->removeGroup(name, keepColors); } int Palette::colorsCountGroup(QString name) { return d->palette->nColorsGroup(name); } diff --git a/libs/libkis/Palette.h b/libs/libkis/Palette.h index 747e6692ba..50c7836c5a 100644 --- a/libs/libkis/Palette.h +++ b/libs/libkis/Palette.h @@ -1,91 +1,93 @@ /* * 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" /** * @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. */ class KRITALIBKIS_EXPORT Palette : public QObject { public: Palette(Resource *resource); + ~Palette() override; + /** * @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(); //setcomment /** * @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 succesful. */ 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 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); //getcolorgroup //Add //Remove //Insert private: struct Private; Private *const d; }; #endif // LIBKIS_PALETTE_H diff --git a/libs/libkis/tests/CMakeLists.txt b/libs/libkis/tests/CMakeLists.txt index 203ecbb6fe..b0aa81efb6 100644 --- a/libs/libkis/tests/CMakeLists.txt +++ b/libs/libkis/tests/CMakeLists.txt @@ -1,15 +1,16 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) include(ECMAddTests) include(KritaAddBrokenUnitTest) macro_add_unittest_definitions() ecm_add_tests( #TestKrita.cpp TestChannel.cpp TestDocument.cpp TestNode.cpp TestFilter.cpp + TestManagedColor.cpp NAME_PREFIX "libs-kritalibkis-" LINK_LIBRARIES kritalibkis Qt5::Test) diff --git a/libs/libkis/tests/TestManagedColor.cpp b/libs/libkis/tests/TestManagedColor.cpp new file mode 100644 index 0000000000..bd2efa2705 --- /dev/null +++ b/libs/libkis/tests/TestManagedColor.cpp @@ -0,0 +1,92 @@ +/* Copyright (C) 2017 Boudewijn Rempt + + 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 "TestManagedColor.h" +#include +#include +#include + +#include +#include + +#include +#include +#include + +QTEST_MAIN(TestManagedColor) + +void TestManagedColor::testOperatorIs() +{ + ManagedColor c1("RGBA", "U8", ""); + ManagedColor c2("RGBA", "U8", ""); + ManagedColor c3("RGBA", "U16", ""); + + QVERIFY(c1 == c2); +} + +void TestManagedColor::testSetColorSpace() +{ + ManagedColor c("RGBA", "U8", ""); + c.setColorSpace("LABA", "U16", ""); + QVERIFY(c.colorDepth() == "U16"); + QVERIFY(c.colorModel() == "LABA"); +} + +void TestManagedColor::testComponentsRoundTrip() +{ + ManagedColor c("RGBA", "U8", ""); + QVector components = c.components(); + QVERIFY(components.size() == 4); + QVERIFY(components[0] == 0); + QVERIFY(components[1] == 0); + QVERIFY(components[2] == 0); + QVERIFY(components[3] == 0); + + components[0] = 0.5; + components[1] = 0.5; + components[2] = 0.5; + components[3] = 0.5; + c.setComponents(components); + + QVERIFY(c.toQString() == "Red 127 Green 127 Blue 127 Alpha 127"); + +} + +void TestManagedColor::testXMLRoundTrip() +{ + ManagedColor c("RGBA", "U8", ""); + QVector components; + components << 0.5 << 0.5 << 0.5 << 0.5; + c.setComponents(components); + + QString xml = c.toXML(); + c.fromXML(xml); + components = c.components(); + QVERIFY(components.size() == 4); + QVERIFY(c.toQString() == "Red 127 Green 127 Blue 127 Alpha 127"); + + +} + +void TestManagedColor::testToQString() +{ + ManagedColor c("RGBA", "U8", ""); + QVector components; + components << 0.5 << 0.5 << 0.5 << 0.5; + c.setComponents(components); + QVERIFY(c.toQString() == "Red 127 Green 127 Blue 127 Alpha 127"); +} diff --git a/libs/libkis/tests/TestManagedColor.h b/libs/libkis/tests/TestManagedColor.h new file mode 100644 index 0000000000..e7526a7528 --- /dev/null +++ b/libs/libkis/tests/TestManagedColor.h @@ -0,0 +1,36 @@ +/* This file is part of the KDE project + Copyright (C) 2017 Boudewijn Rempt + + 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. +*/ +#ifndef TESTMANAGEDCOLOR_H +#define TESTMANAGEDCOLOR_H + +#include + +class TestManagedColor : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testOperatorIs(); + void testSetColorSpace(); + void testComponentsRoundTrip(); + void testXMLRoundTrip(); + void testToQString(); +}; + +#endif + diff --git a/libs/pigment/KoColor.cpp b/libs/pigment/KoColor.cpp index e29daf6f05..b5973762b0 100644 --- a/libs/pigment/KoColor.cpp +++ b/libs/pigment/KoColor.cpp @@ -1,336 +1,336 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (C) 2007 Thomas Zander * Copyright (C) 2007 Cyrille Berger * * 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; 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 "KoColor.h" #include #include #include "DebugPigment.h" #include "KoColorModelStandardIds.h" #include "KoColorProfile.h" #include "KoColorSpace.h" #include "KoColorSpaceRegistry.h" #include "KoChannelInfo.h" class Q_DECL_HIDDEN KoColor::Private { public: Private() : data(0), colorSpace(0) {} ~Private() { delete [] data; } quint8 * data; const KoColorSpace * colorSpace; }; KoColor::KoColor() : d(new Private()) { d->colorSpace = KoColorSpaceRegistry::instance()->rgb16(0); d->data = new quint8[d->colorSpace->pixelSize()]; d->colorSpace->fromQColor(Qt::black, d->data); d->colorSpace->setOpacity(d->data, OPACITY_OPAQUE_U8, 1); } KoColor::KoColor(const KoColorSpace * colorSpace) : d(new Private()) { Q_ASSERT(colorSpace); d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); d->data = new quint8[d->colorSpace->pixelSize()]; memset(d->data, 0, d->colorSpace->pixelSize()); } KoColor::~KoColor() { delete d; } KoColor::KoColor(const QColor & color, const KoColorSpace * colorSpace) : d(new Private()) { Q_ASSERT(color.isValid()); Q_ASSERT(colorSpace); d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); d->data = new quint8[colorSpace->pixelSize()]; memset(d->data, 0, d->colorSpace->pixelSize()); d->colorSpace->fromQColor(color, d->data); } KoColor::KoColor(const quint8 * data, const KoColorSpace * colorSpace) : d(new Private()) { Q_ASSERT(colorSpace); Q_ASSERT(data); d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); d->data = new quint8[colorSpace->pixelSize()]; memset(d->data, 0, d->colorSpace->pixelSize()); memmove(d->data, data, colorSpace->pixelSize()); } KoColor::KoColor(const KoColor &src, const KoColorSpace * colorSpace) : d(new Private()) { Q_ASSERT(colorSpace); d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); d->data = new quint8[colorSpace->pixelSize()]; memset(d->data, 0, d->colorSpace->pixelSize()); src.colorSpace()->convertPixelsTo(src.d->data, d->data, colorSpace, 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } KoColor::KoColor(const KoColor & rhs) : d(new Private()) { d->colorSpace = rhs.colorSpace(); Q_ASSERT(*d->colorSpace == *KoColorSpaceRegistry::instance()->permanentColorspace(d->colorSpace)); if (d->colorSpace && rhs.d->data) { d->data = new quint8[d->colorSpace->pixelSize()]; memcpy(d->data, rhs.d->data, d->colorSpace->pixelSize()); } } KoColor & KoColor::operator=(const KoColor & rhs) { if (this == &rhs) return *this; delete [] d->data; d->data = 0; d->colorSpace = rhs.colorSpace(); if (rhs.d->colorSpace && rhs.d->data) { Q_ASSERT(d->colorSpace == KoColorSpaceRegistry::instance()->permanentColorspace(d->colorSpace)); // here we want to do a check on pointer, since d->colorSpace is supposed to already be a permanent one d->data = new quint8[d->colorSpace->pixelSize()]; memcpy(d->data, rhs.d->data, d->colorSpace->pixelSize()); } return * this; } bool KoColor::operator==(const KoColor &other) const { if (*colorSpace() != *other.colorSpace()) return false; return memcmp(d->data, other.d->data, d->colorSpace->pixelSize()) == 0; } void KoColor::convertTo(const KoColorSpace * cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { //dbgPigment <<"Our colormodel:" << d->colorSpace->id().name() // << ", new colormodel: " << cs->id().name() << "\n"; if (*d->colorSpace == *cs) return; quint8 * data = new quint8[cs->pixelSize()]; memset(data, 0, cs->pixelSize()); d->colorSpace->convertPixelsTo(d->data, data, cs, 1, renderingIntent, conversionFlags); delete [] d->data; d->data = data; d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(cs); } void KoColor::convertTo(const KoColorSpace * cs) { convertTo(cs, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } void KoColor::setProfile(const KoColorProfile *profile) { const KoColorSpace *dstColorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile); if (!dstColorSpace) return; d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(dstColorSpace); } void KoColor::setColor(const quint8 * data, const KoColorSpace * colorSpace) { Q_ASSERT(data); Q_ASSERT(colorSpace); if(d->colorSpace->pixelSize() != colorSpace->pixelSize()) { delete [] d->data; d->data = new quint8[colorSpace->pixelSize()]; } memcpy(d->data, data, colorSpace->pixelSize()); d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); } // To save the user the trouble of doing color->colorSpace()->toQColor(color->data(), &c, &a, profile void KoColor::toQColor(QColor *c) const { Q_ASSERT(c); if (d->colorSpace && d->data) { d->colorSpace->toQColor(d->data, c); } } QColor KoColor::toQColor() const { QColor c; toQColor(&c); return c; } void KoColor::fromQColor(const QColor& c) const { if (d->colorSpace && d->data) { d->colorSpace->fromQColor(c, d->data); } } #ifndef NDEBUG void KoColor::dump() const { dbgPigment <<"KoColor (" << this <<")," << d->colorSpace->id() <<""; QList channels = d->colorSpace->channels(); QList::const_iterator begin = channels.constBegin(); QList::const_iterator end = channels.constEnd(); for (QList::const_iterator it = begin; it != end; ++it) { KoChannelInfo * ch = (*it); // XXX: setNum always takes a byte. if (ch->size() == sizeof(quint8)) { // Byte dbgPigment <<"Channel (byte):" << ch->name() <<":" << QString().setNum(d->data[ch->pos()]) <<""; } else if (ch->size() == sizeof(quint16)) { // Short (may also by an nvidia half) dbgPigment <<"Channel (short):" << ch->name() <<":" << QString().setNum(*((const quint16 *)(d->data+ch->pos()))) <<""; } else if (ch->size() == sizeof(quint32)) { // Integer (may also be float... Find out how to distinguish these!) dbgPigment <<"Channel (int):" << ch->name() <<":" << QString().setNum(*((const quint32 *)(d->data+ch->pos()))) <<""; } } } #endif void KoColor::fromKoColor(const KoColor& src) { src.colorSpace()->convertPixelsTo(src.d->data, d->data, colorSpace(), 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } -const KoColorProfile * KoColor::profile() const +const KoColorProfile *KoColor::profile() const { return d->colorSpace->profile(); } quint8 * KoColor::data() { return d->data; } const quint8 * KoColor::data() const { return d->data; } const KoColorSpace * KoColor::colorSpace() const { return d->colorSpace; } void KoColor::toXML(QDomDocument& doc, QDomElement& colorElt) const { d->colorSpace->colorToXML(d->data, doc, colorElt); } void KoColor::setOpacity(quint8 alpha) { d->colorSpace->setOpacity(d->data, alpha, 1); } void KoColor::setOpacity(qreal alpha) { d->colorSpace->setOpacity(d->data, alpha, 1); } quint8 KoColor::opacityU8() const { return d->colorSpace->opacityU8(d->data); } qreal KoColor::opacityF() const { return d->colorSpace->opacityF(d->data); } KoColor KoColor::fromXML(const QDomElement& elt, const QString & bitDepthId) { QString modelId; if (elt.tagName() == "CMYK") { modelId = CMYKAColorModelID.id(); } else if (elt.tagName() == "RGB") { modelId = RGBAColorModelID.id(); } else if (elt.tagName() == "sRGB") { modelId = RGBAColorModelID.id(); } else if (elt.tagName() == "Lab") { modelId = LABAColorModelID.id(); } else if (elt.tagName() == "XYZ") { modelId = XYZAColorModelID.id(); } else if (elt.tagName() == "Gray") { modelId = GrayAColorModelID.id(); } else if (elt.tagName() == "YCbCr") { modelId = YCbCrAColorModelID.id(); } QString profileName; if (elt.tagName() != "sRGB") { profileName = elt.attribute("space", ""); if (!KoColorSpaceRegistry::instance()->profileByName(profileName)) { profileName.clear(); } } const KoColorSpace* cs = KoColorSpaceRegistry::instance()->colorSpace(modelId, bitDepthId, profileName); if (cs == 0) { QList list = KoColorSpaceRegistry::instance()->colorDepthList(modelId, KoColorSpaceRegistry::AllColorSpaces); if (!list.empty()) { cs = KoColorSpaceRegistry::instance()->colorSpace(modelId, list[0].id(), profileName); } } if (cs) { KoColor c(cs); cs->colorFromXML(c.data(), elt); return c; } else { return KoColor(); } } QString KoColor::toQString(const KoColor &color) { QStringList ls; Q_FOREACH (KoChannelInfo *channel, KoChannelInfo::displayOrderSorted(color.colorSpace()->channels())) { int realIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), color.colorSpace()->channels()); ls << channel->name(); ls << color.colorSpace()->channelValueText(color.data(), realIndex); } return ls.join(" "); } diff --git a/libs/pigment/KoColor.h b/libs/pigment/KoColor.h index b6e4e9c8a8..214c20a137 100644 --- a/libs/pigment/KoColor.h +++ b/libs/pigment/KoColor.h @@ -1,174 +1,179 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (C) 2007 Thomas Zander * * 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. */ #ifndef KOCOLOR_H #define KOCOLOR_H #include #include #include "kritapigment_export.h" #include "KoColorConversionTransformation.h" #include class QDomDocument; class QDomElement; class KoColorProfile; class KoColorSpace; /** * A KoColor describes a color in a certain colorspace. The color is stored in a buffer * that can be manipulated by the function of the color space. */ class KRITAPIGMENT_EXPORT KoColor : public boost::equality_comparable { public: /// Create an empty KoColor. It will be valid, but also black and transparent KoColor(); ~KoColor(); /// Create a null KoColor. It will be valid, but all channels will be set to 0 explicit KoColor(const KoColorSpace * colorSpace); /// Create a KoColor from a QColor. The QColor is immediately converted to native. The QColor /// is assumed to have the current monitor profile. KoColor(const QColor & color, const KoColorSpace * colorSpace); /// Create a KoColor using a native color strategy. The data is copied. KoColor(const quint8 * data, const KoColorSpace * colorSpace); /// Create a KoColor by converting src into another colorspace KoColor(const KoColor &src, const KoColorSpace * colorSpace); /// Copy constructor -- deep copies the colors. KoColor(const KoColor & rhs); /** * assignment operator to copy the data from the param color into this one. * @param other the color we are going to copy * @return this color */ KoColor &operator=(const KoColor &other); bool operator==(const KoColor &other) const; /// return the current colorSpace const KoColorSpace * colorSpace() const; /// return the current profile - const KoColorProfile * profile() const; + const KoColorProfile *profile() const; /// Convert this KoColor to the specified colorspace. If the specified colorspace is the /// same as the original colorspace, do nothing. Returns the converted KoColor. void convertTo(const KoColorSpace * cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); void convertTo(const KoColorSpace * cs); /// assign new profile without converting pixel data void setProfile(const KoColorProfile *profile); /// Replace the existing color data, and colorspace with the specified data. /// The data is copied. void setColor(const quint8 * data, const KoColorSpace * colorSpace = 0); /// Convert the color from src and replace the value of the current color with the converted data. /// Don't convert the color if src and this have the same colorspace. void fromKoColor(const KoColor& src); /// a convenience method for the above. void toQColor(QColor *c) const; /// a convenience method for the above. QColor toQColor() const; /** * Convenient function to set the opacity of the color. */ void setOpacity(quint8 alpha); void setOpacity(qreal alpha); /** * Convenient function that return the opacity of the color */ quint8 opacityU8() const; qreal opacityF() const; /// Convenient function for converting from a QColor void fromQColor(const QColor& c) const; /** * @return the buffer associated with this color object to be used with the * transformation object created by the color space of this KoColor * or to copy to a different buffer from the same color space */ quint8 * data(); /** * @return the buffer associated with this color object to be used with the * transformation object created by the color space of this KoColor * or to copy to a different buffer from the same color space */ const quint8 * data() const; /** * Serialize this color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * * This function doesn't create the element but rather the , * , ... elements. It is assumed that colorElt is the * element. * * @param colorElt root element for the serialization, it is assumed that this * element is * @param doc is the document containing colorElt */ void toXML(QDomDocument& doc, QDomElement& colorElt) const; /** * Unserialize a color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * * @param elt the element to unserialize (, , ) * @param bitDepthId the bit depth is unspecified by the spec, this allow to select * a preferred bit depth for creating the KoColor object (if that * bit depth isn't available, this function will randomly select * an other bit depth) * @return the unserialize color, or an empty color object if the function failed * to unserialize the color */ static KoColor fromXML(const QDomElement& elt, const QString & bitDepthId); + /** + * @brief toQString create a user-visible string of the channel names and the channel values + * @param color the color to create the string from + * @return a string that can be used to display the values of this color to the user. + */ static QString toQString(const KoColor &color); #ifndef NODEBUG /// use qDebug calls to print internal info void dump() const; #endif private: class Private; Private * const d; }; Q_DECLARE_METATYPE(KoColor) #endif diff --git a/plugins/extensions/pykrita/sip/krita/ManagedColor.sip b/plugins/extensions/pykrita/sip/krita/ManagedColor.sip new file mode 100644 index 0000000000..8e7a96a549 --- /dev/null +++ b/plugins/extensions/pykrita/sip/krita/ManagedColor.sip @@ -0,0 +1,23 @@ +class ManagedColor : QObject +{ +%TypeHeaderCode +#include "ManagedColor.h" +%End + ManagedColor(const Palette & __0); +public: + ManagedColor(const QString &colorModel, const QString &colorDepth, const QString &colorProfile, QObject *parent = 0); + bool operator==(const ManagedColor &other) const; + QColor colorForCanvas(Canvas *canvas) const; + QString colorDepth() const; + QString colorModel() const; + QString colorProfile() const; + bool setColorProfile(const QString &colorProfile); + bool setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile); + QVector components() const; + void setComponents(const QVector &values); + QString toXML() const; + void fromXML(const QString &xml); + QString toQString(); + +private: +}; diff --git a/plugins/extensions/pykrita/sip/krita/kritamod.sip b/plugins/extensions/pykrita/sip/krita/kritamod.sip index 5cf52ddd79..24638caef7 100644 --- a/plugins/extensions/pykrita/sip/krita/kritamod.sip +++ b/plugins/extensions/pykrita/sip/krita/kritamod.sip @@ -1,33 +1,34 @@ %Module PyKrita.krita %ModuleHeaderCode #pragma GCC visibility push(default) %End %Import QtCore/QtCoremod.sip %Import QtGui/QtGuimod.sip %Import QtXml/QtXmlmod.sip %Import QtWidgets/QtWidgetsmod.sip %Include Conversions.sip %Include Action.sip %Include Canvas.sip %Include Channel.sip %Include DockWidgetFactoryBase.sip %Include DockWidget.sip %Include Document.sip %Include Filter.sip %Include InfoObject.sip %Include Extension.sip %Include View.sip %Include Window.sip %Include Krita.sip %Include Node.sip %Include Notifier.sip %Include Resource.sip %Include Selection.sip %Include Extension.sip %Include PresetChooser.sip %Include Palette.sip +%Include ManagedColor.sip %Include KisCubicCurve.sip