This commit is contained in:
bubnikv 2019-11-07 14:35:50 +01:00
commit 588734c7b3
31 changed files with 1170 additions and 39 deletions

View file

@ -73,6 +73,8 @@ add_library(libslic3r STATIC
Format/STL.hpp
GCode/Analyzer.cpp
GCode/Analyzer.hpp
GCode/ThumbnailData.cpp
GCode/ThumbnailData.hpp
GCode/CoolingBuffer.cpp
GCode/CoolingBuffer.hpp
GCode/PostProcessor.cpp

View file

@ -3,6 +3,9 @@
#include "../Utils.hpp"
#include "../GCode.hpp"
#include "../Geometry.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
#include "../GCode/ThumbnailData.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR
#include "../I18N.hpp"
@ -40,6 +43,9 @@ 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";
#if ENABLE_THUMBNAIL_GENERATOR
const std::string THUMBNAIL_FILE = "Metadata/thumbnail.png";
#endif // ENABLE_THUMBNAIL_GENERATOR
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
@ -1806,11 +1812,22 @@ namespace Slic3r {
typedef std::map<int, ObjectData> IdToObjectDataMap;
public:
#if ENABLE_THUMBNAIL_GENERATOR
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data = nullptr);
#else
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config);
#endif // ENABLE_THUMBNAIL_GENERATOR
private:
#if ENABLE_THUMBNAIL_GENERATOR
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data);
#else
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config);
#endif // ENABLE_THUMBNAIL_GENERATOR
bool _add_content_types_file_to_archive(mz_zip_archive& archive);
#if ENABLE_THUMBNAIL_GENERATOR
bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
bool _add_relationships_file_to_archive(mz_zip_archive& archive);
bool _add_model_file_to_archive(mz_zip_archive& archive, const Model& model, IdToObjectDataMap &objects_data);
bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets);
@ -1823,13 +1840,25 @@ namespace Slic3r {
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
};
#if ENABLE_THUMBNAIL_GENERATOR
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
{
clear_errors();
return _save_model_to_file(filename, model, config, thumbnail_data);
}
#else
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config)
{
clear_errors();
return _save_model_to_file(filename, model, config);
}
#endif // ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_THUMBNAIL_GENERATOR
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
#else
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
mz_zip_archive archive;
mz_zip_zero_struct(&archive);
@ -1848,6 +1877,19 @@ namespace Slic3r {
return false;
}
#if ENABLE_THUMBNAIL_GENERATOR
if ((thumbnail_data != nullptr) && thumbnail_data->is_valid())
{
// Adds the file Metadata/thumbnail.png.
if (!_add_thumbnail_file_to_archive(archive, *thumbnail_data))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
return false;
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
// Adds relationships file ("_rels/.rels").
// The content of this file is the same for each PrusaSlicer 3mf.
// The relationshis file contains a reference to the geometry file "3D/3dmodel.model", the name was chosen to be compatible with CURA.
@ -1941,6 +1983,9 @@ namespace Slic3r {
stream << "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n";
stream << " <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />\n";
stream << " <Default Extension=\"model\" ContentType=\"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\" />\n";
#if ENABLE_THUMBNAIL_GENERATOR
stream << " <Default Extension=\"png\" ContentType=\"image/png\" />\n";
#endif // ENABLE_THUMBNAIL_GENERATOR
stream << "</Types>";
std::string out = stream.str();
@ -1954,12 +1999,35 @@ namespace Slic3r {
return true;
}
#if ENABLE_THUMBNAIL_GENERATOR
bool _3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data)
{
bool res = false;
size_t png_size = 0;
void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)thumbnail_data.pixels.data(), thumbnail_data.width, thumbnail_data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
if (png_data != nullptr)
{
res = mz_zip_writer_add_mem(&archive, THUMBNAIL_FILE.c_str(), (const void*)png_data, png_size, MZ_DEFAULT_COMPRESSION);
mz_free(png_data);
}
if (!res)
add_error("Unable to add thumbnail file to archive");
return res;
}
#endif // ENABLE_THUMBNAIL_GENERATOR
bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive)
{
std::stringstream stream;
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
stream << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n";
stream << " <Relationship Target=\"/" << MODEL_FILE << "\" Id=\"rel-1\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\" />\n";
#if ENABLE_THUMBNAIL_GENERATOR
stream << " <Relationship Target=\"/" << THUMBNAIL_FILE << "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\" />\n";
#endif // ENABLE_THUMBNAIL_GENERATOR
stream << "</Relationships>";
std::string out = stream.str();
@ -2453,13 +2521,21 @@ namespace Slic3r {
return res;
}
#if ENABLE_THUMBNAIL_GENERATOR
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
#else
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
if ((path == nullptr) || (model == nullptr))
return false;
_3MF_Exporter exporter;
#if ENABLE_THUMBNAIL_GENERATOR
bool res = exporter.save_model_to_file(path, *model, config, thumbnail_data);
#else
bool res = exporter.save_model_to_file(path, *model, config);
#endif // ENABLE_THUMBNAIL_GENERATOR
if (!res)
exporter.log_errors();

View file

@ -22,13 +22,20 @@ namespace Slic3r {
class Model;
class DynamicPrintConfig;
#if ENABLE_THUMBNAIL_GENERATOR
struct ThumbnailData;
#endif // ENABLE_THUMBNAIL_GENERATOR
// Load the content of a 3mf file into the given model and preset bundle.
extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version);
// 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
#if ENABLE_THUMBNAIL_GENERATOR
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data = nullptr);
#else
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config);
#endif // ENABLE_THUMBNAIL_GENERATOR
}; // namespace Slic3r

View file

@ -6,6 +6,9 @@
#include "Geometry.hpp"
#include "GCode/PrintExtents.hpp"
#include "GCode/WipeTower.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
#include "GCode/ThumbnailData.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR
#include "ShortestPath.hpp"
#include "Utils.hpp"
@ -18,6 +21,9 @@
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#if ENABLE_THUMBNAIL_GENERATOR
#include <boost/beast/core/detail/base64.hpp>
#endif // ENABLE_THUMBNAIL_GENERATOR
#include <boost/nowide/iostream.hpp>
#include <boost/nowide/cstdio.hpp>
@ -29,6 +35,10 @@
#include <Shiny/Shiny.h>
#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE
#include "miniz_extension.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE
#if 0
// Enable debugging and asserts, even in the release build.
#define DEBUG
@ -652,7 +662,11 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
return layers_to_print;
}
#if ENABLE_THUMBNAIL_GENERATOR
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, const std::vector<ThumbnailData>* thumbnail_data)
#else
void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
PROFILE_CLEAR();
@ -678,7 +692,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
try {
m_placeholder_parser_failed_templates.clear();
#if ENABLE_THUMBNAIL_GENERATOR
this->_do_export(*print, file, thumbnail_data);
#else
this->_do_export(*print, file);
#endif // ENABLE_THUMBNAIL_GENERATOR
fflush(file);
if (ferror(file)) {
fclose(file);
@ -742,7 +760,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str());
}
#if ENABLE_THUMBNAIL_GENERATOR
void GCode::_do_export(Print& print, FILE* file, const std::vector<ThumbnailData>* thumbnail_data)
#else
void GCode::_do_export(Print &print, FILE *file)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
PROFILE_FUNC();
@ -934,6 +956,77 @@ void GCode::_do_export(Print &print, FILE *file)
// Write information on the generator.
_write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str());
#if ENABLE_THUMBNAIL_GENERATOR
// Write thumbnails using base64 encoding
if (thumbnail_data != nullptr)
{
const unsigned int max_row_length = 78;
for (const ThumbnailData& data : *thumbnail_data)
{
if (data.is_valid())
{
#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE
size_t png_size = 0;
void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
if (png_data != nullptr)
{
_write_format(file, "\n;\n; thumbnail begin %dx%d\n", data.width, data.height);
std::string encoded = boost::beast::detail::base64_encode((const std::uint8_t*)png_data, png_size);
unsigned int row_count = 0;
while (encoded.length() > max_row_length)
{
_write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str());
encoded = encoded.substr(max_row_length);
++row_count;
}
if (encoded.length() > 0)
_write_format(file, "; %s\n", encoded.c_str());
_write(file, "; thumbnail end\n;\n");
mz_free(png_data);
}
#else
_write_format(file, "\n;\n; thumbnail begin %dx%d\n", data.width, data.height);
size_t row_size = 4 * data.width;
for (int r = (int)data.height - 1; r >= 0; --r)
{
std::string encoded = boost::beast::detail::base64_encode((const std::uint8_t*)(data.pixels.data() + r * row_size), row_size);
unsigned int row_count = 0;
while (encoded.length() > max_row_length)
{
if (row_count == 0)
_write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str());
else
_write_format(file, ";>%s\n", encoded.substr(0, max_row_length).c_str());
encoded = encoded.substr(max_row_length);
++row_count;
}
if (encoded.length() > 0)
{
if (row_count == 0)
_write_format(file, "; %s\n", encoded.c_str());
else
_write_format(file, ";>%s\n", encoded.c_str());
}
}
_write(file, "; thumbnail end\n;\n");
#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE
}
print.throw_if_canceled();
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
// Write notes (content of the Print Settings tab -> Notes)
{
std::list<std::string> lines;

View file

@ -30,6 +30,9 @@ namespace Slic3r {
// Forward declarations.
class GCode;
class GCodePreviewData;
#if ENABLE_THUMBNAIL_GENERATOR
struct ThumbnailData;
#endif // ENABLE_THUMBNAIL_GENERATOR
class AvoidCrossingPerimeters {
public:
@ -162,7 +165,11 @@ public:
// throws std::runtime_exception on error,
// throws CanceledException through print->throw_if_canceled().
#if ENABLE_THUMBNAIL_GENERATOR
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, const std::vector<ThumbnailData>* thumbnail_data = nullptr);
#else
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
#endif // ENABLE_THUMBNAIL_GENERATOR
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
const Vec2d& origin() const { return m_origin; }
@ -190,7 +197,11 @@ public:
static void append_full_config(const Print& print, std::string& str);
protected:
#if ENABLE_THUMBNAIL_GENERATOR
void _do_export(Print& print, FILE* file, const std::vector<ThumbnailData>* thumbnail_data);
#else
void _do_export(Print &print, FILE *file);
#endif //ENABLE_THUMBNAIL_GENERATOR
// Object and support extrusions of the same PrintObject at the same print_z.
struct LayerToPrint

View file

@ -0,0 +1,36 @@
#include "libslic3r/libslic3r.h"
#include "ThumbnailData.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
namespace Slic3r {
void ThumbnailData::set(unsigned int w, unsigned int h)
{
if ((w == 0) || (h == 0))
return;
if ((width != w) || (height != h))
{
width = w;
height = h;
// defaults to white texture
pixels = std::vector<unsigned char>(width * height * 4, 255);
}
}
void ThumbnailData::reset()
{
width = 0;
height = 0;
pixels.clear();
}
bool ThumbnailData::is_valid() const
{
return (width != 0) && (height != 0) && ((unsigned int)pixels.size() == 4 * width * height);
}
} // namespace Slic3r
#endif // ENABLE_THUMBNAIL_GENERATOR

View file

@ -0,0 +1,27 @@
#ifndef slic3r_ThumbnailData_hpp_
#define slic3r_ThumbnailData_hpp_
#if ENABLE_THUMBNAIL_GENERATOR
#include <vector>
namespace Slic3r {
struct ThumbnailData
{
unsigned int width;
unsigned int height;
std::vector<unsigned char> pixels;
ThumbnailData() { reset(); }
void set(unsigned int w, unsigned int h);
void reset();
bool is_valid() const;
};
} // namespace Slic3r
#endif // ENABLE_THUMBNAIL_GENERATOR
#endif // slic3r_ThumbnailData_hpp_

View file

@ -1536,7 +1536,11 @@ void Print::process()
// The export_gcode may die for various reasons (fails to process output_filename_format,
// write error into the G-code, cannot execute post-processing scripts).
// It is up to the caller to show an error message.
#if ENABLE_THUMBNAIL_GENERATOR
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const std::vector<ThumbnailData>* thumbnail_data)
#else
std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
// output everything to a G-code file
// The following call may die if the output_filename_format template substitution fails.
@ -1553,7 +1557,11 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa
// The following line may die for multiple reasons.
GCode gcode;
#if ENABLE_THUMBNAIL_GENERATOR
gcode.do_export(this, path.c_str(), preview_data, thumbnail_data);
#else
gcode.do_export(this, path.c_str(), preview_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
return path.c_str();
}

View file

@ -19,6 +19,9 @@ class PrintObject;
class ModelObject;
class GCode;
class GCodePreviewData;
#if ENABLE_THUMBNAIL_GENERATOR
struct ThumbnailData;
#endif // ENABLE_THUMBNAIL_GENERATOR
// Print step IDs for keeping track of the print state.
enum PrintStep {
@ -307,7 +310,11 @@ public:
void process() override;
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
#if ENABLE_THUMBNAIL_GENERATOR
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const std::vector<ThumbnailData>* thumbnail_data = nullptr);
#else
std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
// methods for handling state
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }

View file

@ -32,29 +32,40 @@ void RasterWriter::save(const std::string &fpath, const std::string &prjname)
{
try {
Zipper zipper(fpath); // zipper with no compression
std::string project = prjname.empty()?
boost::filesystem::path(fpath).stem().string() : prjname;
save(zipper, prjname);
zipper.finalize();
} catch(std::exception& e) {
BOOST_LOG_TRIVIAL(error) << e.what();
// Rethrow the exception
throw;
}
}
void RasterWriter::save(Zipper &zipper, const std::string &prjname)
{
try {
std::string project =
prjname.empty() ?
boost::filesystem::path(zipper.get_filename()).stem().string() :
prjname;
zipper.add_entry("config.ini");
zipper << createIniContent(project);
for(unsigned i = 0; i < m_layers_rst.size(); i++)
{
if(m_layers_rst[i].rawbytes.size() > 0) {
char lyrnum[6];
std::sprintf(lyrnum, "%.5d", i);
auto zfilename = project + lyrnum + ".png";
// Add binary entry to the zipper
zipper.add_entry(zfilename,
m_layers_rst[i].rawbytes.data(),
m_layers_rst[i].rawbytes.size());
}
}
zipper.finalize();
} catch(std::exception& e) {
BOOST_LOG_TRIVIAL(error) << e.what();
// Rethrow the exception

View file

@ -12,6 +12,7 @@
#include "libslic3r/PrintConfig.hpp"
#include "SLARaster.hpp"
#include "libslic3r/Zipper.hpp"
namespace Slic3r { namespace sla {
@ -112,9 +113,10 @@ public:
}
void save(const std::string &fpath, const std::string &prjname = "");
void save(Zipper &zipper, const std::string &prjname = "");
void set_statistics(const PrintStatistics &statistics);
void set_config(const DynamicPrintConfig &cfg);
};

View file

@ -1372,7 +1372,12 @@ void SLAPrint::process()
m_print_statistics.fast_layers_count = fast_layers;
m_print_statistics.slow_layers_count = slow_layers;
#if ENABLE_THUMBNAIL_GENERATOR
// second argument set to -3 to differentiate it from the same call made into slice_supports()
m_report_status(*this, -3, "", SlicingStatus::RELOAD_SLA_PREVIEW);
#else
m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
#endif // ENABLE_THUMBNAIL_GENERATOR
};
// Rasterizing the model objects, and their supports

View file

@ -7,6 +7,7 @@
#include "SLA/SLARasterWriter.hpp"
#include "Point.hpp"
#include "MTUtils.hpp"
#include "Zipper.hpp"
#include <libnest2d/backends/clipper/clipper_polygon.hpp>
namespace Slic3r {
@ -364,6 +365,12 @@ public:
if(m_printer) m_printer->save(fpath, projectname);
}
inline void export_raster(Zipper &zipper,
const std::string& projectname = "")
{
if(m_printer) m_printer->save(zipper, projectname);
}
const PrintObjects& objects() const { return m_objects; }
const SLAPrintConfig& print_config() const { return m_print_config; }

View file

@ -32,4 +32,14 @@
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
//====================
// 2.2.0.alpha1 techs
//====================
#define ENABLE_2_2_0_ALPHA1 1
// Enable thumbnail generator
#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1)
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
#define ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE (1 && ENABLE_THUMBNAIL_GENERATOR)
#endif // _technologies_h_

View file

@ -217,4 +217,9 @@ void Zipper::finalize()
m_impl->blow_up();
}
const std::string &Zipper::get_filename() const
{
return m_impl->m_zipname;
}
}

View file

@ -83,6 +83,8 @@ public:
void finish_entry();
void finalize();
const std::string & get_filename() const;
};