From dd18c27c36c9138bc68161ad365bfc61b8d135f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= Date: Thu, 12 Sep 2013 07:23:11 -0300 Subject: Integrating with libdepixelize (bzr r12506.1.1) --- src/ui/dialog/pixelartdialog.cpp | 490 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 src/ui/dialog/pixelartdialog.cpp (limited to 'src/ui/dialog/pixelartdialog.cpp') diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp new file mode 100644 index 000000000..6f0845ada --- /dev/null +++ b/src/ui/dialog/pixelartdialog.cpp @@ -0,0 +1,490 @@ +/** + * @file + * Pixel art tracing settings dialog - implementation. + */ +/* Authors: + * Bob Jamison + * Stéphane Gimenez + * Vinícius dos Santos Oliveira + * Other dudes from The Inkscape Organization + * + * Copyright (C) 2004-2013 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pixelartdialog.h" +#include +#include + +#include //for GTK_RESPONSE* types +#include + +#include "ui/widget/spinbutton.h" +#include "ui/widget/frame.h" + +#include "desktop.h" +#include "desktop-tracker.h" +#include "message-stack.h" +#include "selection.h" +#include "preferences.h" + +#include "sp-image.h" +#include "libdepixelize/kopftracer2011.h" +#include +#include "document.h" +#include "xml/repr.h" +#include "xml/document.h" +#include "svg/svg.h" +#include "svg/svg-color.h" +#include "color.h" +#include "svg/css-ostringstream.h" +#include "document-undo.h" + +#ifdef HAVE_OPENMP +#include +#endif // HAVE_OPENMP + +namespace Inkscape { +namespace UI { +namespace Dialog { + +template +T move(T &obj) +{ +#ifdef LIBDEPIXELIZE_ENABLE_CPP11 + return std::move(obj); +#else + T ret; + std::swap(obj, ret); + return ret; +#endif // LIBDEPIXELIZE_ENABLE_CPP11 +} + +/** + * A dialog for adjusting pixel art -> vector tracing parameters + */ +class PixelArtDialogImpl : public PixelArtDialog +{ +public: + PixelArtDialogImpl(); + + ~PixelArtDialogImpl(); + +private: + void setDesktop(SPDesktop *desktop); + void setTargetDesktop(SPDesktop *desktop); + + //############ Events + + void responseCallback(int response_id); + + //############ UI Logic + + Tracer::Kopf2011::Options options(); + + void vectorize(); + void processLibdepixelize(SPImage *img); + void setDefaults(); + void updatePreview(); + + bool ignorePreview; + bool pendingPreview; + + //############ UI + + Gtk::HBox buttonsHBox; + + Gtk::Button *mainOkButton; + Gtk::Button *mainCancelButton; + Gtk::Button *mainResetButton; + + Gtk::VBox heuristicsVBox; + UI::Widget::Frame heuristicsFrame; + + Gtk::HBox curvesMultiplierHBox; + Gtk::Label curvesMultiplierLabel; + Inkscape::UI::Widget::SpinButton curvesMultiplierSpinner; + + Gtk::HBox islandsWeightHBox; + Gtk::Label islandsWeightLabel; + Inkscape::UI::Widget::SpinButton islandsWeightSpinner; + + Gtk::HBox sparsePixelsMultiplierHBox; + Gtk::Label sparsePixelsMultiplierLabel; + Inkscape::UI::Widget::SpinButton sparsePixelsMultiplierSpinner; + + Gtk::HBox sparsePixelsRadiusHBox; + Gtk::Label sparsePixelsRadiusLabel; + Inkscape::UI::Widget::SpinButton sparsePixelsRadiusSpinner; + + Gtk::VBox outputVBox; + UI::Widget::Frame outputFrame; + Gtk::RadioButtonGroup outputGroup; + + Gtk::RadioButton voronoiRadioButton; + Gtk::RadioButton noOptimizeRadioButton; + Gtk::RadioButton optimizeRadioButton; + + SPDesktop *desktop; + DesktopTracker deskTrack; + sigc::connection desktopChangeConn; +}; + +void PixelArtDialogImpl::setDesktop(SPDesktop *desktop) +{ + Panel::setDesktop(desktop); + deskTrack.setBase(desktop); +} + +void PixelArtDialogImpl::setTargetDesktop(SPDesktop *desktop) +{ + this->desktop = desktop; +} + +PixelArtDialogImpl::PixelArtDialogImpl() : + PixelArtDialog(), + ignorePreview(false), + pendingPreview(false) +{ + + Gtk::Box *contents = _getContents(); + + // Heuristics + { + curvesMultiplierLabel.set_label(_("_Curves (multiplier)")); + curvesMultiplierLabel.set_use_underline(true); + curvesMultiplierLabel.set_mnemonic_widget(curvesMultiplierSpinner); + curvesMultiplierLabel.set_tooltip_text(_("Favors connections that are part of a long curve")); + curvesMultiplierSpinner.set_increments(0.125, 0); + curvesMultiplierSpinner.set_digits(3); + curvesMultiplierSpinner.set_range(-10, 10); + curvesMultiplierSpinner.get_adjustment()->signal_value_changed() + .connect(sigc::mem_fun(*this, &PixelArtDialogImpl::updatePreview)); + + curvesMultiplierHBox.pack_start(curvesMultiplierLabel, false, false); + curvesMultiplierHBox.pack_end(curvesMultiplierSpinner, false, false); + heuristicsVBox.pack_start(curvesMultiplierHBox, false, false); + + islandsWeightLabel.set_label(_("_Islands (weight)")); + islandsWeightLabel.set_use_underline(true); + islandsWeightLabel.set_mnemonic_widget(islandsWeightSpinner); + islandsWeightLabel.set_tooltip_text(_("Avoid single disconnected pixels")); + + islandsWeightSpinner.set_tooltip_text(_("A constant vote value")); + islandsWeightSpinner.set_increments(1, 0); + islandsWeightSpinner.set_range(-20, 20); + islandsWeightSpinner.get_adjustment()->signal_value_changed() + .connect(sigc::mem_fun(*this, &PixelArtDialogImpl::updatePreview)); + + islandsWeightHBox.pack_start(islandsWeightLabel, false, false); + islandsWeightHBox.pack_end(islandsWeightSpinner, false, false); + heuristicsVBox.pack_start(islandsWeightHBox, false, false); + + sparsePixelsRadiusLabel.set_label(_("Sparse pixels (window _radius)")); + sparsePixelsRadiusLabel.set_use_underline(true); + sparsePixelsRadiusLabel.set_mnemonic_widget(sparsePixelsRadiusSpinner); + + sparsePixelsRadiusSpinner.set_increments(1, 0); + sparsePixelsRadiusSpinner.set_range(2, 8); + sparsePixelsRadiusSpinner.get_adjustment()->signal_value_changed() + .connect(sigc::mem_fun(*this, &PixelArtDialogImpl::updatePreview)); + + sparsePixelsRadiusSpinner.set_tooltip_text(_("The radius of the window analyzed")); + sparsePixelsMultiplierLabel.set_label(_("Sparse pixels (_multiplier)")); + sparsePixelsMultiplierLabel.set_use_underline(true); + sparsePixelsMultiplierLabel.set_mnemonic_widget(sparsePixelsMultiplierSpinner); + + sparsePixelsMultiplierSpinner.set_increments(0.125, 0); + sparsePixelsMultiplierSpinner.set_digits(3); + sparsePixelsMultiplierSpinner.set_range(-10, 10); + sparsePixelsMultiplierSpinner.get_adjustment()->signal_value_changed() + .connect(sigc::mem_fun(*this, &PixelArtDialogImpl::updatePreview)); + + { + char const *str = _("Favors connections that are part of foreground color"); + sparsePixelsRadiusLabel.set_tooltip_text(str); + sparsePixelsMultiplierLabel.set_tooltip_text(str); + } + + { + char const *str = _("The heuristic computed vote will be multiplied by this value"); + curvesMultiplierSpinner.set_tooltip_text(str); + sparsePixelsMultiplierSpinner.set_tooltip_text(str); + } + + sparsePixelsRadiusHBox.pack_start(sparsePixelsRadiusLabel, false, false); + sparsePixelsRadiusHBox.pack_end(sparsePixelsRadiusSpinner, false, false); + heuristicsVBox.pack_start(sparsePixelsRadiusHBox, false, false); + + sparsePixelsMultiplierHBox.pack_start(sparsePixelsMultiplierLabel, false, false); + sparsePixelsMultiplierHBox.pack_end(sparsePixelsMultiplierSpinner, false, false); + heuristicsVBox.pack_start(sparsePixelsMultiplierHBox, false, false); + + heuristicsFrame.set_label(_("Heuristics")); + heuristicsFrame.add(heuristicsVBox); + contents->pack_start(heuristicsFrame, false, false); + } + + // Output + { + voronoiRadioButton.set_label(_("_Voronoi diagram")); + voronoiRadioButton.set_tooltip_text(_("Output composed of straight lines")); + voronoiRadioButton.set_use_underline(true); + outputGroup = voronoiRadioButton.get_group(); + + outputVBox.pack_start(voronoiRadioButton, false, false); + + noOptimizeRadioButton.set_label(_("Convert to _B-spline curves")); + noOptimizeRadioButton.set_tooltip_text(_("Preserve staircasing artifacts")); + noOptimizeRadioButton.set_use_underline(true); + noOptimizeRadioButton.set_group(outputGroup); + + outputVBox.pack_start(noOptimizeRadioButton, false, false); + + optimizeRadioButton.set_label(_("_Smooth curves")); + optimizeRadioButton.set_tooltip_text(_("The Kopf-Lischinski algorithm")); + optimizeRadioButton.set_use_underline(true); + optimizeRadioButton.set_group(outputGroup); + + outputVBox.pack_start(optimizeRadioButton, false, false); + + outputFrame.set_label(_("Output")); + outputFrame.add(outputVBox); + contents->pack_start(outputFrame, true, false); + } + + // Buttons + { + mainResetButton = addResponseButton(_("Reset"), GTK_RESPONSE_HELP, true); + mainResetButton ->set_tooltip_text(_("Reset all settings to defaults")); + + //## The OK button + mainCancelButton = addResponseButton(Gtk::Stock::STOP, GTK_RESPONSE_CANCEL); + if (mainCancelButton) { + mainCancelButton->set_tooltip_text(_("Abort a trace in progress")); + mainCancelButton->set_sensitive(false); + } + mainOkButton = addResponseButton(Gtk::Stock::OK, GTK_RESPONSE_OK); + mainOkButton->set_tooltip_text(_("Execute the trace")); + + contents->pack_start(buttonsHBox); + } + + setDefaults(); + + show_all_children(); + + desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &PixelArtDialogImpl::setTargetDesktop) ); + deskTrack.connect(GTK_WIDGET(gobj())); + + signalResponse().connect(sigc::mem_fun(*this, &PixelArtDialogImpl::responseCallback)); +} + +void PixelArtDialogImpl::responseCallback(int response_id) +{ + if (response_id == GTK_RESPONSE_OK) { + vectorize(); + } else if (response_id == GTK_RESPONSE_CANCEL) { + // TODO + } else if (response_id == GTK_RESPONSE_HELP) { + setDefaults(); + } else { + hide(); + return; + } +} + +Tracer::Kopf2011::Options PixelArtDialogImpl::options() +{ + Tracer::Kopf2011::Options options; + + options.curvesMultiplier = curvesMultiplierSpinner.get_value(); + options.islandsWeight = islandsWeightSpinner.get_value_as_int(); + options.sparsePixelsMultiplier = sparsePixelsMultiplierSpinner.get_value(); + options.sparsePixelsRadius = sparsePixelsRadiusSpinner.get_value_as_int(); + options.optimize = optimizeRadioButton.get_active(); + + options.nthreads = Inkscape::Preferences::get() + ->getIntLimited("/options/threading/numthreads", +#ifdef HAVE_OPENMP + omp_get_num_procs(), +#else + 1, +#endif // HAVE_OPENMP + 1, 256); + + return options; +} + +void PixelArtDialogImpl::vectorize() +{ + Inkscape::MessageStack *msgStack = desktop->messageStack(); + + if ( !desktop->selection ) { + char *msg = _("Select an image to trace"); + msgStack->flash(Inkscape::ERROR_MESSAGE, msg); + return; + } + + bool found = false; + + for ( GSList const *list = desktop->selection->itemList() ; list + ; list = list->next ) { + if ( !SP_IS_IMAGE(list->data) ) + continue; + + found = true; + + processLibdepixelize(SP_IMAGE(list->data)); + } + + if ( !found ) { + char *msg = _("Select an image to trace"); + msgStack->flash(Inkscape::ERROR_MESSAGE, msg); + return; + } + + DocumentUndo::done(desktop->doc(), SP_VERB_SELECTION_PIXEL_ART, + _("Trace pixel art")); + + // Flush pending updates + desktop->doc()->ensureUpToDate(); +} + +void PixelArtDialogImpl::processLibdepixelize(SPImage *img) +{ + Tracer::Splines out; + + if ( voronoiRadioButton.get_active() ) { + out = Tracer::Kopf2011::to_voronoi(Glib::wrap(img->pixbuf, true), + options()); + } else { + out = Tracer::Kopf2011::to_splines(Glib::wrap(img->pixbuf, true), + options()); + } + + Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); + Inkscape::XML::Node *group = xml_doc->createElement("svg:g"); + + for ( Tracer::Splines::iterator it = out.begin(), end = out.end() + ; it != end ; ++it ) { + Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); + + { + SPCSSAttr *css = sp_repr_css_attr_new(); + + { + gchar b[64]; + sp_svg_write_color(b, sizeof(b), + SP_RGBA32_U_COMPOSE(unsigned(it->rgba[2]), + unsigned(it->rgba[1]), + unsigned(it->rgba[0]), + unsigned(it->rgba[3]))); + + sp_repr_css_set_property(css, "fill", b); + } + + { + Inkscape::CSSOStringStream osalpha; + osalpha << float(it->rgba[3]) / 255.; + sp_repr_css_set_property(css, "fill-opacity", + osalpha.str().c_str()); + } + + sp_repr_css_set(repr, css, "style"); + sp_repr_css_attr_unref(css); + } + + gchar *str = sp_svg_write_path(move(it->pathVector)); + repr->setAttribute("d", str); + g_free(str); + + group->appendChild(repr); + + Inkscape::GC::release(repr); + } + + { + group->setAttribute("transform", + (std::string("translate(") + + sp_svg_length_write_with_units(img->x) + + ' ' + sp_svg_length_write_with_units(img->y) + + ')').c_str()); + } + + desktop->currentLayer()->appendChildRepr(group); + + Inkscape::GC::release(group); +} + +void PixelArtDialogImpl::setDefaults() +{ + ignorePreview = true; + + curvesMultiplierSpinner.set_value(Tracer::Kopf2011::Options + ::CURVES_MULTIPLIER); + + islandsWeightSpinner.set_value(Tracer::Kopf2011::Options::ISLANDS_WEIGHT); + + sparsePixelsRadiusSpinner.set_value(Tracer::Kopf2011::Options + ::SPARSE_PIXELS_RADIUS); + + sparsePixelsMultiplierSpinner.set_value(Tracer::Kopf2011::Options + ::SPARSE_PIXELS_MULTIPLIER); + + optimizeRadioButton.set_active(); + + ignorePreview = false; + + if ( pendingPreview ) + updatePreview(); +} + +void PixelArtDialogImpl::updatePreview() +{ + if ( ignorePreview ) { + pendingPreview = true; + return; + } + + // TODO: update preview + pendingPreview = false; +} + +/** + * Factory method. Use this to create a new PixelArtDialog + */ +PixelArtDialog &PixelArtDialog::getInstance() +{ + PixelArtDialog *dialog = new PixelArtDialogImpl(); + return *dialog; +} + +PixelArtDialogImpl::~PixelArtDialogImpl() +{ + desktopChangeConn.disconnect(); +} + + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3 From 509ef3751bec8b1d4416e9c136eb5d2776d0c63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= Date: Thu, 19 Sep 2013 01:52:47 -0300 Subject: Updating libdepixelize integration to use new Inkscape::Pixbuf interface. Fixes build issue introduced in last commit. (bzr r12534) --- src/ui/dialog/pixelartdialog.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/ui/dialog/pixelartdialog.cpp') diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp index 6f0845ada..16d3c079d 100644 --- a/src/ui/dialog/pixelartdialog.cpp +++ b/src/ui/dialog/pixelartdialog.cpp @@ -37,6 +37,7 @@ #include "preferences.h" #include "sp-image.h" +#include "display/cairo-utils.h" #include "libdepixelize/kopftracer2011.h" #include #include "document.h" @@ -363,12 +364,13 @@ void PixelArtDialogImpl::processLibdepixelize(SPImage *img) { Tracer::Splines out; + Glib::RefPtr pixbuf + = Glib::wrap(img->pixbuf->getPixbufRaw(), true); + if ( voronoiRadioButton.get_active() ) { - out = Tracer::Kopf2011::to_voronoi(Glib::wrap(img->pixbuf, true), - options()); + out = Tracer::Kopf2011::to_voronoi(pixbuf, options()); } else { - out = Tracer::Kopf2011::to_splines(Glib::wrap(img->pixbuf, true), - options()); + out = Tracer::Kopf2011::to_splines(pixbuf, options()); } Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); -- cgit v1.2.3 From 2454f5dff9f989548b15154707d011b76ac76457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= Date: Thu, 19 Sep 2013 01:58:26 -0300 Subject: Fixing colors in libdepixelize integration output. (bzr r12535) --- src/ui/dialog/pixelartdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/ui/dialog/pixelartdialog.cpp') diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp index 16d3c079d..ef181b357 100644 --- a/src/ui/dialog/pixelartdialog.cpp +++ b/src/ui/dialog/pixelartdialog.cpp @@ -386,9 +386,9 @@ void PixelArtDialogImpl::processLibdepixelize(SPImage *img) { gchar b[64]; sp_svg_write_color(b, sizeof(b), - SP_RGBA32_U_COMPOSE(unsigned(it->rgba[2]), + SP_RGBA32_U_COMPOSE(unsigned(it->rgba[0]), unsigned(it->rgba[1]), - unsigned(it->rgba[0]), + unsigned(it->rgba[2]), unsigned(it->rgba[3]))); sp_repr_css_set_property(css, "fill", b); -- cgit v1.2.3 From 0fea1d0d5af42e2dadf5dd3e4df779e68b7c6dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= Date: Thu, 19 Sep 2013 17:43:38 -0300 Subject: Removing redundant "include config.h" (bzr r12545) --- src/ui/dialog/pixelartdialog.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/ui/dialog/pixelartdialog.cpp') diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp index ef181b357..24c1ec37f 100644 --- a/src/ui/dialog/pixelartdialog.cpp +++ b/src/ui/dialog/pixelartdialog.cpp @@ -16,10 +16,6 @@ # include #endif -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "pixelartdialog.h" #include #include -- cgit v1.2.3 From 47f1c1ee40b8185001b047c2a7bc2ca58e40ab0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= Date: Thu, 19 Sep 2013 18:14:28 -0300 Subject: Show warning when input image of Trace Pixel Art dialog is too large. (bzr r12546) --- src/ui/dialog/pixelartdialog.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/ui/dialog/pixelartdialog.cpp') diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp index 24c1ec37f..e07cbccb5 100644 --- a/src/ui/dialog/pixelartdialog.cpp +++ b/src/ui/dialog/pixelartdialog.cpp @@ -19,6 +19,7 @@ #include "pixelartdialog.h" #include #include +#include #include //for GTK_RESPONSE* types #include @@ -363,6 +364,17 @@ void PixelArtDialogImpl::processLibdepixelize(SPImage *img) Glib::RefPtr pixbuf = Glib::wrap(img->pixbuf->getPixbufRaw(), true); + if ( pixbuf->get_width() > 256 || pixbuf->get_height() > 256 ) { + char *msg = _("Image looks too big. Process may take a while and is" + " wise to save your document before continue." + "\n\nContinue the procedure (without saving)?"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_OK_CANCEL, true); + + if ( dialog.run() != Gtk::RESPONSE_OK ) + return; + } + if ( voronoiRadioButton.get_active() ) { out = Tracer::Kopf2011::to_voronoi(pixbuf, options()); } else { -- cgit v1.2.3