From 8885f5e3447d83e333cf30185189befdee3e9f92 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 13 Feb 2018 15:19:55 +0100 Subject: [PATCH] 3mf import/export of config data --- lib/Slic3r/GUI/Plater.pm | 17 +++- xs/src/libslic3r/Config.cpp | 46 ++++++----- xs/src/libslic3r/Config.hpp | 3 +- xs/src/libslic3r/Format/3mf.cpp | 126 +++++++++++++++++++++-------- xs/src/libslic3r/Format/3mf.hpp | 11 ++- xs/src/libslic3r/GCode.cpp | 29 +++++-- xs/src/libslic3r/GCode.hpp | 3 + xs/src/libslic3r/Model.cpp | 29 ++++++- xs/src/libslic3r/Model.hpp | 2 + xs/src/slic3r/GUI/PresetBundle.cpp | 16 +++- xs/src/slic3r/GUI/PresetBundle.hpp | 5 ++ xs/xsp/Model.xsp | 20 ++++- 12 files changed, 231 insertions(+), 76 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index d9c586685..be94095c9 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -628,8 +628,19 @@ sub load_files { my $input_file = $input_files->[$i]; $process_dialog->Update(100. * $i / @$input_files, "Processing input file\n" . basename($input_file)); - my $model = eval { Slic3r::Model->read_from_file($input_file, 0) }; - Slic3r::GUI::show_error($self, $@) if $@; + my $model; + if ($input_file =~ /.3[mM][fF]$/) + { + $model = eval { Slic3r::Model->read_from_archive($input_file, wxTheApp->{preset_bundle}, 0) }; + Slic3r::GUI::show_error($self, $@) if $@; + $_->load_current_preset for (values %{$self->GetFrame->{options_tabs}}); + wxTheApp->{app_config}->update_config_dir(dirname($input_file)); + } + else + { + $model = eval { Slic3r::Model->read_from_file($input_file, 0) }; + Slic3r::GUI::show_error($self, $@) if $@; + } next if ! defined $model; @@ -1555,7 +1566,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); + my $res = $self->{model}->store_3mf($output_file, $self->{print}); if ($res) { $self->statusbar->SetStatusText("3MF file exported to $output_file"); diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp index 474be7237..1a0b8fb4a 100644 --- a/xs/src/libslic3r/Config.cpp +++ b/xs/src/libslic3r/Config.cpp @@ -324,7 +324,7 @@ void ConfigBase::setenv_() void ConfigBase::load(const std::string &file) { if (boost::iends_with(file, ".gcode") || boost::iends_with(file, ".g")) - this->load_from_gcode(file); + this->load_from_gcode_file(file); else this->load_from_ini(file); } @@ -349,10 +349,10 @@ void ConfigBase::load(const boost::property_tree::ptree &tree) } } -// Load the config keys from the tail of a G-code. -void ConfigBase::load_from_gcode(const std::string &file) +// Load the config keys from the tail of a G-code file. +void ConfigBase::load_from_gcode_file(const std::string &file) { - // 1) Read a 64k block from the end of the G-code. + // Read a 64k block from the end of the G-code. boost::nowide::ifstream ifs(file); { const char slic3r_gcode_header[] = "; generated by Slic3r "; @@ -365,30 +365,39 @@ void ConfigBase::load_from_gcode(const std::string &file) auto file_length = ifs.tellg(); auto data_length = std::min(65535, file_length); ifs.seekg(file_length - data_length, ifs.beg); - std::vector data(size_t(data_length) + 1, 0); - ifs.read(data.data(), data_length); + std::vector data(size_t(data_length) + 1, 0); + ifs.read(data.data(), data_length); ifs.close(); - // 2) Walk line by line in reverse until a non-configuration key appears. - char *data_start = data.data(); + load_from_gcode_string(data.data()); +} + +// Load the config keys from the given string. +void ConfigBase::load_from_gcode_string(const char* str) +{ + if (str == nullptr) + return; + + // Walk line by line in reverse until a non-configuration key appears. + char *data_start = const_cast(str); // boost::nowide::ifstream seems to cook the text data somehow, so less then the 64k of characters may be retrieved. - char *end = data_start + strlen(data.data()); + char *end = data_start + strlen(str); size_t num_key_value_pairs = 0; for (;;) { // Extract next line. - for (-- end; end > data_start && (*end == '\r' || *end == '\n'); -- end); + for (--end; end > data_start && (*end == '\r' || *end == '\n'); --end); if (end == data_start) break; char *start = end; - *(++ end) = 0; - for (; start > data_start && *start != '\r' && *start != '\n'; -- start); + *(++end) = 0; + for (; start > data_start && *start != '\r' && *start != '\n'; --start); if (start == data_start) break; // Extracted a line from start to end. Extract the key = value pair. - if (end - (++ start) < 10 || start[0] != ';' || start[1] != ' ') + if (end - (++start) < 10 || start[0] != ';' || start[1] != ' ') break; char *key = start + 2; - if (! (*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z')) + if (!(*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z')) // A key must start with a letter. break; char *sep = strchr(key, '='); @@ -402,8 +411,8 @@ void ConfigBase::load_from_gcode(const std::string &file) break; *key_end = 0; // The key may contain letters, digits and underscores. - for (char *c = key; c != key_end; ++ c) - if (! ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) { + for (char *c = key; c != key_end; ++c) + if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) { key = nullptr; break; } @@ -411,8 +420,9 @@ void ConfigBase::load_from_gcode(const std::string &file) break; try { this->set_deserialize(key, value); - ++ num_key_value_pairs; - } catch (UnknownOptionException & /* e */) { + ++num_key_value_pairs; + } + catch (UnknownOptionException & /* e */) { // ignore } end = start; diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index e04f4df82..db4b155e8 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -1049,7 +1049,8 @@ public: void setenv_(); void load(const std::string &file); void load_from_ini(const std::string &file); - void load_from_gcode(const std::string &file); + void load_from_gcode_file(const std::string &file); + void load_from_gcode_string(const char* str); void load(const boost::property_tree::ptree &tree); void save(const std::string &file) const; diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp index 7fe9352b3..e8c9cfb32 100644 --- a/xs/src/libslic3r/Format/3mf.cpp +++ b/xs/src/libslic3r/Format/3mf.cpp @@ -1,10 +1,14 @@ #include "../libslic3r.h" #include "../Model.hpp" +#include "../Utils.hpp" +#include "../GCode.hpp" +#include "../slic3r/GUI/PresetBundle.hpp" #include "3mf.hpp" #include #include +#include #include #include @@ -17,6 +21,7 @@ const std::string MODEL_EXTENSION = ".model"; const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA const std::string CONTENT_TYPES_FILE = "[Content_Types].xml"; const std::string RELATIONSHIPS_FILE = "_rels/.rels"; +const std::string CONFIG_FILE = "Metadata/Slic3r_PE.config"; const char* MODEL_TAG = "model"; const char* RESOURCES_TAG = "resources"; @@ -217,7 +222,7 @@ namespace Slic3r { _3MF_Importer(); ~_3MF_Importer(); - bool load_model_from_file(const std::string& filename, Model& model); + bool load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle); const std::vector& get_errors() const; @@ -225,8 +230,9 @@ namespace Slic3r { void _destroy_xml_parser(); void _stop_xml_parser(); - bool _load_model_from_file_miniz(const std::string& filename, Model& model); - bool _extract_model_from_archive_miniz(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); + bool _load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle); + bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); + bool _extract_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename); void _handle_start_xml_element(const char* name, const char** attributes); void _handle_end_xml_element(const char* name); @@ -331,7 +337,7 @@ namespace Slic3r { _destroy_xml_parser(); } - bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model) + bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle) { m_model = &model; m_unit_factor = 1.0f; @@ -341,7 +347,7 @@ namespace Slic3r { m_instances.clear(); m_errors.clear(); - return _load_model_from_file_miniz(filename, model); + return _load_model_from_file(filename, model, bundle); } const std::vector& _3MF_Importer::get_errors() const @@ -364,7 +370,7 @@ namespace Slic3r { XML_StopParser(m_xml_parser, false); } - bool _3MF_Importer::_load_model_from_file_miniz(const std::string& filename, Model& model) + bool _3MF_Importer::_load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle) { mz_zip_archive archive; mz_zip_zero_struct(&archive); @@ -384,21 +390,28 @@ namespace Slic3r { if (mz_zip_reader_file_stat(&archive, i, &stat)) { std::string name(stat.m_filename); - std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); }); std::replace(name.begin(), name.end(), '\\', '/'); - std::string lc_model_folder(MODEL_FOLDER); - std::transform(lc_model_folder.begin(), lc_model_folder.end(), lc_model_folder.begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); }); - - if ((name.find(lc_model_folder) == 0) && (name.rfind(MODEL_EXTENSION) == name.length() - MODEL_EXTENSION.length())) + if (boost::algorithm::istarts_with(name, MODEL_FOLDER) && boost::algorithm::iends_with(name, MODEL_EXTENSION)) { - if (!_extract_model_from_archive_miniz(archive, stat)) + // valid model name -> extract model + if (!_extract_model_from_archive(archive, stat)) { mz_zip_reader_end(&archive); m_errors.push_back("Archive does not contain a valid model"); return false; } } + else if (boost::algorithm::iequals(name, CONFIG_FILE)) + { + // extract slic3r config file + if (!_extract_config_from_archive(archive, stat, bundle, filename)) + { + mz_zip_reader_end(&archive); + m_errors.push_back("Archive does not contain a valid config"); + return false; + } + } } } @@ -406,7 +419,7 @@ namespace Slic3r { return true; } - bool _3MF_Importer::_extract_model_from_archive_miniz(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) + bool _3MF_Importer::_extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) { _destroy_xml_parser(); @@ -430,7 +443,7 @@ namespace Slic3r { mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0); if (res == 0) { - m_errors.push_back("Error while reading data to buffer"); + m_errors.push_back("Error while reading model data to buffer"); return false; } @@ -445,6 +458,25 @@ namespace Slic3r { return true; } + bool _3MF_Importer::_extract_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename) + { + if (stat.m_uncomp_size > 0) + { + std::vector buffer((size_t)stat.m_uncomp_size + 1, 0); + mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); + if (res == 0) + { + m_errors.push_back("Error while reading config data to buffer"); + return false; + } + + buffer.back() = '\0'; + bundle.load_config_string(buffer.data(), archive_filename.c_str()); + } + + return true; + } + void _3MF_Importer::_handle_start_xml_element(const char* name, const char** attributes) { if (m_xml_parser == nullptr) @@ -994,18 +1026,19 @@ namespace Slic3r { std::vector m_errors; public: - bool save_model_to_file(const std::string& filename, Model& model); + bool save_model_to_file(const std::string& filename, Model& model, const Print& print); const std::vector& get_errors() const; private: - bool _save_model_to_file_miniz(const std::string& filename, Model& model); - bool _add_content_types_file_to_archive_miniz(mz_zip_archive& archive); - bool _add_relationships_file_to_archive_miniz(mz_zip_archive& archive); - bool _add_model_file_to_archive_miniz(mz_zip_archive& archive, Model& model); + bool _save_model_to_file(const std::string& filename, Model& model, const Print& print); + 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); bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items); bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object); bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items); + bool _add_config_file_to_archive(mz_zip_archive& archive, const Print& print); }; _3MF_Exporter::BuildItem::BuildItem(unsigned int id, const Matrix4x4& matrix) @@ -1014,9 +1047,9 @@ namespace Slic3r { { } - bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model) + bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const Print& print) { - return _save_model_to_file_miniz(filename, model); + return _save_model_to_file(filename, model, print); } const std::vector& _3MF_Exporter::get_errors() const @@ -1024,7 +1057,7 @@ namespace Slic3r { return m_errors; } - bool _3MF_Exporter::_save_model_to_file_miniz(const std::string& filename, Model& model) + bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const Print& print) { mz_zip_archive archive; mz_zip_zero_struct(&archive); @@ -1037,7 +1070,7 @@ namespace Slic3r { } // adds content types file - if (!_add_content_types_file_to_archive_miniz(archive)) + if (!_add_content_types_file_to_archive(archive)) { mz_zip_writer_end(&archive); boost::filesystem::remove(filename); @@ -1045,7 +1078,7 @@ namespace Slic3r { } // adds relationships file - if (!_add_relationships_file_to_archive_miniz(archive)) + if (!_add_relationships_file_to_archive(archive)) { mz_zip_writer_end(&archive); boost::filesystem::remove(filename); @@ -1053,7 +1086,15 @@ namespace Slic3r { } // adds model file - if (!_add_model_file_to_archive_miniz(archive, model)) + if (!_add_model_file_to_archive(archive, model)) + { + mz_zip_writer_end(&archive); + boost::filesystem::remove(filename); + return false; + } + + // adds slic3r config file + if (!_add_config_file_to_archive(archive, print)) { mz_zip_writer_end(&archive); boost::filesystem::remove(filename); @@ -1073,7 +1114,7 @@ namespace Slic3r { return true; } - bool _3MF_Exporter::_add_content_types_file_to_archive_miniz(mz_zip_archive& archive) + bool _3MF_Exporter::_add_content_types_file_to_archive(mz_zip_archive& archive) { std::stringstream stream; stream << "\n"; @@ -1093,7 +1134,7 @@ namespace Slic3r { return true; } - bool _3MF_Exporter::_add_relationships_file_to_archive_miniz(mz_zip_archive& archive) + bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive) { std::stringstream stream; stream << "\n"; @@ -1112,7 +1153,7 @@ namespace Slic3r { return true; } - bool _3MF_Exporter::_add_model_file_to_archive_miniz(mz_zip_archive& archive, Model& model) + bool _3MF_Exporter::_add_model_file_to_archive(mz_zip_archive& archive, Model& model) { std::stringstream stream; stream << "\n"; @@ -1298,13 +1339,30 @@ namespace Slic3r { return true; } - bool load_3mf(const char* path, Model* model) + bool _3MF_Exporter::_add_config_file_to_archive(mz_zip_archive& archive, const Print& print) { - if ((path == nullptr) || (model == nullptr)) + char buffer[1024]; + sprintf(buffer, "; %s\n\n", header_slic3r_generated().c_str()); + std::string out = buffer; + + GCode::append_full_config(print, out); + + if (!mz_zip_writer_add_mem(&archive, CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) + { + m_errors.push_back("Unable to add config file to archive"); + return false; + } + + return true; + } + + bool load_3mf(const char* path, PresetBundle* bundle, Model* model) + { + if ((path == nullptr) || (bundle == nullptr) || (model == nullptr)) return false; _3MF_Importer importer; - bool res = importer.load_model_from_file(path, *model); + bool res = importer.load_model_from_file(path, *model, *bundle); if (!res) const std::vector& errors = importer.get_errors(); @@ -1312,13 +1370,13 @@ namespace Slic3r { return res; } - bool store_3mf(const char* path, Model* model) + bool store_3mf(const char* path, Model* model, Print* print) { - if ((path == nullptr) || (model == nullptr)) + if ((path == nullptr) || (model == nullptr) || (print == nullptr)) return false; _3MF_Exporter exporter; - bool res = exporter.save_model_to_file(path, *model); + bool res = exporter.save_model_to_file(path, *model, *print); if (!res) const std::vector& errors = exporter.get_errors(); diff --git a/xs/src/libslic3r/Format/3mf.hpp b/xs/src/libslic3r/Format/3mf.hpp index ff178e3de..9b48c860b 100644 --- a/xs/src/libslic3r/Format/3mf.hpp +++ b/xs/src/libslic3r/Format/3mf.hpp @@ -4,13 +4,16 @@ namespace Slic3r { class Model; + class Print; + class PresetBundle; - // Load a 3mf file into the given model. - extern bool load_3mf(const char* path, Model* model); + // Load the content of a 3mf file into the given model and preset bundle. + extern bool load_3mf(const char* path, PresetBundle* bundle, Model* model); - // Save the given model into a 3mf file. + // 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); + extern bool store_3mf(const char* path, Model* model, Print* print); + }; // namespace Slic3r #endif /* slic3r_Format_3mf_hpp_ */ diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index d22040799..d42a61290 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -802,13 +802,10 @@ void GCode::_do_export(Print &print, FILE *file) // Append full config. _write(file, "\n"); { - StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config }; - for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++ i) { - StaticPrintConfig *cfg = configs[i]; - for (const std::string &key : cfg->keys()) - if (key != "compatible_printers") - _write_format(file, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str()); - } + std::string full_config = ""; + append_full_config(print, full_config); + if (!full_config.empty()) + _write(file, full_config); } } @@ -1372,6 +1369,24 @@ void GCode::apply_print_config(const PrintConfig &print_config) m_config.apply(print_config); } +void GCode::append_full_config(const Print& print, std::string& str) +{ + char buff[1024]; + + const StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config }; + for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) { + const StaticPrintConfig *cfg = configs[i]; + for (const std::string &key : cfg->keys()) + { + if (key != "compatible_printers") + { + sprintf(buff, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str()); + str += buff; + } + } + } +} + void GCode::set_extruders(const std::vector &extruder_ids) { m_writer.set_extruders(extruder_ids); diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 5c622ec2d..8129ca1c5 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -155,6 +155,9 @@ public: void set_layer_count(unsigned int value) { m_layer_count = value; } void apply_print_config(const PrintConfig &print_config); + // append full config to the given string + static void append_full_config(const Print& print, std::string& str); + protected: void _do_export(Print &print, FILE *file); diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index b86b7e55e..891438407 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -54,10 +54,8 @@ Model Model::read_from_file(const std::string &input_file, bool add_default_inst else if (boost::algorithm::iends_with(input_file, ".prusa")) result = load_prus(input_file.c_str(), &model); #endif /* SLIC3R_PRUS */ - else if (boost::algorithm::iends_with(input_file, ".3mf")) - result = load_3mf(input_file.c_str(), &model); else - throw std::runtime_error("Unknown file format. Input file must have .stl, .obj, .amf(.xml), .3mf or .prusa extension."); + throw std::runtime_error("Unknown file format. Input file must have .stl, .obj, .amf(.xml) or .prusa extension."); if (! result) throw std::runtime_error("Loading of a model file failed."); @@ -74,6 +72,31 @@ Model Model::read_from_file(const std::string &input_file, bool add_default_inst return model; } +Model Model::read_from_archive(const std::string &input_file, PresetBundle* bundle, bool add_default_instances) +{ + Model model; + + bool result = false; + if (boost::algorithm::iends_with(input_file, ".3mf")) + result = load_3mf(input_file.c_str(), bundle, &model); + else + throw std::runtime_error("Unknown file format. Input file must have .3mf extension."); + + if (!result) + throw std::runtime_error("Loading of a model file failed."); + + if (model.objects.empty()) + throw std::runtime_error("The supplied file couldn't be read because it's empty"); + + for (ModelObject *o : model.objects) + o->input_file = input_file; + + if (add_default_instances) + model.add_default_instances(); + + return model; +} + ModelObject* Model::add_object() { this->objects.emplace_back(new ModelObject(this)); diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 317d7ccbb..cf9bfd85a 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -19,6 +19,7 @@ class ModelInstance; class ModelMaterial; class ModelObject; class ModelVolume; +class PresetBundle; typedef std::string t_model_material_id; typedef std::string t_model_material_attribute; @@ -239,6 +240,7 @@ public: ~Model() { this->clear_objects(); this->clear_materials(); } static Model read_from_file(const std::string &input_file, bool add_default_instances = true); + static Model read_from_archive(const std::string &input_file, PresetBundle* bundle, bool add_default_instances = true); ModelObject* add_object(); ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index decc5d00b..3b4bf097f 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -280,8 +280,8 @@ void PresetBundle::load_config_file(const std::string &path) if (boost::iends_with(path, ".gcode") || boost::iends_with(path, ".g")) { DynamicPrintConfig config; config.apply(FullPrintConfig::defaults()); - config.load_from_gcode(path); - Preset::normalize(config); + config.load_from_gcode_file(path); + Preset::normalize(config); load_config_file_config(path, true, std::move(config)); return; } @@ -320,6 +320,18 @@ void PresetBundle::load_config_file(const std::string &path) } } +void PresetBundle::load_config_string(const char* str, const char* source_filename) +{ + if (str != nullptr) + { + DynamicPrintConfig config; + config.apply(FullPrintConfig::defaults()); + config.load_from_gcode_string(str); + Preset::normalize(config); + load_config_file_config((source_filename == nullptr) ? "" : source_filename, true, std::move(config)); + } +} + // Load a config file from a boost property_tree. This is a private method called from load_config_file. void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config) { diff --git a/xs/src/slic3r/GUI/PresetBundle.hpp b/xs/src/slic3r/GUI/PresetBundle.hpp index df04efd73..e6aea206d 100644 --- a/xs/src/slic3r/GUI/PresetBundle.hpp +++ b/xs/src/slic3r/GUI/PresetBundle.hpp @@ -55,6 +55,11 @@ public: // If the file is loaded successfully, its print / filament / printer profiles will be activated. void load_config_file(const std::string &path); + // Load an external config source containing the print, filament and printer presets. + // The given string must contain the full set of parameters (same as those exported to gcode). + // If the string is parsed successfully, its print / filament / printer profiles will be activated. + void load_config_string(const char* str, const char* source_filename = nullptr); + // Load a config bundle file, into presets and store the loaded presets into separate files // of the local configuration directory. // Load settings into the provided settings instance. diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 9a2a50437..ae0621057 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -3,6 +3,7 @@ %{ #include #include "libslic3r/Model.hpp" +#include "libslic3r/Print.hpp" #include "libslic3r/PrintConfig.hpp" #include "libslic3r/Slicing.hpp" #include "libslic3r/Format/AMF.hpp" @@ -10,6 +11,7 @@ #include "libslic3r/Format/OBJ.hpp" #include "libslic3r/Format/PRUS.hpp" #include "libslic3r/Format/STL.hpp" +#include "slic3r/GUI/PresetBundle.hpp" %} %name{Slic3r::Model} class Model { @@ -25,6 +27,15 @@ } %}; + %name{read_from_archive} Model(std::string input_file, PresetBundle* bundle, bool add_default_instances = true) + %code%{ + try { + RETVAL = new Model(Model::read_from_archive(input_file, bundle, add_default_instances)); + } catch (std::exception& e) { + croak("Error while opening %s: %s\n", input_file.c_str(), e.what()); + } + %}; + Clone clone() %code%{ RETVAL = THIS; %}; @@ -92,8 +103,8 @@ %code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %}; bool store_amf(char *path) %code%{ RETVAL = Slic3r::store_amf(path, THIS); %}; - bool store_3mf(char *path) - %code%{ RETVAL = Slic3r::store_3mf(path, THIS); %}; + bool store_3mf(char *path, Print* print) + %code%{ RETVAL = Slic3r::store_3mf(path, THIS, print); %}; %{ @@ -139,12 +150,13 @@ load_amf(CLASS, path) RETVAL Model* -load_3mf(CLASS, path) +load_3mf(CLASS, bundle, path) char* CLASS; + PresetBundle* bundle; char* path; CODE: RETVAL = new Model(); - if (! load_3mf(path, RETVAL)) { + if (! load_3mf(path, bundle, RETVAL)) { delete RETVAL; RETVAL = NULL; }