Inkscape
Vector Graphics Editor
imagemagick.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Authors:
4 * Christopher Brown <audiere@gmail.com>
5 * Ted Gould <ted@gould.cx>
6 *
7 * Copyright (C) 2007 Authors
8 *
9 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
10 */
11
12#include <string>
13#include <vector>
14
15#include <libintl.h>
16
17#include <gtkmm/box.h>
18#include <gtkmm/adjustment.h>
19#include <gtkmm/spinbutton.h>
20
21#include <glib/gstdio.h>
22
23#include "desktop.h"
24#include "selection.h"
25#include "extension/effect.h"
26#include "extension/system.h"
27#include "imagemagick.h"
29
30#include <Magick++.h>
31
32namespace Inkscape {
33namespace Extension {
34namespace Internal {
35namespace Bitmap {
36
37namespace {
38struct ImageInfo {
40 std::unique_ptr<Magick::Image> image;
41 std::string cache;
42 std::string original;
43 SPItem* item = nullptr;
44};
45}
47 friend class ImageMagick;
48private:
49 void readImage(char const *xlink, char const *id, Magick::Image &image);
50protected:
51 std::vector<ImageInfo> images;
52public:
53 ImageMagickDocCache(SPDesktop *desktop);
54};
55
56ImageMagickDocCache::ImageMagickDocCache(SPDesktop *desktop)
57 : Inkscape::Extension::Implementation::ImplementationDocumentCache(desktop)
58{
59 auto selected_item_list = desktop->getSelection()->items();
60 images.reserve(boost::distance(selected_item_list));
61
62 // Loop through selected items
63 for (auto item : selected_item_list) {
65 if (strcmp(node->name(), "image") != 0 && strcmp(node->name(), "svg:image") != 0) {
66 continue;
67 }
68 char const *xlink = Inkscape::getHrefAttribute(*node).second;
69 images.push_back({
70 .node = node,
71 .image = std::make_unique<Magick::Image>(),
72 .original = xlink,
73 .item = item
74 });
75 readImage(xlink, node->attribute("id"), *images.back().image);
76 }
77}
78
79void ImageMagickDocCache::readImage(const char *xlink, const char *id, Magick::Image &image)
80{
81 // Find if the xlink:href is base64 data, i.e. if the image is embedded
82 gchar *search = g_strndup(xlink, 30);
83 if (strstr(search, "base64") != (char*)NULL) {
84 // 7 = strlen("base64") + strlen(",")
85 const char* pureBase64 = strstr(xlink, "base64") + 7;
86 Magick::Blob blob;
87 blob.base64(pureBase64);
88 try {
89 image.read(blob);
90 } catch (Magick::Exception &error_) {
91 g_warning("ImageMagick could not read '%s'\nDetails: %s", id, error_.what());
92 }
93 } else {
94 gchar *path;
95 if (strncmp (xlink,"file:", 5) == 0) {
96 path = g_filename_from_uri(xlink, NULL, NULL);
97 } else {
98 path = g_strdup(xlink);
99 }
100 try {
101 image.read(path);
102 } catch (Magick::Exception &error_) {
103 g_warning("ImageMagick could not read '%s' from '%s'\nDetails: %s", id, path, error_.what());
104 }
105 g_free(path);
106 }
107 g_free(search);
108}
109
110bool
111ImageMagick::load(Inkscape::Extension::Extension */*module*/)
112{
113 return true;
114}
115
117ImageMagick::newDocCache(Inkscape::Extension::Extension * /*ext*/, SPDesktop *desktop) {
118 return new ImageMagickDocCache(desktop);
119}
120
121void
123{
124 refreshParameters(module);
125 ImageMagickDocCache * dc = dynamic_cast<ImageMagickDocCache *>(docCache);
126 if (!dc) { // should really never happen
127 return;
128 }
129 unsigned constexpr b64_line_length = 76;
130
131 try {
132 for (auto &image : dc->images) {
133 Magick::Image effected_image = *image.image; // make a copy
134 applyEffect(&effected_image);
135
136 // postEffect can be used to change things on the item itself
137 // e.g. resize the image element, after the effecti is applied
138 postEffect(&effected_image, image.item);
139
140 auto blob = std::make_unique<Magick::Blob>();
141 effected_image.write(blob.get());
142
143 std::string base64_string = blob->base64();
144 for (size_t newline_pos = b64_line_length;
145 newline_pos < base64_string.length();
146 newline_pos += b64_line_length + 1) {
147 base64_string.insert(newline_pos, "\n");
148 }
149 image.cache = "data:image/" + effected_image.magick() + ";base64, \n" + base64_string;
150
152 image.node->removeAttribute("sodipodi:absref");
153 }
154 } catch (Magick::Exception &error) {
155 std::cerr << "ImageMagick effect exception:" << error.what() << std::endl;
156 }
157}
158
165Gtk::Widget *
166ImageMagick::prefs_effect(Inkscape::Extension::Effect *module, SPDesktop *desktop, sigc::signal<void ()> * changeSignal,
168{
169 SPDocument * current_document = desktop->doc();
170
171 auto selected = desktop->getSelection()->items();
172 Inkscape::XML::Node * first_select = NULL;
173 if (!selected.empty()) {
174 first_select = (selected.front())->getRepr();
175 }
176 return module->autogui(current_document, first_select, changeSignal);
177}
178
179}; /* namespace Bitmap */
180}; /* namespace Internal */
181}; /* namespace Extension */
182}; /* namespace Inkscape */
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:130
Gtk::Widget * autogui(SPDocument *doc, Inkscape::XML::Node *node, sigc::signal< void()> *changeSignal=nullptr)
A function to automatically generate a GUI from the extensions' widgets.
Definition: extension.cpp:975
A cache for the document and this implementation.
SPItemRange items()
Returns a range of selected SPItems.
Definition: object-set.h:267
Interface for refcounted XML nodes.
Definition: node.h:80
virtual char const * name() const =0
Get the name of the element node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
To do: update description of desktop.
Definition: desktop.h:150
Inkscape::Selection * getSelection() const
Definition: desktop.h:186
SPDocument * doc() const
Definition: desktop.h:163
Typed SVG document implementation.
Definition: document.h:106
Base class for visual SVG elements.
Definition: sp-item.h:107
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
Definition: sp-object.cpp:232
Editable view implementation.
std::string cache
Definition: imagemagick.cpp:41
std::unique_ptr< Magick::Image > image
Definition: imagemagick.cpp:40
SPItem * item
Definition: imagemagick.cpp:43
std::string original
Definition: imagemagick.cpp:42
Inkscape::XML::Node * node
Definition: imagemagick.cpp:39
Angle distance(Angle const &a, Angle const &b)
Definition: angle.h:163
CMYK to sRGB conversion routines.
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.
std::pair< char const *, char const * > getHrefAttribute(XML::Node const &node)
Get the 'href' or 'xlink:href' (fallback) attribute from an XML node.