Code

move filedialog to its new home
[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     //########## General items
88     Gtk::Frame            sioxFrame;
89     Gtk::VBox             sioxVBox;
90     Gtk::HBox             sioxBox;
91     Gtk::CheckButton      sioxButton;
93     //########## Potrace items
94     Gtk::VBox             potraceBox;
95     Gtk::RadioButtonGroup potraceGroup;
96     Gtk::CheckButton      potraceInvertButton;
97     Gtk::HBox             potraceInvertBox;
98     Gtk::Button           *potraceOkButton;
99     Gtk::Button           *potraceCancelButton;
101     //brightness
102     Gtk::Frame            potraceBrightnessFrame;
103     Gtk::VBox             potraceBrightnessVBox;
104     Gtk::HBox             potraceBrightnessBox;
105     Gtk::RadioButton      potraceBrightnessRadioButton;
106     Gtk::Label            potraceBrightnessSpinnerLabel;
107     Gtk::SpinButton       potraceBrightnessSpinner;
110     //edge detection
111     Gtk::Frame            potraceCannyFrame;
112     Gtk::HBox             potraceCannyBox;
113     Gtk::VBox             potraceCannyVBox;
114     Gtk::RadioButton      potraceCannyRadioButton;
115     //Gtk::HSeparator     potraceCannySeparator;
116     //Gtk::Label          potraceCannyLoSpinnerLabel;
117     //Gtk::SpinButton     potraceCannyLoSpinner;
118     Gtk::Label            potraceCannyHiSpinnerLabel;
119     Gtk::SpinButton       potraceCannyHiSpinner;
121     //quantization
122     Gtk::Frame            potraceQuantFrame;
123     Gtk::HBox             potraceQuantBox;
124     Gtk::VBox             potraceQuantVBox;
125     Gtk::RadioButton      potraceQuantRadioButton;
126     Gtk::Label            potraceQuantNrColorLabel;
127     Gtk::SpinButton       potraceQuantNrColorSpinner;
129     //multiple path scanning
130     Gtk::Frame            potraceMultiScanFrame;
131     Gtk::VBox             potraceMultiScanVBox;
133     Gtk::HBox             potraceMultiScanHBox1;
134     Gtk::RadioButton      potraceMultiScanBrightnessRadioButton;
135     Gtk::SpinButton       potraceMultiScanNrColorSpinner;
137     Gtk::HBox             potraceMultiScanHBox2;
138     Gtk::RadioButton      potraceMultiScanColorRadioButton;
140     Gtk::HBox             potraceMultiScanHBox3;
141     Gtk::RadioButton      potraceMultiScanMonoRadioButton;
142     Gtk::Label            potraceMultiScanNrColorLabel;
144     Gtk::CheckButton      potraceMultiScanStackButton;
145     Gtk::CheckButton      potraceMultiScanSmoothButton;
146     Gtk::CheckButton      potraceMultiScanBackgroundButton;
149     //preview
150     Gtk::Frame            potracePreviewFrame;
151     Gtk::HBox             potracePreviewBox;
152     Gtk::Button           potracePreviewButton;
153     Gtk::Image            potracePreviewImage;
155     //credits
156     Gtk::Frame            potraceCreditsFrame;
157     Gtk::VBox             potraceCreditsVBox;
158     Gtk::Label            potraceCreditsLabel;
160     //########## Other items
161     Gtk::VBox             otherBox;
165 };
170 //#########################################################################
171 //## E V E N T S
172 //#########################################################################
174 /**
175  * This does potrace processing
176  * Only preview if do_i_trace is false
177  */
178 void TraceDialogImpl::potraceProcess(bool do_i_trace)
180     //##### Get the tracer and engine
181     Inkscape::Trace::Potrace::PotraceTracingEngine pte;
183     /* inversion */
184     bool invert = potraceInvertButton.get_active();
185     pte.setInvert(invert);
187     //##### Get the preprocessor settings
188     /* siox -- performed by Tracer, and before any of the others */
189     if (sioxButton.get_active())
190         tracer.enableSiox(true);
191     else
192         tracer.enableSiox(false);
194     /* one of the following */
195     if (potraceBrightnessRadioButton.get_active())
196         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_BRIGHTNESS);
197     else if (potraceMultiScanBrightnessRadioButton.get_active())
198         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_BRIGHTNESS_MULTI);
199     else if (potraceCannyRadioButton.get_active())
200         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_CANNY);
201     else if (potraceQuantRadioButton.get_active())
202         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT);
203     else if (potraceMultiScanColorRadioButton.get_active())
204         {
205         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT_COLOR);
206         pte.setInvert(false);
207         }
208     else if (potraceMultiScanMonoRadioButton.get_active())
209         {
210         pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT_MONO);
211         pte.setInvert(false);
212         }
214     //##### Get the single-scan settings
215     /* brightness */
216     double brightnessThreshold = potraceBrightnessSpinner.get_value();
217     pte.setBrightnessThreshold(brightnessThreshold);
219     /* canny */
220     double cannyHighThreshold = potraceCannyHiSpinner.get_value();
221     pte.setCannyHighThreshold(cannyHighThreshold);
223     /* quantization */
224     int quantNrColors = potraceQuantNrColorSpinner.get_value_as_int();
225     pte.setQuantizationNrColors(quantNrColors);
227     //##### Get multiple-scan settings
228     int multiScanNrColors = potraceMultiScanNrColorSpinner.get_value_as_int();
229     pte.setMultiScanNrColors(multiScanNrColors);
230     bool do_i_stack = potraceMultiScanStackButton.get_active();
231     pte.setMultiScanStack(do_i_stack);
232     bool do_i_smooth = potraceMultiScanSmoothButton.get_active();
233     pte.setMultiScanSmooth(do_i_smooth);
234     bool do_i_remove_background = potraceMultiScanBackgroundButton.get_active();
235     pte.setMultiScanRemoveBackground(do_i_remove_background);
237     //##### Get intermediate bitmap image
238     Glib::RefPtr<Gdk::Pixbuf> pixbuf = tracer.getSelectedImage();
239     if (pixbuf)
240          {
241          Glib::RefPtr<Gdk::Pixbuf> preview = pte.preview(pixbuf);
242          if (preview)
243              {
244              int width  = preview->get_width();
245              int height = preview->get_height();
246              double scaleFactor = 100.0 / (double)height;
247              int newWidth  = (int) (((double)width)  * scaleFactor);
248              int newHeight = (int) (((double)height) * scaleFactor);
249              Glib::RefPtr<Gdk::Pixbuf> scaledPreview =
250                     preview->scale_simple(newWidth, newHeight,
251                        Gdk::INTERP_NEAREST);
252              //g_object_unref(preview);
253              potracePreviewImage.set(scaledPreview);
254              }
255          }
257     //##### Convert
258     if (do_i_trace)
259         {
260         if (potraceCancelButton)
261             potraceCancelButton->set_sensitive(true);
262         if (potraceOkButton)
263             potraceOkButton->set_sensitive(false);
264         tracer.trace(&pte);
265         if (potraceCancelButton)
266             potraceCancelButton->set_sensitive(false);
267         if (potraceOkButton)
268             potraceOkButton->set_sensitive(true);
269         }
274 /**
275  * Abort processing
276  */
277 void TraceDialogImpl::abort()
279     //### Do some GUI thing
281     //### Make the abort() call to the tracer
282     tracer.abort();
288 //#########################################################################
289 //## E V E N T S
290 //#########################################################################
292 /**
293  * Callback from the Preview button.  Can be called from elsewhere.
294  */
295 void TraceDialogImpl::potracePreviewCallback()
297     potraceProcess(false);
300 /**
301  * Default response from the dialog.  Let's intercept it
302  */
303 void TraceDialogImpl::responseCallback(int response_id)
306     if (response_id == GTK_RESPONSE_OK)
307         {
308         int panelNr = notebook.get_current_page();
309         //g_message("selected panel:%d\n", panelNr);
311         if (panelNr == 0)
312             {
313             potraceProcess(true);
314             }
315         }
316     else if (response_id == GTK_RESPONSE_CANCEL)
317         {
318         abort();
319         }
320     else
321         {
322         hide();
323         return;
324         }
333 //#########################################################################
334 //## C O N S T R U C T O R    /    D E S T R U C T O R
335 //#########################################################################
336 /**
337  * Constructor
338  */
339 TraceDialogImpl::TraceDialogImpl()
342     Gtk::VBox *mainVBox = get_vbox();
344 #define MARGIN 4
346     /*#### SIOX ####*/
347     //# for now, put at the top of the potrace box.  something better later
348     sioxButton.set_label(_("SIOX foreground selection"));
349     sioxBox.pack_start(sioxButton, false, false, MARGIN);
350     tips.set_tip(sioxButton, 
351         _("Cover the area you want to select as the foreground"));
352     sioxVBox.pack_start(sioxBox, false, false, MARGIN);
353     sioxFrame.set_label(_("SIOX"));
354     sioxFrame.add(sioxVBox);
355     potraceBox.pack_start(sioxFrame, false, false, 0);
358     //##Set up the Potrace panel
360     /*#### brightness ####*/
361     potraceBrightnessRadioButton.set_label(_("Brightness"));
362     potraceGroup = potraceBrightnessRadioButton.get_group();
363     potraceBrightnessBox.pack_start(potraceBrightnessRadioButton, false, false, MARGIN);
364     tips.set_tip(potraceBrightnessRadioButton, _("Trace by a given brightness level"));
366     potraceBrightnessSpinner.set_digits(3);
367     potraceBrightnessSpinner.set_increments(0.01, 0.1);
368     potraceBrightnessSpinner.set_range(0.0, 1.0);
369     potraceBrightnessSpinner.set_value(0.45);
370     potraceBrightnessBox.pack_end(potraceBrightnessSpinner, false, false, MARGIN);
371     tips.set_tip(potraceBrightnessSpinner, _("Brightness cutoff for black/white"));
373     potraceBrightnessSpinnerLabel.set_label(_("Threshold:"));
374     potraceBrightnessBox.pack_end(potraceBrightnessSpinnerLabel, false, false, MARGIN);
376     potraceBrightnessVBox.pack_start(potraceBrightnessBox, false, false, MARGIN);
378     potraceBrightnessFrame.set_label(_("Image Brightness"));
379     //potraceBrightnessFrame.set_shadow_type(Gtk::SHADOW_NONE);
380     potraceBrightnessFrame.add(potraceBrightnessVBox);
381     potraceBox.pack_start(potraceBrightnessFrame, false, false, 0);
383     /*#### canny edge detection ####*/
384     // TRANSLATORS: "Canny" is the name of the inventor of this edge detection method
385     potraceCannyRadioButton.set_label(_("Optimal Edge Detection (Canny)"));
386     potraceCannyRadioButton.set_group(potraceGroup);
387     potraceCannyBox.pack_start(potraceCannyRadioButton, false, false, MARGIN);
388     tips.set_tip(potraceCannyRadioButton, _("Trace with edge detection by J. Canny's algorithm"));
389     /*
390     potraceCannyBox.pack_start(potraceCannySeparator);
391     potraceCannyLoSpinnerLabel.set_label(_("Low"));
392     potraceCannyBox.pack_start(potraceCannyLoSpinnerLabel);
393     potraceCannyLoSpinner.set_digits(5);
394     potraceCannyLoSpinner.set_increments(0.01, 0.1);
395     potraceCannyLoSpinner.set_range(0.0, 1.0);
396     potraceCannyLoSpinner.set_value(0.1);
397     potraceCannyBox.pack_start(potraceCannyLoSpinner);
398     */
399     potraceCannyHiSpinner.set_digits(3);
400     potraceCannyHiSpinner.set_increments(0.01, 0.1);
401     potraceCannyHiSpinner.set_range(0.0, 1.0);
402     potraceCannyHiSpinner.set_value(0.65);
403     potraceCannyBox.pack_end(potraceCannyHiSpinner, false, false, MARGIN);
404     tips.set_tip(potraceCannyHiSpinner, _("Brightness cutoff for adjacent pixels (determines edge thickness)"));
406     potraceCannyHiSpinnerLabel.set_label(_("Threshold:"));
407     potraceCannyBox.pack_end(potraceCannyHiSpinnerLabel, false, false, MARGIN);
409     potraceCannyVBox.pack_start(potraceCannyBox, false, false, MARGIN);
411     potraceCannyFrame.set_label(_("Edge Detection"));
412     //potraceCannyFrame.set_shadow_type(Gtk::SHADOW_NONE);
413     potraceCannyFrame.add(potraceCannyVBox);
414     potraceBox.pack_start(potraceCannyFrame, false, false, 0);
416     /*#### quantization ####*/
417     // TRANSLATORS: Color Quantization: the process of reducing the number of colors
418     //  in an image by selecting an optimized set of representative colors and then
419     //  re-applying this reduced set to the original image.
420     potraceQuantRadioButton.set_label(_("Color Quantization"));
421     potraceQuantRadioButton.set_group(potraceGroup);
422     potraceQuantBox.pack_start(potraceQuantRadioButton, false, false, MARGIN);
423     tips.set_tip(potraceQuantRadioButton, _("Trace along the boundaries of reduced colors"));
425     potraceQuantNrColorSpinner.set_digits(2);
426     potraceQuantNrColorSpinner.set_increments(1.0, 4.0);
427     potraceQuantNrColorSpinner.set_range(2.0, 64.0);
428     potraceQuantNrColorSpinner.set_value(8.0);
429     potraceQuantBox.pack_end(potraceQuantNrColorSpinner, false, false, MARGIN);
430     tips.set_tip(potraceQuantNrColorSpinner, _("The number of reduced colors"));
432     potraceQuantNrColorLabel.set_label(_("Colors:"));
433     potraceQuantBox.pack_end(potraceQuantNrColorLabel, false, false, MARGIN);
435     potraceQuantVBox.pack_start(potraceQuantBox, false, false, MARGIN);
437     potraceQuantFrame.set_label(_("Quantization / Reduction"));
438     //potraceQuantFrame.set_shadow_type(Gtk::SHADOW_NONE);
439     potraceQuantFrame.add(potraceQuantVBox);
440     potraceBox.pack_start(potraceQuantFrame, false, false, 0);
442     /*#### Multiple scanning####*/
443     //----Hbox1
444     potraceMultiScanBrightnessRadioButton.set_label(_("Brightness"));
445     potraceMultiScanBrightnessRadioButton.set_group(potraceGroup);
446     potraceMultiScanHBox1.pack_start(potraceMultiScanBrightnessRadioButton, false, false, MARGIN);
447     tips.set_tip(potraceMultiScanBrightnessRadioButton, _("Trace the given number of brightness levels"));
449     potraceMultiScanNrColorSpinner.set_digits(0);
450     potraceMultiScanNrColorSpinner.set_increments(1.0, 4.0);
451     potraceMultiScanNrColorSpinner.set_range(2.0, 256.0);
452     potraceMultiScanNrColorSpinner.set_value(8.0);
453     potraceMultiScanHBox1.pack_end(potraceMultiScanNrColorSpinner, false, false, MARGIN);
454     potraceMultiScanNrColorLabel.set_label(_("Scans:"));
455     potraceMultiScanHBox1.pack_end(potraceMultiScanNrColorLabel, false, false, MARGIN);
456     tips.set_tip(potraceMultiScanNrColorSpinner, _("The desired number of scans"));
458     potraceMultiScanVBox.pack_start(potraceMultiScanHBox1, false, false, MARGIN);
460     //----Hbox2
461     potraceMultiScanColorRadioButton.set_label(_("Color"));
462     potraceMultiScanColorRadioButton.set_group(potraceGroup);
463     potraceMultiScanHBox2.pack_start(potraceMultiScanColorRadioButton, false, false, MARGIN);
464     tips.set_tip(potraceMultiScanColorRadioButton, _("Trace the given number of reduced colors"));
467     // TRANSLATORS: "Layer" refers to one of the stacked paths in the multiscan
468     potraceMultiScanBackgroundButton.set_label(_("Remove background"));
469     potraceMultiScanBackgroundButton.set_active(false);
470     potraceMultiScanHBox2.pack_end(potraceMultiScanBackgroundButton, false, false, MARGIN);
471     tips.set_tip(potraceMultiScanBackgroundButton, _("Remove bottom (background) layer when done"));
473     potraceMultiScanVBox.pack_start(potraceMultiScanHBox2, false, false, MARGIN);
475     //---Hbox3
476     potraceMultiScanMonoRadioButton.set_label(_("Monochrome"));
477     potraceMultiScanMonoRadioButton.set_group(potraceGroup);
478     potraceMultiScanHBox3.pack_start(potraceMultiScanMonoRadioButton, false, false, MARGIN);
479     tips.set_tip(potraceMultiScanMonoRadioButton, _("Same as Color, but convert result to grayscale"));
481     // TRANSLATORS: "Stack" is a verb here
482     potraceMultiScanStackButton.set_label(_("Stack"));
483     potraceMultiScanStackButton.set_active(true);
484     potraceMultiScanHBox3.pack_end(potraceMultiScanStackButton, false, false, MARGIN);
485     tips.set_tip(potraceMultiScanStackButton, _("Stack scans vertically (no gaps) or tile horizontally (usually with gaps)"));
487     // TRANSLATORS: "Smooth" is a verb here
488     potraceMultiScanSmoothButton.set_label(_("Smooth"));
489     potraceMultiScanSmoothButton.set_active(true);
490     potraceMultiScanHBox3.pack_end(potraceMultiScanSmoothButton, false, false, MARGIN);
491     tips.set_tip(potraceMultiScanSmoothButton, _("Apply Gaussian blur to the bitmap before tracing"));
494     potraceMultiScanVBox.pack_start(potraceMultiScanHBox3, false, false, MARGIN);
496     potraceMultiScanFrame.set_label(_("Multiple Scanning"));
497     //potraceQuantFrame.set_shadow_type(Gtk::SHADOW_NONE);
498     potraceMultiScanFrame.add(potraceMultiScanVBox);
499     potraceBox.pack_start(potraceMultiScanFrame, false, false, 0);
501     /*#### Preview ####*/
502     potracePreviewButton.set_label(_("Preview"));
503     potracePreviewButton.signal_clicked().connect(
504          sigc::mem_fun(*this, &TraceDialogImpl::potracePreviewCallback) );
505     potracePreviewBox.pack_end(potracePreviewButton, false, false, 0);//do not expand
506     tips.set_tip(potracePreviewButton, _("Preview the result without actual tracing"));
509     potracePreviewImage.set_size_request(100,100);
510     //potracePreviewImage.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
511     potracePreviewBox.pack_start(potracePreviewImage, true, true, 0);
512     potracePreviewFrame.set_label(_("Preview")); // I guess it's correct to call the "intermediate bitmap" a preview of the trace
513     //potracePreviewFrame.set_shadow_type(Gtk::SHADOW_NONE);
514     potracePreviewFrame.add(potracePreviewBox);
515     potraceBox.pack_start(potracePreviewFrame, true, true, 0);
517     /*#### swap black and white ####*/
518     potraceInvertButton.set_label(_("Invert"));
519     potraceInvertButton.set_active(false);
520     potraceInvertBox.pack_end(potraceInvertButton, false, false, MARGIN);
521     potraceBox.pack_start(potraceInvertBox, false, false, MARGIN);
522     tips.set_tip(potraceInvertButton, _("Invert black and white regions for single traces"));
524     /*#### Credits ####*/
525     potraceCreditsLabel.set_text(
526                                                          _("Thanks to Peter Selinger, http://potrace.sourceforge.net")
527                          );
528     potraceCreditsVBox.pack_start(potraceCreditsLabel, false, false, MARGIN);
529     potraceCreditsFrame.set_label(_("Credits"));
530     potraceCreditsFrame.set_shadow_type(Gtk::SHADOW_NONE);
531     potraceCreditsFrame.add(potraceCreditsVBox);
532     potraceBox.pack_start(potraceCreditsFrame, false, false, 0);
534     /*done */
535     // TRANSLATORS: Potrace is an application for transforming bitmaps into
536     //  vector graphics (http://potrace.sourceforge.net/)
537     notebook.append_page(potraceBox, _("Potrace"));
539     //##Set up the Other panel
540     // This may be reenabled when we have another tracer; now an empty tab is confusing so I'm disabling it
541     //    notebook.append_page(otherBox, _("Other"));
543     //##Put the notebook on the dialog
544     mainVBox->pack_start(notebook);
546     //## The OK button
547     potraceCancelButton = add_button(Gtk::Stock::STOP, GTK_RESPONSE_CANCEL);
548     if (potraceCancelButton)
549         {
550         tips.set_tip((*potraceCancelButton), _("Abort a trace in progress"));
551         potraceCancelButton->set_sensitive(false);
552         }
553     potraceOkButton     = add_button(Gtk::Stock::OK,   GTK_RESPONSE_OK);
554     tips.set_tip((*potraceOkButton), _("Execute the trace"));
556     show_all_children();
558     //## Connect the signal
559     signal_response().connect(
560          sigc::mem_fun(*this, &TraceDialogImpl::responseCallback) );
563 /**
564  * Factory method.  Use this to create a new TraceDialog
565  */
566 TraceDialog *TraceDialog::create()
568     TraceDialog *dialog = new TraceDialogImpl();
569     return dialog;
573 /**
574  * Constructor
575  */
576 TraceDialogImpl::~TraceDialogImpl()
587 } //namespace Dialog
588 } //namespace UI
589 } //namespace Inkscape
591 //#########################################################################
592 //## E N D    O F    F I L E
593 //#########################################################################