imagemagick.cpp revision 0ff4eef7ffaeb576f4810bd8677b9383bf660a3b
/*
* Authors:
* Christopher Brown <audiere@gmail.com>
* Ted Gould <ted@gould.cx>
*
* Copyright (C) 2007 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <libintl.h>
#include <gtkmm/box.h>
#include <gtkmm/adjustment.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm.h>
#include <glib/gstdio.h>
#include "desktop.h"
#include "desktop-handles.h"
#include "selection.h"
#include "sp-object.h"
#include "util/glib-list-iterators.h"
#include "extension/effect.h"
#include "extension/system.h"
#include "imagemagick.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, Magick::Image *image);
protected:
Inkscape::XML::Node** _nodes;
Magick::Image** _images;
int _imageCount;
char** _caches;
unsigned* _cacheLengths;
const char** _originals;
public:
ImageMagickDocCache(Inkscape::UI::View::View * view);
~ImageMagickDocCache ( );
};
ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) :
Inkscape::Extension::Implementation::ImplementationDocumentCache(view),
_nodes(NULL),
_images(NULL),
_imageCount(0),
_caches(NULL),
_cacheLengths(NULL),
_originals(NULL)
{
SPDesktop *desktop = (SPDesktop*)view;
const GSList *selectedReprList = desktop->selection->reprList();
int selectCount = g_slist_length((GSList *)selectedReprList);
// 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;
// Loop through selected nodes
for (; selectedReprList != NULL; selectedReprList = g_slist_next(selectedReprList))
{
Inkscape::XML::Node *node = reinterpret_cast<Inkscape::XML::Node *>(selectedReprList->data);
if (!strcmp(node->name(), "image") || !strcmp(node->name(), "svg:image"))
{
_nodes[_imageCount] = node;
char const *xlink = node->attribute("xlink:href");
_originals[_imageCount] = xlink;
_caches[_imageCount] = "";
_cacheLengths[_imageCount] = 0;
_images[_imageCount] = new Magick::Image();
readImage(xlink, _images[_imageCount]);
_imageCount++;
}
}
}
ImageMagickDocCache::~ImageMagickDocCache ( ) {
if (_nodes)
delete _nodes;
if (_originals)
delete _originals;
if (_caches)
delete _caches;
if (_cacheLengths)
delete _cacheLengths;
if (_images)
delete _images;
return;
}
void
ImageMagickDocCache::readImage(const char *xlink, Magick::Image *image)
{
// Find if the xlink:href is base64 data, i.e. if the image is embedded
char *search = (char *) g_strndup(xlink, 30);
if (strstr(search, "base64") != (char*)NULL) {
// 7 = strlen("base64") + strlen(",")
char* pureBase64 = strstr(xlink, "base64") + 7;
Magick::Blob blob;
blob.base64(pureBase64);
image->read(blob);
}
else {
image->read(xlink);
}
}
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);
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], true);
dc->_nodes[i]->setAttribute("sodipodi:absref", NULL, true);
}
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 prefences for the grid
\param moudule 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();
using Inkscape::Util::GSListConstIterator;
GSListConstIterator<SPItem *> selected = sp_desktop_selection((SPDesktop *)view)->itemList();
Inkscape::XML::Node * first_select = NULL;
if (selected != NULL)
first_select = SP_OBJECT_REPR(*selected);
return module->autogui(current_document, first_select, changeSignal);
}
}; /* namespace Bitmap */
}; /* namespace Internal */
}; /* namespace Extension */
}; /* namespace Inkscape */