diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp
index 81ccb64fae545a7066b1631b08a93e1980b8629f..95c144e28b18b831023685a779ee699601fb8c18 100644 (file)
--- a/src/trace/trace.cpp
+++ b/src/trace/trace.cpp
-/*
+/**
* A generic interface for plugging different
* autotracers into Inkscape.
*
#include <desktop-handles.h>
#include <document.h>
#include <message-stack.h>
+#include <gtkmm.h>
#include <glibmm/i18n.h>
#include <selection.h>
#include <xml/repr.h>
#include <sp-item.h>
#include <sp-shape.h>
#include <sp-image.h>
+#include <libnr/nr-matrix-ops.h>
+#include <libnr/nr-scale-translate-ops.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)
{
- g_warning("Trace: No active desktop\n");
+ g_warning("Trace: No active desktop");
return NULL;
}
+ 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_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+ msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
//g_warning(msg);
return NULL;
}
if (img) //we want only one
{
char *msg = _("Select only one <b>image</b> to trace");
- sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+ msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
return NULL;
}
img = SP_IMAGE(item);
if (!img || sioxShapes.size() < 1)
{
char *msg = _("Select one image and one or more shapes above it");
- sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+ msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
return NULL;
}
return img;
if (!item)
{
char *msg = _("Select an <b>image</b> to trace"); //same as above
- sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+ msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
//g_warning(msg);
return NULL;
}
if (!SP_IS_IMAGE(item))
{
char *msg = _("Select an <b>image</b> to trace");
- sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+ msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
//g_warning(msg);
return NULL;
}
-/**
- *
- */
-GdkPixbuf *
-Tracer::getSelectedImage()
+typedef org::siox::SioxImage SioxImage;
+typedef org::siox::SioxObserver SioxObserver;
+typedef org::siox::Siox Siox;
+
+
+class TraceSioxObserver : public SioxObserver
{
+public:
+
+ /**
+ *
+ */
+ TraceSioxObserver (void *contextArg) :
+ SioxObserver(contextArg)
+ {}
+
+ /**
+ *
+ */
+ virtual ~TraceSioxObserver ()
+ { }
+
+ /**
+ * Informs the observer how much has been completed.
+ * Return false if the processing should be aborted.
+ */
+ virtual bool progress(float /*percentCompleted*/)
+ {
+ //Tracer *tracer = (Tracer *)context;
+ //## Allow the GUI to update
+ Gtk::Main::iteration(false); //at least once, non-blocking
+ while( Gtk::Main::events_pending() )
+ Gtk::Main::iteration();
+ return true;
+ }
- SPImage *img = getSelectedSPImage();
- if (!img)
- return NULL;
+ /**
+ * Send an error string to the Observer. Processing will
+ * be halted.
+ */
+ virtual void error(const std::string &/*msg*/)
+ {
+ //Tracer *tracer = (Tracer *)context;
+ }
+
+
+};
- GdkPixbuf *pixbuf = img->pixbuf;
- return pixbuf;
-}
-GdkPixbuf *
-Tracer::sioxProcessImage(SPImage *img, GdkPixbuf *origPixbuf)
+/**
+ * Process a GdkPixbuf, according to which areas have been
+ * obscured in the GUI.
+ */
+Glib::RefPtr<Gdk::Pixbuf>
+Tracer::sioxProcessImage(SPImage *img,
+ Glib::RefPtr<Gdk::Pixbuf>origPixbuf)
{
+ if (!sioxEnabled)
+ return origPixbuf;
+
+ if (origPixbuf == lastOrigPixbuf)
+ return lastSioxPixbuf;
+
+ //g_message("siox: start");
//Convert from gdk, so a format we know. By design, the pixel
//format in PackedPixelMap is identical to what is needed by SIOX
- PackedPixelMap *ppMap = gdkPixbufToPackedPixelMap(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
- unsigned long *imgBuf = ppMap->pixels;
- float *confidenceMatrix = new float[ppMap->width * ppMap->height];
+ SioxImage simage(origPixbuf->gobj());
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (!desktop)
{
- g_warning("Trace: No active desktop\n");
- return NULL;
+ g_warning(_("Trace: No active desktop"));
+ return Glib::RefPtr<Gdk::Pixbuf>(NULL);
}
+ 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_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+ msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
//g_warning(msg);
- return NULL;
+ return Glib::RefPtr<Gdk::Pixbuf>(NULL);
}
NRArenaItem *aImg = sp_item_get_arenaitem(img, desktop->dkey);
double width = (double)(aImg->bbox.x1 - aImg->bbox.x0);
double height = (double)(aImg->bbox.y1 - aImg->bbox.y0);
- double iwidth = (double)ppMap->width;
- double iheight = (double)ppMap->height;
+ double iwidth = (double)simage.getWidth();
+ double iheight = (double)simage.getHeight();
double iwscale = width / iwidth;
double ihscale = height / iheight;
- unsigned long cmIndex = 0;
-
-
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());
- PackedPixelMap *dumpMap = PackedPixelMapCreate(ppMap->width, ppMap->height);
+ //PackedPixelMap *dumpMap = PackedPixelMapCreate(
+ // simage.getWidth(), simage.getHeight());
- for (int row=0 ; row<ppMap->height ; row++)
+ //g_message("siox: start selection");
+
+ for (int row=0 ; row<iheight ; row++)
{
double ypos = ((double)aImg->bbox.y0) + ihscale * (double) row;
- for (int col=0 ; col<ppMap->width ; col++)
+ for (int col=0 ; col<simage.getWidth() ; col++)
{
//Get absolute X,Y position
double xpos = ((double)aImg->bbox.x0) + iwscale * (double)col;
NR::Point point(xpos, ypos);
- point *= aImg->transform;
+ 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;
if (weHaveAHit)
{
//g_message("hit!\n");
- dumpMap->setPixelLong(dumpMap, col, row, 0L);
- confidenceMatrix[cmIndex] =
- org::siox::SioxSegmentator::CERTAIN_FOREGROUND_CONFIDENCE;
+ //dumpMap->setPixelLong(dumpMap, col, row, 0L);
+ simage.setConfidence(col, row,
+ Siox::UNKNOWN_REGION_CONFIDENCE);
}
else
{
- dumpMap->setPixelLong(dumpMap, col, row,
- ppMap->getPixel(ppMap, col, row));
- confidenceMatrix[cmIndex] =
- org::siox::SioxSegmentator::CERTAIN_BACKGROUND_CONFIDENCE;
+ //g_message("miss!\n");
+ //dumpMap->setPixelLong(dumpMap, col, row,
+ // simage.getPixel(col, row));
+ simage.setConfidence(col, row,
+ Siox::CERTAIN_BACKGROUND_CONFIDENCE);
}
- cmIndex++;
}
}
+ //g_message("siox: selection done");
+
+ //dumpMap->writePPM(dumpMap, "siox1.ppm");
+ //dumpMap->destroy(dumpMap);
+
//## ok we have our pixel buf
- org::siox::SioxSegmentator ss(ppMap->width, ppMap->height, NULL, 0);
- ss.segmentate(imgBuf, confidenceMatrix, 0, 0.0);
+ TraceSioxObserver observer(this);
+ Siox sengine(&observer);
+ SioxImage result = sengine.extractForeground(simage, 0xffffff);
+ if (!result.isValid())
+ {
+ g_warning(_("Invalid SIOX result"));
+ return Glib::RefPtr<Gdk::Pixbuf>(NULL);
+ }
- dumpMap->writePPM(dumpMap, "siox.ppm");
- dumpMap->destroy(dumpMap);
+ //result.writePPM("siox2.ppm");
/* Free Arena and ArenaItem */
/*
nr_object_unref((NRObject *) arena);
*/
- GdkPixbuf *newPixbuf = packedPixelMapToGdkPixbuf(ppMap);
- ppMap->destroy(ppMap);
- delete confidenceMatrix;
+ Glib::RefPtr<Gdk::Pixbuf> newPixbuf = Glib::wrap(result.getGdkPixbuf());
+
+ //g_message("siox: done");
+
+ lastSioxPixbuf = newPixbuf;
return newPixbuf;
}
+/**
+ *
+ */
+Glib::RefPtr<Gdk::Pixbuf>
+Tracer::getSelectedImage()
+{
+
+
+ SPImage *img = getSelectedSPImage();
+ if (!img)
+ return Glib::RefPtr<Gdk::Pixbuf>(NULL);
+
+ if (!img->pixbuf)
+ return Glib::RefPtr<Gdk::Pixbuf>(NULL);
+
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf =
+ Glib::wrap(img->pixbuf, true);
+
+ if (sioxEnabled)
+ {
+ Glib::RefPtr<Gdk::Pixbuf> sioxPixbuf =
+ sioxProcessImage(img, pixbuf);
+ if (!sioxPixbuf)
+ {
+ return pixbuf;
+ }
+ else
+ {
+ return sioxPixbuf;
+ }
+ }
+ else
+ {
+ return pixbuf;
+ }
+
+}
+
//#########################################################################
return;
}
+ 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_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
+ msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
//g_warning(msg);
engine = NULL;
return;
return;
}
- GdkPixbuf *pixbuf = img->pixbuf;
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(img->pixbuf, true);
+
+ pixbuf = sioxProcessImage(img, pixbuf);
if (!pixbuf)
{
char *msg = _("Trace: Image has no bitmap data");
- sp_desktop_message_stack(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);
- }
+ msgStack->flash(Inkscape::NORMAL_MESSAGE, _("Trace: Starting trace..."));
+ desktop->updateCanvasNow();
- int nrPaths;
- TracingEngineResult *results = engine->trace(pixbuf, &nrPaths);
- //printf("nrPaths:%d\n", nrPaths);
+ std::vector<TracingEngineResult> results =
+ engine->trace(pixbuf);
+ //printf("nrPaths:%d\n", results.size());
+ int nrPaths = results.size();
//### Check if we should stop
- if (!keepGoing || !results || nrPaths<1)
+ if (!keepGoing || nrPaths<1)
{
engine = NULL;
return;
if (sp_repr_get_double(imgRepr, "height", &dval))
height = dval;
- NR::Matrix trans(NR::translate(x, y));
-
- double iwidth = (double)gdk_pixbuf_get_width(pixbuf);
- double iheight = (double)gdk_pixbuf_get_height(pixbuf);
+ double iwidth = (double)pixbuf->get_width();
+ double iheight = (double)pixbuf->get_height();
double iwscale = width / iwidth;
double ihscale = height / iheight;
- NR::Matrix scal(NR::scale(iwscale, ihscale));
+ NR::translate trans(x, y);
+ NR::scale scal(iwscale, ihscale);
//# Convolve scale, translation, and the original transform
- NR::Matrix tf(scal);
- tf *= trans;
+ NR::Matrix tf(scal * trans);
tf *= img->transform;
//#OK. Now let's start making new nodes
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc());
Inkscape::XML::Node *groupRepr = NULL;
//# if more than 1, make a <g>roup of <path>s
if (nrPaths > 1)
{
- groupRepr = sp_repr_new("svg:g");
+ groupRepr = xml_doc->createElement("svg:g");
par->addChild(groupRepr, imgRepr);
}
long totalNodeCount = 0L;
- for (TracingEngineResult *result=results ;
- result ; result=result->next)
+ for (unsigned int i=0 ; i<results.size() ; i++)
{
- totalNodeCount += result->getNodeCount();
+ TracingEngineResult result = results[i];
+ totalNodeCount += result.getNodeCount();
- Inkscape::XML::Node *pathRepr = sp_repr_new("svg:path");
- pathRepr->setAttribute("style", result->getStyle());
- pathRepr->setAttribute("d", result->getPathData());
+ Inkscape::XML::Node *pathRepr = xml_doc->createElement("svg:path");
+ pathRepr->setAttribute("style", result.getStyle().c_str());
+ pathRepr->setAttribute("d", result.getPathData().c_str());
if (nrPaths > 1)
groupRepr->addChild(pathRepr, NULL);
Inkscape::GC::release(pathRepr);
}
- //did we allocate a pixbuf copy?
- if (sioxEnabled)
- {
- g_free(pixbuf);
- }
-
- delete results;
-
// If we have a group, then focus on, then forget it
if (nrPaths > 1)
{
}
//## inform the document, so we can undo
- sp_document_done(doc);
+ sp_document_done(doc, SP_VERB_SELECTION_TRACE, _("Trace bitmap"));
engine = NULL;
char *msg = g_strdup_printf(_("Trace: Done. %ld nodes created"), totalNodeCount);
- sp_desktop_message_stack(desktop)->flash(Inkscape::NORMAL_MESSAGE, msg);
+ msgStack->flash(Inkscape::NORMAL_MESSAGE, msg);
g_free(msg);
}