Code

Mnemonics in "Fill and stroke", "Align and distribute", and "Transform" dialogs ...
[inkscape.git] / src / extension / internal / bitmap / imagemagick.cpp
index 83650aaa788b84c2640544e0d0b0677974a0ddb5..e907612fdaa093098e27d6f361e7976d7aa7a26e 100644 (file)
@@ -8,9 +8,12 @@
  * 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>
 
@@ -30,122 +33,182 @@ namespace Extension {
 namespace Internal {
 namespace Bitmap {
 
-bool
-ImageMagick::load(Inkscape::Extension::Extension *module)
+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)
 {
-       _loaded = FALSE;
-       return TRUE;
-}
+       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");
 
-void
-ImageMagick::commitDocument(void) {
-       _loaded = FALSE;
-}
+                       _originals[_imageCount] = xlink;
+                       _caches[_imageCount] = "";
+                       _cacheLengths[_imageCount] = 0;
+                       _images[_imageCount] = new Magick::Image();
+                       readImage(xlink, _images[_imageCount]);                 
 
-void
-ImageMagick::cancelDocument(void) {    
-       for (int i = 0; i < _imageCount; i++) {
-               _nodes[i]->setAttribute("xlink:href", _originals[i], true);
+                       _imageCount++;
+               }                       
        }
-       
-       _loaded = FALSE;
+}
+
+ImageMagickDocCache::~ImageMagickDocCache ( ) {
+       if (_nodes)
+               delete _nodes;
+       if (_originals)
+               delete _originals;
+       if (_caches)
+               delete _caches;
+       if (_cacheLengths)
+               delete _cacheLengths;
+       if (_images)
+               delete _images;
+
+       return;
 }
 
 void
-ImageMagick::readImage(const char *xlink, Magick::Image *image)
+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 = strndup(xlink, 30);
+       // 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;         
+               const char* pureBase64 = strstr(xlink, "base64") + 7;           
                Magick::Blob blob;
                blob.base64(pureBase64);
                image->read(blob);
        }
        else {
-               image->read(xlink);
+               const gchar *path = xlink;
+    if (strncmp (xlink,"file:", 5) == 0) {
+      path = g_filename_from_uri(xlink, NULL, NULL);
+               }
+
+               try {
+                       image->read(path);
+               } catch (...) {}
        }
+       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)
+ImageMagick::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document, Inkscape::Extension::Implementation::ImplementationDocumentCache * docCache)
 {
        refreshParameters(module);
-       
-       if (!_loaded)
-       {               
-               SPDesktop *desktop = (SPDesktop*)document;
-               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];
-               _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;
-                               
-                               readImage(xlink, &_images[_imageCount]);
-                               
-                               _imageCount++;
-                       }                       
-               }
-               
-               _loaded = 1;
+
+       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 < _imageCount; i++)
+       for (int i = 0; i < dc->_imageCount; i++)
        {
                try
                {
-                       Magick::Image effectedImage = _images[i];
+                       Magick::Image effectedImage = *dc->_images[i]; // make a copy
                        applyEffect(&effectedImage);
 
-                       Magick::Blob blob;
-                       effectedImage.write(&blob);
-                               
-                               std::string raw_string = blob.base64();
-                               const int raw_len = raw_string.length();
-                               const char *raw = raw_string.c_str();
-                               const char *raw_i = raw;        
-                               
-                               int formatted_len = (int)(raw_len / 76.0 * 78.0) + 100;
-                               char *formatted = new char[formatted_len];
-                               char *formatted_i = formatted;
-                               // data:image/png;base64,
-                               formatted_i = stpcpy(formatted_i, "data:image/");
-                               formatted_i = stpcpy(formatted_i, effectedImage.magick().c_str());
-                               formatted_i = stpcpy(formatted_i, ";base64, \n");
-                               while (strnlen(raw_i, 80) > 76)
-                               {
-                                       formatted_i = stpncpy(formatted_i, raw_i, 76);
-                                       formatted_i = stpcpy(formatted_i, "\n");                                        
-                                       raw_i += 76;            
-                               }
-                               if (strlen(raw_i) > 0)
-                               {
-                                       formatted_i = stpcpy(formatted_i, raw_i);
-                                       formatted_i = stpcpy(formatted_i, "\n");
-                               }
-                               
-                               formatted_i = stpcpy(formatted_i, "\0");
-                               
-                               _nodes[i]->setAttribute("xlink:href", formatted, true);
+                       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();
+               //}
        }
 }
 
@@ -156,7 +219,7 @@ ImageMagick::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::Vi
     Uses AutoGUI for creating the GUI.
 */
 Gtk::Widget *
-ImageMagick::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View * view, sigc::signal<void> * changeSignal)
+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();