Code

add enableSiox() for testing
[inkscape.git] / src / trace / trace.cpp
1 /*
2  * A generic interface for plugging different
3  *  autotracers into Inkscape.
4  *
5  * Authors:
6  *   Bob Jamison <rjamison@titan.com>
7  *
8  * Copyright (C) 2004 Bob Jamison
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
15 #include "trace/potrace/inkscape-potrace.h"
17 #include <inkscape.h>
18 #include <desktop-handles.h>
19 #include <document.h>
20 #include "message-stack.h"
21 #include <glibmm/i18n.h>
22 #include <selection.h>
23 #include <xml/repr.h>
24 #include "sp-item.h"
25 #include "sp-image.h"
27 namespace Inkscape {
29 namespace Trace {
31 /**
32  *
33  */
34 SPImage *
35 Tracer::getSelectedSPImage()
36 {
37     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
38     if (!desktop)
39         {
40         g_warning("Trace: No active desktop\n");
41         return NULL;
42         }
44     Inkscape::Selection *sel = SP_DT_SELECTION(desktop);
45     if (!sel)
46         {
47         char *msg = _("Select an <b>image</b> to trace");
48         SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
49         //g_warning(msg);
50         return NULL;
51         }
53     SPItem *item = sel->singleItem();
54     if (!item)
55         {
56         char *msg = _("Select an <b>image</b> to trace");  //same as above
57         SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
58         //g_warning(msg);
59         return NULL;
60         }
62     if (!SP_IS_IMAGE(item))
63         {
64         char *msg = _("Select an <b>image</b> to trace");
65         SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
66         //g_warning(msg);
67         return NULL;
68         }
70     selectedItem = item;
72     SPImage *img = SP_IMAGE(item);
74     return img;
76 }
80 /**
81  *
82  */
83 GdkPixbuf *
84 Tracer::getSelectedImage()
85 {
87     SPImage *img = getSelectedSPImage();
88     if (!img)
89         return NULL;
91     GdkPixbuf *pixbuf = img->pixbuf;
93     return pixbuf;
95 }
99 //#########################################################################
100 //#  T R A C E
101 //#########################################################################
103 /**
104  *  Whether we want to enable SIOX subimage selection
105  */
106 void Tracer::enableSiox(bool enable)
108     sioxEnabled = enable;
112 /**
113  *  Threaded method that does single bitmap--->path conversion
114  */
115 void Tracer::traceThread()
117     //## Remember. NEVER leave this method without setting
118     //## engine back to NULL
120     //## Prepare our kill flag.  We will watch this later to
121     //## see if the main thread wants us to stop
122     keepGoing = true;
124     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
125     if (!desktop)
126         {
127         g_warning("Trace: No active desktop\n");
128         return;
129         }
131     Inkscape::Selection *selection = SP_DT_SELECTION (desktop);
133     if (!SP_ACTIVE_DOCUMENT)
134         {
135         char *msg = _("Trace: No active document");
136         SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
137         //g_warning(msg);
138         engine = NULL;
139         return;
140         }
141     SPDocument *doc = SP_ACTIVE_DOCUMENT;
142     sp_document_ensure_up_to_date(doc);
145     SPImage *img = getSelectedSPImage();
146     if (!img || !selectedItem)
147         {
148         engine = NULL;
149         return;
150         }
152     GdkPixbuf *pixbuf = img->pixbuf;
154     if (!pixbuf)
155         {
156         char *msg = _("Trace: Image has no bitmap data");
157         SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
158         //g_warning(msg);
159         engine = NULL;
160         return;
161         }
163     int nrPaths;
164     TracingEngineResult *results = engine->trace(pixbuf, &nrPaths);
165     //printf("nrPaths:%d\n", nrPaths);
167     //### Check if we should stop
168     if (!keepGoing || !results || nrPaths<1)
169         {
170         engine = NULL;
171         return;
172         }
174     //### Get pointers to the <image> and its parent
175     Inkscape::XML::Node *imgRepr   = SP_OBJECT(img)->repr;
176     Inkscape::XML::Node *par       = sp_repr_parent(imgRepr);
178     //### Get some information for the new transform()
179     double x      = 0.0;
180     double y      = 0.0;
181     double width  = 0.0;
182     double height = 0.0;
183     double dval   = 0.0;
185     if (sp_repr_get_double(imgRepr, "x", &dval))
186         x = dval;
187     if (sp_repr_get_double(imgRepr, "y", &dval))
188         y = dval;
190     if (sp_repr_get_double(imgRepr, "width", &dval))
191         width = dval;
192     if (sp_repr_get_double(imgRepr, "height", &dval))
193         height = dval;
195     NR::Matrix trans(NR::translate(x, y));
197     double iwidth  = (double)gdk_pixbuf_get_width(pixbuf);
198     double iheight = (double)gdk_pixbuf_get_height(pixbuf);
200     double iwscale = width  / iwidth;
201     double ihscale = height / iheight;
203     NR::Matrix scal(NR::scale(iwscale, ihscale));
205     //# Convolve scale, translation, and the original transform
206     NR::Matrix tf(scal);
207     tf *= trans;
208     tf *= selectedItem->transform;
211     //#OK.  Now let's start making new nodes
213     Inkscape::XML::Node *groupRepr = NULL;
215     //# if more than 1, make a <g>roup of <path>s
216     if (nrPaths > 1)
217         {
218         groupRepr = sp_repr_new("svg:g");
219         par->addChild(groupRepr, imgRepr);
220         }
222     long totalNodeCount = 0L;
224     for (TracingEngineResult *result=results ;
225                   result ; result=result->next)
226         {
227             totalNodeCount += result->getNodeCount();
229         Inkscape::XML::Node *pathRepr = sp_repr_new("svg:path");
230         pathRepr->setAttribute("style", result->getStyle());
231         pathRepr->setAttribute("d",     result->getPathData());
233         if (nrPaths > 1)
234             groupRepr->addChild(pathRepr, NULL);
235         else
236             par->addChild(pathRepr, imgRepr);
238         //### Apply the transform from the image to the new shape
239         SPObject *reprobj = doc->getObjectByRepr(pathRepr);
240         if (reprobj)
241             {
242             SPItem *newItem = SP_ITEM(reprobj);
243             sp_item_write_transform(newItem, pathRepr, tf, NULL);
244             }
245         if (nrPaths == 1)
246             {
247             selection->clear();
248             selection->add(pathRepr);
249             }
250         Inkscape::GC::release(pathRepr);
251         }
254     delete results;
256     // If we have a group, then focus on, then forget it
257     if (nrPaths > 1)
258         {
259         selection->clear();
260         selection->add(groupRepr);
261         Inkscape::GC::release(groupRepr);
262         }
264     //## inform the document, so we can undo
265     sp_document_done(doc);
267     engine = NULL;
269     char *msg = g_strdup_printf(_("Trace: Done. %ld nodes created"), totalNodeCount);
270     SP_DT_MSGSTACK(desktop)->flash(Inkscape::NORMAL_MESSAGE, msg);
271     g_free(msg);
275 /**
276  *  Main tracing method
277  */
278 void Tracer::trace(TracingEngine *theEngine)
280     //Check if we are already running
281     if (engine)
282         return;
284     engine = theEngine;
286 #if HAVE_THREADS
287     //Ensure that thread support is running
288     if (!Glib::thread_supported())
289         Glib::thread_init();
291     //Create our thread and run it
292     Glib::Thread::create(
293         sigc::mem_fun(*this, &Tracer::traceThread), false);
294 #else
295     traceThread();
296 #endif
304 /**
305  *  Abort the thread that is executing trace()
306  */
307 void Tracer::abort()
310     //## Inform Trace's working thread
311     keepGoing = false;
313     if (engine)
314         {
315         engine->abort();
316         }
322 } // namespace Trace
324 } // namespace Inkscape
327 //#########################################################################
328 //# E N D   O F   F I L E
329 //#########################################################################