Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
color-profile.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
5 * Authors: see git history
6 *
7 * Copyright (C) 2018 Authors
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10
11#include "color-profile.h"
12
13#include <cstring>
14#include <giomm/error.h>
15
16#include "attributes.h"
17#include "colors/cms/profile.h"
18#include "document.h"
19#include "inkscape.h"
20#include "preferences.h"
21#include "sp-defs.h"
22#include "uri.h"
23#include "xml/document.h"
25
26namespace Inkscape {
27
29{
30 // Unregister ourselves
31 if (this->document) {
32 this->document->removeResource("iccprofile", this);
33 }
34
36}
37
42{
44
49
50 // Register
51 if (document) {
52 document->addResource("iccprofile", this);
53 }
54}
55
59void ColorProfile::set(SPAttr key, gchar const *value)
60{
61 switch (key) {
63 // Href is the filename or the data of the icc profile itself and is used before local
64 if (value) {
65 auto fn = document->getDocumentFilename();
66 _uri = std::make_unique<Inkscape::URI>(value, fn ? ("file://" + std::string(fn)).c_str() : nullptr);
67 } else {
68 _uri.reset();
69 }
70 break;
71
72 case SPAttr::LOCAL:
73 // Local is the ID of the profile as a hex string. Provided by Colors::CMS::Profile::getId()
74 // it's only used if the href isn't set or isn't found on this system in the specified place
75 _local = value ? value : "";
76 break;
77
78 case SPAttr::NAME:
79 // Name is used by the icc-color format to match this profile to a color. It over-rides the
80 // name given in the icc profile if it's provided.
81 _name = value ? value : "";
82 break;
83
85 // There is a standard set of rendering intents, the default fallback intent is decided in the
86 // color CMS system and not here.
88 if (value) {
89 for (auto &pair : Colors::intentIds) {
90 if (pair.second == value) {
91 _intent = pair.first;
92 break;
93 }
94 }
95 }
96 break;
97
98 default:
99 return SPObject::set(key, value);
100 }
101 this->requestModified(SP_OBJECT_MODIFIED_FLAG);
102}
103
108{
109 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
110 repr = xml_doc->createElement("svg:color-profile");
111 }
112
113 if ((flags & SP_OBJECT_WRITE_ALL) || _uri) {
114 auto fn = document->getDocumentFilename();
115 Inkscape::setHrefAttribute(*repr, fn ? _uri->str(("file://" + std::string(fn)).c_str()).c_str() : nullptr);
116 }
117
121
122 SPObject::write(xml_doc, repr, flags);
123 return repr;
124}
125
131{
132 // Note: The returned data could be Megabytes in length, but we're
133 // copying the data. We should find a way to pass the const string back
134 if (_uri) {
135 try {
136 return _uri->getContents();
137 } catch (const Gio::Error &e) {
138 g_warning("Couldn't get color profile: %s", e.what());
139 }
140 }
141 return "";
142}
143
148{
149 setAttribute("rendering-intent", Colors::intentIds[intent]);
150}
151
167 std::string const &name, ColorProfileStorage storage,
168 std::optional<Colors::RenderingIntent> intent)
169{
170 if (name.empty()) {
171 g_error("Refusing to create a color profile with an empty name!");
172 return nullptr;
173 }
174 if (storage == ColorProfileStorage::HREF_FILE && profile.getPath().empty()) {
175 storage = ColorProfileStorage::HREF_DATA; // fallback to data
176 }
177
178 // Create new object and attach it to the document
179 auto repr = doc->getReprDoc()->createElement("svg:color-profile");
180
181 // It's expected that the color manager will hace checked for collisions before this call.
183
184 switch (storage) {
186 repr->setAttributeOrRemoveIfEmpty("local", profile.getId());
187 break;
189 Inkscape::setHrefAttribute(*repr, "data:application/vnd.iccprofile;base64," + profile.dumpBase64());
190 break;
192 auto uri = Inkscape::URI::from_native_filename(profile.getPath().c_str());
193 auto fn = doc->getDocumentFilename();
194 Inkscape::setHrefAttribute(*repr, uri.str(fn ? (std::string("file://") + fn).c_str() : nullptr));
195 } break;
196 }
197 if (intent) {
198 repr->setAttributeOrRemoveIfEmpty("rendering-intent", Colors::intentIds[*intent]);
199 }
200 // Complete the creation by appending to the defs. This must be done last.
201 return cast<ColorProfile>(doc->getDefs()->appendChildRepr(repr));
202}
203
204} // namespace Inkscape
205
206/*
207 Local Variables:
208 mode:c++
209 c-file-style:"stroustrup"
210 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
211 indent-tabs-mode:nil
212 fill-column:99
213 End:
214*/
215// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Lookup dictionary for attributes/properties.
SPAttr
Definition attributes.h:27
@ RENDERING_INTENT
@ XLINK_HREF
std::string getProfileData() const
Return the profile data, if any.
Colors::RenderingIntent _intent
static ColorProfile * createFromProfile(SPDocument *doc, Colors::CMS::Profile const &profile, std::string const &name, ColorProfileStorage storage, std::optional< Colors::RenderingIntent > intent)
Create a profile for the given profile in the given document.
std::unique_ptr< Inkscape::URI > _uri
void set(SPAttr key, char const *value) override
Callback: set attribute.
void release() override
void build(SPDocument *doc, Inkscape::XML::Node *repr) override
Callback: set attributes from associated repr.
Inkscape::XML::Node * write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags) override
Callback: write attributes to associated repr.
void setRenderingIntent(Colors::RenderingIntent intent)
Set the rendering intent for this color profile.
const std::string & getId() const
Definition profile.h:49
std::string dumpBase64() const
Dump the entire profile as a base64 encoded string.
Definition profile.cpp:275
std::string const & getPath() const
Definition profile.h:45
static URI from_native_filename(char const *path)
Construct a "file" URI from an absolute filename.
Definition uri.cpp:190
Interface for refcounted XML nodes.
Definition node.h:80
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:167
Typed SVG document implementation.
Definition document.h:101
bool removeResource(char const *key, SPObject *object)
char const * getDocumentFilename() const
Definition document.h:229
bool addResource(char const *key, SPObject *object)
SPDefs * getDefs()
Return the main defs object for the document.
Definition document.cpp:247
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
Definition document.h:211
Inkscape::XML::Node * repr
Definition sp-object.h:193
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
void requestModified(unsigned int flags)
Requests that a modification notification signal be emitted later (e.g.
SPDocument * document
Definition sp-object.h:188
virtual void set(SPAttr key, const char *value)
virtual Inkscape::XML::Node * write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags)
virtual void release()
void readAttr(char const *key)
Read value of key attribute from XML node into object.
SPObject * appendChildRepr(Inkscape::XML::Node *repr)
Append repr as child of this object.
virtual void build(SPDocument *doc, Inkscape::XML::Node *repr)
SPObject of the color-profile object found a direct child of defs.
static std::map< RenderingIntent, std::string > intentIds
Definition enum.h:34
Helper class to stream background task notifications as a series of messages.
void setHrefAttribute(XML::Node &node, Util::const_char_ptr value)
If the 'href' attribute already exists for the given node, then set a new value for it.
static cairo_user_data_key_t key
Singleton class to access the preferences file in a convenient way.
Authors: see git history.
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
Glib::ustring name
Definition toolbars.cpp:55
Interface for XML documents.