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/CMakeLists.txt | 1 + src/ui/dialog/Makefile_insert | 2 + src/ui/dialog/dialog-manager.cpp | 3 + src/ui/dialog/pixelartdialog.cpp | 490 +++++++++++++++++++++++++++++++++++++++ src/ui/dialog/pixelartdialog.h | 69 ++++++ 5 files changed, 565 insertions(+) create mode 100644 src/ui/dialog/pixelartdialog.cpp create mode 100644 src/ui/dialog/pixelartdialog.h (limited to 'src/ui') diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index c95dd35cc..233e01862 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -71,6 +71,7 @@ set(ui_SRC dialog/text-edit.cpp dialog/tile.cpp dialog/tracedialog.cpp + dialog/pixelartdialog.cpp dialog/transformation.cpp dialog/undo-history.cpp # dialog/whiteboard-connect.cpp diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index 09a7ef573..c37767a08 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -101,6 +101,8 @@ ink_common_sources += \ ui/dialog/tile.h \ ui/dialog/tracedialog.cpp \ ui/dialog/tracedialog.h \ + ui/dialog/pixelartdialog.cpp \ + ui/dialog/pixelartdialog.h \ ui/dialog/transformation.cpp \ ui/dialog/transformation.h \ ui/dialog/undo-history.cpp \ diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index 0ce74f54e..17f6ae74d 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -35,6 +35,7 @@ #include "ui/dialog/symbols.h" #include "ui/dialog/tile.h" #include "ui/dialog/tracedialog.h" +#include "ui/dialog/pixelartdialog.h" #include "ui/dialog/transformation.h" #include "ui/dialog/undo-history.h" #include "ui/dialog/panel-dialog.h" @@ -118,6 +119,7 @@ DialogManager::DialogManager() { registerFactory("Symbols", &create); registerFactory("TileDialog", &create); registerFactory("Trace", &create); + registerFactory("PixelArt", &create); registerFactory("Transformation", &create); registerFactory("UndoHistory", &create); registerFactory("InputDevices", &create); @@ -151,6 +153,7 @@ DialogManager::DialogManager() { registerFactory("Symbols", &create); registerFactory("TileDialog", &create); registerFactory("Trace", &create); + registerFactory("PixelArt", &create); registerFactory("Transformation", &create); registerFactory("UndoHistory", &create); registerFactory("InputDevices", &create); 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 : diff --git a/src/ui/dialog/pixelartdialog.h b/src/ui/dialog/pixelartdialog.h new file mode 100644 index 000000000..b2be4b077 --- /dev/null +++ b/src/ui/dialog/pixelartdialog.h @@ -0,0 +1,69 @@ +/** @file + * @brief Bitmap tracing settings dialog + */ +/* Authors: + * Bob Jamison + * Vinícius dos Santos Oliveira + * Other dudes from The Inkscape Organization + * + * Copyright (C) 2004, 2005 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef __PIXELARTDIALOG_H__ +#define __PIXELARTDIALOG_H__ + +#include "ui/widget/panel.h" +#include "verbs.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + + +/** + * A dialog that displays log messages + */ +class PixelArtDialog : public UI::Widget::Panel +{ + +public: + + /** + * Constructor + */ + PixelArtDialog() : + UI::Widget::Panel("", "/dialogs/pixelart", SP_VERB_SELECTION_PIXEL_ART) + {} + + + /** + * Factory method + */ + static PixelArtDialog &getInstance(); + + /** + * Destructor + */ + virtual ~PixelArtDialog() {}; + + +}; + + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +#endif /* __PIXELARTDIALOGDIALOG_H__ */ + +/* + 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 d956a27f7d3b8fbe82bc5ef3d991d963db79fedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= Date: Fri, 13 Sep 2013 03:59:44 -0300 Subject: Removing obvious comments from PixelArtDialog (bzr r12506.1.2) --- src/ui/dialog/pixelartdialog.h | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'src/ui') diff --git a/src/ui/dialog/pixelartdialog.h b/src/ui/dialog/pixelartdialog.h index b2be4b077..165cb8699 100644 --- a/src/ui/dialog/pixelartdialog.h +++ b/src/ui/dialog/pixelartdialog.h @@ -29,25 +29,14 @@ class PixelArtDialog : public UI::Widget::Panel public: - /** - * Constructor - */ PixelArtDialog() : - UI::Widget::Panel("", "/dialogs/pixelart", SP_VERB_SELECTION_PIXEL_ART) - {} + UI::Widget::Panel("", "/dialogs/pixelart", SP_VERB_SELECTION_PIXEL_ART) + {} - /** - * Factory method - */ static PixelArtDialog &getInstance(); - /** - * Destructor - */ virtual ~PixelArtDialog() {}; - - }; -- cgit v1.2.3