diff options
Diffstat (limited to 'src/extension/internal/bitmap/imagemagick.cpp')
-rw-r--r-- | src/extension/internal/bitmap/imagemagick.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp new file mode 100644 index 0000000..36176bc --- /dev/null +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Authors: + * Christopher Brown <audiere@gmail.com> + * Ted Gould <ted@gould.cx> + * + * Copyright (C) 2007 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <libintl.h> + +#include <gtkmm/box.h> +#include <gtkmm/adjustment.h> +#include <gtkmm/spinbutton.h> + +#include <glib/gstdio.h> + +#include "desktop.h" + +#include "selection.h" + +#include "extension/effect.h" +#include "extension/system.h" + +#include "imagemagick.h" +#include <Magick++.h> + +namespace Inkscape { +namespace Extension { +namespace Internal { +namespace Bitmap { + +class ImageMagickDocCache: public Inkscape::Extension::Implementation::ImplementationDocumentCache { + friend class ImageMagick; +private: + void readImage(char const *xlink, char const *id, Magick::Image *image); +protected: + Inkscape::XML::Node** _nodes; + + Magick::Image** _images; + int _imageCount; + char** _caches; + unsigned* _cacheLengths; + const char** _originals; + SPItem** _imageItems; +public: + ImageMagickDocCache(Inkscape::UI::View::View * view); + ~ImageMagickDocCache ( ) override; +}; + +ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) : + Inkscape::Extension::Implementation::ImplementationDocumentCache(view), + _nodes(NULL), + _images(NULL), + _imageCount(0), + _caches(NULL), + _cacheLengths(NULL), + _originals(NULL), + _imageItems(NULL) +{ + SPDesktop *desktop = (SPDesktop*)view; + auto selectedItemList = desktop->selection->items(); + int selectCount = (int) boost::distance(selectedItemList); + + // Init the data-holders + _nodes = new Inkscape::XML::Node*[selectCount]; + _originals = new const char*[selectCount]; + _caches = new char*[selectCount]; + _cacheLengths = new unsigned int[selectCount]; + _images = new Magick::Image*[selectCount]; + _imageCount = 0; + _imageItems = new SPItem*[selectCount]; + + // Loop through selected items + for (auto i = selectedItemList.begin(); i != selectedItemList.end(); ++i) { + SPItem *item = *i; + Inkscape::XML::Node *node = reinterpret_cast<Inkscape::XML::Node *>(item->getRepr()); + if (!strcmp(node->name(), "image") || !strcmp(node->name(), "svg:image")) + { + _nodes[_imageCount] = node; + char const *xlink = node->attribute("xlink:href"); + char const *id = node->attribute("id"); + _originals[_imageCount] = xlink; + _caches[_imageCount] = (char*)""; + _cacheLengths[_imageCount] = 0; + _images[_imageCount] = new Magick::Image(); + readImage(xlink, id, _images[_imageCount]); + _imageItems[_imageCount] = item; + _imageCount++; + } + } +} + +ImageMagickDocCache::~ImageMagickDocCache ( ) { + if (_nodes) + delete _nodes; + if (_originals) + delete _originals; + if (_caches) + delete _caches; + if (_cacheLengths) + delete _cacheLengths; + if (_images) + delete _images; + if (_imageItems) + delete _imageItems; + return; +} + +void +ImageMagickDocCache::readImage(const char *xlink, const char *id, Magick::Image *image) +{ + // Find if the xlink:href is base64 data, i.e. if the image is embedded + gchar *search = g_strndup(xlink, 30); + if (strstr(search, "base64") != (char*)NULL) { + // 7 = strlen("base64") + strlen(",") + const char* pureBase64 = strstr(xlink, "base64") + 7; + Magick::Blob blob; + blob.base64(pureBase64); + try { + image->read(blob); + } catch (Magick::Exception &error_) { + g_warning("ImageMagick could not read '%s'\nDetails: %s", id, error_.what()); + } + } else { + gchar *path; + if (strncmp (xlink,"file:", 5) == 0) { + path = g_filename_from_uri(xlink, NULL, NULL); + } else { + path = g_strdup(xlink); + } + try { + image->read(path); + } catch (Magick::Exception &error_) { + g_warning("ImageMagick could not read '%s' from '%s'\nDetails: %s", id, path, error_.what()); + } + g_free(path); + } + g_free(search); +} + +bool +ImageMagick::load(Inkscape::Extension::Extension */*module*/) +{ + return true; +} + +Inkscape::Extension::Implementation::ImplementationDocumentCache * +ImageMagick::newDocCache (Inkscape::Extension::Extension * /*ext*/, Inkscape::UI::View::View * view) { + return new ImageMagickDocCache(view); +} + +void +ImageMagick::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document, Inkscape::Extension::Implementation::ImplementationDocumentCache * docCache) +{ + refreshParameters(module); + + if (docCache == NULL) { // should never happen + docCache = newDocCache(module, document); + } + ImageMagickDocCache * dc = dynamic_cast<ImageMagickDocCache *>(docCache); + if (dc == NULL) { // should really never happen + printf("AHHHHHHHHH!!!!!"); + exit(1); + } + + for (int i = 0; i < dc->_imageCount; i++) + { + try + { + Magick::Image effectedImage = *dc->_images[i]; // make a copy + + applyEffect(&effectedImage); + + // postEffect can be used to change things on the item itself + // e.g. resize the image element, after the effecti is applied + postEffect(&effectedImage, dc->_imageItems[i]); + +// dc->_nodes[i]->setAttribute("xlink:href", dc->_caches[i]); + + Magick::Blob *blob = new Magick::Blob(); + effectedImage.write(blob); + + std::string raw_string = blob->base64(); + const int raw_len = raw_string.length(); + const char *raw_i = raw_string.c_str(); + + unsigned new_len = (int)(raw_len * (77.0 / 76.0) + 100); + if (new_len > dc->_cacheLengths[i]) { + dc->_cacheLengths[i] = (int)(new_len * 1.2); + dc->_caches[i] = new char[dc->_cacheLengths[i]]; + } + char *formatted_i = dc->_caches[i]; + const char *src; + + for (src = "data:image/"; *src; ) + *formatted_i++ = *src++; + for (src = effectedImage.magick().c_str(); *src ; ) + *formatted_i++ = *src++; + for (src = ";base64, \n" ; *src; ) + *formatted_i++ = *src++; + + int col = 0; + while (*raw_i) { + *formatted_i++ = *raw_i++; + if (col++ > 76) { + *formatted_i++ = '\n'; + col = 0; + } + } + if (col) { + *formatted_i++ = '\n'; + } + *formatted_i = '\0'; + + dc->_nodes[i]->setAttribute("xlink:href", dc->_caches[i]); + dc->_nodes[i]->removeAttribute("sodipodi:absref"); + delete blob; + } + catch (Magick::Exception &error_) { + printf("Caught exception: %s \n", error_.what()); + } + + //while(Gtk::Main::events_pending()) { + // Gtk::Main::iteration(); + //} + } +} + +/** \brief A function to get the preferences for the grid + \param module Module which holds the params + \param view Unused today - may get style information in the future. + + Uses AutoGUI for creating the GUI. +*/ +Gtk::Widget * +ImageMagick::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View * view, sigc::signal<void> * changeSignal, Inkscape::Extension::Implementation::ImplementationDocumentCache * /*docCache*/) +{ + SPDocument * current_document = view->doc(); + + auto selected = ((SPDesktop *) view)->getSelection()->items(); + Inkscape::XML::Node * first_select = NULL; + if (!selected.empty()) { + first_select = (selected.front())->getRepr(); + } + + return module->autogui(current_document, first_select, changeSignal); +} + +}; /* namespace Bitmap */ +}; /* namespace Internal */ +}; /* namespace Extension */ +}; /* namespace Inkscape */ |