Store shape as svg into 3mf

Without obfuscation of svg.
This commit is contained in:
Filip Sykala - NTB T15p 2023-08-02 22:34:33 +02:00
parent f36330df4f
commit 480c571499
6 changed files with 267 additions and 32 deletions

View File

@ -73,7 +73,7 @@ struct EmbossShape
ExPolygonsWithIds shapes_with_ids; ExPolygonsWithIds shapes_with_ids;
// scale of shape, multiplier to get 3d point in mm from integer shape // scale of shape, multiplier to get 3d point in mm from integer shape
double scale = 1.; double scale = SCALING_FACTOR;
// Define how to emboss shape // Define how to emboss shape
EmbossProjection projection; EmbossProjection projection;
@ -98,6 +98,9 @@ struct EmbossShape
// Loaded svg file data. // Loaded svg file data.
// !!! It is not serialized on undo/redo stack // !!! It is not serialized on undo/redo stack
std::shared_ptr<NSVGimage> image = nullptr; std::shared_ptr<NSVGimage> image = nullptr;
// Loaded string data from file
std::shared_ptr<char[]> file_data = nullptr;
}; };
SvgFile svg_file; SvgFile svg_file;

View File

@ -39,6 +39,8 @@ namespace pt = boost::property_tree;
#include "EmbossShape.hpp" #include "EmbossShape.hpp"
#include "ExPolygonSerialize.hpp" #include "ExPolygonSerialize.hpp"
#include "NSVGUtils.hpp"
#include <fast_float/fast_float.h> #include <fast_float/fast_float.h>
// Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter, // Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter,
@ -173,9 +175,9 @@ static constexpr const char *FONT_WEIGHT_ATTR = "weight";
// Store / load of EmbossShape // Store / load of EmbossShape
static constexpr const char *SHAPE_TAG = "slic3rpe:shape"; static constexpr const char *SHAPE_TAG = "slic3rpe:shape";
static constexpr const char *SHAPE_EXPOLYS_ATTR = "expolygons";
static constexpr const char *SHAPE_SCALE_ATTR = "scale"; static constexpr const char *SHAPE_SCALE_ATTR = "scale";
static constexpr const char *SVG_FILE_PATH_ATTR = "filepath"; static constexpr const char *SVG_FILE_PATH_ATTR = "filepath";
static constexpr const char *SVG_FILE_PATH_IN_3MF_ATTR = "filepath3mf";
// EmbossProjection // EmbossProjection
static constexpr const char *DEPTH_ATTR = "depth"; static constexpr const char *DEPTH_ATTR = "depth";
@ -467,7 +469,7 @@ namespace Slic3r {
typedef std::map<int, CutObjectInfo> IdToCutObjectInfoMap; typedef std::map<int, CutObjectInfo> IdToCutObjectInfoMap;
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap; typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
typedef std::map<int, std::vector<sla::DrainHole>> IdToSlaDrainHolesMap; typedef std::map<int, std::vector<sla::DrainHole>> IdToSlaDrainHolesMap;
using PathToEmbossShapeFileMap = std::map<std::string, std::shared_ptr<char[]>>;
// Version of the 3mf file // Version of the 3mf file
unsigned int m_version; unsigned int m_version;
bool m_check_version; bool m_check_version;
@ -497,6 +499,7 @@ namespace Slic3r {
IdToLayerConfigRangesMap m_layer_config_ranges; IdToLayerConfigRangesMap m_layer_config_ranges;
IdToSlaSupportPointsMap m_sla_support_points; IdToSlaSupportPointsMap m_sla_support_points;
IdToSlaDrainHolesMap m_sla_drain_holes; IdToSlaDrainHolesMap m_sla_drain_holes;
PathToEmbossShapeFileMap m_path_to_emboss_shape_files;
std::string m_curr_metadata_name; std::string m_curr_metadata_name;
std::string m_curr_characters; std::string m_curr_characters;
std::string m_name; std::string m_name;
@ -523,6 +526,7 @@ namespace Slic3r {
} }
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions); bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions);
bool _is_svg_shape_file(const std::string &filename);
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions); void _extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
@ -534,6 +538,7 @@ namespace Slic3r {
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& subs_context, const std::string& archive_filename); void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& subs_context, const std::string& archive_filename);
bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model); bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
void _extract_embossed_svg_shape_file(const std::string &filename, mz_zip_archive &archive, const mz_zip_archive_file_stat &stat);
// handlers to parse the .model file // handlers to parse the .model file
void _handle_start_model_xml_element(const char* name, const char** attributes); void _handle_start_model_xml_element(const char* name, const char** attributes);
@ -762,6 +767,9 @@ namespace Slic3r {
return false; return false;
} }
} }
else if (_is_svg_shape_file(name)) {
_extract_embossed_svg_shape_file(name, archive, stat);
}
} }
} }
@ -936,6 +944,10 @@ namespace Slic3r {
return true; return true;
} }
bool _3MF_Importer::_is_svg_shape_file(const std::string &name) {
return name._Starts_with(MODEL_FOLDER) && boost::algorithm::ends_with(name, ".svg");
}
bool _3MF_Importer::_extract_model_from_archive(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)
{ {
if (stat.m_uncomp_size == 0) { if (stat.m_uncomp_size == 0) {
@ -1368,6 +1380,36 @@ namespace Slic3r {
} }
} }
void _3MF_Importer::_extract_embossed_svg_shape_file(const std::string &filename, mz_zip_archive &archive, const mz_zip_archive_file_stat &stat){
assert(m_path_to_emboss_shape_files.find(filename) == m_path_to_emboss_shape_files.end());
std::unique_ptr<char[]> file{new char[stat.m_uncomp_size + 1]};
if (file == nullptr){
add_error("Cannot alocate space for SVG file.");
return;
}
mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void *) file.get(), (size_t) stat.m_uncomp_size, 0);
if (res == 0) {
add_error("Error while reading svg shape for emboss");
return;
}
file.get()[stat.m_uncomp_size] = '\0'; // Must be null terminated.
// store for case svg is loaded before volume
m_path_to_emboss_shape_files[filename] = std::move(file);
// find embossed volume, for case svg is loaded after volume
for (ModelObject* object : m_model->objects)
for (ModelVolume *volume : object->volumes) {
std::optional<EmbossShape> &es = volume->emboss_shape;
if (!es.has_value())
continue;
if (filename.compare(es->svg_file.path_in_3mf) == 0)
es->svg_file.file_data = m_path_to_emboss_shape_files[filename];
}
}
bool _3MF_Importer::_extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model) bool _3MF_Importer::_extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model)
{ {
if (stat.m_uncomp_size == 0) { if (stat.m_uncomp_size == 0) {
@ -1977,7 +2019,7 @@ namespace Slic3r {
} }
// Definition of read/write method for EmbossShape // Definition of read/write method for EmbossShape
static void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume& volume); static void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume, mz_zip_archive &archive);
static std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes); static std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes);
bool _3MF_Importer::_handle_start_shape_configuration(const char **attributes, unsigned int num_attributes) bool _3MF_Importer::_handle_start_shape_configuration(const char **attributes, unsigned int num_attributes)
@ -1994,7 +2036,21 @@ namespace Slic3r {
} }
ObjectMetadata::VolumeMetadata &volume = volumes.back(); ObjectMetadata::VolumeMetadata &volume = volumes.back();
volume.shape_configuration = read_emboss_shape(attributes, num_attributes); volume.shape_configuration = read_emboss_shape(attributes, num_attributes);
return volume.shape_configuration.has_value(); if (!volume.shape_configuration.has_value())
return false;
// Fill svg file content into shape_configuration
EmbossShape::SvgFile &svg = volume.shape_configuration->svg_file;
const std::string &path = svg.path_in_3mf;
if (path.empty()) // do not contain svg file
return true;
auto it = m_path_to_emboss_shape_files.find(path);
if (it == m_path_to_emboss_shape_files.end())
return true; // svg file is not loaded yet
svg.file_data = it->second;
return true;
} }
bool _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter) bool _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter)
@ -2413,6 +2469,7 @@ namespace Slic3r {
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data, bool zip64); bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data, bool zip64);
static void add_transformation(std::stringstream &stream, const Transform3d &tr); static void add_transformation(std::stringstream &stream, const Transform3d &tr);
private: private:
void _publish(Model &model);
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data); bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data);
bool _add_content_types_file_to_archive(mz_zip_archive& archive); bool _add_content_types_file_to_archive(mz_zip_archive& archive);
bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data); bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data);
@ -3359,7 +3416,7 @@ namespace Slic3r {
if (const std::optional<EmbossShape> &es = volume->emboss_shape; if (const std::optional<EmbossShape> &es = volume->emboss_shape;
es.has_value()) es.has_value())
to_xml(stream, *es, *volume); to_xml(stream, *es, *volume, archive);
if (const std::optional<TextConfiguration> &tc = volume->text_configuration; if (const std::optional<TextConfiguration> &tc = volume->text_configuration;
tc.has_value()) tc.has_value())
@ -3681,21 +3738,37 @@ Transform3d create_fix(const std::optional<Transform3d> &prev, const ModelVolume
return *prev * fix_trmat; return *prev * fix_trmat;
} }
std::string to_string(const ExPolygonsWithIds &shapes) bool to_xml(std::stringstream &stream, const EmbossShape::SvgFile &svg, const ModelVolume &volume, mz_zip_archive &archive){
{ assert(!svg.path_in_3mf.empty());
// TODO: Need to implement if (svg.path_in_3mf.empty())
return {}; return false; // unwanted store .svg file into .3mf (protection of copyRight)
if (!svg.path.empty())
stream << SVG_FILE_PATH_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(svg.path) << "\" ";
stream << SVG_FILE_PATH_IN_3MF_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(svg.path_in_3mf) << "\" ";
char *data = svg.file_data.get();
assert(data != nullptr);
if (data == nullptr)
return false;
// NOTE: file data must be null terminated
size_t size = 0;
for (char *c = data; *c != '\0'; ++c) ++size;
if (!mz_zip_writer_add_mem(&archive, svg.path_in_3mf.c_str(), (const void *) data, size, MZ_DEFAULT_COMPRESSION))
return false;
return true;
} }
} // namespace } // namespace
void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume) { void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume, mz_zip_archive &archive)
{
stream << " <" << SHAPE_TAG << " "; stream << " <" << SHAPE_TAG << " ";
stream << SVG_FILE_PATH_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(es.svg_file.path) << "\" "; if(!to_xml(stream, es.svg_file, volume, archive))
stream << SHAPE_SCALE_ATTR << "=\"" << es.scale << "\" "; BOOST_LOG_TRIVIAL(warning) << "Can't write svg file defiden embossed shape into 3mf";
std::string expolygons_str = to_string(es.shapes_with_ids); // cereal serialize expolygons stream << SHAPE_SCALE_ATTR << "=\"" << es.scale << "\" ";
stream << SHAPE_EXPOLYS_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(expolygons_str) << "\" ";
// projection // projection
const EmbossProjection &p = es.projection; const EmbossProjection &p = es.projection;
@ -3708,11 +3781,11 @@ void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume
stream << TRANSFORM_ATTR << "=\""; stream << TRANSFORM_ATTR << "=\"";
_3MF_Exporter::add_transformation(stream, fix); _3MF_Exporter::add_transformation(stream, fix);
stream << "\" "; stream << "\" ";
stream << "/>\n"; // end SHAPE_TAG stream << "/>\n"; // end SHAPE_TAG
} }
std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes) { std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes) {
double scale = get_attribute_value_float(attributes, num_attributes, SHAPE_SCALE_ATTR); double scale = get_attribute_value_float(attributes, num_attributes, SHAPE_SCALE_ATTR);
EmbossProjection projection; EmbossProjection projection;
@ -3726,9 +3799,13 @@ std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned i
if (!fix_tr_mat_str.empty()) { if (!fix_tr_mat_str.empty()) {
fix_tr_mat = get_transform_from_3mf_specs_string(fix_tr_mat_str); fix_tr_mat = get_transform_from_3mf_specs_string(fix_tr_mat_str);
} }
std::string file_path = get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_ATTR); std::string file_path = get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_ATTR);
std::string file_path_3mf = get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_IN_3MF_ATTR);
ExPolygonsWithIds shapes; // TODO: need to implement ExPolygonsWithIds shapes; // TODO: need to implement
return EmbossShape{shapes, scale, std::move(projection), std::move(fix_tr_mat), std::move(file_path)};
EmbossShape::SvgFile svg{file_path, file_path_3mf};
return EmbossShape{shapes, scale, std::move(projection), std::move(fix_tr_mat), std::move(svg)};
} }

View File

@ -54,13 +54,43 @@ NSVGimage_ptr nsvgParseFromFile(const std::string &filename, const char *units,
return {image, ::nsvgDelete}; return {image, ::nsvgDelete};
} }
bool save(const NSVGimage &image, const std::string &svg_file_path) std::unique_ptr<char[]> read_from_disk(const std::string& path)
{ {
FILE * file = boost::nowide::fopen(svg_file_path.c_str(), "w"); FILE *fp = boost::nowide::fopen(path.c_str(), "rb");
if (file == NULL) if (!fp)
return false; return nullptr;
fprintf(file, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"); fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
fseek(fp, 0, SEEK_SET);
std::unique_ptr<char[]> result{new char[size + 1]};
if (result == nullptr)
return nullptr;
if (fread(result.get(), 1, size, fp) != size)
return nullptr;
result.get()[size] = '\0'; // Must be null terminated.
fclose(fp);
return result;
}
NSVGimage_ptr nsvgParse(const std::shared_ptr<char[]> file_data, const char *units, float dpi){
size_t size = 0;
for (char *c = file_data.get(); *c != '\0'; ++c)
++size;
// NOTE: nsvg parser consume data from pointer
std::unique_ptr<char[]> data_copy(new char[size]);
memcpy(data_copy.get(), file_data.get(), size);
NSVGimage *image = ::nsvgParse(data_copy.get(), units, dpi);
return {image, ::nsvgDelete};
}
void save(const NSVGimage &image, std::ostream &data)
{
data << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>";
// tl .. top left // tl .. top left
Vec2f tl(std::numeric_limits<float>::max(), std::numeric_limits<float>::max()); Vec2f tl(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
@ -76,9 +106,11 @@ bool save(const NSVGimage &image, const std::string &svg_file_path)
Vec2f s = br - tl; Vec2f s = br - tl;
Point size = s.cast<Point::coord_type>(); Point size = s.cast<Point::coord_type>();
fprintf(file, "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"%dmm\" height=\"%dmm\" viewBox=\"0 0 %d %d\" >\n", data << "<svg xmlns=\"http://www.w3.org/2000/svg\" "
size.x(), size.y(), size.x(), size.y()); << "width=\"" << size.x() << "mm\" "
fprintf(file, "<!-- Created with PrusaSlicer (https://www.prusa3d.com/prusaslicer/) -->\n"); << "height=\"" << size.y() << "mm\" "
<< "viewBox=\"0 0 " << size.x() << " " << size.y() << "\" >\n";
data << "<!-- Created with PrusaSlicer (https://www.prusa3d.com/prusaslicer/) -->\n";
std::array<char, 128> buffer; std::array<char, 128> buffer;
auto write_point = [&tl, &buffer](std::string &d, const float *p) { auto write_point = [&tl, &buffer](std::string &d, const float *p) {
@ -143,10 +175,18 @@ bool save(const NSVGimage &image, const std::string &svg_file_path)
type = Type::close; type = Type::close;
d += "Z"; // closed path d += "Z"; // closed path
} }
fprintf(file, "<path fill=\"#D2D2D2\" d=\"%s\" />\n", d.c_str()); data << "<path fill=\"#D2D2D2\" d=\"" << d << "\" />\n";
} }
fprintf(file, "</svg>\n"); data << "</svg>\n";
fclose(file); }
bool save(const NSVGimage &image, const std::string &svg_file_path)
{
std::ofstream file{svg_file_path};
if (!file.is_open())
return false;
save(image, file);
return true;
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <sstream>
#include "Polygon.hpp" #include "Polygon.hpp"
#include "ExPolygon.hpp" #include "ExPolygon.hpp"
#include "nanosvg/nanosvg.h" // load SVG file #include "nanosvg/nanosvg.h" // load SVG file
@ -26,8 +27,14 @@ ExPolygons to_expolygons(const NSVGimage &image, float tessTol = 10., int max_le
void bounds(const NSVGimage &image, Vec2f &min, Vec2f &max); void bounds(const NSVGimage &image, Vec2f &min, Vec2f &max);
// read text data from file
std::unique_ptr<char[]> read_from_disk(const std::string &path);
using NSVGimage_ptr = std::unique_ptr<NSVGimage, void (*)(NSVGimage*)>; using NSVGimage_ptr = std::unique_ptr<NSVGimage, void (*)(NSVGimage*)>;
NSVGimage_ptr nsvgParseFromFile(const std::string &svg_file_path, const char *units = "mm", float dpi = 96.0f); NSVGimage_ptr nsvgParseFromFile(const std::string &svg_file_path, const char *units = "mm", float dpi = 96.0f);
NSVGimage_ptr nsvgParse(const std::shared_ptr<char[]> file_data, const char *units = "mm", float dpi = 96.0f);
void save(const NSVGimage &image, std::ostream &data);
bool save(const NSVGimage &image, const std::string &svg_file_path); bool save(const NSVGimage &image, const std::string &svg_file_path);
} // namespace Slic3r } // namespace Slic3r
#endif // slic3r_NSVGUtils_hpp_ #endif // slic3r_NSVGUtils_hpp_

View File

@ -1229,7 +1229,14 @@ bool GLGizmoSVG::draw_preview(){
if (dlg.ShowModal() == wxID_OK ){ if (dlg.ShowModal() == wxID_OK ){
wxString out_path = dlg.GetPath(); wxString out_path = dlg.GetPath();
std::string path{out_path.c_str()}; std::string path{out_path.c_str()};
Slic3r::save(*m_volume_shape.svg_file.image, path); //Slic3r::save(*m_volume_shape.svg_file.image, path);
std::ofstream stream(path);
if (stream.is_open()){
stream << svg.file_data.get();
} else {
BOOST_LOG_TRIVIAL(error) << "Opening file: \"" << path << "\" Failed";
}
} }
} else if (ImGui::IsItemHovered()) { } else if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", _u8L("Save as '.svg' file").c_str()); ImGui::SetTooltip("%s", _u8L("Save as '.svg' file").c_str());

View File

@ -6666,6 +6666,103 @@ void Plater::export_amf()
} }
} }
namespace {
std::string get_file_name(const std::string &file_path)
{
size_t pos_last_delimiter = file_path.find_last_of("/\\");
size_t pos_point = file_path.find_last_of('.');
size_t offset = pos_last_delimiter + 1;
size_t count = pos_point - pos_last_delimiter - 1;
return file_path.substr(offset, count);
}
using SvgFile = EmbossShape::SvgFile;
using SvgFiles = std::vector<SvgFile*>;
std::string create_unique_3mf_filepath(const std::string &file, const SvgFiles svgs)
{
// const std::string MODEL_FOLDER = "3D/"; // copy from file 3mf.cpp
std::string path_in_3mf = "3D/" + file + ".svg";
size_t suffix_number = 0;
bool is_unique = false;
do{
is_unique = true;
path_in_3mf = "3D/" + file + ((suffix_number++)? ("_" + std::to_string(suffix_number)) : "") + ".svg";
for (SvgFile *svgfile : svgs) {
if (svgfile->path_in_3mf.empty())
continue;
if (svgfile->path_in_3mf.compare(path_in_3mf) == 0) {
is_unique = false;
break;
}
}
} while (!is_unique);
return path_in_3mf;
}
bool set_by_local_path(SvgFile &svg, const SvgFiles& svgs)
{
// Try to find already used svg file
for (SvgFile *svg_ : svgs) {
if (svg_->path_in_3mf.empty())
continue;
if (svg.path.compare(svg_->path) == 0) {
svg.path_in_3mf = svg_->path_in_3mf;
return true;
}
}
return false;
}
/// <summary>
/// Function to secure private data before store to 3mf
/// </summary>
/// <param name="model">Data(also private) to clean before publishing</param>
void publish(Model &model) {
// SVG file publishing
bool exist_new = false;
SvgFiles svgfiles;
for (ModelObject *object: model.objects){
for (ModelVolume *volume : object->volumes) {
if (!volume->emboss_shape.has_value())
continue;
SvgFile* svg = &volume->emboss_shape->svg_file;
if (svg->path_in_3mf.empty())
exist_new = true;
svgfiles.push_back(svg);
}
}
if (exist_new){
MessageDialog dialog(nullptr,
_L("Are you sure you want to store original SVGs with their local path into .3mf ?\n "
"When you hit 'NO', all Embossed shape will not be editable any more."),
_L("Private protection"), wxYES_NO | wxICON_QUESTION);
if (dialog.ShowModal() == wxID_NO){
for (ModelObject *object : model.objects)
for (ModelVolume *volume : object->volumes)
if (volume->emboss_shape.has_value())
volume->emboss_shape.reset();
}
}
for (SvgFile* svgfile : svgfiles){
if (!svgfile->path_in_3mf.empty())
continue; // already suggested path (previous save)
// create unique name for svgs, when local path differ
std::string filename = "unknown";
if (!svgfile->path.empty()) {
if (set_by_local_path(*svgfile, svgfiles))
continue;
// check whether original filename is already in:
filename = get_file_name(svgfile->path);
}
svgfile->path_in_3mf = create_unique_3mf_filepath(filename, svgfiles);
}
}
}
bool Plater::export_3mf(const boost::filesystem::path& output_path) bool Plater::export_3mf(const boost::filesystem::path& output_path)
{ {
if (p->model.objects.empty()) { if (p->model.objects.empty()) {
@ -6686,6 +6783,10 @@ bool Plater::export_3mf(const boost::filesystem::path& output_path)
if (!path.Lower().EndsWith(".3mf")) if (!path.Lower().EndsWith(".3mf"))
return false; return false;
// take care about private data stored into .3mf
// modify model
publish(p->model);
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure();
const std::string path_u8 = into_u8(path); const std::string path_u8 = into_u8(path);
wxBusyCursor wait; wxBusyCursor wait;