Code

Applied patch 1500171
[inkscape.git] / src / trace / trace.cpp
index b7e83a979012358b1f9a5dac2b595e3ea5e72f26..d40fb89d7e67567b2e112c53ec1824e85c78d67f 100644 (file)
 #include "trace/potrace/inkscape-potrace.h"
 
 #include <inkscape.h>
+#include <desktop.h>
 #include <desktop-handles.h>
 #include <document.h>
-#include "message-stack.h"
+#include <message-stack.h>
 #include <glibmm/i18n.h>
 #include <selection.h>
 #include <xml/repr.h>
-#include "sp-item.h"
-#include "sp-image.h"
+#include <xml/attribute-record.h>
+#include <sp-item.h>
+#include <sp-shape.h>
+#include <sp-image.h>
+
+#include <display/nr-arena.h>
+#include <display/nr-arena-shape.h>
 
 #include "siox.h"
 #include "imagemap-gdk.h"
 
-namespace Inkscape {
 
-namespace Trace {
+
+namespace Inkscape
+{
+
+namespace Trace
+{
+
+
+
+
+
 
 /**
- *
+ * Get the selected image.  Also check for any SPItems over it, in
+ * case the user wants SIOX pre-processing.
  */
 SPImage *
 Tracer::getSelectedSPImage()
 {
+
     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
     if (!desktop)
         {
@@ -44,11 +61,13 @@ Tracer::getSelectedSPImage()
         return NULL;
         }
 
-    Inkscape::Selection *sel = SP_DT_SELECTION(desktop);
+    Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
+
+    Inkscape::Selection *sel = sp_desktop_selection(desktop);
     if (!sel)
         {
         char *msg = _("Select an <b>image</b> to trace");
-        SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
         //g_warning(msg);
         return NULL;
         }
@@ -57,8 +76,9 @@ Tracer::getSelectedSPImage()
         {
         SPImage *img = NULL;
         GSList const *list = sel->itemList();
-        sioxItems.clear();
         std::vector<SPItem *> items;
+        sioxShapes.clear();
+
         /*
            First, things are selected top-to-bottom, so we need to invert
            them as bottom-to-top so that we can discover the image and any
@@ -82,32 +102,37 @@ Tracer::getSelectedSPImage()
                 if (img) //we want only one
                     {
                     char *msg = _("Select only one <b>image</b> to trace");
-                    SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+                    msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
                     return NULL;
                     }
                 img = SP_IMAGE(item);
                 }
-            else if (img) //# items -after- the image in tree (above it in Z)
+            else // if (img) //# items -after- the image in tree (above it in Z)
                 {
-                sioxItems.push_back(item);
+                if (SP_IS_SHAPE(item))
+                    {
+                    SPShape *shape = SP_SHAPE(item);
+                    sioxShapes.push_back(shape);
+                    }
                 }
             }
-        if (!img || sioxItems.size() < 1)
+
+        if (!img || sioxShapes.size() < 1)
             {
-            char *msg = _("Select one image and one or more items above it");
-            SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+            char *msg = _("Select one image and one or more shapes above it");
+            msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
             return NULL;
             }
         return img;
         }
     else
-        //### No SIOX.  We want exactly one image selected
+        //### SIOX not enabled.  We want exactly one image selected
         {
         SPItem *item = sel->singleItem();
         if (!item)
             {
             char *msg = _("Select an <b>image</b> to trace");  //same as above
-            SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+            msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
             //g_warning(msg);
             return NULL;
             }
@@ -115,7 +140,7 @@ Tracer::getSelectedSPImage()
         if (!SP_IS_IMAGE(item))
             {
             char *msg = _("Select an <b>image</b> to trace");
-            SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+            msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
             //g_warning(msg);
             return NULL;
             }
@@ -129,73 +154,180 @@ Tracer::getSelectedSPImage()
 
 
 
-/**
- *
- */
+typedef org::siox::SioxImage SioxImage;
+typedef org::siox::Siox Siox;
+
 GdkPixbuf *
-Tracer::getSelectedImage()
+Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
 {
+    if (!sioxEnabled)
+        return origPixbuf;
 
-    SPImage *img = getSelectedSPImage();
-    if (!img)
+    //Convert from gdk, so a format we know.  By design, the pixel
+    //format in PackedPixelMap is identical to what is needed by SIOX
+    SioxImage simage(origPixbuf);
+
+    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+    if (!desktop)
+        {
+        g_warning("Trace: No active desktop\n");
         return NULL;
+        }
 
-    GdkPixbuf *pixbuf = img->pixbuf;
+    Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
 
-    return pixbuf;
+    Inkscape::Selection *sel = sp_desktop_selection(desktop);
+    if (!sel)
+        {
+        char *msg = _("Select an <b>image</b> to trace");
+        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
+        //g_warning(msg);
+        return NULL;
+        }
 
-}
+    NRArenaItem *aImg = sp_item_get_arenaitem(img, desktop->dkey);
+    //g_message("img: %d %d %d %d\n", aImg->bbox.x0, aImg->bbox.y0,
+    //                                aImg->bbox.x1, aImg->bbox.y1);
 
+    double width  = (double)(aImg->bbox.x1 - aImg->bbox.x0);
+    double height = (double)(aImg->bbox.y1 - aImg->bbox.y0);
 
-GdkPixbuf *
-Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
-{
+    double iwidth  = (double)simage.getWidth();
+    double iheight = (double)simage.getHeight();
+
+    double iwscale = width  / iwidth;
+    double ihscale = height / iheight;
+
+    std::vector<NRArenaItem *> arenaItems;
+    std::vector<SPShape *>::iterator iter;
+    for (iter = sioxShapes.begin() ; iter!=sioxShapes.end() ; iter++)
+        {
+        SPItem *item = *iter;
+        //### Create ArenaItems and set transform
+        NRArenaItem *aItem = sp_item_get_arenaitem(item, desktop->dkey);
+
+        //nr_arena_item_set_transform(aItem, item->transform);
+        //g_message("%d %d %d %d\n", aItem->bbox.x0, aItem->bbox.y0,
+        //                           aItem->bbox.x1, aItem->bbox.y1);
+        arenaItems.push_back(aItem);
+        }
+    //g_message("%d arena items\n", arenaItems.size());
 
-    RgbMap *rgbMap = gdkPixbufToRgbMap(origPixbuf);
-    //We need to create two things:
-    //  1.  An array of long pixel values of ARGB
-    //  2.  A matching array of per-pixel float 'confidence' values
-    long *imgBuf = new long[rgbMap->width * rgbMap->height];
-    float *confidenceMatrix = new float[rgbMap->width * rgbMap->height];
+    PackedPixelMap *dumpMap = PackedPixelMapCreate(
+                    simage.getWidth(), simage.getHeight());
 
-    long idx = 0;
-    for (int j=0 ; j<rgbMap->height ; j++)
-        for (int i=0 ; i<rgbMap->width ; i++)
+    for (int row=0 ; row<simage.getHeight() ; row++)
+        {
+        double ypos = ((double)aImg->bbox.y0) + ihscale * (double) row;
+        for (int col=0 ; col<simage.getWidth() ; col++)
             {
-            RGB rgb = rgbMap->getPixel(rgbMap, i, j);
-            long pix = (((long)rgb.r) << 16 & 0xFF0000L) |
-                       (((long)rgb.g) <<  8 & 0x00FF00L) |
-                       (((long)rgb.b)       & 0x0000FFL);
-            imgBuf[idx++] = pix;
+            //Get absolute X,Y position
+            double xpos = ((double)aImg->bbox.x0) + iwscale * (double)col;
+            NR::Point point(xpos, ypos);
+            point *= aImg->transform;
+            //point *= imgMat;
+            //point = desktop->doc2dt(point);
+            std::vector<SPShape *>::iterator iter;
+            //g_message("x:%f    y:%f\n", point[0], point[1]);
+            bool weHaveAHit = false;
+            std::vector<NRArenaItem *>::iterator aIter;
+            for (aIter = arenaItems.begin() ; aIter!=arenaItems.end() ; aIter++)
+                {
+                NRArenaItem *arenaItem = *aIter;
+                NRArenaItemClass *arenaClass =
+                    (NRArenaItemClass *) NR_OBJECT_GET_CLASS (arenaItem);
+                if (arenaClass->pick(arenaItem, point, 1.0f, 1))
+                    {
+                    weHaveAHit = true;
+                    break;
+                    }
+                }
+
+            if (weHaveAHit)
+                {
+                //g_message("hit!\n");
+                dumpMap->setPixelLong(dumpMap, col, row, 0L);
+                simage.setConfidence(col, row, 
+                        Siox::UNKNOWN_REGION_CONFIDENCE);
+                }
+            else
+                {
+                dumpMap->setPixelLong(dumpMap, col, row,
+                        simage.getPixel(col, row));
+                simage.setConfidence(col, row,
+                        Siox::CERTAIN_BACKGROUND_CONFIDENCE);
+                }
             }
+        }
+
+    //dumpMap->writePPM(dumpMap, "siox1.ppm");
+    dumpMap->destroy(dumpMap);
 
     //## ok we have our pixel buf
-    org::siox::SioxSegmentator ss(rgbMap->width, rgbMap->height, NULL, 0);
-    ss.segmentate(imgBuf, rgbMap->width * rgbMap->height,
-                  confidenceMatrix, rgbMap->width * rgbMap->height,
-                  0, 0.0);
-
-    idx = 0;
-    for (int j=0 ; j<rgbMap->height ; j++)
-        for (int i=0 ; i<rgbMap->width ; i++)
-            {
-            long pix = imgBuf[idx++];
-            RGB rgb;
-            rgb.r = (pix>>16) & 0xff;
-            rgb.g = (pix>> 8) & 0xff;
-            rgb.b = (pix    ) & 0xff;
-            rgbMap->setPixelRGB(rgbMap, i, j, rgb);
-            }
+    org::siox::Siox sengine;
+    org::siox::SioxImage result =
+            sengine.extractForeground(simage, 0xffffff);
+    if (!result.isValid())
+        {
+        g_warning("Invalid SIOX result");
+        return NULL;
+        }
 
-    GdkPixbuf *newPixbuf = rgbMapToGdkPixbuf(rgbMap);
-    rgbMap->destroy(rgbMap);
-    delete imgBuf;
-    delete confidenceMatrix;
+    //result.writePPM("siox2.ppm");
+
+    /* Free Arena and ArenaItem */
+    /*
+    std::vector<NRArenaItem *>::iterator aIter;
+    for (aIter = arenaItems.begin() ; aIter!=arenaItems.end() ; aIter++)
+       {
+       NRArenaItem *arenaItem = *aIter;
+       nr_arena_item_unref(arenaItem);
+       }
+    nr_object_unref((NRObject *) arena);
+    */
+
+    GdkPixbuf *newPixbuf = result.getGdkPixbuf();
 
     return newPixbuf;
 }
 
 
+/**
+ *
+ */
+GdkPixbuf *
+Tracer::getSelectedImage()
+{
+
+    SPImage *img = getSelectedSPImage();
+    if (!img)
+        return NULL;
+
+    GdkPixbuf *pixbuf = img->pixbuf;
+    if (!pixbuf)
+        return NULL;
+
+    if (sioxEnabled)
+        {
+        GdkPixbuf *sioxPixbuf = sioxProcessImage(img, pixbuf);
+        if (!sioxPixbuf)
+            {
+            g_object_ref(pixbuf);
+            return pixbuf;
+            }
+        else
+            {
+            return sioxPixbuf;
+            }
+        }
+    else
+        {
+        g_object_ref(pixbuf);
+        return pixbuf;
+        }
+
+}
+
 
 
 //#########################################################################
@@ -230,12 +362,14 @@ void Tracer::traceThread()
         return;
         }
 
-    Inkscape::Selection *selection = SP_DT_SELECTION (desktop);
+    Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
+
+    Inkscape::Selection *selection = sp_desktop_selection (desktop);
 
     if (!SP_ACTIVE_DOCUMENT)
         {
         char *msg = _("Trace: No active document");
-        SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
         //g_warning(msg);
         engine = NULL;
         return;
@@ -252,30 +386,19 @@ void Tracer::traceThread()
         }
 
     GdkPixbuf *pixbuf = img->pixbuf;
+    g_object_ref(pixbuf);
+
+    pixbuf = sioxProcessImage(img, pixbuf);
 
     if (!pixbuf)
         {
         char *msg = _("Trace: Image has no bitmap data");
-        SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
         //g_warning(msg);
         engine = NULL;
         return;
         }
 
-    //## SIOX pre-processing to get a smart subimage of the pixbuf.
-    //## This is done before any other filters
-    if (sioxEnabled)
-        {
-        /*
-           Ok, we have requested siox, and getSelectedSPImage() has found a single
-           bitmap and one or more SPItems above it.  Now what we need to do is create
-           a siox-segmented subimage pixbuf.  We not need alter 'img' at all, since this
-           pixbuf will be the same dimensions and at the same location.
-           Remember to free this new pixbuf later.
-        */
-        pixbuf = sioxProcessImage(img, pixbuf);
-        }
-
     int nrPaths;
     TracingEngineResult *results = engine->trace(pixbuf, &nrPaths);
     //printf("nrPaths:%d\n", nrPaths);
@@ -366,11 +489,8 @@ void Tracer::traceThread()
         Inkscape::GC::release(pathRepr);
         }
 
-    //did we allocate a pixbuf copy?
-    if (sioxEnabled)
-        {
-        g_free(pixbuf);
-        }
+    //release our pixbuf
+    g_object_unref(pixbuf);
 
     delete results;
 
@@ -388,7 +508,7 @@ void Tracer::traceThread()
     engine = NULL;
 
     char *msg = g_strdup_printf(_("Trace: Done. %ld nodes created"), totalNodeCount);
-    SP_DT_MSGSTACK(desktop)->flash(Inkscape::NORMAL_MESSAGE, msg);
+    msgStack->flash(Inkscape::NORMAL_MESSAGE, msg);
     g_free(msg);
 
 }