diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 3e0af50c2..5bd4ea2b6 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -161,6 +161,8 @@ add_library(libslic3r STATIC
     utils.cpp
     Utils.hpp
     MTUtils.hpp
+    Zipper.hpp
+    Zipper.cpp
     SLA/SLABoilerPlate.hpp
     SLA/SLABasePool.hpp
     SLA/SLABasePool.cpp
diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp
index df9446cf5..99a2110b3 100644
--- a/src/libslic3r/PrintExport.hpp
+++ b/src/libslic3r/PrintExport.hpp
@@ -97,7 +97,7 @@ public:
 
     bool is_ok() { return false; }
 
-    template<class T> LayerWriter& operator<<(const T& /*arg*/) {
+    template<class T> LayerWriter& operator<<(T&& /*arg*/) {
         return *this;
     }
 
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index c06e2fc77..6e2d7ae0d 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -6,6 +6,7 @@
 #include "PrintExport.hpp"
 #include "Point.hpp"
 #include "MTUtils.hpp"
+#include "Zipper.hpp"
 
 namespace Slic3r {
 
@@ -200,6 +201,32 @@ struct SLAPrintStatistics
     }
 };
 
+struct SLAminzZipper {};
+
+// The implementation of creating zipped archives with wxWidgets
+template<> class LayerWriter<SLAminzZipper> {
+    Zipper m_zip;
+public:
+
+    inline LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {}
+
+    inline void next_entry(const std::string& fname) { m_zip.add_entry(fname); }
+
+    inline std::string get_name() const {
+        return m_zip.get_name();
+    }
+
+    template<class T> inline LayerWriter& operator<<(T&& arg) {
+        m_zip << std::forward<T>(arg); return *this;
+    }
+
+    bool is_ok() const {
+        return true; // m_zip blows up if something goes wrong...
+    }
+
+    inline void close() { /* m_zip closes upon destruction */ }
+};
+
 /**
  * @brief This class is the high level FSM for the SLA printing process.
  *
@@ -231,9 +258,11 @@ public:
     // Returns true if the last step was finished with success.
 	bool                finished() const override { return this->is_step_done(slaposIndexSlices) && this->Inherited::is_step_done(slapsRasterize); }
 
-    template<class Fmt> void export_raster(const std::string& fname) {
+    template<class Fmt = SLAminzZipper>
+    void export_raster(const std::string& fname) {
         if(m_printer) m_printer->save<Fmt>(fname);
     }
+
     const PrintObjects& objects() const { return m_objects; }
 
 	std::string         output_filename() const override;
diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp
new file mode 100644
index 000000000..941d9719d
--- /dev/null
+++ b/src/libslic3r/Zipper.cpp
@@ -0,0 +1,177 @@
+#include <exception>
+#include <sstream>
+#include <iostream>
+
+#include "Zipper.hpp"
+#include "miniz/miniz_zip.h"
+#include <boost/filesystem/path.hpp>
+
+#include "I18N.hpp"
+
+//! macro used to mark string used at localization,
+//! return same string
+#define L(s) Slic3r::I18N::translate(s)
+
+#if defined(_MSC_VER) &&  _MSC_VER <= 1800 || __cplusplus < 201103L
+    #define SLIC3R_NORETURN
+#elif __cplusplus >= 201103L
+    #define SLIC3R_NORETURN [[noreturn]]
+#endif
+
+namespace Slic3r {
+
+class Zipper::Impl {
+public:
+    mz_zip_archive arch;
+    std::string m_zipname;
+
+    std::string get_errorstr(mz_zip_error mz_err)
+    {
+        switch (mz_err)
+        {
+            case MZ_ZIP_NO_ERROR:
+                return "no error";
+            case MZ_ZIP_UNDEFINED_ERROR:
+                return L("undefined error");
+            case MZ_ZIP_TOO_MANY_FILES:
+                return L("too many files");
+            case MZ_ZIP_FILE_TOO_LARGE:
+                return L("file too large");
+            case MZ_ZIP_UNSUPPORTED_METHOD:
+                return L("unsupported method");
+            case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
+                return L("unsupported encryption");
+            case MZ_ZIP_UNSUPPORTED_FEATURE:
+                return L("unsupported feature");
+            case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
+                return L("failed finding central directory");
+            case MZ_ZIP_NOT_AN_ARCHIVE:
+                return L("not a ZIP archive");
+            case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
+                return L("invalid header or archive is corrupted");
+            case MZ_ZIP_UNSUPPORTED_MULTIDISK:
+                return L("unsupported multidisk archive");
+            case MZ_ZIP_DECOMPRESSION_FAILED:
+                return L("decompression failed or archive is corrupted");
+            case MZ_ZIP_COMPRESSION_FAILED:
+                return L("compression failed");
+            case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
+                return L("unexpected decompressed size");
+            case MZ_ZIP_CRC_CHECK_FAILED:
+                return L("CRC-32 check failed");
+            case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
+                return L("unsupported central directory size");
+            case MZ_ZIP_ALLOC_FAILED:
+                return L("allocation failed");
+            case MZ_ZIP_FILE_OPEN_FAILED:
+                return L("file open failed");
+            case MZ_ZIP_FILE_CREATE_FAILED:
+                return L("file create failed");
+            case MZ_ZIP_FILE_WRITE_FAILED:
+                return L("file write failed");
+            case MZ_ZIP_FILE_READ_FAILED:
+                return L("file read failed");
+            case MZ_ZIP_FILE_CLOSE_FAILED:
+                return L("file close failed");
+            case MZ_ZIP_FILE_SEEK_FAILED:
+                return L("file seek failed");
+            case MZ_ZIP_FILE_STAT_FAILED:
+                return L("file stat failed");
+            case MZ_ZIP_INVALID_PARAMETER:
+                return L("invalid parameter");
+            case MZ_ZIP_INVALID_FILENAME:
+                return L("invalid filename");
+            case MZ_ZIP_BUF_TOO_SMALL:
+                return L("buffer too small");
+            case MZ_ZIP_INTERNAL_ERROR:
+                return L("internal error");
+            case MZ_ZIP_FILE_NOT_FOUND:
+                return L("file not found");
+            case MZ_ZIP_ARCHIVE_TOO_LARGE:
+                return L("archive is too large");
+            case MZ_ZIP_VALIDATION_FAILED:
+                return L("validation failed");
+            case MZ_ZIP_WRITE_CALLBACK_FAILED:
+                return L("write calledback failed");
+            default:
+                break;
+        }
+
+        return "unknown error";
+    }
+
+    SLIC3R_NORETURN void blow_up() {
+        std::string prefix(L("Error with zip archive"));
+        throw std::runtime_error(prefix + " " + m_zipname + ": " +
+                                 get_errorstr(arch.m_last_error) + "!");
+    }
+};
+
+Zipper::Zipper(const std::string &zipfname, e_compression compression)
+{
+    m_impl.reset(new Impl());
+
+    m_compression = compression;
+    m_impl->m_zipname = zipfname;
+
+    memset(&m_impl->arch, 0, sizeof(m_impl->arch));
+
+    // Initialize the archive data
+    if(!mz_zip_writer_init_file(&m_impl->arch, zipfname.c_str(), 0))
+        m_impl->blow_up();
+}
+
+Zipper::~Zipper()
+{
+    finish_entry();
+
+    if(!mz_zip_writer_finalize_archive(&m_impl->arch)) m_impl->blow_up();
+    if(!mz_zip_writer_end(&m_impl->arch)) m_impl->blow_up();
+}
+
+Zipper::Zipper(Zipper &&m):
+    m_impl(std::move(m.m_impl)),
+    m_data(std::move(m.m_data)),
+    m_entry(std::move(m.m_entry)),
+    m_compression(m.m_compression) {}
+
+Zipper &Zipper::operator=(Zipper &&m) {
+    m_impl = std::move(m.m_impl);
+    m_data = std::move(m.m_data);
+    m_entry = std::move(m.m_entry);
+    m_compression = m.m_compression;
+    return *this;
+}
+
+void Zipper::add_entry(const std::string &name)
+{
+    finish_entry(); // finish previous business
+    m_entry = name;
+}
+
+void Zipper::finish_entry()
+{
+    if(!m_data.empty() > 0 && !m_entry.empty()) {
+        mz_uint compression = MZ_NO_COMPRESSION;
+
+        switch (m_compression) {
+        case NO_COMPRESSION: compression = MZ_NO_COMPRESSION; break;
+        case FAST_COMPRESSION: compression = MZ_BEST_SPEED; break;
+        case TIGHT_COMPRESSION: compression = MZ_BEST_COMPRESSION; break;
+        }
+
+        if(!mz_zip_writer_add_mem(&m_impl->arch, m_entry.c_str(),
+                                  m_data.c_str(),
+                                  m_data.size(),
+                                  compression)) m_impl->blow_up();
+    }
+
+    m_data.clear();
+    m_entry.clear();
+}
+
+std::string Zipper::get_name() const {
+    return boost::filesystem::path(m_impl->m_zipname).stem().string();
+}
+
+}
diff --git a/src/libslic3r/Zipper.hpp b/src/libslic3r/Zipper.hpp
new file mode 100644
index 000000000..526ffed2e
--- /dev/null
+++ b/src/libslic3r/Zipper.hpp
@@ -0,0 +1,83 @@
+#ifndef ZIPPER_HPP
+#define ZIPPER_HPP
+
+#include <string>
+#include <memory>
+
+namespace Slic3r {
+
+// Class for creating zip archives.
+class Zipper {
+public:
+    // Three compression levels supported
+    enum e_compression {
+        NO_COMPRESSION,
+        FAST_COMPRESSION,
+        TIGHT_COMPRESSION
+    };
+
+private:
+    class Impl;
+    std::unique_ptr<Impl> m_impl;
+    std::string m_data;
+    std::string m_entry;
+    e_compression m_compression;
+
+public:
+
+    // Will blow up in a runtime exception if the file cannot be created.
+    explicit Zipper(const std::string& zipfname,
+                    e_compression level = NO_COMPRESSION);
+    ~Zipper();
+
+    // No copies allwed, this is a file resource...
+    Zipper(const Zipper&) = delete;
+    Zipper& operator=(const Zipper&) = delete;
+
+    // Moving is fine.
+    // Zipper(Zipper&&) = default;
+    // Zipper& operator=(Zipper&&) = default;
+    // All becouse of VS2013:
+    Zipper(Zipper &&m);
+    Zipper& operator=(Zipper &&m);
+
+    /// Adding an entry means a file inside the new archive. Name param is the
+    /// name of the new file. To create directories, append a forward slash.
+    /// The previous entry is finished (see finish_entry)
+    void add_entry(const std::string& name);
+
+    // 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.
+
+    // Template taking only arithmetic values, that std::to_string can handle.
+    template<class T> inline
+    typename std::enable_if<std::is_arithmetic<T>::value, Zipper&>::type
+    operator<<(T &&val) {
+        return this->operator<<(std::to_string(std::forward<T>(val)));
+    }
+
+    // Template applied only for types that std::string can handle for append
+    // and copy. This includes c style strings...
+    template<class T> inline
+    typename std::enable_if<!std::is_arithmetic<T>::value, Zipper&>::type
+    operator<<(T &&val) {
+        if(m_data.empty()) m_data = std::forward<T>(val);
+        else m_data.append(val);
+        return *this;
+    }
+
+    /// Finishing an entry means that subsequent writes will no longer be
+    /// appended to the previous entry. They will be written into the internal
+    /// buffer and ones an entry is added, the buffer will bind to the new entry
+    /// If the buffer was written, but no entry was added, the buffer will be
+    /// cleared after this call.
+    void finish_entry();
+
+    /// Gets the name of the archive without the path or extension.
+    std::string get_name() const;
+};
+
+
+}
+
+#endif // ZIPPER_HPP
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index 7c2f6c68c..2601842ef 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -92,64 +92,13 @@ void BackgroundSlicingProcess::process_fff()
 	}
 }
 
-// Pseudo type for specializing LayerWriter trait class
-struct SLAZipFmt {};
-
-// The implementation of creating zipped archives with wxWidgets
-template<> class LayerWriter<SLAZipFmt> {
-    wxFileName fpath;
-    wxFFileOutputStream zipfile;
-    wxZipOutputStream zipstream;
-    wxStdOutputStream pngstream;
-
-public:
-
-    inline LayerWriter(const std::string& zipfile_path):
-        fpath(zipfile_path),
-        zipfile(zipfile_path),
-        zipstream(zipfile),
-        pngstream(zipstream)
-    {
-        if(!is_ok())
-            throw std::runtime_error("Cannot create zip file.");
-    }
-
-    ~LayerWriter() {
-        // In case of an error (disk space full) zipstream destructor would
-        // crash.
-        pngstream.clear();
-        zipstream.CloseEntry();
-    }
-
-    inline void next_entry(const std::string& fname) {
-        zipstream.PutNextEntry(fname);
-    }
-
-    inline std::string get_name() const {
-        return fpath.GetName().ToUTF8().data();
-    }
-
-    template<class T> inline LayerWriter& operator<<(const T& arg) {
-        pngstream << arg; return *this;
-    }
-
-    bool is_ok() const {
-        return pngstream.good() && zipstream.IsOk() && zipfile.IsOk();
-    }
-
-    inline void close() {
-        zipstream.Close();
-        zipfile.Close();
-    }
-};
-
 void BackgroundSlicingProcess::process_sla()
 {
     assert(m_print == m_sla_print);
     m_print->process();
     if (this->set_step_started(bspsGCodeFinalize)) {
         if (! m_export_path.empty()) {
-            m_sla_print->export_raster<SLAZipFmt>(m_export_path);
+            m_sla_print->export_raster(m_export_path);
             m_print->set_status(100, "Masked SLA file exported to " + m_export_path);
         } else if (! m_upload_job.empty()) {
             prepare_upload();
@@ -449,8 +398,8 @@ void BackgroundSlicingProcess::prepare_upload()
 		}
 		run_post_process_scripts(source_path.string(), m_fff_print->config());
 		m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
-	} else {
-		m_sla_print->export_raster<SLAZipFmt>(source_path.string());
+    } else {
+        m_sla_print->export_raster(source_path.string());
 		// TODO: Also finalize upload path like with FFF when there are statistics for SLA print
 	}