X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ftrace%2Ftrace.cpp;h=925e4e195de41aa2068d7f20fc56645ab0197563;hb=724821145d62dee9f97465c706952582da6e432d;hp=2e46dd854fba8789f826d11a197e4b1635796b5d;hpb=56f61e36105050ffd48acd3984664d9994231456;p=inkscape.git diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 2e46dd854..925e4e195 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -1,4 +1,4 @@ -/* +/** * A generic interface for plugging different * autotracers into Inkscape. * @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,33 +27,47 @@ #include #include #include -#include //for intersection boolop + +#include +#include #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::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 image to trace"); - SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg); + msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } @@ -87,12 +102,12 @@ Tracer::getSelectedSPImage() if (img) //we want only one { char *msg = _("Select only one image 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) { if (SP_IS_SHAPE(item)) { @@ -101,10 +116,11 @@ Tracer::getSelectedSPImage() } } } + if (!img || sioxShapes.size() < 1) { char *msg = _("Select one image and one or more shapes above it"); - SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg); + msgStack->flash(Inkscape::ERROR_MESSAGE, msg); return NULL; } return img; @@ -116,7 +132,7 @@ Tracer::getSelectedSPImage() if (!item) { char *msg = _("Select an image 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; } @@ -124,7 +140,7 @@ Tracer::getSelectedSPImage() if (!SP_IS_IMAGE(item)) { char *msg = _("Select an image to trace"); - SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg); + msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } @@ -138,138 +154,245 @@ Tracer::getSelectedSPImage() -/** - * - */ -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 +Tracer::sioxProcessImage(SPImage *img, + Glib::RefPtrorigPixbuf) { + if (!sioxEnabled) + return origPixbuf; - 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]; + if (origPixbuf == lastOrigPixbuf) + return lastSioxPixbuf; - Inkscape::XML::Node *imgRepr = SP_OBJECT(img)->repr; - /* - //## Make a Rect overlaying the image - Inkscape::XML::Node *parent = imgRepr->parent(); + //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 + SioxImage simage(origPixbuf->gobj()); - Inkscape::XML::Node *rect = sp_repr_new("svg:rect"); - Inkscape::Util::List attr = - imgRepr->attributeList(); - for ( ; attr ; attr++) + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (!desktop) { - rect->setAttribute(g_quark_to_string(attr->key), attr->value, false); + g_warning(_("Trace: No active desktop")); + return Glib::RefPtr(NULL); } + Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop); - //Inkscape::XML::Node *rect = imgRepr->duplicate(); - parent->appendChild(rect); - Inkscape::GC::release(rect); - */ + Inkscape::Selection *sel = sp_desktop_selection(desktop); + if (!sel) + { + char *msg = _("Select an image to trace"); + msgStack->flash(Inkscape::ERROR_MESSAGE, msg); + //g_warning(msg); + return Glib::RefPtr(NULL); + } - //### element - double x = 0.0; - double y = 0.0; - double width = 0.0; - double height = 0.0; - double dval = 0.0; + 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); - if (sp_repr_get_double(imgRepr, "x", &dval)) - x = dval; - if (sp_repr_get_double(imgRepr, "y", &dval)) - y = dval; + double width = (double)(aImg->bbox.x1 - aImg->bbox.x0); + double height = (double)(aImg->bbox.y1 - aImg->bbox.y0); - if (sp_repr_get_double(imgRepr, "width", &dval)) - width = dval; - if (sp_repr_get_double(imgRepr, "height", &dval)) - height = dval; - - 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; - SPDesktop *desktop = SP_ACTIVE_DESKTOP; + std::vector arenaItems; + std::vector::iterator iter; + for (iter = sioxShapes.begin() ; iter!=sioxShapes.end() ; iter++) + { + SPItem *item = *iter; + NRArenaItem *aItem = sp_item_get_arenaitem(item, desktop->dkey); + arenaItems.push_back(aItem); + } + + //g_message("%d arena items\n", arenaItems.size()); + + //PackedPixelMap *dumpMap = PackedPixelMapCreate( + // simage.getWidth(), simage.getHeight()); + + //g_message("siox: start selection"); - unsigned long cmIndex = 0; - for (int row=0 ; rowheight ; row++) + for (int row=0 ; rowwidth ; col++) + double ypos = ((double)aImg->bbox.y0) + ihscale * (double) row; + for (int col=0 ; colbbox.x0) + iwscale * (double)col; NR::Point point(xpos, ypos); - point *= img->transform; - point = desktop->doc2dt(point); - std::vector::iterator iter; - g_message("x:%f y:%f\n", point[0], point[1]); - SPItem *itemOverPoint = desktop->item_at_point(point, false, NULL); - int weHaveAHit = false; - if (itemOverPoint) + point *= aImg->transform; + //point *= imgMat; + //point = desktop->doc2dt(point); + //g_message("x:%f y:%f\n", point[0], point[1]); + bool weHaveAHit = false; + std::vector::iterator aIter; + for (aIter = arenaItems.begin() ; aIter!=arenaItems.end() ; aIter++) { - printf("searching\n"); - for (iter = sioxShapes.begin() ; iter!=sioxShapes.end() ; iter++) + NRArenaItem *arenaItem = *aIter; + NRArenaItemClass *arenaClass = + (NRArenaItemClass *) NR_OBJECT_GET_CLASS (arenaItem); + if (arenaClass->pick(arenaItem, point, 1.0f, 1)) { - SPShape *shape = *iter; - if (shape == itemOverPoint) - { - weHaveAHit = true; - break; - } + weHaveAHit = true; + break; } } + if (weHaveAHit) { - g_message("hit!\n"); - confidenceMatrix[cmIndex] = - org::siox::SioxSegmentator::CERTAIN_FOREGROUND_CONFIDENCE; + //g_message("hit!\n"); + //dumpMap->setPixelLong(dumpMap, col, row, 0L); + simage.setConfidence(col, row, + Siox::UNKNOWN_REGION_CONFIDENCE); } else { - 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, ppMap->width * ppMap->height, - confidenceMatrix, ppMap->width * ppMap->height, - 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(NULL); + } + + //result.writePPM("siox2.ppm"); + + /* Free Arena and ArenaItem */ + /* + std::vector::iterator aIter; + for (aIter = arenaItems.begin() ; aIter!=arenaItems.end() ; aIter++) + { + NRArenaItem *arenaItem = *aIter; + nr_arena_item_unref(arenaItem); + } + nr_object_unref((NRObject *) arena); + */ + Glib::RefPtr newPixbuf = Glib::wrap(result.getGdkPixbuf()); + //g_message("siox: done"); - GdkPixbuf *newPixbuf = packedPixelMapToGdkPixbuf(ppMap); - ppMap->destroy(ppMap); - delete confidenceMatrix; + lastSioxPixbuf = newPixbuf; return newPixbuf; } +/** + * + */ +Glib::RefPtr +Tracer::getSelectedImage() +{ + + + SPImage *img = getSelectedSPImage(); + if (!img) + return Glib::RefPtr(NULL); + + if (!img->pixbuf) + return Glib::RefPtr(NULL); + + Glib::RefPtr pixbuf = + Glib::wrap(img->pixbuf, true); + + if (sioxEnabled) + { + Glib::RefPtr sioxPixbuf = + sioxProcessImage(img, pixbuf); + if (!sioxPixbuf) + { + return pixbuf; + } + else + { + return sioxPixbuf; + } + } + else + { + return pixbuf; + } + +} + //######################################################################### @@ -304,12 +427,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; @@ -325,37 +450,29 @@ void Tracer::traceThread() return; } - GdkPixbuf *pixbuf = img->pixbuf; + Glib::RefPtr pixbuf = Glib::wrap(img->pixbuf, true); + + 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); + msgStack->flash(Inkscape::NORMAL_MESSAGE, _("Trace: Starting trace...")); + desktop->updateCanvasNow(); + + std::vector 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; @@ -384,8 +501,8 @@ void Tracer::traceThread() 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; @@ -400,25 +517,26 @@ void Tracer::traceThread() //#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 roup of 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 ; igetNodeCount(); + 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); @@ -440,14 +558,6 @@ void Tracer::traceThread() 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) { @@ -457,12 +567,12 @@ void Tracer::traceThread() } //## 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_DT_MSGSTACK(desktop)->flash(Inkscape::NORMAL_MESSAGE, msg); + msgStack->flash(Inkscape::NORMAL_MESSAGE, msg); g_free(msg); }