Logo Search packages:      
Sourcecode: inkscape version File versions

tracedialog.cpp

/*
 * A simple dialog for setting the parameters for autotracing a
 * bitmap <image> into an svg <path>
 *
 * Authors:
 *   Bob Jamison
 *   Other dudes from The Inkscape Organization
 *
 * Copyright (C) 2004 Bob Jamison
 *
 * Released under GNU GPL, read the file 'COPYING' for more information
 */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "tracedialog.h"
#include <trace/trace.h>
#include <trace/potrace/inkscape-potrace.h>

#include <gtkmm.h>
#include <gtkmm/box.h>
#include <gtkmm/dialog.h>
#include <gtkmm/button.h>

#include <gtk/gtk.h>

#include <dialogs/dialog-events.h>
#include <gtk/gtkdialog.h> //for GTK_RESPONSE* types
#include <glibmm/i18n.h>
#include "interface.h"
#include "verbs.h"
#include "prefs-utils.h"
#include "inkscape.h"
#include "macros.h"

#include <glib.h>

namespace Inkscape {
namespace UI {
namespace Dialogs {


//#########################################################################
//## I M P L E M E N T A T I O N
//#########################################################################

/**
 * A dialog for adjusting bitmap->vector tracing parameters
 */
00051 class TraceDialogImpl : public TraceDialog, public Gtk::Dialog
{

    public:
    

    /**
     * Constructor
     */
    TraceDialogImpl();

    /**
     * Destructor
     */
    ~TraceDialogImpl();


    /**
     * Show the dialog
     */
    void show();
    void showF12();

    /**
     * Do not show the dialog
     */
    void hide();
    void hideF12();

    /**
     * Callback from OK or Cancel
     */
    void responseCallback(int response_id);

    private:

    bool userHidden;

    /**
     * This is the big almighty McGuffin
     */
00092     Inkscape::Trace::Tracer tracer;

    /**
     * This does potrace processing
     * Only preview if do_i_trace is false
     */
    void potraceProcess(bool do_i_trace);

    /**
     * Abort processing
     */
    void abort();

    void potracePreviewCallback();

    Gtk::Notebook   notebook;
    Gtk::Tooltips   tips;

    //########## Potrace items
    Gtk::VBox             potraceBox;
    Gtk::RadioButtonGroup potraceGroup;
    Gtk::CheckButton      potraceInvertButton;
    Gtk::HBox             potraceInvertBox;
    Gtk::Button           *potraceOkButton;
    Gtk::Button           *potraceCancelButton;

    //brightness
    Gtk::Frame            potraceBrightnessFrame;
    Gtk::VBox             potraceBrightnessVBox;
    Gtk::HBox             potraceBrightnessBox;
    Gtk::RadioButton      potraceBrightnessRadioButton;
    Gtk::Label            potraceBrightnessSpinnerLabel;
    Gtk::SpinButton       potraceBrightnessSpinner;


    //edge detection
    Gtk::Frame            potraceCannyFrame;
    Gtk::HBox             potraceCannyBox;
    Gtk::VBox             potraceCannyVBox;
    Gtk::RadioButton      potraceCannyRadioButton;
    //Gtk::HSeparator     potraceCannySeparator;
    //Gtk::Label          potraceCannyLoSpinnerLabel;
    //Gtk::SpinButton     potraceCannyLoSpinner;
    Gtk::Label            potraceCannyHiSpinnerLabel;
    Gtk::SpinButton       potraceCannyHiSpinner;

    //quantization
    Gtk::Frame            potraceQuantFrame;
    Gtk::HBox             potraceQuantBox;
    Gtk::VBox             potraceQuantVBox;
    Gtk::RadioButton      potraceQuantRadioButton;
    Gtk::Label            potraceQuantNrColorLabel;
    Gtk::SpinButton       potraceQuantNrColorSpinner;

    //multiple path scanning
    Gtk::Frame            potraceMultiScanFrame;
    Gtk::VBox             potraceMultiScanVBox;

    Gtk::HBox             potraceMultiScanHBox1;
    Gtk::RadioButton      potraceMultiScanBrightnessRadioButton;
    Gtk::SpinButton       potraceMultiScanNrColorSpinner;

    Gtk::HBox             potraceMultiScanHBox2;
    Gtk::RadioButton      potraceMultiScanColorRadioButton;
    Gtk::CheckButton      potraceMultiScanStackButton;

    Gtk::HBox             potraceMultiScanHBox3;
    Gtk::RadioButton      potraceMultiScanMonoRadioButton;
    Gtk::Label            potraceMultiScanNrColorLabel;

    Gtk::CheckButton      potraceMultiScanSmoothButton;


    //preview
    Gtk::Frame            potracePreviewFrame;
    Gtk::HBox             potracePreviewBox;
    Gtk::Button           potracePreviewButton;
    Gtk::Image            potracePreviewImage;

    //credits
    Gtk::Frame            potraceCreditsFrame;
    Gtk::VBox             potraceCreditsVBox;
    Gtk::Label            potraceCreditsLabel;

    //########## Other items
    Gtk::VBox             otherBox;



};




//#########################################################################
//## E V E N T S
//#########################################################################

/**
 * This does potrace processing
 * Only preview if do_i_trace is false
 */
00194 void TraceDialogImpl::potraceProcess(bool do_i_trace)
{
    //##### Get the tracer and engine
    Inkscape::Trace::Potrace::PotraceTracingEngine pte;

    /* inversion */
    bool invert = potraceInvertButton.get_active();
    pte.setInvert(invert);

    //##### Get the single-scan settings
    /* which one? */
    if (potraceBrightnessRadioButton.get_active())
        pte.setTraceType(Inkscape::Trace::Potrace::TRACE_BRIGHTNESS);
    else if (potraceMultiScanBrightnessRadioButton.get_active())
        pte.setTraceType(Inkscape::Trace::Potrace::TRACE_BRIGHTNESS_MULTI);
    else if (potraceCannyRadioButton.get_active())
        pte.setTraceType(Inkscape::Trace::Potrace::TRACE_CANNY);
    else if (potraceQuantRadioButton.get_active())
        pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT);
    else if (potraceMultiScanColorRadioButton.get_active())
        {
        pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT_COLOR);
        pte.setInvert(false);
        }
    else if (potraceMultiScanMonoRadioButton.get_active())
        {
        pte.setTraceType(Inkscape::Trace::Potrace::TRACE_QUANT_MONO);
        pte.setInvert(false);
        }

    /* brightness */
    double brightnessThreshold = potraceBrightnessSpinner.get_value();
    pte.setBrightnessThreshold(brightnessThreshold);

    /* canny */
    double cannyHighThreshold = potraceCannyHiSpinner.get_value();
    pte.setCannyHighThreshold(cannyHighThreshold);

    /* quantization */
    int quantNrColors = potraceQuantNrColorSpinner.get_value_as_int();
    pte.setQuantizationNrColors(quantNrColors);

    //##### Get multiple-scan settings
    int multiScanNrColors = potraceMultiScanNrColorSpinner.get_value_as_int();
    pte.setMultiScanNrColors(multiScanNrColors);
    bool do_i_stack = potraceMultiScanStackButton.get_active();
    pte.setMultiScanStack(do_i_stack);
    bool do_i_smooth = potraceMultiScanSmoothButton.get_active();
    pte.setMultiScanSmooth(do_i_smooth);

    //##### Get intermediate bitmap image
    GdkPixbuf *pixbuf = tracer.getSelectedImage();
    if (pixbuf)
         {
         GdkPixbuf *preview = pte.preview(pixbuf);
         if (preview)
             {
             Glib::RefPtr<Gdk::Pixbuf> thePreview = Glib::wrap(preview);
             int width  = thePreview->get_width();
             int height = thePreview->get_height();
             double scaleFactor = 100.0 / (double)height;
             int newWidth  = (int) (((double)width)  * scaleFactor);
             int newHeight = (int) (((double)height) * scaleFactor);
             Glib::RefPtr<Gdk::Pixbuf> scaledPreview =
                    thePreview->scale_simple(newWidth, newHeight,
                       Gdk::INTERP_NEAREST);
             //g_object_unref(preview);
             potracePreviewImage.set(scaledPreview);
             }
         }

    //##### Convert
    if (do_i_trace)
        {
        if (potraceCancelButton)
            potraceCancelButton->set_sensitive(true);
        if (potraceOkButton)
            potraceOkButton->set_sensitive(false);
        tracer.trace(&pte);
        if (potraceCancelButton)
            potraceCancelButton->set_sensitive(false);
        if (potraceOkButton)
            potraceOkButton->set_sensitive(true);
        }

}


/**
 * Abort processing
 */
00285 void TraceDialogImpl::abort()
{
    //### Do some GUI thing
 
    //### Make the abort() call to the tracer
    tracer.abort();
    
}



//#########################################################################
//## E V E N T S
//#########################################################################

/**
 * Callback from the Preview button.  Can be called from elsewhere.
 */
00303 void TraceDialogImpl::potracePreviewCallback()
{
    potraceProcess(false);
}

/**
 * Default response from the dialog.  Let's intercept it
 */
00311 void TraceDialogImpl::responseCallback(int response_id)
{
    
    if (response_id == GTK_RESPONSE_OK)
        {
        int panelNr = notebook.get_current_page();
        //g_message("selected panel:%d\n", panelNr);

        if (panelNr == 0)
            {
            potraceProcess(true);
            }
        }
    else if (response_id == GTK_RESPONSE_CANCEL)
        {
        abort();
        }
    else
        {
        hide();
        return;
        }



}


/*##########################
## Experimental
##########################*/
static void hideCallback(GtkObject *object, gpointer dlgPtr)
{
    TraceDialogImpl *dlg = (TraceDialogImpl *) dlgPtr;
    dlg->hideF12();
}

static void unhideCallback(GtkObject *object, gpointer dlgPtr)
{
    TraceDialogImpl *dlg = (TraceDialogImpl *) dlgPtr;
    dlg->showF12();
}



//#########################################################################
//## C O N S T R U C T O R    /    D E S T R U C T O R
//#########################################################################
/**
 * Constructor
 */
00362 TraceDialogImpl::TraceDialogImpl()
{
    { 
    // This block is a much simplified version of the code used in all other dialogs for
    // saving/restoring geometry, transientising, passing events to the aplication, and
    // hiding/unhiding on F12. This code fits badly into gtkmm so it had to be abridged and
    // mutilated somewhat. This block should be removed when the same functionality is made
    // available to all gtkmm dialogs via a base class.
        GtkWidget *dlg = GTK_WIDGET(gobj());

        gchar title[500];
        sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_SELECTION_POTRACE), title);
      set_title(title);

        gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);

        sp_transientize (dlg);
                           
        gtk_signal_connect ( GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg );
                        
        //g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg );
        //g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg );

        g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (hideCallback), (void *)this );
        g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (unhideCallback), (void *)this );
    }

    Gtk::VBox *mainVBox = get_vbox();

#define MARGIN 4

    //##Set up the Potrace panel

    /*#### brightness ####*/
    potraceBrightnessRadioButton.set_label(_("Brightness"));
    potraceGroup = potraceBrightnessRadioButton.get_group();
    potraceBrightnessBox.pack_start(potraceBrightnessRadioButton, false, false, MARGIN);
    tips.set_tip(potraceBrightnessRadioButton, _("Trace by a given brightness level"));

    potraceBrightnessSpinner.set_digits(3);
    potraceBrightnessSpinner.set_increments(0.01, 0.1);
    potraceBrightnessSpinner.set_range(0.0, 1.0);
    potraceBrightnessSpinner.set_value(0.45);
    potraceBrightnessBox.pack_end(potraceBrightnessSpinner, false, false, MARGIN);
    tips.set_tip(potraceBrightnessSpinner, _("Brightness cutoff for black/white"));

    potraceBrightnessSpinnerLabel.set_label(_("Threshold:"));
    potraceBrightnessBox.pack_end(potraceBrightnessSpinnerLabel, false, false, MARGIN);

    potraceBrightnessVBox.pack_start(potraceBrightnessBox, false, false, MARGIN);

    potraceBrightnessFrame.set_label(_("Image Brightness"));
    //potraceBrightnessFrame.set_shadow_type(Gtk::SHADOW_NONE);
    potraceBrightnessFrame.add(potraceBrightnessVBox);
    potraceBox.pack_start(potraceBrightnessFrame, false, false, 0);

    /*#### canny edge detection ####*/
    // TRANSLATORS: "Canny" is the name of the inventor of this edge detection method
    potraceCannyRadioButton.set_label(_("Optimal Edge Detection (Canny)"));
    potraceCannyRadioButton.set_group(potraceGroup);
    potraceCannyBox.pack_start(potraceCannyRadioButton, false, false, MARGIN);
    tips.set_tip(potraceCannyRadioButton, _("Trace with edge detection by J. Canny's algorithm"));
    /*
    potraceCannyBox.pack_start(potraceCannySeparator);
    potraceCannyLoSpinnerLabel.set_label(_("Low"));
    potraceCannyBox.pack_start(potraceCannyLoSpinnerLabel);
    potraceCannyLoSpinner.set_digits(5);
    potraceCannyLoSpinner.set_increments(0.01, 0.1);
    potraceCannyLoSpinner.set_range(0.0, 1.0);
    potraceCannyLoSpinner.set_value(0.1);
    potraceCannyBox.pack_start(potraceCannyLoSpinner);
    */
    potraceCannyHiSpinner.set_digits(3);
    potraceCannyHiSpinner.set_increments(0.01, 0.1);
    potraceCannyHiSpinner.set_range(0.0, 1.0);
    potraceCannyHiSpinner.set_value(0.65);
    potraceCannyBox.pack_end(potraceCannyHiSpinner, false, false, MARGIN);
    tips.set_tip(potraceCannyHiSpinner, _("Brightness cutoff for adjacent pixels (determines edge thickness)"));

    potraceCannyHiSpinnerLabel.set_label(_("Threshold:"));
    potraceCannyBox.pack_end(potraceCannyHiSpinnerLabel, false, false, MARGIN);

    potraceCannyVBox.pack_start(potraceCannyBox, false, false, MARGIN);

    potraceCannyFrame.set_label(_("Edge Detection"));
    //potraceCannyFrame.set_shadow_type(Gtk::SHADOW_NONE);
    potraceCannyFrame.add(potraceCannyVBox);
    potraceBox.pack_start(potraceCannyFrame, false, false, 0);

    /*#### quantization ####*/
    // TRANSLATORS: Color Quantization: the process of reducing the number of colors
    //  in an image by selecting an optimized set of representative colors and then
    //  re-applying this reduced set to the original image.
    potraceQuantRadioButton.set_label(_("Color Quantization"));
    potraceQuantRadioButton.set_group(potraceGroup);
    potraceQuantBox.pack_start(potraceQuantRadioButton, false, false, MARGIN);
    tips.set_tip(potraceQuantRadioButton, _("Trace along the boundaries of reduced colors"));

    potraceQuantNrColorSpinner.set_digits(2);
    potraceQuantNrColorSpinner.set_increments(1.0, 4.0);
    potraceQuantNrColorSpinner.set_range(2.0, 64.0);
    potraceQuantNrColorSpinner.set_value(8.0);
    potraceQuantBox.pack_end(potraceQuantNrColorSpinner, false, false, MARGIN);
    tips.set_tip(potraceQuantNrColorSpinner, _("The number of reduced colors"));

    potraceQuantNrColorLabel.set_label(_("Colors:"));
    potraceQuantBox.pack_end(potraceQuantNrColorLabel, false, false, MARGIN);

    potraceQuantVBox.pack_start(potraceQuantBox, false, false, MARGIN);

    potraceQuantFrame.set_label(_("Quantization / Reduction"));
    //potraceQuantFrame.set_shadow_type(Gtk::SHADOW_NONE);
    potraceQuantFrame.add(potraceQuantVBox);
    potraceBox.pack_start(potraceQuantFrame, false, false, 0);
  
    /*#### Multiple scanning####*/
    //----Hbox1
    potraceMultiScanBrightnessRadioButton.set_label(_("Brightness"));
    potraceMultiScanBrightnessRadioButton.set_group(potraceGroup);
    potraceMultiScanHBox1.pack_start(potraceMultiScanBrightnessRadioButton, false, false, MARGIN);
    tips.set_tip(potraceMultiScanBrightnessRadioButton, _("Trace the given number of brightness levels"));

    potraceMultiScanNrColorSpinner.set_digits(2);
    potraceMultiScanNrColorSpinner.set_increments(1.0, 4.0);
    potraceMultiScanNrColorSpinner.set_range(2.0, 64.0);
    potraceMultiScanNrColorSpinner.set_value(8.0);
    potraceMultiScanHBox1.pack_end(potraceMultiScanNrColorSpinner, false, false, MARGIN);
    potraceMultiScanNrColorLabel.set_label(_("Scans:"));
    potraceMultiScanHBox1.pack_end(potraceMultiScanNrColorLabel, false, false, MARGIN);
    tips.set_tip(potraceMultiScanNrColorSpinner, _("The desired number of scans"));

    potraceMultiScanVBox.pack_start(potraceMultiScanHBox1, false, false, MARGIN);

    //----Hbox2
    potraceMultiScanColorRadioButton.set_label(_("Color"));
    potraceMultiScanColorRadioButton.set_group(potraceGroup);
    potraceMultiScanHBox2.pack_start(potraceMultiScanColorRadioButton, false, false, MARGIN);
    tips.set_tip(potraceMultiScanColorRadioButton, _("Trace the given number of reduced colors"));


    potraceMultiScanVBox.pack_start(potraceMultiScanHBox2, false, false, MARGIN);

    //---Hbox3
    potraceMultiScanMonoRadioButton.set_label(_("Monochrome"));
    potraceMultiScanMonoRadioButton.set_group(potraceGroup);
    potraceMultiScanHBox3.pack_start(potraceMultiScanMonoRadioButton, false, false, MARGIN);
    tips.set_tip(potraceMultiScanMonoRadioButton, _("Same as Color, but convert result to grayscale"));

    // TRANSLATORS: "Stack" is a verb here
    potraceMultiScanStackButton.set_label(_("Stack"));
    potraceMultiScanStackButton.set_active(true);
    potraceMultiScanHBox3.pack_end(potraceMultiScanStackButton, false, false, MARGIN);
    tips.set_tip(potraceMultiScanStackButton, _("Stack scans vertically (no gaps) or tile horizontally (usually with gaps)"));

    // TRANSLATORS: "Smooth" is a verb here
    potraceMultiScanSmoothButton.set_label(_("Smooth"));
    potraceMultiScanSmoothButton.set_active(true);
    potraceMultiScanHBox3.pack_end(potraceMultiScanSmoothButton, false, false, MARGIN);
    tips.set_tip(potraceMultiScanSmoothButton, _("Apply Gaussian blur to the bitmap before tracing"));

    potraceMultiScanVBox.pack_start(potraceMultiScanHBox3, false, false, MARGIN);

    potraceMultiScanFrame.set_label(_("Multiple Scanning"));
    //potraceQuantFrame.set_shadow_type(Gtk::SHADOW_NONE);
    potraceMultiScanFrame.add(potraceMultiScanVBox);
    potraceBox.pack_start(potraceMultiScanFrame, false, false, 0);
  
    /*#### Preview ####*/
    potracePreviewButton.set_label(_("Preview"));
    potracePreviewButton.signal_clicked().connect( 
         sigc::mem_fun(*this, &TraceDialogImpl::potracePreviewCallback) );
    potracePreviewBox.pack_end(potracePreviewButton, false, false, 0);//do not expand
    tips.set_tip(potracePreviewButton, _("Preview the result without actual tracing"));


    potracePreviewImage.set_size_request(100,100);
    //potracePreviewImage.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
    potracePreviewBox.pack_start(potracePreviewImage, true, true, 0);
    potracePreviewFrame.set_label(_("Preview")); // I guess it's correct to call the "intermediate bitmap" a preview of the trace
    //potracePreviewFrame.set_shadow_type(Gtk::SHADOW_NONE);
    potracePreviewFrame.add(potracePreviewBox);
    potraceBox.pack_start(potracePreviewFrame, true, true, 0);

    /*#### swap black and white ####*/
    potraceInvertButton.set_label(_("Invert"));
    potraceInvertButton.set_active(false);
    potraceInvertBox.pack_end(potraceInvertButton, false, false, MARGIN);
    potraceBox.pack_start(potraceInvertBox, false, false, MARGIN);
    tips.set_tip(potraceInvertButton, _("Invert black and white regions for single traces"));

    /*#### Credits ####*/
    potraceCreditsLabel.set_text(
                                           _("Thanks to Peter Selinger, http://potrace.sourceforge.net")
                         );
    potraceCreditsVBox.pack_start(potraceCreditsLabel, false, false, MARGIN);
    potraceCreditsFrame.set_label(_("Credits"));
    potraceCreditsFrame.set_shadow_type(Gtk::SHADOW_NONE);
    potraceCreditsFrame.add(potraceCreditsVBox);
    potraceBox.pack_start(potraceCreditsFrame, false, false, 0);

    /*done */
    // TRANSLATORS: Potrace is an application for transforming bitmaps into
    //  vector graphics (http://potrace.sourceforge.net/)
    notebook.append_page(potraceBox, _("Potrace"));

    //##Set up the Other panel
    // This may be reenabled when we have another tracer; now an empty tab is confusing so I'm disabling it
    //    notebook.append_page(otherBox, _("Other"));

    //##Put the notebook on the dialog
    mainVBox->pack_start(notebook);

    //## The OK button
    potraceCancelButton = add_button(Gtk::Stock::STOP, GTK_RESPONSE_CANCEL);
    if (potraceCancelButton)
        {
        tips.set_tip((*potraceCancelButton), _("Abort a trace in progress"));
        potraceCancelButton->set_sensitive(false);
        }
    potraceOkButton     = add_button(Gtk::Stock::OK,   GTK_RESPONSE_OK);
    tips.set_tip((*potraceOkButton), _("Execute the trace"));

    show_all_children();

    //## Connect the signal
    signal_response().connect( 
         sigc::mem_fun(*this, &TraceDialogImpl::responseCallback) );
}

/**
 * Factory method.  Use this to create a new TraceDialog
 */
00594 TraceDialog *TraceDialog::create()
{
    TraceDialog *dialog = new TraceDialogImpl();
    return dialog;
}


/**
 * Constructor
 */
00604 TraceDialogImpl::~TraceDialogImpl()
{


}


/* static instance, to reduce dependencies */
static TraceDialog *traceDialogInstance = NULL;

00614 TraceDialog *TraceDialog::getInstance()
{
    if ( !traceDialogInstance )
        {
        traceDialogInstance = new TraceDialogImpl();
        }
    return traceDialogInstance;
}



00625 void TraceDialog::showInstance()
{
    TraceDialog *traceDialog = getInstance();
    traceDialog->show();
}


//#########################################################################
//## M E T H O D S
//#########################################################################

00636 void TraceDialogImpl::show()
{
    userHidden = false;
    //call super()
    Gtk::Dialog::show();
    //sp_transientize((GtkWidget *)gobj());  //Make transient
    raise();
    Gtk::Dialog::present();
}

void TraceDialogImpl::showF12()
{
    if (userHidden)
        return;
    //call super()
    Gtk::Dialog::show();
    //sp_transientize((GtkWidget *)gobj());  //Make transient
    raise();

}


00658 void TraceDialogImpl::hide()
{
    userHidden = true;
    //call super()
    Gtk::Dialog::hide();
}

void TraceDialogImpl::hideF12()
{
    //userHidden = true;
    //call super()
    Gtk::Dialog::hide();
}




} //namespace Dialogs
} //namespace UI
} //namespace Inkscape

//#########################################################################
//## E N D    O F    F I L E
//#########################################################################




Generated by  Doxygen 1.6.0   Back to index