Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
filter.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Authors:
4 * Ted Gould <ted@gould.cx>
5 *
6 * Copyright (C) 2008 Authors
7 *
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10
11#include "filter.h"
12
13#include "desktop.h"
14#include "document.h"
15#include "selection.h"
16
17#include "extension/extension.h"
18#include "extension/effect.h"
19#include "extension/system.h"
20#include "object/sp-defs.h"
21#include "xml/repr.h"
22#include "xml/simple-node.h"
24
25
26namespace Inkscape {
27namespace Extension {
28namespace Internal {
29namespace Filter {
30
32 Inkscape::Extension::Implementation::Implementation(),
33 _filter(nullptr) {
34 return;
35}
36
37Filter::Filter(gchar const * filter) :
38 Inkscape::Extension::Implementation::Implementation(),
39 _filter(filter) {
40 return;
41}
42
44 if (_filter != nullptr) {
45 _filter = nullptr;
46 }
47
48 return;
49}
50
52{
53 return true;
54}
55
58{
59 return nullptr;
60}
61
63{
64 return _filter;
65}
66
69 gchar const * filter = get_filter_text(ext);
70 return sp_repr_read_mem(filter, strlen(filter), nullptr);
71}
72
75 gchar const * srcGraphic = nullptr, gchar const * srcGraphicAlpha = nullptr)
76{
77 if (from == nullptr) return;
78
79 // copy attributes
80 for ( const auto & iter : from->attributeList()) {
81 gchar const * attr = g_quark_to_string(iter.key);
82
83 if (!strcmp(attr, "id")) continue; // nope, don't copy that one!
84 to->setAttribute(attr, from->attribute(attr));
85
86 if (!strcmp(attr, "in") || !strcmp(attr, "in2") || !strcmp(attr, "in3")) {
87 if (srcGraphic != nullptr && !strcmp(from->attribute(attr), "SourceGraphic")) {
88 to->setAttribute(attr, srcGraphic);
89 }
90
91 if (srcGraphicAlpha != nullptr && !strcmp(from->attribute(attr), "SourceAlpha")) {
92 to->setAttribute(attr, srcGraphicAlpha);
93 }
94 }
95 }
96
97 // for each child call recursively
98 for (Inkscape::XML::Node * from_child = from->firstChild();
99 from_child != nullptr ; from_child = from_child->next()) {
100 Glib::ustring name = "svg:";
101 name += from_child->name();
102
103 Inkscape::XML::Node * to_child = doc->createElement(name.c_str());
104 to->appendChild(to_child);
105 merge_filters(to_child, from_child, doc, srcGraphic, srcGraphicAlpha);
106
107 if (from_child == from->firstChild() && !strcmp("filter", from->name()) && srcGraphic != nullptr && to_child->attribute("in") == nullptr) {
108 to_child->setAttribute("in", srcGraphic);
109 }
110 Inkscape::GC::release(to_child);
111 }
112}
113
115 if (!item) return;
116
118 auto document = item->document;
119 Inkscape::XML::Document * xmldoc = document->getReprDoc();
120 Inkscape::XML::Node * defsrepr = document->getDefs()->getRepr();
121 Inkscape::XML::Node * newfilterroot = xmldoc->createElement("svg:filter");
122 merge_filters(newfilterroot, filterdoc->root(), xmldoc);
123 defsrepr->appendChild(newfilterroot);
124 document->resources_changed_signals[g_quark_from_string("filter")].emit();
125
126 Glib::ustring url = "url(#"; url += newfilterroot->attribute("id"); url += ")";
127 Inkscape::GC::release(newfilterroot);
128
129 SPCSSAttr* css = sp_repr_css_attr(node, "style");
130 sp_repr_css_set_property(css, "filter", url.c_str());
131 sp_repr_css_set(node, css, "style");
132}
133
134#define FILTER_SRC_GRAPHIC "fbSourceGraphic"
135#define FILTER_SRC_GRAPHIC_ALPHA "fbSourceGraphicAlpha"
136
139{
140 Inkscape::XML::Document *filterdoc = get_filter(module);
141 if (filterdoc == nullptr) {
142 return; // could not parse the XML source of the filter; typically parser will stderr a warning
143 }
144
146
147 // TODO need to properly refcount the items, at least
148 std::vector<SPItem*> items(selection->items().begin(), selection->items().end());
149
151 Inkscape::XML::Node * defsrepr = desktop->doc()->getDefs()->getRepr();
152
153 for(auto spitem : items) {
154 Inkscape::XML::Node *node = spitem->getRepr();
155
156 SPCSSAttr * css = sp_repr_css_attr(node, "style");
157 gchar const * filter = sp_repr_css_property(css, "filter", nullptr);
158
159 if (filter == nullptr) {
160 create_and_apply_filter(spitem, filterdoc);
161 } else {
162 if (strncmp(filter, "url(#", strlen("url(#")) || filter[strlen(filter) - 1] != ')') {
163 // This is not url(#id) -- we can't handle it
164 continue;
165 }
166
167 gchar * lfilter = g_strndup(filter + 5, strlen(filter) - 6);
168 Inkscape::XML::Node * filternode = nullptr;
169 for (Inkscape::XML::Node * child = defsrepr->firstChild(); child != nullptr; child = child->next()) {
170 const char * child_id = child->attribute("id");
171 if (child_id != nullptr && !strcmp(lfilter, child_id)) {
172 filternode = child;
173 break;
174 }
175 }
176 g_free(lfilter);
177
178 // no filter
179 if (filternode == nullptr) {
180 g_warning("no assigned filter found!");
181 continue;
182 }
183
184 if (filternode->lastChild() == nullptr) {
185 // empty filter, we insert
186 merge_filters(filternode, filterdoc->root(), xmldoc);
187 } else {
188 // existing filter, we merge
189 filternode->lastChild()->setAttribute("result", FILTER_SRC_GRAPHIC);
190 Inkscape::XML::Node * alpha = xmldoc->createElement("svg:feColorMatrix");
191 alpha->setAttribute("result", FILTER_SRC_GRAPHIC_ALPHA);
192 alpha->setAttribute("in", FILTER_SRC_GRAPHIC); // not required, but we're being explicit
193 alpha->setAttribute("values", "0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0");
194
195 filternode->appendChild(alpha);
196
197 merge_filters(filternode, filterdoc->root(), xmldoc, FILTER_SRC_GRAPHIC, FILTER_SRC_GRAPHIC_ALPHA);
198
200 }
201 }
202 }
203
204 return;
205}
206
208
209void
210Filter::filter_init (gchar const * id, gchar const * name, gchar const * submenu, gchar const * tip, gchar const * filter)
211{
212 // clang-format off
213 gchar * xml_str = g_strdup_printf(
214 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
215 "<name>%s</name>\n"
216 "<id>org.inkscape.effect.filter.%s</id>\n"
217 "<effect>\n"
218 "<object-type>all</object-type>\n"
219 "<effects-menu>\n"
220 "<submenu name=\"" N_("Filters") "\" />\n"
221 "<submenu name=\"%s\"/>\n"
222 "</effects-menu>\n"
223 "<menu-tip>%s</menu-tip>\n"
224 "</effect>\n"
225 "</inkscape-extension>\n", name, id, submenu, tip);
226 // clang-format on
227 Inkscape::Extension::build_from_mem(xml_str, std::make_unique<Filter>(filter));
228 g_free(xml_str);
229 return;
230}
231
233 if (!item) return false;
234
235 Inkscape::XML::Document* filterdoc = get_filter(module);
236 if (!filterdoc) return false;
237
238 create_and_apply_filter(item, filterdoc);
239 return true;
240}
241
242}; /* namespace Filter */
243}; /* namespace Internal */
244}; /* namespace Extension */
245}; /* namespace Inkscape */
246
247/*
248 Local Variables:
249 mode:c++
250 c-file-style:"stroustrup"
251 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
252 indent-tabs-mode:nil
253 fill-column:99
254 End:
255*/
256// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
TODO: insert short description here.
Effects are extensions that take a document and do something to it in place.
Definition effect.h:39
The object that is the basis for the Extension system.
Definition extension.h:133
A cache for the document and this implementation.
void effect(Inkscape::Extension::Effect *module, ExecutionEnv *executionEnv, SPDesktop *desktop, Inkscape::Extension::Implementation::ImplementationDocumentCache *docCache) override
Definition filter.cpp:137
static void filter_init(gchar const *id, gchar const *name, gchar const *submenu, gchar const *tip, gchar const *filter)
Definition filter.cpp:210
Inkscape::Extension::Implementation::ImplementationDocumentCache * newDocCache(Inkscape::Extension::Extension *ext, SPDesktop *desktop) override
Create a new document cache object.
Definition filter.cpp:57
bool apply_filter(Inkscape::Extension::Effect *module, SPItem *item) override
Definition filter.cpp:232
bool load(Inkscape::Extension::Extension *module) override
Definition filter.cpp:51
Inkscape::XML::Document * get_filter(Inkscape::Extension::Extension *ext)
Definition filter.cpp:68
virtual gchar const * get_filter_text(Inkscape::Extension::Extension *ext)
Definition filter.cpp:62
SPItemRange items()
Returns a range of selected SPItems.
Definition object-set.h:230
The set of selected SPObjects for a given document and layer model.
Definition selection.h:80
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.
virtual char const * name() const =0
Get the name of the element node.
virtual const AttributeVector & attributeList() const =0
Get a list of the node's attributes.
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.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual Node * lastChild()=0
Get the last child of this node.
virtual Node * root()=0
Get the root node of this node's document.
To do: update description of desktop.
Definition desktop.h:149
Inkscape::Selection * getSelection() const
Definition desktop.h:188
SPDocument * doc() const
Definition desktop.h:159
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
Base class for visual SVG elements.
Definition sp-item.h:109
SPDocument * document
Definition sp-object.h:188
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
A way to clear the N_ macro, which is defined as an inline function.
std::shared_ptr< Css const > css
Editable view implementation.
Inkscape::Extension::Extension: Frontend to certain, possibly pluggable, actions.
SPItem * item
Inkscape::XML::Node * node
void merge_filters(Inkscape::XML::Node *to, Inkscape::XML::Node *from, Inkscape::XML::Document *doc, gchar const *srcGraphic=nullptr, gchar const *srcGraphicAlpha=nullptr)
Definition filter.cpp:73
void create_and_apply_filter(SPItem *item, Inkscape::XML::Document *filterdoc)
Definition filter.cpp:114
void build_from_mem(gchar const *buffer, std::unique_ptr< Implementation::Implementation > in_imp)
Create a module from a buffer holding an XML description.
Definition system.cpp:459
static R & release(R &r)
Decrements the reference count of a anchored object.
Helper class to stream background task notifications as a series of messages.
Ocnode * child[8]
Definition quantize.cpp:33
void sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
Sets an attribute (e.g.
Definition repr-css.cpp:264
SPCSSAttr * sp_repr_css_attr(Node const *repr, gchar const *attr)
Creates a new SPCSSAttr with one attribute (i.e.
Definition repr-css.cpp:88
char const * sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval)
Returns a character string of the value of a given style property or a default value if the attribute...
Definition repr-css.cpp:147
void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
Definition repr-css.cpp:190
Document * sp_repr_read_mem(const gchar *buffer, gint length, const gchar *default_ns)
Reads and parses XML from a buffer, returning it as an Document.
Definition repr-io.cpp:324
C facade to Inkscape::XML::Node.
GList * items
GC-managed XML node implementation.
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
SPDesktop * desktop
Glib::ustring name
Definition toolbars.cpp:55