Text configuration serialize / deserialize to metadata string
This commit is contained in:
parent
28528c8344
commit
8792331516
3 changed files with 97 additions and 73 deletions
|
@ -121,6 +121,7 @@ static constexpr const char* VOLUME_TYPE = "volume";
|
|||
|
||||
static constexpr const char* NAME_KEY = "name";
|
||||
static constexpr const char* MODIFIER_KEY = "modifier";
|
||||
static constexpr const char* TEXT_CONFIGURATION_KEY = "text_configuration";
|
||||
static constexpr const char* VOLUME_TYPE_KEY = "volume_type";
|
||||
static constexpr const char* MATRIX_KEY = "matrix";
|
||||
static constexpr const char* SOURCE_FILE_KEY = "source_file";
|
||||
|
@ -1985,6 +1986,8 @@ namespace Slic3r {
|
|||
volume->set_type(ModelVolumeType::PARAMETER_MODIFIER);
|
||||
else if (metadata.key == VOLUME_TYPE_KEY)
|
||||
volume->set_type(ModelVolume::type_from_string(metadata.value));
|
||||
else if (metadata.key == TEXT_CONFIGURATION_KEY)
|
||||
volume->text_configuration = TextConfigurationSerialization::deserialize(metadata.value);
|
||||
else if (metadata.key == SOURCE_FILE_KEY)
|
||||
volume->source.input_file = metadata.value;
|
||||
else if (metadata.key == SOURCE_OBJECT_ID_KEY)
|
||||
|
@ -2900,6 +2903,24 @@ namespace Slic3r {
|
|||
|
||||
bool _3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data)
|
||||
{
|
||||
enum class MetadataType{
|
||||
object,
|
||||
volume
|
||||
};
|
||||
|
||||
auto add_metadata = [](std::stringstream &stream, unsigned indent, MetadataType type,
|
||||
const std::string &key, const std::string &value) {
|
||||
const char *type_value;
|
||||
switch (type) {
|
||||
case MetadataType::object: type_value = OBJECT_TYPE; break;
|
||||
case MetadataType::volume: type_value = VOLUME_TYPE; break;
|
||||
};
|
||||
stream << std::string(indent, ' ') << '<' << METADATA_TAG << " "
|
||||
<< TYPE_ATTR << "=\"" << type_value << "\" "
|
||||
<< KEY_ATTR << "=\"" << key << "\" "
|
||||
<< VALUE_ATTR << "=\"" << value << "\"/>\n";
|
||||
};
|
||||
|
||||
std::stringstream stream;
|
||||
// Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
|
||||
// when loaded as accurately as possible.
|
||||
|
@ -2914,13 +2935,11 @@ namespace Slic3r {
|
|||
stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << obj_metadata.first << "\" " << INSTANCESCOUNT_ATTR << "=\"" << obj->instances.size() << "\">\n";
|
||||
|
||||
// stores object's name
|
||||
if (!obj->name.empty())
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << xml_escape(obj->name) << "\"/>\n";
|
||||
|
||||
if (!obj->name.empty())
|
||||
add_metadata(stream, 2, MetadataType::object, "name", xml_escape(obj->name));
|
||||
// stores object's config data
|
||||
for (const std::string& key : obj->config.keys()) {
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << obj->config.opt_serialize(key) << "\"/>\n";
|
||||
}
|
||||
for (const std::string& key : obj->config.keys())
|
||||
add_metadata(stream, 2, MetadataType::object, key, obj->config.opt_serialize(key));
|
||||
|
||||
for (const ModelVolume* volume : obj_metadata.second.object->volumes) {
|
||||
if (volume != nullptr) {
|
||||
|
@ -2934,18 +2953,18 @@ namespace Slic3r {
|
|||
|
||||
// stores volume's name
|
||||
if (!volume->name.empty())
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n";
|
||||
add_metadata(stream, 3, MetadataType::volume, NAME_KEY, xml_escape(volume->name));
|
||||
|
||||
// stores volume's modifier field (legacy, to support old slicers)
|
||||
if (volume->is_modifier())
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n";
|
||||
add_metadata(stream, 3, MetadataType::volume, MODIFIER_KEY, "1");
|
||||
// stores volume's type (overrides the modifier field above)
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " <<
|
||||
VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n";
|
||||
add_metadata(stream, 3, MetadataType::volume, VOLUME_TYPE_KEY, ModelVolume::type_to_string(volume->type()));
|
||||
|
||||
// stores volume's text data
|
||||
if (volume->text_configuration.has_value())
|
||||
stream << " " << TextConfigurationSerialization::to_string(*volume->text_configuration) << "\n";
|
||||
add_metadata(stream, 3, MetadataType::volume, TEXT_CONFIGURATION_KEY,
|
||||
xml_escape(TextConfigurationSerialization::serialize(*volume->text_configuration)));
|
||||
|
||||
// stores volume's local matrix
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\"";
|
||||
|
@ -2979,10 +2998,9 @@ namespace Slic3r {
|
|||
}
|
||||
|
||||
// stores volume's config data
|
||||
for (const std::string& key : volume->config.keys()) {
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
|
||||
}
|
||||
|
||||
for (const std::string& key : volume->config.keys())
|
||||
add_metadata(stream, 3, MetadataType::volume, key, volume->config.opt_serialize(key));
|
||||
|
||||
stream << " </" << VOLUME_TAG << ">\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,16 @@ const std::map<FontItem::Type, std::string> TextConfigurationSerialization::to_s
|
|||
{FontItem::Type::wx_font_descr, "wx_font_descriptor"}
|
||||
};
|
||||
|
||||
const char TextConfigurationSerialization::separator = '|';
|
||||
|
||||
const std::map<std::string, FontItem::Type> TextConfigurationSerialization::to_type =
|
||||
TextConfigurationSerialization::create_oposit_map(TextConfigurationSerialization::to_string);
|
||||
|
||||
const char TextConfigurationSerialization::separator = '|';
|
||||
|
||||
std::string TextConfigurationSerialization::serialize(const TextConfiguration &text_configuration)
|
||||
{
|
||||
// IMPROVE: make general and move to string utils
|
||||
auto twice_separator = [](const std::string& data) {
|
||||
// no value is one space
|
||||
if (data.empty()) return std::string(" ");
|
||||
std::string::size_type pos = data.find(separator);
|
||||
if (pos == data.npos) return data;
|
||||
|
@ -41,61 +43,67 @@ std::string TextConfigurationSerialization::serialize(const TextConfiguration &t
|
|||
std::to_string(font_prop.line_gap);
|
||||
}
|
||||
|
||||
void TextConfigurationSerialization::to_xml(
|
||||
const TextConfiguration &text_configuration,
|
||||
unsigned count_indent,
|
||||
std::stringstream & stream)
|
||||
std::optional<TextConfiguration> TextConfigurationSerialization::deserialize(const std::string &data)
|
||||
{
|
||||
// Because of back compatibility must be main tag metadata (source: 3mf.cpp)
|
||||
const std::string_view main_tag = "metadata";
|
||||
const std::string_view main_name_attr = "name";
|
||||
const std::string_view main_name_value= "TextConfiguration";
|
||||
|
||||
const std::string_view font_item_tag = "fontItem";
|
||||
const std::string_view name_attr = "name";
|
||||
const std::string_view path_attr = "path";
|
||||
const std::string_view type_attr = "type";
|
||||
|
||||
const std::string_view font_prop_tag = "fontProp";
|
||||
const std::string_view char_gap_attr = "charGap";
|
||||
const std::string_view line_gap_attr = "lineGap";
|
||||
const std::string_view flatness_attr = "flatness";
|
||||
const std::string_view height_attr = "height";
|
||||
const std::string_view depth_attr = "depth";
|
||||
|
||||
const std::string_view text_tag = "text";
|
||||
|
||||
auto get_path = [&text_configuration]() {
|
||||
const std::string &path = text_configuration.font_item.path;
|
||||
return xml_escape(
|
||||
(text_configuration.font_item.type == FontItem::Type::file_path) ?
|
||||
path.substr(path.find_last_of("/\\") + 1) : path);
|
||||
// IMPROVE: make general and move to string utils
|
||||
auto find_separator = [&data](std::string::size_type pos) {
|
||||
pos = data.find(separator, pos);
|
||||
while (pos != data.npos && data[pos + 1] == separator)
|
||||
pos = data.find(separator, pos + 2);
|
||||
return pos;
|
||||
};
|
||||
// IMPROVE: make general and move to string utils
|
||||
auto reduce_separator = [](const std::string& item) {
|
||||
std::string::size_type pos = item.find(separator);
|
||||
if (pos == item.npos) return item;
|
||||
std::string copy = item;
|
||||
do {
|
||||
assert(copy[pos] == separator);
|
||||
assert(copy[pos+1] == separator);
|
||||
copy.erase(pos, size_t(1));
|
||||
pos = copy.find(separator, pos + 1);
|
||||
} while (pos != copy.npos);
|
||||
return copy;
|
||||
};
|
||||
|
||||
std::string indent = std::string(count_indent, ' ');
|
||||
std::string indent2 = std::string(count_indent+1, ' ');
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type size = find_separator(start);
|
||||
auto reduce_and_move = [&data, &start, &size, &reduce_separator, &find_separator]() {
|
||||
if (start == data.npos) return std::string();
|
||||
std::string res = reduce_separator(data.substr(start, size));
|
||||
start = size + 1;
|
||||
size = find_separator(start) - start;
|
||||
return res;
|
||||
};
|
||||
auto get_float_and_move = [&data, &start, &size, &find_separator]() {
|
||||
if (start == data.npos) return 0.f;
|
||||
float res = std::atof(data.substr(start, size).c_str());
|
||||
start = size + 1;
|
||||
size = find_separator(start) - start;
|
||||
return res;
|
||||
};
|
||||
auto get_int_and_move = [&data, &start, &size, &find_separator]() {
|
||||
if (start == data.npos) return 0;
|
||||
int res = std::atoi(data.substr(start, size).c_str());
|
||||
start = size + 1;
|
||||
size = find_separator(start) - start;
|
||||
return res;
|
||||
};
|
||||
|
||||
stream << indent << "<" << main_tag << " " << main_name_attr << "=\"" << main_name_value << "\">\n";
|
||||
stream << indent2 << "<" << font_item_tag
|
||||
<< ' ' << name_attr << "=\"" << xml_escape(text_configuration.font_item.name) << '"'
|
||||
<< ' ' << path_attr << "=\"" << get_path() << '"'
|
||||
<< ' ' << type_attr << "=\"" << to_string.at(text_configuration.font_item.type) << '"'
|
||||
<< "/>\n";
|
||||
stream << indent2 << "<" << font_prop_tag
|
||||
<< ' ' << char_gap_attr << "=\"" << text_configuration.font_prop.char_gap << '"'
|
||||
<< ' ' << line_gap_attr << "=\"" << text_configuration.font_prop.line_gap << '"'
|
||||
<< ' ' << flatness_attr << "=\"" << text_configuration.font_prop.flatness << '"'
|
||||
<< ' ' << height_attr << "=\"" << text_configuration.font_prop.size_in_mm << '"'
|
||||
<< ' ' << depth_attr << "=\"" << text_configuration.font_prop.emboss << '"'
|
||||
<< "/>\n";
|
||||
stream << indent2 << "<" << text_tag << ">";
|
||||
stream << xml_escape(text_configuration.text);
|
||||
stream << indent2 << "</" << text_tag << ">\n";
|
||||
stream << indent << "</" << main_tag << ">\n";
|
||||
}
|
||||
std::string text = reduce_and_move();
|
||||
std::string name = reduce_and_move();
|
||||
std::string path = reduce_and_move();
|
||||
std::string type = reduce_and_move();
|
||||
auto it = to_type.find(type);
|
||||
if (it == to_type.end()) return {}; // no valid type
|
||||
FontItem font_item(name,path,it->second);
|
||||
|
||||
std::optional<TextConfiguration> TextConfigurationSerialization::from_string(const std::string &data)
|
||||
{
|
||||
TextConfiguration tc;
|
||||
return tc;
|
||||
FontProp font_prop;
|
||||
font_prop.emboss = get_float_and_move();
|
||||
font_prop.flatness = get_float_and_move();
|
||||
font_prop.size_in_mm = get_float_and_move();
|
||||
font_prop.char_gap = get_int_and_move();
|
||||
if (start == data.npos) return {}; // no valid data
|
||||
font_prop.line_gap = get_int_and_move();
|
||||
return TextConfiguration(font_item, font_prop, text);
|
||||
}
|
|
@ -15,9 +15,7 @@ class TextConfigurationSerialization
|
|||
public:
|
||||
TextConfigurationSerialization() = delete; // only static functions
|
||||
static std::string serialize(const TextConfiguration &text_configuration);
|
||||
|
||||
static void to_xml(const TextConfiguration &text_configuration, unsigned count_indent, std::stringstream& stream);
|
||||
static std::optional<TextConfiguration> from_string(const std::string &data);
|
||||
static std::optional<TextConfiguration> deserialize(const std::string &data);
|
||||
|
||||
// convert type to string and vice versa
|
||||
static const std::map<std::string, FontItem::Type> to_type;
|
||||
|
@ -25,7 +23,7 @@ public:
|
|||
|
||||
static const char separator;
|
||||
|
||||
// Move to map utility
|
||||
// Move to map utils
|
||||
template<typename Key, typename Value>
|
||||
static std::map<Value, Key> create_oposit_map(
|
||||
const std::map<Key, Value> &map)
|
||||
|
|
Loading…
Reference in a new issue