Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
svg.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * This is the code that moves all of the SVG loading and saving into
4 * the module format. Really Inkscape is built to handle these formats
5 * internally, so this is just calling those internal functions.
6 *
7 * Authors:
8 * Lauris Kaplinski <lauris@kaplinski.com>
9 * Ted Gould <ted@gould.cx>
10 * Jon A. Cruz <jon@joncruz.org>
11 * Abhishek Sharma
12 *
13 * Copyright (C) 2002-2003 Authors
14 *
15 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
16 */
17
18#include <giomm/file.h>
19
20#include "document.h"
21#include "inkscape.h"
22#include "preferences.h"
23#include "extension/output.h"
24#include "extension/input.h"
25#include "extension/system.h"
26#include "svg.h"
27#include "display/cairo-utils.h"
28#include "extension/system.h"
29#include "extension/output.h"
30
31#include "object/sp-image.h"
32#include "object/sp-root.h"
33
34#include "util/units.h"
36
37#include "selection-chemistry.h"
38
39// TODO due to internal breakage in glibmm headers, this must be last:
40#include <glibmm/i18n.h>
41
43
44#include "clear-n_.h"
45
58void
60{
61 // clang-format off
62 /* SVG in */
64 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
65 "<name>" N_("SVG Input") "</name>\n"
66 "<id>" SP_MODULE_KEY_INPUT_SVG "</id>\n"
67 SVG_COMMON_INPUT_PARAMS
68 "<input priority='1'>\n"
69 "<extension>.svg</extension>\n"
70 "<mimetype>image/svg+xml</mimetype>\n"
71 "<filetypename>" N_("Scalable Vector Graphic (*.svg)") "</filetypename>\n"
72 "<filetypetooltip>" N_("Inkscape native file format and W3C standard") "</filetypetooltip>\n"
73 "</input>\n"
74 "</inkscape-extension>", std::make_unique<Svg>());
75
76 /* SVG out Inkscape */
78 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
79 "<name>" N_("SVG Output Inkscape") "</name>\n"
80 "<id>" SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE "</id>\n"
81 "<output is_exported='true' priority='1'>\n"
82 "<extension>.svg</extension>\n"
83 "<mimetype>image/x-inkscape-svg</mimetype>\n"
84 "<filetypename>" N_("Inkscape SVG (*.svg)") "</filetypename>\n"
85 "<filetypetooltip>" N_("SVG format with Inkscape extensions") "</filetypetooltip>\n"
86 "<dataloss>false</dataloss>\n"
87 "</output>\n"
88 "<action>prune-proprietary-namespaces</action>\n"
89 "<action>set-svg-version-2</action>\n"
90 "<action>set-inkscape-version</action>\n"
91 "<action pref='!/dialogs/save_as/enable_svgexport'>reverse-auto-start-markers</action>\n"
92 "<action pref='!/dialogs/save_as/enable_svgexport'>remove-marker-context-paint</action>\n"
93 "<action pref='!/dialogs/save_as/enable_svgexport'>set-svg-version-1</action>\n"
94 "<action pref='/options/svgexport/text_insertfallback'>insert-text-fallback</action>\n"
95 "<action pref='/options/svgexport/mesh_insertpolyfill'>insert-mesh-polyfill</action>\n"
96 "<action pref='/options/svgexport/hatch_insertpolyfill'>insert-hatch-polyfill</action>\n"
97 "</inkscape-extension>", std::make_unique<Svg>());
98
99 /* SVG out */
101 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
102 "<name>" N_("SVG Output") "</name>\n"
103 "<id>" SP_MODULE_KEY_OUTPUT_SVG "</id>\n"
104 "<output is_exported='true' priority='2'>\n"
105 "<extension>.svg</extension>\n"
106 "<mimetype>image/svg+xml</mimetype>\n"
107 "<filetypename>" N_("Plain SVG (*.svg)") "</filetypename>\n"
108 "<filetypetooltip>" N_("Scalable Vector Graphics format as defined by the W3C") "</filetypetooltip>\n"
109 "</output>\n"
110 "<action>set-svg-version-2</action>\n"
111 "<action pref='!/dialogs/save_as/enable_svgexport'>reverse-auto-start-markers</action>\n"
112 "<action pref='!/dialogs/save_as/enable_svgexport'>remove-marker-context-paint</action>\n"
113 "<action pref='!/dialogs/save_as/enable_svgexport'>set-svg-version-1</action>\n"
114 "<action pref='/options/svgexport/text_insertfallback'>insert-text-fallback</action>\n"
115 "<action>prune-proprietary-namespaces</action>\n"
116 "<action>prune-inkscape-namespaces</action>\n"
117 "</inkscape-extension>", std::make_unique<Svg>());
118 // clang-format on
119
120 return;
121}
122
123
140std::unique_ptr<SPDocument> Svg::open(Inkscape::Extension::Input *mod, char const *uri, bool is_importing)
141{
142 g_assert(mod);
143
144 // This is only used at the end... but it should go here once uri stuff is fixed.
145 auto file = Gio::File::create_for_commandline_arg(uri);
146 const auto path = file->get_path();
147
148 // Fixing this means fixing a whole string of things.
149 // if (path.empty()) {
150 // // We lied, the uri wasn't a uri, try as path.
151 // file = Gio::File::create_for_path(uri);
152 // }
153
154 // std::cout << "Svg::open: uri in: " << uri << std::endl;
155 // std::cout << " : uri: " << file->get_uri() << std::endl;
156 // std::cout << " : scheme: " << file->get_uri_scheme() << std::endl;
157 // std::cout << " : path: " << file->get_path() << std::endl;
158 // std::cout << " : parse: " << file->get_parse_name() << std::endl;
159 // std::cout << " : base: " << file->get_basename() << std::endl;
160
162
163 // Get import preferences.
164 bool ask_svg = prefs->getBool( "/dialogs/import/ask_svg");
165 Glib::ustring import_mode_svg = prefs->getString("/dialogs/import/import_mode_svg");
166 Glib::ustring scale = prefs->getString("/dialogs/import/scale");
167
168 // Selecting some of the pages (via command line) in some future update
169 // we could add an option which would allow user page selection.
170 auto page_nums = INKSCAPE.get_pages();
171
172 // If we popped up a window asking about import preferences, get values from
173 // there and update preferences.
174 if(mod->get_gui() && ask_svg) {
175 ask_svg = !mod->get_param_bool("do_not_ask");
176 import_mode_svg = mod->get_param_optiongroup("import_mode_svg");
177 scale = mod->get_param_optiongroup("scale");
178
179 prefs->setBool( "/dialogs/import/ask_svg", ask_svg);
180 prefs->setString("/dialogs/import/import_mode_svg", import_mode_svg );
181 prefs->setString("/dialogs/import/scale", scale );
182 }
183
184 bool const import_pages = import_mode_svg == "pages";
185 bool const import_new = import_mode_svg == "new";
186
187 // Do we "import" as <image>?
188 if (is_importing && import_mode_svg != "include" && !import_pages && !import_new) {
189 // We import!
190
191 // New wrapper document.
192 auto doc = SPDocument::createNewDoc(nullptr, true, true);
193
194 // Imported document
195 auto ret = SPDocument::createNewDoc(uri, true);
196
197 if (!ret) {
198 return nullptr;
199 }
200
201 // What is display unit doing here?
202 Glib::ustring display_unit = doc->getDisplayUnit()->abbr;
203 double width = ret->getWidth().value(display_unit);
204 double height = ret->getHeight().value(display_unit);
205 if (width < 0 || height < 0) {
206 return nullptr;
207 }
208
209 // Create image node
210 Inkscape::XML::Document *xml_doc = doc->getReprDoc();
211 Inkscape::XML::Node *image_node = xml_doc->createElement("svg:image");
212
213 // Set default value as we honor "preserveAspectRatio".
214 image_node->setAttribute("preserveAspectRatio", "none");
215
216 double svgdpi = mod->get_param_float("svgdpi");
217 image_node->setAttribute("inkscape:svg-dpi", Inkscape::ustring::format_classic(svgdpi));
218
221
222 // This is actually "image-rendering"
223 Glib::ustring scale = prefs->getString("/dialogs/import/scale");
224 if( scale != "auto") {
226 sp_repr_css_set_property(css, "image-rendering", scale.c_str());
227 sp_repr_css_set(image_node, css, "style");
229 }
230
231 // Do we embed or link?
232 if (import_mode_svg == "embed") {
233 std::unique_ptr<Inkscape::Pixbuf> pb(Inkscape::Pixbuf::create_from_file(uri, svgdpi));
234 if(pb) {
235 sp_embed_svg(image_node, uri);
236 }
237 } else {
238 // Convert filename to uri (why do we need to do this, we claimed it was already a uri).
239 gchar* _uri = g_filename_to_uri(uri, nullptr, nullptr);
240 if(_uri) {
241 // if (strcmp(_uri, uri) != 0) {
242 // std::cout << "Svg::open: _uri != uri! " << _uri << ":" << uri << std::endl;
243 // }
244 image_node->setAttribute("xlink:href", _uri);
245 g_free(_uri);
246 } else {
247 image_node->setAttribute("xlink:href", uri);
248 }
249 }
250
251 // Add the image to a layer.
252 Inkscape::XML::Node *layer_node = xml_doc->createElement("svg:g");
253 layer_node->setAttribute("inkscape:groupmode", "layer");
254 layer_node->setAttribute("inkscape:label", "Image");
255 doc->getRoot()->appendChildRepr(layer_node);
256 layer_node->appendChild(image_node);
257 Inkscape::GC::release(image_node);
258 Inkscape::GC::release(layer_node);
259 fit_canvas_to_drawing(doc.get());
260
261 // Set viewBox if it doesn't exist. What is display unit doing here?
262 if (!doc->getRoot()->viewBox_set) {
263 doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit())));
264 }
265 return doc;
266 }
267
268 // We are not importing as <image>. Open as new document.
269
270 // Try to open non-local file (when does this occur?).
271 if (!file->get_uri_scheme().empty()) {
272 if (path.empty()) {
273 try {
274 char *contents;
275 gsize length;
276 file->load_contents(contents, length);
277 return SPDocument::createNewDocFromMem({contents, length}, true);
278 } catch (Gio::Error &e) {
279 g_warning("Could not load contents of non-local URI %s\n", uri);
280 return nullptr;
281 }
282 } else {
283 // Do we ever get here and does this actually work?
284 uri = path.c_str();
285 }
286 }
287
288 auto doc = SPDocument::createNewDoc(uri, true);
289
290 // Page selection is achieved by removing any page not in the found list, the exports
291 // Can later figure out how they'd like to process the remaining pages.
292 if (doc && !page_nums.empty()) {
293 doc->prunePages(page_nums, true);
294 }
295
296 // Convert single page docs into multi page mode, and visa-versa if
297 // we are importing. We never change the mode for opening.
298 if (doc && is_importing && !import_new) {
299 doc->setPages(import_pages);
300 }
301
302 return doc;
303}
304
314void
315Svg::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
316{
317 g_return_if_fail(doc != nullptr);
318 g_return_if_fail(filename != nullptr);
319
320 if (!sp_repr_save_rebased_file(doc->getReprDoc(), filename, SP_SVG_NS_URI,
321 doc->getDocumentBase(),
322 m_detachbase ? nullptr : filename)) {
324 }
325}
326
327} // namespace Inkscape::Extension::Internal
328
329/*
330 Local Variables:
331 mode:c++
332 c-file-style:"stroustrup"
333 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
334 indent-tabs-mode:nil
335 fill-column:99
336 End:
337*/
338// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
double scale
Definition aa.cpp:228
Cairo integration helpers.
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
std::unique_ptr< SPDocument > open(Inkscape::Extension::Input *mod, char const *uri, bool is_importing) override
This function takes in a filename of a SVG document and turns it into a SPDocument.
Definition svg.cpp:140
static void init()
What would an SVG editor be without loading/saving SVG files. This function sets that up.
Definition svg.cpp:59
void save(Inkscape::Extension::Output *mod, SPDocument *doc, char const *filename) override
This is the function that does all of the SVG saves in Inkscape. It detects whether it should do a In...
Definition svg.cpp:315
Generic failure for an undescribed reason.
Definition output.h:34
static Pixbuf * create_from_file(std::string const &fn, double svgddpi=0)
Preference storage class.
Definition preferences.h:61
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
Glib::ustring getString(Glib::ustring const &pref_path, Glib::ustring const &def="")
Retrieve an UTF-8 string.
static Preferences * get()
Access the singleton Preferences object.
void setString(Glib::ustring const &pref_path, Glib::ustring const &value)
Set an UTF-8 string value.
void setBool(Glib::ustring const &pref_path, bool value)
Set a Boolean value.
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 setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
Typed SVG document implementation.
Definition document.h:101
static std::unique_ptr< SPDocument > createNewDocFromMem(std::span< char const > buffer, bool keepalive, std::string const &filename="")
Definition document.cpp:709
char const * getDocumentBase() const
Definition document.h:233
static std::unique_ptr< SPDocument > createNewDoc(char const *filename, bool keepalive, bool make_new=false, SPDocument *parent=nullptr)
Fetches document from filename, or creates new, if NULL; public document appears in document list.
Definition document.cpp:659
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
Definition document.h:211
A way to clear the N_ macro, which is defined as an inline function.
std::shared_ptr< Css const > css
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.
Glib::ustring format_classic(T const &... args)
Singleton class to access the preferences file in a convenient way.
SPCSSAttr * sp_repr_css_attr_new()
Creates an empty SPCSSAttr (a class for manipulating CSS style properties).
Definition repr-css.cpp:67
void sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
Sets an attribute (e.g.
Definition repr-css.cpp:264
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
Definition repr-css.cpp:76
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
bool sp_repr_save_rebased_file(Document *doc, gchar const *const filename, gchar const *default_ns, gchar const *old_base, gchar const *for_filename)
Returns true if file successfully saved.
Definition repr-io.cpp:669
bool fit_canvas_to_drawing(SPDocument *doc, bool with_margins)
void sp_embed_svg(Inkscape::XML::Node *image_node, std::string const &fn)
Definition sp-image.cpp:759
SVG <image> implementation.
SPRoot: SVG <svg> implementation.
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
double height
double width