Code

moving trunk for module inkscape
[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 //#########################################################################
104 /**
105  *  Threaded method that does single bitmap--->path conversion
106  */
107 void Tracer::traceThread()
109     //## Remember. NEVER leave this method without setting
110     //## engine back to NULL
112     //## Prepare our kill flag.  We will watch this later to
113     //## see if the main thread wants us to stop
114     keepGoing = true;
116     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
117     if (!desktop)
118         {
119         g_warning("Trace: No active desktop\n");
120         return;
121         }
123     Inkscape::Selection *selection = SP_DT_SELECTION (desktop);
125     if (!SP_ACTIVE_DOCUMENT)
126         {
127         char *msg = _("Trace: No active document");
128         SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
129         //g_warning(msg);
130         engine = NULL;
131         return;
132         }
133     SPDocument *doc = SP_ACTIVE_DOCUMENT;
134     sp_document_ensure_up_to_date(doc);
137     SPImage *img = getSelectedSPImage();
138     if (!img || !selectedItem)
139         {
140         engine = NULL;
141         return;
142         }
144     GdkPixbuf *pixbuf = img->pixbuf;
146     if (!pixbuf)
147         {
148         char *msg = _("Trace: Image has no bitmap data");
149         SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, msg);
150         //g_warning(msg);
151         engine = NULL;
152         return;
153         }
155     int nrPaths;
156     TracingEngineResult *results = engine->trace(pixbuf, &nrPaths);
157     //printf("nrPaths:%d\n", nrPaths);
159     //### Check if we should stop
160     if (!keepGoing || !results || nrPaths<1)
161         {
162         engine = NULL;
163         return;
164         }
166     //### Get pointers to the <image> and its parent
167     Inkscape::XML::Node *imgRepr   = SP_OBJECT(img)->repr;
168     Inkscape::XML::Node *par       = sp_repr_parent(imgRepr);
170     //### Get some information for the new transform()
171     double x      = 0.0;
172     double y      = 0.0;
173     double width  = 0.0;
174     double height = 0.0;
175     double dval   = 0.0;
177     if (sp_repr_get_double(imgRepr, "x", &dval))
178         x = dval;
179     if (sp_repr_get_double(imgRepr, "y", &dval))
180         y = dval;
182     if (sp_repr_get_double(imgRepr, "width", &dval))
183         width = dval;
184     if (sp_repr_get_double(imgRepr, "height", &dval))
185         height = dval;
187     NR::Matrix trans(NR::translate(x, y));
189     double iwidth  = (double)gdk_pixbuf_get_width(pixbuf);
190     double iheight = (double)gdk_pixbuf_get_height(pixbuf);
192     double iwscale = width  / iwidth;
193     double ihscale = height / iheight;
195     NR::Matrix scal(NR::scale(iwscale, ihscale));
197     //# Convolve scale, translation, and the original transform
198     NR::Matrix tf(scal);
199     tf *= trans;
200     tf *= selectedItem->transform;
203     //#OK.  Now let's start making new nodes
205     Inkscape::XML::Node *groupRepr = NULL;
207     //# if more than 1, make a <g>roup of <path>s
208     if (nrPaths > 1)
209         {
210         groupRepr = sp_repr_new("svg:g");
211         par->addChild(groupRepr, imgRepr);
212         }
214     long totalNodeCount = 0L;
216     for (TracingEngineResult *result=results ;
217                   result ; result=result->next)
218         {
219             totalNodeCount += result->getNodeCount();
221         Inkscape::XML::Node *pathRepr = sp_repr_new("svg:path");
222         pathRepr->setAttribute("style", result->getStyle());
223         pathRepr->setAttribute("d",     result->getPathData());
225         if (nrPaths > 1)
226             groupRepr->addChild(pathRepr, NULL);
227         else
228             par->addChild(pathRepr, imgRepr);
230         //### Apply the transform from the image to the new shape
231         SPObject *reprobj = doc->getObjectByRepr(pathRepr);
232         if (reprobj)
233             {
234             SPItem *newItem = SP_ITEM(reprobj);
235             sp_item_write_transform(newItem, pathRepr, tf, NULL);
236             }
237         if (nrPaths == 1)
238             {
239             selection->clear();
240             selection->add(pathRepr);
241             }
242         Inkscape::GC::release(pathRepr);
243         }
246     delete results;
248     // If we have a group, then focus on, then forget it
249     if (nrPaths > 1)
250         {
251         selection->clear();
252         selection->add(groupRepr);
253         Inkscape::GC::release(groupRepr);
254         }
256     //## inform the document, so we can undo
257     sp_document_done(doc);
259     engine = NULL;
261     char *msg = g_strdup_printf(_("Trace: Done. %ld nodes created"), totalNodeCount);
262     SP_DT_MSGSTACK(desktop)->flash(Inkscape::NORMAL_MESSAGE, msg);
263     g_free(msg);
267 /**
268  *  Main tracing method
269  */
270 void Tracer::trace(TracingEngine *theEngine)
272     //Check if we are already running
273     if (engine)
274         return;
276     engine = theEngine;
278 #if HAVE_THREADS
279     //Ensure that thread support is running
280     if (!Glib::thread_supported())
281         Glib::thread_init();
283     //Create our thread and run it
284     Glib::Thread::create(
285         sigc::mem_fun(*this, &Tracer::traceThread), false);
286 #else
287     traceThread();
288 #endif
296 /**
297  *  Abort the thread that is executing trace()
298  */
299 void Tracer::abort()
302     //## Inform Trace's working thread
303     keepGoing = false;
305     if (engine)
306         {
307         engine->abort();
308         }
314 } // namespace Trace
316 } // namespace Inkscape
319 //#########################################################################
320 //# E N D   O F   F I L E
321 //#########################################################################