From 04e03c840deb02547eccab647243f6cf6ddf2764 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 18 Mar 2019 18:02:50 +0100 Subject: [PATCH] Reducing copies when writing png data. --- src/libslic3r/PrintExport.hpp | 25 ++++++++-------- src/libslic3r/Rasterizer/Rasterizer.cpp | 39 +++++++++++++++++++++++++ src/libslic3r/Rasterizer/Rasterizer.hpp | 9 ++++++ src/libslic3r/SLAPrint.hpp | 7 +++++ src/libslic3r/Zipper.cpp | 17 +++++++++++ src/libslic3r/Zipper.hpp | 3 ++ 6 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index 99a2110b3..4a0bb4eef 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -93,6 +93,10 @@ public: void next_entry(const std::string& /*fname*/) {} + // binary entry + void binary_entry(const std::string& /*fname*/, + const std::uint8_t* buf, size_t len); + std::string get_name() { return ""; } bool is_ok() { return false; } @@ -111,7 +115,7 @@ template<> class FilePrinter { struct Layer { Raster first; - std::stringstream second; + RawBytes second; Layer() {} @@ -226,15 +230,15 @@ public: inline void finish_layer(unsigned lyr_id) { assert(lyr_id < m_layers_rst.size()); - m_layers_rst[lyr_id].first.save(m_layers_rst[lyr_id].second, - Raster::Compression::PNG); + m_layers_rst[lyr_id].second = + m_layers_rst[lyr_id].first.save(Raster::Compression::PNG); m_layers_rst[lyr_id].first.reset(); } inline void finish_layer() { if(!m_layers_rst.empty()) { - m_layers_rst.back().first.save(m_layers_rst.back().second, - Raster::Compression::PNG); + m_layers_rst.back().second = + m_layers_rst.back().first.save(Raster::Compression::PNG); m_layers_rst.back().first.reset(); } } @@ -254,18 +258,15 @@ public: for(unsigned i = 0; i < m_layers_rst.size() && writer.is_ok(); i++) { - if(m_layers_rst[i].second.rdbuf()->in_avail() > 0) { + if(m_layers_rst[i].second.size > 0) { char lyrnum[6]; std::sprintf(lyrnum, "%.5d", i); auto zfilename = project + lyrnum + ".png"; - writer.next_entry(zfilename); - if(!writer.is_ok()) break; - writer << m_layers_rst[i].second.str(); - // writer << m_layers_rst[i].second.rdbuf(); - // we can keep the date for later calls of this method - //m_layers_rst[i].second.str(""); + writer.binary_entry(zfilename, + m_layers_rst[i].second.buffer.get(), + m_layers_rst[i].second.size); } } } catch(std::exception& e) { diff --git a/src/libslic3r/Rasterizer/Rasterizer.cpp b/src/libslic3r/Rasterizer/Rasterizer.cpp index 0967c84ae..4393f21b8 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -18,6 +18,8 @@ // Experimental minz image write: #include +#include + namespace Slic3r { class Raster::Impl { @@ -211,4 +213,41 @@ void Raster::save(std::ostream& stream, Compression comp) } } +RawBytes Raster::save(Raster::Compression comp) +{ + assert(m_impl); + + RawBytes ret; + + switch(comp) { + case Compression::PNG: { + + void *rawdata = tdefl_write_image_to_png_file_in_memory( + m_impl->buffer().data(), + int(resolution().width_px), + int(resolution().height_px), 1, &ret.size); + + if(rawdata == nullptr) break; + + ret.buffer.reset(static_cast(rawdata)); + + break; + } + case Compression::RAW: { + auto header = std::string("P5 ") + + std::to_string(m_impl->resolution().width_px) + " " + + std::to_string(m_impl->resolution().height_px) + " " + "255 "; + + auto sz = m_impl->buffer().size()*sizeof(Impl::TBuffer::value_type); + + ret.buffer.reset(new std::uint8_t[sz + header.size()]); + + auto buff = reinterpret_cast(m_impl->buffer().data()); + std::copy(buff, buff+sz, ret.buffer.get() + header.size()); + } + } + + return ret; +} + } diff --git a/src/libslic3r/Rasterizer/Rasterizer.hpp b/src/libslic3r/Rasterizer/Rasterizer.hpp index 06d5b88c6..2739605c9 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.hpp +++ b/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -3,11 +3,18 @@ #include #include +#include namespace Slic3r { class ExPolygon; +// Raw byte buffer paired with its size. Suitable for compressed PNG data. +struct RawBytes { + std::unique_ptr buffer = nullptr; + size_t size = 0; +}; + /** * @brief Raster captures an anti-aliased monochrome canvas where vectorial * polygons can be rasterized. Fill color is always white and the background is @@ -87,6 +94,8 @@ public: /// Save the raster on the specified stream. void save(std::ostream& stream, Compression comp = Compression::RAW); + + RawBytes save(Compression comp = Compression::RAW); }; } diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 6e2d7ae0d..0b72a3abb 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -212,6 +212,13 @@ public: inline void next_entry(const std::string& fname) { m_zip.add_entry(fname); } + inline void binary_entry(const std::string& fname, + const std::uint8_t* buf, + size_t l) + { + m_zip.add_entry(fname, buf, l); + } + inline std::string get_name() const { return m_zip.get_name(); } diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp index 941d9719d..a318d659a 100644 --- a/src/libslic3r/Zipper.cpp +++ b/src/libslic3r/Zipper.cpp @@ -149,6 +149,23 @@ void Zipper::add_entry(const std::string &name) m_entry = name; } +void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l) +{ + finish_entry(); + mz_uint cmpr = MZ_NO_COMPRESSION; + switch (m_compression) { + case NO_COMPRESSION: cmpr = MZ_NO_COMPRESSION; break; + case FAST_COMPRESSION: cmpr = MZ_BEST_SPEED; break; + case TIGHT_COMPRESSION: cmpr = MZ_BEST_COMPRESSION; break; + } + + if(!mz_zip_writer_add_mem(&m_impl->arch, name.c_str(), data, l, cmpr)) + m_impl->blow_up(); + + m_entry.clear(); + m_data.clear(); +} + void Zipper::finish_entry() { if(!m_data.empty() > 0 && !m_entry.empty()) { diff --git a/src/libslic3r/Zipper.hpp b/src/libslic3r/Zipper.hpp index 526ffed2e..a7b0c6e7f 100644 --- a/src/libslic3r/Zipper.hpp +++ b/src/libslic3r/Zipper.hpp @@ -46,6 +46,9 @@ public: /// The previous entry is finished (see finish_entry) void add_entry(const std::string& name); + /// Add a new binary file entry with an instantly given byte buffer. + void add_entry(const std::string& name, const std::uint8_t* data, size_t l); + // Writing data to the archive works like with standard streams. The target // within the zip file is the entry created with the add_entry method.