4bfb66f3dfdced3de13ac9201c66a39e2420b0c5
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;
139 Gtk::CheckButton potraceMultiScanStackButton;
141 Gtk::HBox potraceMultiScanHBox3;
142 Gtk::RadioButton potraceMultiScanMonoRadioButton;
143 Gtk::Label potraceMultiScanNrColorLabel;
145 Gtk::CheckButton potraceMultiScanSmoothButton;
148 //preview
149 Gtk::Frame potracePreviewFrame;
150 Gtk::HBox potracePreviewBox;
151 Gtk::Button potracePreviewButton;
152 Gtk::Image potracePreviewImage;
154 //credits
155 Gtk::Frame potraceCreditsFrame;
156 Gtk::VBox potraceCreditsVBox;
157 Gtk::Label potraceCreditsLabel;
159 //########## Other items
160 Gtk::VBox otherBox;
164 };
169 //#########################################################################
170 //## E V E N T S
171 //#########################################################################
173 /**
174 * This does potrace processing
175 * Only preview if do_i_trace is false
176 */
177 void TraceDialogImpl::potraceProcess(bool do_i_trace)
178 {
179 //##### Get the tracer and engine
180 Inkscape::Trace::Potrace::PotraceTracingEngine pte;
182 /* inversion */
183 bool invert = potraceInvertButton.get_active();
184 pte.setInvert(invert);
186 //##### Get the preprocessor settings
187 /* siox -- performed by Tracer, and before any of the others */
188 if (sioxButton.get_active())
189 tracer.enableSiox(true);
190 else
191 tracer.enableSiox(false);
193 /* one of the following */
194 if (potraceBrightnessRadioButton.get_active())
195 pte.setTraceType(Inkscape::Trace::Potrace::TRACE_BRIGHTNESS);
196 else if (potraceMultiScanBrightnessRadioButton.get_active())
197 pte.setTraceType(Inkscape::Trace::Potrace::TRACE_BRIGHTNESS_MULTI);
198 else if (potraceCannyRadioButton.get_active())
199 pte.setTraceType(Inkscape::Trace::Potrace::TRACE_CANNY);
200 else if (potraceQuantRadioButton.get_active())
201 pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT);
202 else if (potraceMultiScanColorRadioButton.get_active())
203 {
204 pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT_COLOR);
205 pte.setInvert(false);
206 }
207 else if (potraceMultiScanMonoRadioButton.get_active())
208 {
209 pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT_MONO);
210 pte.setInvert(false);
211 }
213 //##### Get the single-scan settings
214 /* brightness */
215 double brightnessThreshold = potraceBrightnessSpinner.get_value();
216 pte.setBrightnessThreshold(brightnessThreshold);
218 /* canny */
219 double cannyHighThreshold = potraceCannyHiSpinner.get_value();
220 pte.setCannyHighThreshold(cannyHighThreshold);
222 /* quantization */
223 int quantNrColors = potraceQuantNrColorSpinner.get_value_as_int();
224 pte.setQuantizationNrColors(quantNrColors);
226 //##### Get multiple-scan settings
227 int multiScanNrColors = potraceMultiScanNrColorSpinner.get_value_as_int();
228 pte.setMultiScanNrColors(multiScanNrColors);
229 bool do_i_stack = potraceMultiScanStackButton.get_active();
230 pte.setMultiScanStack(do_i_stack);
231 bool do_i_smooth = potraceMultiScanSmoothButton.get_active();
232 pte.setMultiScanSmooth(do_i_smooth);
234 //##### Get intermediate bitmap image
235 GdkPixbuf *pixbuf = tracer.getSelectedImage();
236 if (pixbuf)
237 {
238 GdkPixbuf *preview = pte.preview(pixbuf);
239 if (preview)
240 {
241 Glib::RefPtr<Gdk::Pixbuf> thePreview = Glib::wrap(preview);
242 int width = thePreview->get_width();
243 int height = thePreview->get_height();
244 double scaleFactor = 100.0 / (double)height;
245 int newWidth = (int) (((double)width) * scaleFactor);
246 int newHeight = (int) (((double)height) * scaleFactor);
247 Glib::RefPtr<Gdk::Pixbuf> scaledPreview =
248 thePreview->scale_simple(newWidth, newHeight,
249 Gdk::INTERP_NEAREST);
250 //g_object_unref(preview);
251 potracePreviewImage.set(scaledPreview);
252 }
253 }
255 //##### Convert
256 if (do_i_trace)
257 {
258 if (potraceCancelButton)
259 potraceCancelButton->set_sensitive(true);
260 if (potraceOkButton)
261 potraceOkButton->set_sensitive(false);
262 tracer.trace(&pte);
263 if (potraceCancelButton)
264 potraceCancelButton->set_sensitive(false);
265 if (potraceOkButton)
266 potraceOkButton->set_sensitive(true);
267 }
269 }
272 /**
273 * Abort processing
274 */
275 void TraceDialogImpl::abort()
276 {
277 //### Do some GUI thing
279 //### Make the abort() call to the tracer
280 tracer.abort();
282 }
286 //#########################################################################
287 //## E V E N T S
288 //#########################################################################
290 /**
291 * Callback from the Preview button. Can be called from elsewhere.
292 */
293 void TraceDialogImpl::potracePreviewCallback()
294 {
295 potraceProcess(false);
296 }
298 /**
299 * Default response from the dialog. Let's intercept it
300 */
301 void TraceDialogImpl::responseCallback(int response_id)
302 {
304 if (response_id == GTK_RESPONSE_OK)
305 {
306 int panelNr = notebook.get_current_page();
307 //g_message("selected panel:%d\n", panelNr);
309 if (panelNr == 0)
310 {
311 potraceProcess(true);
312 }
313 }
314 else if (response_id == GTK_RESPONSE_CANCEL)
315 {
316 abort();
317 }
318 else
319 {
320 hide();
321 return;
322 }
326 }
331 //#########################################################################
332 //## C O N S T R U C T O R / D E S T R U C T O R
333 //#########################################################################
334 /**
335 * Constructor
336 */
337 TraceDialogImpl::TraceDialogImpl()
338 {
340 Gtk::VBox *mainVBox = get_vbox();
342 #define MARGIN 4
344 /*#### SIOX ####*/
345 //# for now, put at the top of the potrace box. something better later
346 sioxButton.set_label(_("SIOX foreground selection"));
347 sioxBox.pack_start(sioxButton, false, false, MARGIN);
348 tips.set_tip(sioxButton,
349 _("Cover the area you want to select as the foreground"));
350 sioxVBox.pack_start(sioxBox, false, false, MARGIN);
351 sioxFrame.set_label(_("SIOX"));
352 sioxFrame.add(sioxVBox);
353 potraceBox.pack_start(sioxFrame, false, false, 0);
356 //##Set up the Potrace panel
358 /*#### brightness ####*/
359 potraceBrightnessRadioButton.set_label(_("Brightness"));
360 potraceGroup = potraceBrightnessRadioButton.get_group();
361 potraceBrightnessBox.pack_start(potraceBrightnessRadioButton, false, false, MARGIN);
362 tips.set_tip(potraceBrightnessRadioButton, _("Trace by a given brightness level"));
364 potraceBrightnessSpinner.set_digits(3);
365 potraceBrightnessSpinner.set_increments(0.01, 0.1);
366 potraceBrightnessSpinner.set_range(0.0, 1.0);
367 potraceBrightnessSpinner.set_value(0.45);
368 potraceBrightnessBox.pack_end(potraceBrightnessSpinner, false, false, MARGIN);
369 tips.set_tip(potraceBrightnessSpinner, _("Brightness cutoff for black/white"));
371 potraceBrightnessSpinnerLabel.set_label(_("Threshold:"));
372 potraceBrightnessBox.pack_end(potraceBrightnessSpinnerLabel, false, false, MARGIN);
374 potraceBrightnessVBox.pack_start(potraceBrightnessBox, false, false, MARGIN);
376 potraceBrightnessFrame.set_label(_("Image Brightness"));
377 //potraceBrightnessFrame.set_shadow_type(Gtk::SHADOW_NONE);
378 potraceBrightnessFrame.add(potraceBrightnessVBox);
379 potraceBox.pack_start(potraceBrightnessFrame, false, false, 0);
381 /*#### canny edge detection ####*/
382 // TRANSLATORS: "Canny" is the name of the inventor of this edge detection method
383 potraceCannyRadioButton.set_label(_("Optimal Edge Detection (Canny)"));
384 potraceCannyRadioButton.set_group(potraceGroup);
385 potraceCannyBox.pack_start(potraceCannyRadioButton, false, false, MARGIN);
386 tips.set_tip(potraceCannyRadioButton, _("Trace with edge detection by J. Canny's algorithm"));
387 /*
388 potraceCannyBox.pack_start(potraceCannySeparator);
389 potraceCannyLoSpinnerLabel.set_label(_("Low"));
390 potraceCannyBox.pack_start(potraceCannyLoSpinnerLabel);
391 potraceCannyLoSpinner.set_digits(5);
392 potraceCannyLoSpinner.set_increments(0.01, 0.1);
393 potraceCannyLoSpinner.set_range(0.0, 1.0);
394 potraceCannyLoSpinner.set_value(0.1);
395 potraceCannyBox.pack_start(potraceCannyLoSpinner);
396 */
397 potraceCannyHiSpinner.set_digits(3);
398 potraceCannyHiSpinner.set_increments(0.01, 0.1);
399 potraceCannyHiSpinner.set_range(0.0, 1.0);
400 potraceCannyHiSpinner.set_value(0.65);
401 potraceCannyBox.pack_end(potraceCannyHiSpinner, false, false, MARGIN);
402 tips.set_tip(potraceCannyHiSpinner, _("Brightness cutoff for adjacent pixels (determines edge thickness)"));
404 potraceCannyHiSpinnerLabel.set_label(_("Threshold:"));
405 potraceCannyBox.pack_end(potraceCannyHiSpinnerLabel, false, false, MARGIN);
407 potraceCannyVBox.pack_start(potraceCannyBox, false, false, MARGIN);
409 potraceCannyFrame.set_label(_("Edge Detection"));
410 //potraceCannyFrame.set_shadow_type(Gtk::SHADOW_NONE);
411 potraceCannyFrame.add(potraceCannyVBox);
412 potraceBox.pack_start(potraceCannyFrame, false, false, 0);
414 /*#### quantization ####*/
415 // TRANSLATORS: Color Quantization: the process of reducing the number of colors
416 // in an image by selecting an optimized set of representative colors and then
417 // re-applying this reduced set to the original image.
418 potraceQuantRadioButton.set_label(_("Color Quantization"));
419 potraceQuantRadioButton.set_group(potraceGroup);
420 potraceQuantBox.pack_start(potraceQuantRadioButton, false, false, MARGIN);
421 tips.set_tip(potraceQuantRadioButton, _("Trace along the boundaries of reduced colors"));
423 potraceQuantNrColorSpinner.set_digits(2);
424 potraceQuantNrColorSpinner.set_increments(1.0, 4.0);
425 potraceQuantNrColorSpinner.set_range(2.0, 64.0);
426 potraceQuantNrColorSpinner.set_value(8.0);
427 potraceQuantBox.pack_end(potraceQuantNrColorSpinner, false, false, MARGIN);
428 tips.set_tip(potraceQuantNrColorSpinner, _("The number of reduced colors"));
430 potraceQuantNrColorLabel.set_label(_("Colors:"));
431 potraceQuantBox.pack_end(potraceQuantNrColorLabel, false, false, MARGIN);
433 potraceQuantVBox.pack_start(potraceQuantBox, false, false, MARGIN);
435 potraceQuantFrame.set_label(_("Quantization / Reduction"));
436 //potraceQuantFrame.set_shadow_type(Gtk::SHADOW_NONE);
437 potraceQuantFrame.add(potraceQuantVBox);
438 potraceBox.pack_start(potraceQuantFrame, false, false, 0);
440 /*#### Multiple scanning####*/
441 //----Hbox1
442 potraceMultiScanBrightnessRadioButton.set_label(_("Brightness"));
443 potraceMultiScanBrightnessRadioButton.set_group(potraceGroup);
444 potraceMultiScanHBox1.pack_start(potraceMultiScanBrightnessRadioButton, false, false, MARGIN);
445 tips.set_tip(potraceMultiScanBrightnessRadioButton, _("Trace the given number of brightness levels"));
447 potraceMultiScanNrColorSpinner.set_digits(0);
448 potraceMultiScanNrColorSpinner.set_increments(1.0, 4.0);
449 potraceMultiScanNrColorSpinner.set_range(2.0, 256.0);
450 potraceMultiScanNrColorSpinner.set_value(8.0);
451 potraceMultiScanHBox1.pack_end(potraceMultiScanNrColorSpinner, false, false, MARGIN);
452 potraceMultiScanNrColorLabel.set_label(_("Scans:"));
453 potraceMultiScanHBox1.pack_end(potraceMultiScanNrColorLabel, false, false, MARGIN);
454 tips.set_tip(potraceMultiScanNrColorSpinner, _("The desired number of scans"));
456 potraceMultiScanVBox.pack_start(potraceMultiScanHBox1, false, false, MARGIN);
458 //----Hbox2
459 potraceMultiScanColorRadioButton.set_label(_("Color"));
460 potraceMultiScanColorRadioButton.set_group(potraceGroup);
461 potraceMultiScanHBox2.pack_start(potraceMultiScanColorRadioButton, false, false, MARGIN);
462 tips.set_tip(potraceMultiScanColorRadioButton, _("Trace the given number of reduced colors"));
465 potraceMultiScanVBox.pack_start(potraceMultiScanHBox2, false, false, MARGIN);
467 //---Hbox3
468 potraceMultiScanMonoRadioButton.set_label(_("Monochrome"));
469 potraceMultiScanMonoRadioButton.set_group(potraceGroup);
470 potraceMultiScanHBox3.pack_start(potraceMultiScanMonoRadioButton, false, false, MARGIN);
471 tips.set_tip(potraceMultiScanMonoRadioButton, _("Same as Color, but convert result to grayscale"));
473 // TRANSLATORS: "Stack" is a verb here
474 potraceMultiScanStackButton.set_label(_("Stack"));
475 potraceMultiScanStackButton.set_active(true);
476 potraceMultiScanHBox3.pack_end(potraceMultiScanStackButton, false, false, MARGIN);
477 tips.set_tip(potraceMultiScanStackButton, _("Stack scans vertically (no gaps) or tile horizontally (usually with gaps)"));
479 // TRANSLATORS: "Smooth" is a verb here
480 potraceMultiScanSmoothButton.set_label(_("Smooth"));
481 potraceMultiScanSmoothButton.set_active(true);
482 potraceMultiScanHBox3.pack_end(potraceMultiScanSmoothButton, false, false, MARGIN);
483 tips.set_tip(potraceMultiScanSmoothButton, _("Apply Gaussian blur to the bitmap before tracing"));
485 potraceMultiScanVBox.pack_start(potraceMultiScanHBox3, false, false, MARGIN);
487 potraceMultiScanFrame.set_label(_("Multiple Scanning"));
488 //potraceQuantFrame.set_shadow_type(Gtk::SHADOW_NONE);
489 potraceMultiScanFrame.add(potraceMultiScanVBox);
490 potraceBox.pack_start(potraceMultiScanFrame, false, false, 0);
492 /*#### Preview ####*/
493 potracePreviewButton.set_label(_("Preview"));
494 potracePreviewButton.signal_clicked().connect(
495 sigc::mem_fun(*this, &TraceDialogImpl::potracePreviewCallback) );
496 potracePreviewBox.pack_end(potracePreviewButton, false, false, 0);//do not expand
497 tips.set_tip(potracePreviewButton, _("Preview the result without actual tracing"));
500 potracePreviewImage.set_size_request(100,100);
501 //potracePreviewImage.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
502 potracePreviewBox.pack_start(potracePreviewImage, true, true, 0);
503 potracePreviewFrame.set_label(_("Preview")); // I guess it's correct to call the "intermediate bitmap" a preview of the trace
504 //potracePreviewFrame.set_shadow_type(Gtk::SHADOW_NONE);
505 potracePreviewFrame.add(potracePreviewBox);
506 potraceBox.pack_start(potracePreviewFrame, true, true, 0);
508 /*#### swap black and white ####*/
509 potraceInvertButton.set_label(_("Invert"));
510 potraceInvertButton.set_active(false);
511 potraceInvertBox.pack_end(potraceInvertButton, false, false, MARGIN);
512 potraceBox.pack_start(potraceInvertBox, false, false, MARGIN);
513 tips.set_tip(potraceInvertButton, _("Invert black and white regions for single traces"));
515 /*#### Credits ####*/
516 potraceCreditsLabel.set_text(
517 _("Thanks to Peter Selinger, http://potrace.sourceforge.net")
518 );
519 potraceCreditsVBox.pack_start(potraceCreditsLabel, false, false, MARGIN);
520 potraceCreditsFrame.set_label(_("Credits"));
521 potraceCreditsFrame.set_shadow_type(Gtk::SHADOW_NONE);
522 potraceCreditsFrame.add(potraceCreditsVBox);
523 potraceBox.pack_start(potraceCreditsFrame, false, false, 0);
525 /*done */
526 // TRANSLATORS: Potrace is an application for transforming bitmaps into
527 // vector graphics (http://potrace.sourceforge.net/)
528 notebook.append_page(potraceBox, _("Potrace"));
530 //##Set up the Other panel
531 // This may be reenabled when we have another tracer; now an empty tab is confusing so I'm disabling it
532 // notebook.append_page(otherBox, _("Other"));
534 //##Put the notebook on the dialog
535 mainVBox->pack_start(notebook);
537 //## The OK button
538 potraceCancelButton = add_button(Gtk::Stock::STOP, GTK_RESPONSE_CANCEL);
539 if (potraceCancelButton)
540 {
541 tips.set_tip((*potraceCancelButton), _("Abort a trace in progress"));
542 potraceCancelButton->set_sensitive(false);
543 }
544 potraceOkButton = add_button(Gtk::Stock::OK, GTK_RESPONSE_OK);
545 tips.set_tip((*potraceOkButton), _("Execute the trace"));
547 show_all_children();
549 //## Connect the signal
550 signal_response().connect(
551 sigc::mem_fun(*this, &TraceDialogImpl::responseCallback) );
552 }
554 /**
555 * Factory method. Use this to create a new TraceDialog
556 */
557 TraceDialog *TraceDialog::create()
558 {
559 TraceDialog *dialog = new TraceDialogImpl();
560 return dialog;
561 }
564 /**
565 * Constructor
566 */
567 TraceDialogImpl::~TraceDialogImpl()
568 {
571 }
578 } //namespace Dialog
579 } //namespace UI
580 } //namespace Inkscape
582 //#########################################################################
583 //## E N D O F F I L E
584 //#########################################################################