fix slic3r/superslicer .3mf compatibility

This commit is contained in:
remi durand 2021-04-29 02:03:21 +02:00
parent 7c1d29acd8
commit 7ec55736dc

View File

@ -50,6 +50,8 @@ const std::string RELATIONSHIPS_FILE = "_rels/.rels";
const std::string THUMBNAIL_FILE = "Metadata/thumbnail.png";
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r.config";
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_model.config";
const std::string PRINT_SUPER_CONFIG_FILE = "Metadata/SuperSlicer.config";
const std::string MODEL_SUPER_CONFIG_FILE = "Metadata/SuperSlicer_model.config";
const std::string PRINT_PRUSA_CONFIG_FILE = "Metadata/Slic3r_PE.config";
const std::string MODEL_PRUSA_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
@ -635,18 +637,15 @@ namespace Slic3r {
{
// extract slic3r layer config ranges file
_extract_layer_config_ranges_from_archive(archive, stat);
}
else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
} else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
{
// extract sla support points file
_extract_sla_support_points_from_archive(archive, stat);
}
else if (boost::algorithm::iequals(name, SLA_DRAIN_HOLES_FILE))
} else if (boost::algorithm::iequals(name, SLA_DRAIN_HOLES_FILE))
{
// extract sla support points file
_extract_sla_drain_holes_from_archive(archive, stat);
}
else if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE))
} else if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE))
{
// extract slic3r print config file
_extract_print_config_from_archive(archive, stat, config, filename);
@ -656,8 +655,7 @@ namespace Slic3r {
{
// extract slic3r layer config ranges file
_extract_custom_gcode_per_print_z_from_archive(archive, stat);
}
else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE))
} else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE))
{
// extract slic3r model config file
if (!_extract_model_config_from_archive(archive, stat, model))
@ -666,11 +664,13 @@ namespace Slic3r {
add_error("Archive does not contain a valid model config");
return false;
}
model_config_parsed = true;
print_config_parsed = true;
}
}
}
//parsed prusa files if superslicer not found
//parsed superslicer/prusa files if slic3r not found
//note that is we successfully read one of the config file, then the other ones should also have the same name
auto read_from_other_storage = [this, &print_config_parsed, num_entries, &archive, &stat, &config, &model, &filename](const std::string &print_config_name, const std::string& model_config_name) -> bool {
for (mz_uint i = 0; i < num_entries; ++i)
{
if (mz_zip_reader_file_stat(&archive, i, &stat))
@ -679,11 +679,12 @@ namespace Slic3r {
std::replace(name.begin(), name.end(), '\\', '/');
//TODO use special methods to convert them better?
if (!print_config_parsed && boost::algorithm::iequals(name, PRINT_PRUSA_CONFIG_FILE))
if (boost::algorithm::iequals(name, print_config_name))
{
// extract slic3r print config file
_extract_print_config_from_archive(archive, stat, config, filename);
} else if (!model_config_parsed && boost::algorithm::iequals(name, MODEL_PRUSA_CONFIG_FILE))
print_config_parsed = true;
} else if (boost::algorithm::iequals(name, model_config_name))
{
// extract slic3r model config file
if (!_extract_model_config_from_archive(archive, stat, model))
@ -692,9 +693,18 @@ namespace Slic3r {
add_error("Archive does not contain a valid model config");
return false;
}
print_config_parsed = true;
}
}
}
return true;
};
if (!print_config_parsed)
if (!read_from_other_storage(PRINT_SUPER_CONFIG_FILE, MODEL_SUPER_CONFIG_FILE))
return false;
if (!print_config_parsed)
if (!read_from_other_storage(PRINT_PRUSA_CONFIG_FILE, MODEL_PRUSA_CONFIG_FILE))
return false;
close_zip_reader(&archive);
@ -2066,8 +2076,8 @@ namespace Slic3r {
bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config, const std::string &file_path);
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data, const std::string &file_path);
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config);
};
@ -2180,7 +2190,11 @@ namespace Slic3r {
// This file contains the content of FullPrintConfing / SLAFullPrintConfig.
if (config != nullptr)
{
if (!_add_print_config_file_to_archive(archive, *config))
// also add prusa (& superslicer for backward comp, just for some version from 2.3.56) print config
bool error = !_add_print_config_file_to_archive(archive, *config, PRINT_CONFIG_FILE);
error = error || !_add_print_config_file_to_archive(archive, *config, PRINT_PRUSA_CONFIG_FILE);
error = error || !_add_print_config_file_to_archive(archive, *config, PRINT_SUPER_CONFIG_FILE);
if(error)
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
@ -2188,11 +2202,25 @@ namespace Slic3r {
}
}
// Adds slic3r model config file ("Metadata/Slic3r_PE_model.config").
// Adds slic3r model config file ("Metadata/Slic3r_model.config").
// This file contains all the attributes of all ModelObjects and their ModelVolumes (names, parameter overrides).
// As there is just a single Indexed Triangle Set data stored per ModelObject, offsets of volumes into their respective Indexed Triangle Set data
// is stored here as well.
if (!_add_model_config_file_to_archive(archive, model, objects_data))
if (!_add_model_config_file_to_archive(archive, model, objects_data, MODEL_CONFIG_FILE))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
return false;
}
// also add prusa
if (!_add_model_config_file_to_archive(archive, model, objects_data, MODEL_PRUSA_CONFIG_FILE))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
return false;
}
// also superslicer for backward comp, just for some version from 2.3.56
if (!_add_model_config_file_to_archive(archive, model, objects_data, MODEL_SUPER_CONFIG_FILE))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
@ -2294,7 +2322,8 @@ namespace Slic3r {
date = date.substr(0, 10);
stream << " <" << METADATA_TAG << " name=\"CreationDate\">" << date << "</" << METADATA_TAG << ">\n";
stream << " <" << METADATA_TAG << " name=\"ModificationDate\">" << date << "</" << METADATA_TAG << ">\n";
stream << " <" << METADATA_TAG << " name=\"Application\">" << SLIC3R_APP_KEY << "-" << SLIC3R_VERSION << "</" << METADATA_TAG << ">\n";
stream << " <" << METADATA_TAG << " name=\"Application\">" << SLIC3R_APP_KEY << "</" << METADATA_TAG << ">\n";
stream << " <" << METADATA_TAG << " name=\"ApplicationVersion\">" << SLIC3R_VERSION_FULL << "</" << METADATA_TAG << ">\n";
stream << " <" << RESOURCES_TAG << ">\n";
// Instance transformations, indexed by the 3MF object ID (which is a linear serialization of all instances of all ModelObjects).
@ -2695,28 +2724,12 @@ namespace Slic3r {
return true;
}
bool _3MF_Exporter::_add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig& config)
bool _3MF_Exporter::_add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig& config, const std::string &config_name)
{
char buffer[1024];
sprintf(buffer, "; %s\n\n", header_slic3r_generated().c_str());
std::string out = buffer;
for (const std::string& key : config.keys())
if (key != "compatible_printers")
out += "; " + key + " = " + config.opt_serialize(key) + "\n";
if (!out.empty())
{
if (!mz_zip_writer_add_mem(&archive, PRINT_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
{
add_error("Unable to add print config file to archive");
return false;
}
}
//add prusa print config
out = buffer;
if (config_name == PRINT_PRUSA_CONFIG_FILE) {
for (std::string key : config.keys())
if (key != "compatible_printers") {
std::string value = config.opt_serialize(key);
@ -2724,12 +2737,17 @@ namespace Slic3r {
if (!key.empty())
out += "; " + key + " = " + value + "\n";
}
} else {
for (const std::string& key : config.keys())
if (key != "compatible_printers")
out += "; " + key + " = " + config.opt_serialize(key) + "\n";
}
if (!out.empty())
{
if (!mz_zip_writer_add_mem(&archive, PRINT_PRUSA_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
if (!mz_zip_writer_add_mem(&archive, config_name.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
{
add_error("Unable to add prusa print config file to archive");
add_error("Unable to add print config file to archive");
return false;
}
}
@ -2737,20 +2755,15 @@ namespace Slic3r {
return true;
}
bool _3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data)
bool _3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data, const std::string &file_path)
{
std::stringstream stream;
std::stringstream stream_prusa;
// Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
// when loaded as accurately as possible.
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
stream << "<" << CONFIG_TAG << ">\n";
stream_prusa << std::setprecision(std::numeric_limits<double>::max_digits10);
stream_prusa << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
stream_prusa << "<" << CONFIG_TAG << ">\n";
for (const IdToObjectDataMap::value_type& obj_metadata : objects_data)
{
@ -2759,18 +2772,15 @@ namespace Slic3r {
{
// Output of instances count added because of github #3435, currently not used by PrusaSlicer
stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << obj_metadata.first << "\" " << INSTANCESCOUNT_ATTR << "=\"" << obj->instances.size() << "\">\n";
stream_prusa << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << obj_metadata.first << "\" " << INSTANCESCOUNT_ATTR << "=\"" << obj->instances.size() << "\">\n";
// stores object's name
if (!obj->name.empty()) {
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << xml_escape(obj->name) << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << xml_escape(obj->name) << "\"/>\n";
}
// stores object's config data
for (const std::string& key : obj->config.keys()) {
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << obj->config.opt_serialize(key) << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << obj->config.opt_serialize(key) << "\"/>\n";
}
for (const ModelVolume* volume : obj_metadata.second.object->volumes)
@ -2785,30 +2795,22 @@ namespace Slic3r {
stream << " <" << VOLUME_TAG << " ";
stream << FIRST_TRIANGLE_ID_ATTR << "=\"" << it->second.first_triangle_id << "\" ";
stream << LAST_TRIANGLE_ID_ATTR << "=\"" << it->second.last_triangle_id << "\">\n";
stream_prusa << " <" << VOLUME_TAG << " ";
stream_prusa << FIRST_TRIANGLE_ID_ATTR << "=\"" << it->second.first_triangle_id << "\" ";
stream_prusa << LAST_TRIANGLE_ID_ATTR << "=\"" << it->second.last_triangle_id << "\">\n";
// stores volume's name
if (!volume->name.empty()) {
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n";
}
// stores volume's modifier field (legacy, to support old slicers)
if (volume->is_modifier()) {
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n";
}
// stores volume's type (overrides the modifier field above)
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " <<
VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " <<
VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n";
// stores volume's local matrix
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\"";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\"";
Transform3d matrix = volume->get_matrix() * volume->source.transform.get_matrix();
for (int r = 0; r < 4; ++r)
{
@ -2817,13 +2819,9 @@ namespace Slic3r {
stream << matrix(r, c);
if ((r != 3) || (c != 3))
stream << " ";
stream_prusa << matrix(r, c);
if ((r != 3) || (c != 3))
stream_prusa << " ";
}
}
stream << "\"/>\n";
stream_prusa << "\"/>\n";
// stores volume's source data
{
@ -2840,55 +2838,42 @@ namespace Slic3r {
}
if (volume->source.is_converted_from_inches)
stream << prefix << SOURCE_IN_INCHES << "\" " << VALUE_ATTR << "=\"1\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_FILE_KEY << "\" " << VALUE_ATTR << "=\"" << input_file << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OBJECT_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.object_idx << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_VOLUME_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.volume_idx << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_X_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(0) << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_Y_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(1) << "\"/>\n";
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_Z_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(2) << "\"/>\n";
}
// stores volume's config data
for (std::string key : volume->config.keys())
{
//superslicer config
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
//now the prusa config
// config
if (file_path == MODEL_PRUSA_CONFIG_FILE) {
// convert to prusa config
std::string value = volume->config.opt_serialize(key);
volume->config.to_prusa(key, value);
if (!key.empty())
stream_prusa << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << value << "\"/>\n";
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << value << "\"/>\n";
} else {
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
}
}
stream << " </" << VOLUME_TAG << ">\n";
stream_prusa << " </" << VOLUME_TAG << ">\n";
}
}
}
stream << " </" << OBJECT_TAG << ">\n";
stream_prusa << " </" << OBJECT_TAG << ">\n";
}
}
stream << "</" << CONFIG_TAG << ">\n";
stream_prusa << "</" << CONFIG_TAG << ">\n";
std::string out = stream.str();
if (!mz_zip_writer_add_mem(&archive, MODEL_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
if (!mz_zip_writer_add_mem(&archive, file_path.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
{
add_error("Unable to add model config file to archive");
return false;
}
out = stream_prusa.str();
if (!mz_zip_writer_add_mem(&archive, MODEL_PRUSA_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
{
add_error("Unable to add prusa model config file to archive");
return false;
}
return true;
}