Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
xml-color.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Author:
4 * Martin Owens <doctormo@geek-2.com>
5 *
6 * Copyright (C) 2023 author
7 *
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10
11#include "xml-color.h"
12
13#include "cms/profile.h"
14#include "cms/system.h"
15#include "colors/color.h"
16#include "document-cms.h"
17#include "document.h"
18#include "manager.h"
19#include "spaces/base.h"
20#include "spaces/cms.h"
21#include "spaces/components.h"
22#include "xml/node-iterators.h"
23#include "xml/node.h"
24#include "xml/repr.h"
25#include "xml/simple-document.h"
26
27namespace Inkscape::Colors {
28
34std::string paint_to_xml_string(Paint const &paint)
35{
36 auto doc = paint_to_xml(paint);
37 auto ret = sp_repr_save_buf(doc);
38 GC::release(doc);
39 return ret;
40}
41
48Paint xml_string_to_paint(std::string const &xmls, SPDocument *doc)
49{
50 auto color_doc = sp_repr_read_buf(xmls, nullptr);
51 auto ret = xml_to_paint(color_doc, doc);
52 GC::release(color_doc);
53 return ret;
54}
55
57{
58 auto *document = new XML::SimpleDocument();
59 auto root = document->createElement("paint");
60 document->appendChild(root);
61
62 if (std::holds_alternative<NoColor>(paint)) {
63 auto node = document->createElement("nocolor");
67 return document;
68 }
69
70 auto &color = std::get<Color>(paint);
71 auto space = color.getSpace();
72
73 // This format is entirely inkscape's creation and doesn't work with anything
74 // outside of inkscape. It's completely safe to change at any time since the
75 // data is never saved to a file.
76 auto node = document->createElement("color");
77 node->setAttribute("space", space->getName());
78 node->setAttributeOrRemoveIfEmpty("name", color.getName());
79 root->appendChild(node);
80
81 if (auto cms = std::dynamic_pointer_cast<Space::CMS>(space)) {
82 if (auto profile = cms->getProfile()) {
83 // Store the unique icc profile id, so we have a chance of matching it
84 node->setAttribute("icc", profile->getId());
85 }
86 }
87
88 if (color.hasOpacity()) {
89 node->setAttributeSvgDouble("opacity", color.getOpacity());
90 }
91
92 auto components = space->getComponents();
93 for (unsigned int i = 0; i < components.size() && i < color.size(); i++) {
94 node->setAttributeCssDouble(components[i].id, color[i]);
95 }
96
99 return document;
100}
101
103{
104 auto get_node = [](XML::Node const *node, std::string const &name) {
106 for (; iter; ++iter) {
107 if (iter->name() && name == iter->name()) {
108 return &*iter;
109 }
110 }
111 return (const Inkscape::XML::Node *)(nullptr);
112 };
113
114 if (auto const paint = get_node(xml, "paint")) {
115 if (get_node(paint, "nocolor")) {
116 return NoColor();
117 }
118 if (auto color_xml = get_node(paint, "color")) {
119 auto space_name = color_xml->attribute("space");
120
121 if (!space_name) {
122 throw ColorError("Invalid color data, no space specified.");
123 }
124
125 auto space = Manager::get().find(space_name);
126
127 if (!space && doc)
128 space = doc->getDocumentCMS().getSpace(space_name);
129
130 if (auto icc_id = color_xml->attribute("icc")) {
131 // Make a temporary space for the icc information, if possible
132 if (!space)
133 if (auto profile = CMS::System::get().getProfile(icc_id)) {
134 auto cms = std::make_shared<Space::CMS>(profile);
135 cms->setIntent(RenderingIntent::AUTO);
136 space = cms;
137 }
138
139 if (auto cms = std::dynamic_pointer_cast<Space::CMS>(space)) {
140 // Check named space has a cms profile that is actually the same Id
141 if (cms->getProfile()->getId() != icc_id) {
142 g_warning("Mismatched icc profiles in color data: '%s'", space_name);
143 // Not returning, will still return something
144 }
145 }
146 }
147 if (!space) {
148 throw ColorError("No color space available.");
149 }
150
151 XML::NodeConstSiblingIterator color_iter{color_xml->firstChild()};
152 std::vector<double> values;
153 for (auto &comp : space->getComponents()) {
154 values.emplace_back(color_xml->getAttributeDouble(comp.id));
155 }
156 auto color = Color(space, values);
157
158 if (color_xml->attribute("opacity")) {
159 color.setOpacity(color_xml->getAttributeDouble("opacity"));
160 }
161 if (auto name = color_xml->attribute("name")) {
162 color.setName(name);
163 }
164 return color;
165 }
166 }
167 throw ColorError("No color data found");
168}
169
170} // namespace Inkscape::Colors
171
172/*
173 Local Variables:
174 mode:c++
175 c-file-style:"stroustrup"
176 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
177 indent-tabs-mode:nil
178 fill-column:99
179 End:
180*/
181// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
static System & get()
Definition system.h:35
std::shared_ptr< Space::CMS > getSpace(std::string const &name) const
Get the specific color space from the list of available spaces.
std::shared_ptr< Space::AnySpace > find(Space::Type type) const
Finds the first global color space matching the given type.
Definition manager.cpp:97
static Manager & get()
Definition manager.h:36
Interface for refcounted XML nodes.
Definition node.h:80
virtual void appendChild(Node *child)=0
Append a node as the last child of this node.
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:167
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
virtual Node * firstChild()=0
Get the first child of this node.
bool setAttributeCssDouble(Util::const_char_ptr key, double val)
Set a property attribute to val [slightly rounded], in the format required for CSS properties: in par...
Definition node.cpp:102
bool setAttributeSvgDouble(Util::const_char_ptr key, double val)
For attributes where an exponent is allowed.
Definition node.cpp:111
Typed SVG document implementation.
Definition document.h:101
Inkscape::Colors::DocumentCMS & getDocumentCMS()
Definition document.h:165
Access operating system wide information about color management.
RootCluster root
Inkscape::XML::Node * node
A set of useful color modifying functions which do not fit as generic methods on the color class itse...
Definition profile.cpp:24
std::variant< NoColor, Color > Paint
Definition xml-color.h:32
Paint xml_to_paint(XML::Document const *xml, SPDocument *doc)
XML::Document * paint_to_xml(Paint const &paint)
Definition xml-color.cpp:56
Paint xml_string_to_paint(std::string const &xmls, SPDocument *doc)
Parse an xml document into a color.
Definition xml-color.cpp:48
std::string paint_to_xml_string(Paint const &paint)
Turn a color into a color xml document, used for drag and drop.
Definition xml-color.cpp:34
static R & release(R &r)
Decrements the reference count of a anchored object.
Authors: see git history.
Document * sp_repr_read_buf(const Glib::ustring &buf, const gchar *default_ns)
Reads and parses XML from a buffer, returning it as an Document.
Definition repr-io.cpp:350
Glib::ustring sp_repr_save_buf(Document *doc)
Definition repr-io.cpp:631
C facade to Inkscape::XML::Node.
Inkscape::XML::SimpleDocument - generic XML document implementation.
Interface for XML documents.
Definition document.h:43
Glib::ustring name
Definition toolbars.cpp:55
Interface for XML nodes.