From 4b8bd48663106c133914d4a89c80d89d57fe7ed7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 22 Mar 2018 13:49:48 +0100 Subject: [PATCH 1/2] AMF and 3MF export - Export of print config customizable by user in the select file dialog --- lib/Slic3r/GUI/Plater.pm | 6 +++-- xs/src/libslic3r/Format/3mf.cpp | 25 ++++++++++-------- xs/src/libslic3r/Format/3mf.hpp | 2 +- xs/src/libslic3r/Format/AMF.cpp | 14 +++++----- xs/src/libslic3r/Format/AMF.hpp | 2 +- xs/src/slic3r/GUI/GUI.cpp | 45 +++++++++++++++++++++++++++++++++ xs/src/slic3r/GUI/GUI.hpp | 3 +++ xs/xsp/GUI.xsp | 7 +++++ xs/xsp/Model.xsp | 8 +++--- 9 files changed, 87 insertions(+), 25 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index d3513897f..1b26857e9 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1560,7 +1560,7 @@ sub export_amf { return if !@{$self->{objects}}; # Ask user for a file name to write into. my $output_file = $self->_get_export_file('AMF') or return; - my $res = $self->{model}->store_amf($output_file, $self->{print}); + my $res = $self->{model}->store_amf($output_file, $self->{print}, $self->{export_option}); if ($res) { $self->statusbar->SetStatusText(L("AMF file exported to ").$output_file); @@ -1576,7 +1576,7 @@ sub export_3mf { return if !@{$self->{objects}}; # Ask user for a file name to write into. my $output_file = $self->_get_export_file('3MF') or return; - my $res = $self->{model}->store_3mf($output_file, $self->{print}); + my $res = $self->{model}->store_3mf($output_file, $self->{print}, $self->{export_option}); if ($res) { $self->statusbar->SetStatusText(L("3MF file exported to ").$output_file); @@ -1618,11 +1618,13 @@ sub _get_export_file { $output_file =~ s/\.[gG][cC][oO][dD][eE]$/$suffix/; my $dlg = Wx::FileDialog->new($self, L("Save ").$format.L(" file as:"), dirname($output_file), basename($output_file), &Slic3r::GUI::FILE_WILDCARDS->{$wildcard}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + Slic3r::GUI::add_export_option($dlg, $format); if ($dlg->ShowModal != wxID_OK) { $dlg->Destroy; return undef; } $output_file = $dlg->GetPath; + $self->{export_option} = Slic3r::GUI::get_export_option($dlg); $dlg->Destroy; return $output_file; } diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp index b34b8989e..89f9b277f 100644 --- a/xs/src/libslic3r/Format/3mf.cpp +++ b/xs/src/libslic3r/Format/3mf.cpp @@ -1443,10 +1443,10 @@ namespace Slic3r { IdToObjectDataMap m_objects_data; public: - bool save_model_to_file(const std::string& filename, Model& model, const Print& print); + bool save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config); private: - bool _save_model_to_file(const std::string& filename, Model& model, const Print& print); + bool _save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config); bool _add_content_types_file_to_archive(mz_zip_archive& archive); bool _add_relationships_file_to_archive(mz_zip_archive& archive); bool _add_model_file_to_archive(mz_zip_archive& archive, Model& model); @@ -1457,13 +1457,13 @@ namespace Slic3r { bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model); }; - bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const Print& print) + bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config) { clear_errors(); - return _save_model_to_file(filename, model, print); + return _save_model_to_file(filename, model, print, export_print_config); } - bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const Print& print) + bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config) { mz_zip_archive archive; mz_zip_zero_struct(&archive); @@ -1502,11 +1502,14 @@ namespace Slic3r { } // adds slic3r print config file - if (!_add_print_config_file_to_archive(archive, print)) + if (export_print_config) { - mz_zip_writer_end(&archive); - boost::filesystem::remove(filename); - return false; + if (!_add_print_config_file_to_archive(archive, print)) + { + mz_zip_writer_end(&archive); + boost::filesystem::remove(filename); + return false; + } } // adds slic3r model config file @@ -1863,13 +1866,13 @@ namespace Slic3r { return res; } - bool store_3mf(const char* path, Model* model, Print* print) + bool store_3mf(const char* path, Model* model, Print* print, bool export_print_config) { if ((path == nullptr) || (model == nullptr) || (print == nullptr)) return false; _3MF_Exporter exporter; - bool res = exporter.save_model_to_file(path, *model, *print); + bool res = exporter.save_model_to_file(path, *model, *print, export_print_config); if (!res) exporter.log_errors(); diff --git a/xs/src/libslic3r/Format/3mf.hpp b/xs/src/libslic3r/Format/3mf.hpp index 9b48c860b..85bc812e3 100644 --- a/xs/src/libslic3r/Format/3mf.hpp +++ b/xs/src/libslic3r/Format/3mf.hpp @@ -12,7 +12,7 @@ namespace Slic3r { // Save the given model and the config data contained in the given Print into a 3mf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices - extern bool store_3mf(const char* path, Model* model, Print* print); + extern bool store_3mf(const char* path, Model* model, Print* print, bool export_print_config); }; // namespace Slic3r diff --git a/xs/src/libslic3r/Format/AMF.cpp b/xs/src/libslic3r/Format/AMF.cpp index a52dd532a..8c08b4673 100644 --- a/xs/src/libslic3r/Format/AMF.cpp +++ b/xs/src/libslic3r/Format/AMF.cpp @@ -576,8 +576,7 @@ bool load_amf_archive(const char *path, PresetBundle* bundle, Model *model) return false; } - std::string internal_amf_filename = boost::ireplace_last_copy(boost::filesystem::path(path).filename().string(), ".zip.amf", ".amf"); - if (internal_amf_filename != stat.m_filename) + if (!boost::iends_with(stat.m_filename, ".amf")) { printf("Found invalid internal filename\n"); mz_zip_reader_end(&archive); @@ -644,7 +643,7 @@ bool load_amf(const char *path, PresetBundle* bundle, Model *model) return false; } -bool store_amf(const char *path, Model *model, Print* print) +bool store_amf(const char *path, Model *model, Print* print, bool export_print_config) { if ((path == nullptr) || (model == nullptr) || (print == nullptr)) return false; @@ -661,9 +660,12 @@ bool store_amf(const char *path, Model *model, Print* print) stream << "\n"; stream << "Slic3r " << SLIC3R_VERSION << "\n"; - std::string config = "\n"; - GCode::append_full_config(*print, config); - stream << "" << config << "\n"; + if (export_print_config) + { + std::string config = "\n"; + GCode::append_full_config(*print, config); + stream << "" << config << "\n"; + } for (const auto &material : model->materials) { if (material.first.empty()) diff --git a/xs/src/libslic3r/Format/AMF.hpp b/xs/src/libslic3r/Format/AMF.hpp index 027ebdab3..4779e9a51 100644 --- a/xs/src/libslic3r/Format/AMF.hpp +++ b/xs/src/libslic3r/Format/AMF.hpp @@ -12,7 +12,7 @@ extern bool load_amf(const char *path, PresetBundle* bundle, Model *model); // Save the given model and the config data contained in the given Print into an amf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices -extern bool store_amf(const char *path, Model *model, Print* print); +extern bool store_amf(const char *path, Model *model, Print* print, bool export_print_config); }; // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 0410b7969..454852639 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -686,4 +686,49 @@ ConfigOptionsGroup* get_optgroup() return m_optgroup.get(); } +wxWindow* export_option_creator(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, -1); + wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); + wxCheckBox* cbox = new wxCheckBox(panel, wxID_HIGHEST + 1, L("Export print config")); + sizer->AddSpacer(5); + sizer->Add(cbox, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); + panel->SetSizer(sizer); + sizer->SetSizeHints(panel); + return panel; +} + +void add_export_option(wxFileDialog* dlg, const std::string& format) +{ + if ((dlg != nullptr) && (format == "AMF") || (format == "3MF")) + { + if (dlg->SupportsExtraControl()) + dlg->SetExtraControlCreator(export_option_creator); + } +} + +int get_export_option(wxFileDialog* dlg) +{ + if (dlg != nullptr) + { + wxWindow* wnd = dlg->GetExtraControl(); + if (wnd != nullptr) + { + wxPanel* panel = dynamic_cast(wnd); + if (panel != nullptr) + { + wxWindow* child = panel->FindWindow(wxID_HIGHEST + 1); + if (child != nullptr) + { + wxCheckBox* cbox = dynamic_cast(child); + if (cbox != nullptr) + return cbox->IsChecked() ? 1 : 0; + } + } + } + } + + return 0; +} + } } diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 084b6de46..7b23702b2 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -18,6 +18,7 @@ class wxArrayLong; class wxColour; class wxBoxSizer; class wxFlexGridSizer; +class wxFileDialog; namespace Slic3r { @@ -130,6 +131,8 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl ConfigOptionsGroup* get_optgroup(); +void add_export_option(wxFileDialog* dlg, const std::string& format); +int get_export_option(wxFileDialog* dlg); } } diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index d306f12ce..1376ff164 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -67,3 +67,10 @@ void add_frequently_changed_parameters(SV *ui_parent, SV *ui_sizer, SV *ui_p_siz std::string fold_utf8_to_ascii(const char *src) %code%{ RETVAL = Slic3r::fold_utf8_to_ascii(src); %}; + +void add_export_option(SV *ui, std::string format) + %code%{ Slic3r::GUI::add_export_option((wxFileDialog*)wxPli_sv_2_object(aTHX_ ui, "Wx::FileDialog"), format); %}; + +int get_export_option(SV *ui) + %code%{ RETVAL = Slic3r::GUI::get_export_option((wxFileDialog*)wxPli_sv_2_object(aTHX_ ui, "Wx::FileDialog")); %}; + \ No newline at end of file diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 78c94661e..702839537 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -104,10 +104,10 @@ bool store_stl(char *path, bool binary) %code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %}; - bool store_amf(char *path, Print* print) - %code%{ RETVAL = Slic3r::store_amf(path, THIS, print); %}; - bool store_3mf(char *path, Print* print) - %code%{ RETVAL = Slic3r::store_3mf(path, THIS, print); %}; + bool store_amf(char *path, Print* print, bool export_print_config) + %code%{ RETVAL = Slic3r::store_amf(path, THIS, print, export_print_config); %}; + bool store_3mf(char *path, Print* print, bool export_print_config) + %code%{ RETVAL = Slic3r::store_3mf(path, THIS, print, export_print_config); %}; %{ From 903a90f37a0aea3a7e8f93835f403e236e7e38da Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 26 Mar 2018 08:58:44 +0200 Subject: [PATCH 2/2] AMF I/O - Forces .zip.amf extension on export --- xs/src/libslic3r/Format/AMF.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/xs/src/libslic3r/Format/AMF.cpp b/xs/src/libslic3r/Format/AMF.cpp index 8c08b4673..98683cd8a 100644 --- a/xs/src/libslic3r/Format/AMF.cpp +++ b/xs/src/libslic3r/Format/AMF.cpp @@ -648,10 +648,15 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c if ((path == nullptr) || (model == nullptr) || (print == nullptr)) return false; + // forces ".zip.amf" extension + std::string export_path = path; + if (!boost::iends_with(export_path, ".zip.amf")) + export_path = boost::filesystem::path(export_path).replace_extension(".zip.amf").string(); + mz_zip_archive archive; mz_zip_zero_struct(&archive); - mz_bool res = mz_zip_writer_init_file(&archive, path, 0); + mz_bool res = mz_zip_writer_init_file(&archive, export_path.c_str(), 0); if (res == 0) return false; @@ -769,20 +774,20 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c } stream << "\n"; - std::string internal_amf_filename = boost::ireplace_last_copy(boost::filesystem::path(path).filename().string(), ".zip.amf", ".amf"); + std::string internal_amf_filename = boost::ireplace_last_copy(boost::filesystem::path(export_path).filename().string(), ".zip.amf", ".amf"); std::string out = stream.str(); if (!mz_zip_writer_add_mem(&archive, internal_amf_filename.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { mz_zip_writer_end(&archive); - boost::filesystem::remove(path); + boost::filesystem::remove(export_path); return false; } if (!mz_zip_writer_finalize_archive(&archive)) { mz_zip_writer_end(&archive); - boost::filesystem::remove(path); + boost::filesystem::remove(export_path); return false; }