Code

remove screen pixel toggle for now, add always-snap widget for all
[inkscape.git] / src / ui / dialog / tracedialog.cpp
1 /*
2  * A simple dialog for setting the parameters for autotracing a
3  * bitmap <image> into an svg <path>
4  *
5  * Authors:
6  *   Bob Jamison
7  *   Other dudes from The Inkscape Organization
8  *
9  * Copyright (C) 2004, 2005 Authors
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
13 #ifdef HAVE_CONFIG_H
14 # include <config.h>
15 #endif
17 #include <gtkmm/notebook.h>
18 #include <gtkmm/frame.h>
19 #include <gtkmm/spinbutton.h>
20 #include <gtkmm/stock.h>
22 #include <gtk/gtkdialog.h> //for GTK_RESPONSE* types
23 #include <glibmm/i18n.h>
27 #include "tracedialog.h"
28 #include "trace/potrace/inkscape-potrace.h"
31 namespace Inkscape {
32 namespace UI {
33 namespace Dialog {
36 //#########################################################################
37 //## I M P L E M E N T A T I O N
38 //#########################################################################
40 /**
41  * A dialog for adjusting bitmap->vector tracing parameters
42  */
43 class TraceDialogImpl : public TraceDialog
44 {
46     public:
49     /**
50      * Constructor
51      */
52     TraceDialogImpl();
54     /**
55      * Destructor
56      */
57     ~TraceDialogImpl();
59     /**
60      * Callback from OK or Cancel
61      */
62     void responseCallback(int response_id);
64     private:
66     /**
67      * This is the big almighty McGuffin
68      */
69     Inkscape::Trace::Tracer tracer;
71     /**
72      * This does potrace processing
73      * Only preview if do_i_trace is false
74      */
75     void potraceProcess(bool do_i_trace);
77     /**
78      * Abort processing
79      */
80     void abort();
82     void potracePreviewCallback();
84     Gtk::Notebook   notebook;
85     Gtk::Tooltips   tips;
87     //########## Potrace items
88     Gtk::VBox             potraceBox;
89     Gtk::RadioButtonGroup potraceGroup;
90     Gtk::CheckButton      potraceInvertButton;
91     Gtk::HBox             potraceInvertBox;
92     Gtk::Button           *potraceOkButton;
93     Gtk::Button           *potraceCancelButton;
95     //brightness
96     Gtk::Frame            potraceBrightnessFrame;
97     Gtk::VBox             potraceBrightnessVBox;
98     Gtk::HBox             potraceBrightnessBox;
99     Gtk::RadioButton      potraceBrightnessRadioButton;
100     Gtk::Label            potraceBrightnessSpinnerLabel;
101     Gtk::SpinButton       potraceBrightnessSpinner;
104     //edge detection
105     Gtk::Frame            potraceCannyFrame;
106     Gtk::HBox             potraceCannyBox;
107     Gtk::VBox             potraceCannyVBox;
108     Gtk::RadioButton      potraceCannyRadioButton;
109     //Gtk::HSeparator     potraceCannySeparator;
110     //Gtk::Label          potraceCannyLoSpinnerLabel;
111     //Gtk::SpinButton     potraceCannyLoSpinner;
112     Gtk::Label            potraceCannyHiSpinnerLabel;
113     Gtk::SpinButton       potraceCannyHiSpinner;
115     //quantization
116     Gtk::Frame            potraceQuantFrame;
117     Gtk::HBox             potraceQuantBox;
118     Gtk::VBox             potraceQuantVBox;
119     Gtk::RadioButton      potraceQuantRadioButton;
120     Gtk::Label            potraceQuantNrColorLabel;
121     Gtk::SpinButton       potraceQuantNrColorSpinner;
123     //multiple path scanning
124     Gtk::Frame            potraceMultiScanFrame;
125     Gtk::VBox             potraceMultiScanVBox;
127     Gtk::HBox             potraceMultiScanHBox1;
128     Gtk::RadioButton      potraceMultiScanBrightnessRadioButton;
129     Gtk::SpinButton       potraceMultiScanNrColorSpinner;
131     Gtk::HBox             potraceMultiScanHBox2;
132     Gtk::RadioButton      potraceMultiScanColorRadioButton;
133     Gtk::CheckButton      potraceMultiScanStackButton;
135     Gtk::HBox             potraceMultiScanHBox3;
136     Gtk::RadioButton      potraceMultiScanMonoRadioButton;
137     Gtk::Label            potraceMultiScanNrColorLabel;
139     Gtk::CheckButton      potraceMultiScanSmoothButton;
142     //preview
143     Gtk::Frame            potracePreviewFrame;
144     Gtk::HBox             potracePreviewBox;
145     Gtk::Button           potracePreviewButton;
146     Gtk::Image            potracePreviewImage;
148     //credits
149     Gtk::Frame            potraceCreditsFrame;
150     Gtk::VBox             potraceCreditsVBox;
151     Gtk::Label            potraceCreditsLabel;
153     //########## Other items
154     Gtk::VBox             otherBox;
158 };
163 //#########################################################################
164 //## E V E N T S
165 //#########################################################################
167 /**
168  * This does potrace processing
169  * Only preview if do_i_trace is false
170  */
171 void TraceDialogImpl::potraceProcess(bool do_i_trace)
173     //##### Get the tracer and engine
174     Inkscape::Trace::Potrace::PotraceTracingEngine pte;
176     /* inversion */
177     bool invert = potraceInvertButton.get_active();
178     pte.setInvert(invert);
180     //##### Get the single-scan settings
181     /* which one? */
182     if (potraceBrightnessRadioButton.get_active())
183         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_BRIGHTNESS);
184     else if (potraceMultiScanBrightnessRadioButton.get_active())
185         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_BRIGHTNESS_MULTI);
186     else if (potraceCannyRadioButton.get_active())
187         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_CANNY);
188     else if (potraceQuantRadioButton.get_active())
189         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT);
190     else if (potraceMultiScanColorRadioButton.get_active())
191         {
192         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT_COLOR);
193         pte.setInvert(false);
194         }
195     else if (potraceMultiScanMonoRadioButton.get_active())
196         {
197         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT_MONO);
198         pte.setInvert(false);
199         }
201     /* brightness */
202     double brightnessThreshold = potraceBrightnessSpinner.get_value();
203     pte.setBrightnessThreshold(brightnessThreshold);
205     /* canny */
206     double cannyHighThreshold = potraceCannyHiSpinner.get_value();
207     pte.setCannyHighThreshold(cannyHighThreshold);
209     /* quantization */
210     int quantNrColors = potraceQuantNrColorSpinner.get_value_as_int();
211     pte.setQuantizationNrColors(quantNrColors);
213     //##### Get multiple-scan settings
214     int multiScanNrColors = potraceMultiScanNrColorSpinner.get_value_as_int();
215     pte.setMultiScanNrColors(multiScanNrColors);
216     bool do_i_stack = potraceMultiScanStackButton.get_active();
217     pte.setMultiScanStack(do_i_stack);
218     bool do_i_smooth = potraceMultiScanSmoothButton.get_active();
219     pte.setMultiScanSmooth(do_i_smooth);
221     //##### Get intermediate bitmap image
222     GdkPixbuf *pixbuf = tracer.getSelectedImage();
223     if (pixbuf)
224          {
225          GdkPixbuf *preview = pte.preview(pixbuf);
226          if (preview)
227              {
228              Glib::RefPtr<Gdk::Pixbuf> thePreview = Glib::wrap(preview);
229              int width  = thePreview->get_width();
230              int height = thePreview->get_height();
231              double scaleFactor = 100.0 / (double)height;
232              int newWidth  = (int) (((double)width)  * scaleFactor);
233              int newHeight = (int) (((double)height) * scaleFactor);
234              Glib::RefPtr<Gdk::Pixbuf> scaledPreview =
235                     thePreview->scale_simple(newWidth, newHeight,
236                        Gdk::INTERP_NEAREST);
237              //g_object_unref(preview);
238              potracePreviewImage.set(scaledPreview);
239              }
240          }
242     //##### Convert
243     if (do_i_trace)
244         {
245         if (potraceCancelButton)
246             potraceCancelButton->set_sensitive(true);
247         if (potraceOkButton)
248             potraceOkButton->set_sensitive(false);
249         tracer.trace(&pte);
250         if (potraceCancelButton)
251             potraceCancelButton->set_sensitive(false);
252         if (potraceOkButton)
253             potraceOkButton->set_sensitive(true);
254         }
259 /**
260  * Abort processing
261  */
262 void TraceDialogImpl::abort()
264     //### Do some GUI thing
266     //### Make the abort() call to the tracer
267     tracer.abort();
273 //#########################################################################
274 //## E V E N T S
275 //#########################################################################
277 /**
278  * Callback from the Preview button.  Can be called from elsewhere.
279  */
280 void TraceDialogImpl::potracePreviewCallback()
282     potraceProcess(false);
285 /**
286  * Default response from the dialog.  Let's intercept it
287  */
288 void TraceDialogImpl::responseCallback(int response_id)
291     if (response_id == GTK_RESPONSE_OK)
292         {
293         int panelNr = notebook.get_current_page();
294         //g_message("selected panel:%d\n", panelNr);
296         if (panelNr == 0)
297             {
298             potraceProcess(true);
299             }
300         }
301     else if (response_id == GTK_RESPONSE_CANCEL)
302         {
303         abort();
304         }
305     else
306         {
307         hide();
308         return;
309         }
318 //#########################################################################
319 //## C O N S T R U C T O R    /    D E S T R U C T O R
320 //#########################################################################
321 /**
322  * Constructor
323  */
324 TraceDialogImpl::TraceDialogImpl()
327     Gtk::VBox *mainVBox = get_vbox();
329 #define MARGIN 4
331     //##Set up the Potrace panel
333     /*#### brightness ####*/
334     potraceBrightnessRadioButton.set_label(_("Brightness"));
335     potraceGroup = potraceBrightnessRadioButton.get_group();
336     potraceBrightnessBox.pack_start(potraceBrightnessRadioButton, false, false, MARGIN);
337     tips.set_tip(potraceBrightnessRadioButton, _("Trace by a given brightness level"));
339     potraceBrightnessSpinner.set_digits(3);
340     potraceBrightnessSpinner.set_increments(0.01, 0.1);
341     potraceBrightnessSpinner.set_range(0.0, 1.0);
342     potraceBrightnessSpinner.set_value(0.45);
343     potraceBrightnessBox.pack_end(potraceBrightnessSpinner, false, false, MARGIN);
344     tips.set_tip(potraceBrightnessSpinner, _("Brightness cutoff for black/white"));
346     potraceBrightnessSpinnerLabel.set_label(_("Threshold:"));
347     potraceBrightnessBox.pack_end(potraceBrightnessSpinnerLabel, false, false, MARGIN);
349     potraceBrightnessVBox.pack_start(potraceBrightnessBox, false, false, MARGIN);
351     potraceBrightnessFrame.set_label(_("Image Brightness"));
352     //potraceBrightnessFrame.set_shadow_type(Gtk::SHADOW_NONE);
353     potraceBrightnessFrame.add(potraceBrightnessVBox);
354     potraceBox.pack_start(potraceBrightnessFrame, false, false, 0);
356     /*#### canny edge detection ####*/
357     // TRANSLATORS: "Canny" is the name of the inventor of this edge detection method
358     potraceCannyRadioButton.set_label(_("Optimal Edge Detection (Canny)"));
359     potraceCannyRadioButton.set_group(potraceGroup);
360     potraceCannyBox.pack_start(potraceCannyRadioButton, false, false, MARGIN);
361     tips.set_tip(potraceCannyRadioButton, _("Trace with edge detection by J. Canny's algorithm"));
362     /*
363     potraceCannyBox.pack_start(potraceCannySeparator);
364     potraceCannyLoSpinnerLabel.set_label(_("Low"));
365     potraceCannyBox.pack_start(potraceCannyLoSpinnerLabel);
366     potraceCannyLoSpinner.set_digits(5);
367     potraceCannyLoSpinner.set_increments(0.01, 0.1);
368     potraceCannyLoSpinner.set_range(0.0, 1.0);
369     potraceCannyLoSpinner.set_value(0.1);
370     potraceCannyBox.pack_start(potraceCannyLoSpinner);
371     */
372     potraceCannyHiSpinner.set_digits(3);
373     potraceCannyHiSpinner.set_increments(0.01, 0.1);
374     potraceCannyHiSpinner.set_range(0.0, 1.0);
375     potraceCannyHiSpinner.set_value(0.65);
376     potraceCannyBox.pack_end(potraceCannyHiSpinner, false, false, MARGIN);
377     tips.set_tip(potraceCannyHiSpinner, _("Brightness cutoff for adjacent pixels (determines edge thickness)"));
379     potraceCannyHiSpinnerLabel.set_label(_("Threshold:"));
380     potraceCannyBox.pack_end(potraceCannyHiSpinnerLabel, false, false, MARGIN);
382     potraceCannyVBox.pack_start(potraceCannyBox, false, false, MARGIN);
384     potraceCannyFrame.set_label(_("Edge Detection"));
385     //potraceCannyFrame.set_shadow_type(Gtk::SHADOW_NONE);
386     potraceCannyFrame.add(potraceCannyVBox);
387     potraceBox.pack_start(potraceCannyFrame, false, false, 0);
389     /*#### quantization ####*/
390     // TRANSLATORS: Color Quantization: the process of reducing the number of colors
391     //  in an image by selecting an optimized set of representative colors and then
392     //  re-applying this reduced set to the original image.
393     potraceQuantRadioButton.set_label(_("Color Quantization"));
394     potraceQuantRadioButton.set_group(potraceGroup);
395     potraceQuantBox.pack_start(potraceQuantRadioButton, false, false, MARGIN);
396     tips.set_tip(potraceQuantRadioButton, _("Trace along the boundaries of reduced colors"));
398     potraceQuantNrColorSpinner.set_digits(2);
399     potraceQuantNrColorSpinner.set_increments(1.0, 4.0);
400     potraceQuantNrColorSpinner.set_range(2.0, 64.0);
401     potraceQuantNrColorSpinner.set_value(8.0);
402     potraceQuantBox.pack_end(potraceQuantNrColorSpinner, false, false, MARGIN);
403     tips.set_tip(potraceQuantNrColorSpinner, _("The number of reduced colors"));
405     potraceQuantNrColorLabel.set_label(_("Colors:"));
406     potraceQuantBox.pack_end(potraceQuantNrColorLabel, false, false, MARGIN);
408     potraceQuantVBox.pack_start(potraceQuantBox, false, false, MARGIN);
410     potraceQuantFrame.set_label(_("Quantization / Reduction"));
411     //potraceQuantFrame.set_shadow_type(Gtk::SHADOW_NONE);
412     potraceQuantFrame.add(potraceQuantVBox);
413     potraceBox.pack_start(potraceQuantFrame, false, false, 0);
415     /*#### Multiple scanning####*/
416     //----Hbox1
417     potraceMultiScanBrightnessRadioButton.set_label(_("Brightness"));
418     potraceMultiScanBrightnessRadioButton.set_group(potraceGroup);
419     potraceMultiScanHBox1.pack_start(potraceMultiScanBrightnessRadioButton, false, false, MARGIN);
420     tips.set_tip(potraceMultiScanBrightnessRadioButton, _("Trace the given number of brightness levels"));
422     potraceMultiScanNrColorSpinner.set_digits(2);
423     potraceMultiScanNrColorSpinner.set_increments(1.0, 4.0);
424     potraceMultiScanNrColorSpinner.set_range(2.0, 256.0);
425     potraceMultiScanNrColorSpinner.set_value(8.0);
426     potraceMultiScanHBox1.pack_end(potraceMultiScanNrColorSpinner, false, false, MARGIN);
427     potraceMultiScanNrColorLabel.set_label(_("Scans:"));
428     potraceMultiScanHBox1.pack_end(potraceMultiScanNrColorLabel, false, false, MARGIN);
429     tips.set_tip(potraceMultiScanNrColorSpinner, _("The desired number of scans"));
431     potraceMultiScanVBox.pack_start(potraceMultiScanHBox1, false, false, MARGIN);
433     //----Hbox2
434     potraceMultiScanColorRadioButton.set_label(_("Color"));
435     potraceMultiScanColorRadioButton.set_group(potraceGroup);
436     potraceMultiScanHBox2.pack_start(potraceMultiScanColorRadioButton, false, false, MARGIN);
437     tips.set_tip(potraceMultiScanColorRadioButton, _("Trace the given number of reduced colors"));
440     potraceMultiScanVBox.pack_start(potraceMultiScanHBox2, false, false, MARGIN);
442     //---Hbox3
443     potraceMultiScanMonoRadioButton.set_label(_("Monochrome"));
444     potraceMultiScanMonoRadioButton.set_group(potraceGroup);
445     potraceMultiScanHBox3.pack_start(potraceMultiScanMonoRadioButton, false, false, MARGIN);
446     tips.set_tip(potraceMultiScanMonoRadioButton, _("Same as Color, but convert result to grayscale"));
448     // TRANSLATORS: "Stack" is a verb here
449     potraceMultiScanStackButton.set_label(_("Stack"));
450     potraceMultiScanStackButton.set_active(true);
451     potraceMultiScanHBox3.pack_end(potraceMultiScanStackButton, false, false, MARGIN);
452     tips.set_tip(potraceMultiScanStackButton, _("Stack scans vertically (no gaps) or tile horizontally (usually with gaps)"));
454     // TRANSLATORS: "Smooth" is a verb here
455     potraceMultiScanSmoothButton.set_label(_("Smooth"));
456     potraceMultiScanSmoothButton.set_active(true);
457     potraceMultiScanHBox3.pack_end(potraceMultiScanSmoothButton, false, false, MARGIN);
458     tips.set_tip(potraceMultiScanSmoothButton, _("Apply Gaussian blur to the bitmap before tracing"));
460     potraceMultiScanVBox.pack_start(potraceMultiScanHBox3, false, false, MARGIN);
462     potraceMultiScanFrame.set_label(_("Multiple Scanning"));
463     //potraceQuantFrame.set_shadow_type(Gtk::SHADOW_NONE);
464     potraceMultiScanFrame.add(potraceMultiScanVBox);
465     potraceBox.pack_start(potraceMultiScanFrame, false, false, 0);
467     /*#### Preview ####*/
468     potracePreviewButton.set_label(_("Preview"));
469     potracePreviewButton.signal_clicked().connect(
470          sigc::mem_fun(*this, &TraceDialogImpl::potracePreviewCallback) );
471     potracePreviewBox.pack_end(potracePreviewButton, false, false, 0);//do not expand
472     tips.set_tip(potracePreviewButton, _("Preview the result without actual tracing"));
475     potracePreviewImage.set_size_request(100,100);
476     //potracePreviewImage.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
477     potracePreviewBox.pack_start(potracePreviewImage, true, true, 0);
478     potracePreviewFrame.set_label(_("Preview")); // I guess it's correct to call the "intermediate bitmap" a preview of the trace
479     //potracePreviewFrame.set_shadow_type(Gtk::SHADOW_NONE);
480     potracePreviewFrame.add(potracePreviewBox);
481     potraceBox.pack_start(potracePreviewFrame, true, true, 0);
483     /*#### swap black and white ####*/
484     potraceInvertButton.set_label(_("Invert"));
485     potraceInvertButton.set_active(false);
486     potraceInvertBox.pack_end(potraceInvertButton, false, false, MARGIN);
487     potraceBox.pack_start(potraceInvertBox, false, false, MARGIN);
488     tips.set_tip(potraceInvertButton, _("Invert black and white regions for single traces"));
490     /*#### Credits ####*/
491     potraceCreditsLabel.set_text(
492                                                          _("Thanks to Peter Selinger, http://potrace.sourceforge.net")
493                          );
494     potraceCreditsVBox.pack_start(potraceCreditsLabel, false, false, MARGIN);
495     potraceCreditsFrame.set_label(_("Credits"));
496     potraceCreditsFrame.set_shadow_type(Gtk::SHADOW_NONE);
497     potraceCreditsFrame.add(potraceCreditsVBox);
498     potraceBox.pack_start(potraceCreditsFrame, false, false, 0);
500     /*done */
501     // TRANSLATORS: Potrace is an application for transforming bitmaps into
502     //  vector graphics (http://potrace.sourceforge.net/)
503     notebook.append_page(potraceBox, _("Potrace"));
505     //##Set up the Other panel
506     // This may be reenabled when we have another tracer; now an empty tab is confusing so I'm disabling it
507     //    notebook.append_page(otherBox, _("Other"));
509     //##Put the notebook on the dialog
510     mainVBox->pack_start(notebook);
512     //## The OK button
513     potraceCancelButton = add_button(Gtk::Stock::STOP, GTK_RESPONSE_CANCEL);
514     if (potraceCancelButton)
515         {
516         tips.set_tip((*potraceCancelButton), _("Abort a trace in progress"));
517         potraceCancelButton->set_sensitive(false);
518         }
519     potraceOkButton     = add_button(Gtk::Stock::OK,   GTK_RESPONSE_OK);
520     tips.set_tip((*potraceOkButton), _("Execute the trace"));
522     show_all_children();
524     //## Connect the signal
525     signal_response().connect(
526          sigc::mem_fun(*this, &TraceDialogImpl::responseCallback) );
529 /**
530  * Factory method.  Use this to create a new TraceDialog
531  */
532 TraceDialog *TraceDialog::create()
534     TraceDialog *dialog = new TraceDialogImpl();
535     return dialog;
539 /**
540  * Constructor
541  */
542 TraceDialogImpl::~TraceDialogImpl()
553 } //namespace Dialog
554 } //namespace UI
555 } //namespace Inkscape
557 //#########################################################################
558 //## E N D    O F    F I L E
559 //#########################################################################