mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-20 05:07:51 -06:00
ENH: Open Prinables.com Links and Zip Archives (#3823)
* Enable ability to open `prusaslicer://` links * Add needed function to miniz * Import Zip Functionality Allows zip file to be drag and dropped or imported via the menu option Based on prusa3d/PrusaSlicer@ce38e57 and current master branch files * Update dialog style to match Orca * Ensure link is from printables * add toggle option in preferences doesn't actually control anything yet * Add Downloader classes As-is from PS master * Create Orca Styled Variant of Icons * Add Icons to ImGui * Use PS's Downloader impl for `prusaslicer://` links * Implement URL Registering on Windows * Implement prusaslicer:// link on macOS * Remove unnecessary class name qualifier in Plater.hpp * Add downloader desktop integration registration and undo * Revert Info.plist --------- Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
parent
0dbf610226
commit
a764d836e1
39 changed files with 3109 additions and 41 deletions
147
src/libslic3r/Format/ZipperArchiveImport.cpp
Normal file
147
src/libslic3r/Format/ZipperArchiveImport.cpp
Normal file
|
@ -0,0 +1,147 @@
|
|||
///|/ Copyright (c) Prusa Research 2022 - 2023 Tomáš Mészáros @tamasmeszaros, David Kocík @kocikdav
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "ZipperArchiveImport.hpp"
|
||||
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
#include "libslic3r/Exception.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace {
|
||||
|
||||
// Read an ini file into boost property tree
|
||||
boost::property_tree::ptree read_ini(const mz_zip_archive_file_stat &entry,
|
||||
MZ_Archive &zip)
|
||||
{
|
||||
std::string buf(size_t(entry.m_uncomp_size), '\0');
|
||||
|
||||
if (!mz_zip_reader_extract_to_mem(&zip.arch, entry.m_file_index,
|
||||
buf.data(), buf.size(), 0))
|
||||
throw Slic3r::FileIOError(zip.get_errorstr());
|
||||
|
||||
boost::property_tree::ptree tree;
|
||||
std::stringstream ss(buf);
|
||||
boost::property_tree::read_ini(ss, tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
// Read an arbitrary file into EntryBuffer
|
||||
EntryBuffer read_entry(const mz_zip_archive_file_stat &entry,
|
||||
MZ_Archive &zip,
|
||||
const std::string &name)
|
||||
{
|
||||
std::vector<uint8_t> buf(entry.m_uncomp_size);
|
||||
|
||||
if (!mz_zip_reader_extract_to_mem(&zip.arch, entry.m_file_index,
|
||||
buf.data(), buf.size(), 0))
|
||||
throw Slic3r::FileIOError(zip.get_errorstr());
|
||||
|
||||
return {std::move(buf), (name.empty() ? entry.m_filename : name)};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ZipperArchive read_zipper_archive(const std::string &zipfname,
|
||||
const std::vector<std::string> &includes,
|
||||
const std::vector<std::string> &excludes)
|
||||
{
|
||||
ZipperArchive arch;
|
||||
|
||||
// Little RAII
|
||||
struct Arch : public MZ_Archive
|
||||
{
|
||||
Arch(const std::string &fname)
|
||||
{
|
||||
if (!open_zip_reader(&arch, fname))
|
||||
throw Slic3r::FileIOError(get_errorstr());
|
||||
}
|
||||
|
||||
~Arch() { close_zip_reader(&arch); }
|
||||
} zip(zipfname);
|
||||
|
||||
mz_uint num_entries = mz_zip_reader_get_num_files(&zip.arch);
|
||||
|
||||
for (mz_uint i = 0; i < num_entries; ++i) {
|
||||
mz_zip_archive_file_stat entry;
|
||||
|
||||
if (mz_zip_reader_file_stat(&zip.arch, i, &entry)) {
|
||||
std::string name = entry.m_filename;
|
||||
boost::algorithm::to_lower(name);
|
||||
|
||||
if (!std::any_of(includes.begin(), includes.end(),
|
||||
[&name](const std::string &incl) {
|
||||
return boost::algorithm::contains(name, incl);
|
||||
}))
|
||||
continue;
|
||||
|
||||
if (std::any_of(excludes.begin(), excludes.end(),
|
||||
[&name](const std::string &excl) {
|
||||
return boost::algorithm::contains(name, excl);
|
||||
}))
|
||||
continue;
|
||||
|
||||
if (name == CONFIG_FNAME) {
|
||||
arch.config = read_ini(entry, zip);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name == PROFILE_FNAME) {
|
||||
arch.profile = read_ini(entry, zip);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = std::lower_bound(
|
||||
arch.entries.begin(), arch.entries.end(),
|
||||
EntryBuffer{{}, name},
|
||||
[](const EntryBuffer &r1, const EntryBuffer &r2) {
|
||||
return std::less<std::string>()(r1.fname, r2.fname);
|
||||
});
|
||||
|
||||
arch.entries.insert(it, read_entry(entry, zip, name));
|
||||
}
|
||||
}
|
||||
|
||||
return arch;
|
||||
}
|
||||
|
||||
std::pair<DynamicPrintConfig, ConfigSubstitutions> extract_profile(
|
||||
const ZipperArchive &arch, DynamicPrintConfig &profile_out)
|
||||
{
|
||||
DynamicPrintConfig profile_in, profile_use;
|
||||
ConfigSubstitutions config_substitutions =
|
||||
profile_in.load(arch.profile,
|
||||
ForwardCompatibilitySubstitutionRule::Enable);
|
||||
|
||||
if (profile_in.empty()) { // missing profile... do guess work
|
||||
// try to recover the layer height from the config.ini which was
|
||||
// present in all versions of sl1 files.
|
||||
if (auto lh_opt = arch.config.find("layerHeight");
|
||||
lh_opt != arch.config.not_found()) {
|
||||
auto lh_str = lh_opt->second.data();
|
||||
|
||||
size_t pos = 0;
|
||||
double lh = string_to_double_decimal_point(lh_str, &pos);
|
||||
if (pos) { // TODO: verify that pos is 0 when parsing fails
|
||||
profile_out.set("layer_height", lh);
|
||||
profile_out.set("initial_layer_height", lh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the archive contains an empty profile, use the one that was passed
|
||||
// as output argument then replace it with the readed profile to report
|
||||
// that it was empty.
|
||||
profile_use = profile_in.empty() ? profile_out : profile_in;
|
||||
profile_out = profile_in;
|
||||
|
||||
return {profile_use, std::move(config_substitutions)};
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
58
src/libslic3r/Format/ZipperArchiveImport.hpp
Normal file
58
src/libslic3r/Format/ZipperArchiveImport.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
///|/ Copyright (c) Prusa Research 2022 Tomáš Mészáros @tamasmeszaros
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef ZIPPERARCHIVEIMPORT_HPP
|
||||
#define ZIPPERARCHIVEIMPORT_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Buffer for arbitraryfiles inside a zipper archive.
|
||||
struct EntryBuffer
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
std::string fname;
|
||||
};
|
||||
|
||||
// Structure holding the data read from a zipper archive.
|
||||
struct ZipperArchive
|
||||
{
|
||||
boost::property_tree::ptree profile, config;
|
||||
std::vector<EntryBuffer> entries;
|
||||
};
|
||||
|
||||
// Names of the files containing metadata inside the archive.
|
||||
const constexpr char *CONFIG_FNAME = "config.ini";
|
||||
const constexpr char *PROFILE_FNAME = "prusaslicer.ini";
|
||||
|
||||
// Read an archive that was written using the Zipper class.
|
||||
// The includes parameter is a set of file name substrings that the entries
|
||||
// must contain to be included in ZipperArchive.
|
||||
// The excludes parameter may contain substrings that filenames must not
|
||||
// contain.
|
||||
// Every file in the archive is read into ZipperArchive::entries
|
||||
// except the files CONFIG_FNAME, and PROFILE_FNAME which are read into
|
||||
// ZipperArchive::config and ZipperArchive::profile structures.
|
||||
ZipperArchive read_zipper_archive(const std::string &zipfname,
|
||||
const std::vector<std::string> &includes,
|
||||
const std::vector<std::string> &excludes);
|
||||
|
||||
// Extract the print profile form the archive into 'out'.
|
||||
// Returns a profile that has correct parameters to use for model reconstruction
|
||||
// even if the needed parameters were not fully found in the archive's metadata.
|
||||
// The inout argument shall be a usable fallback profile if the archive
|
||||
// has totally corrupted metadata.
|
||||
std::pair<DynamicPrintConfig, ConfigSubstitutions> extract_profile(
|
||||
const ZipperArchive &arch, DynamicPrintConfig &inout);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ZIPPERARCHIVEIMPORT_HPP
|
Loading…
Add table
Add a link
Reference in a new issue