From b1b8eee3c997ea693de9fbb61eea84fca5d5b5a5 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Thu, 6 Jan 2022 11:29:16 +0100 Subject: [PATCH] add is italic check for font file --- src/libslic3r/Emboss.cpp | 57 ++++++++++++--- src/libslic3r/Emboss.hpp | 8 +++ tests/libslic3r/test_emboss.cpp | 27 +++++++ tests/libslic3r/test_indexed_triangle_set.cpp | 71 ------------------- 4 files changed, 82 insertions(+), 81 deletions(-) diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index b3dcdf4b36..da7353e515 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -45,12 +45,12 @@ std::optional Private::load_font_info(const Emboss::Font &font) { int font_offset = stbtt_GetFontOffsetForIndex(font.buffer.data(), font.index); if (font_offset < 0) { - std::cerr << "Font index("< Emboss::load_font(std::vector data) --index; // last one is bad // at least one font must be inside collection if (index < 1) { - std::cerr << "There is no font collection inside data."; + std::cerr << "There is no font collection inside data." << std::endl; return {}; } // select default font on index 0 @@ -457,18 +457,18 @@ std::optional Emboss::load_font(const char *file_path) { FILE *file = fopen(file_path, "rb"); if (file == nullptr) { - std::cerr << "Couldn't open " << file_path << " for reading."; + std::cerr << "Couldn't open " << file_path << " for reading." << std::endl; return {}; } // find size of file if (fseek(file, 0L, SEEK_END) != 0) { - std::cerr << "Couldn't fseek file " << file_path << " for size measure."; + std::cerr << "Couldn't fseek file " << file_path << " for size measure." << std::endl; return {}; } size_t size = ftell(file); if (size == 0) { - std::cerr << "Size of font file is zero. Can't read."; + std::cerr << "Size of font file is zero. Can't read." << std::endl; return {}; } rewind(file); @@ -476,7 +476,7 @@ std::optional Emboss::load_font(const char *file_path) std::vector buffer(size); size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file); if (count_loaded_bytes != size) { - std::cerr << "Different loaded(from file) data size."; + std::cerr << "Different loaded(from file) data size." << std::endl; return {}; } return load_font(std::move(buffer)); @@ -488,7 +488,7 @@ std::optional Emboss::load_font(HFONT hfont) { HDC hdc = ::CreateCompatibleDC(NULL); if (hdc == NULL) { - std::cerr << "Can't create HDC by CreateCompatibleDC(NULL)."; + std::cerr << "Can't create HDC by CreateCompatibleDC(NULL)." << std::endl; return {}; } @@ -506,7 +506,7 @@ std::optional Emboss::load_font(HFONT hfont) } if (size == 0 || size == GDI_ERROR) { - std::cerr << "HFONT doesn't have size."; + std::cerr << "HFONT doesn't have size." << std::endl; ::DeleteDC(hdc); return {}; } @@ -515,7 +515,7 @@ std::optional Emboss::load_font(HFONT hfont) size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer.data(), size); ::DeleteDC(hdc); if (size != loaded_size) { - std::cerr << "Different loaded(from HFONT) data size."; + std::cerr << "Different loaded(from HFONT) data size." << std::endl; return {}; } @@ -601,6 +601,43 @@ ExPolygons Emboss::text2shapes(Font & font, return Private::dilate_to_unique_points(result); } +bool Emboss::is_italic(Font &font) { + std::optional font_info_opt = + Private::load_font_info(font); + + if (!font_info_opt.has_value()) return false; + stbtt_fontinfo *info = &(*font_info_opt); + + // https://docs.microsoft.com/cs-cz/typography/opentype/spec/name + // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html + // 2 ==> Style / Subfamily name + int name_id = 2; + int length; + const char* value = stbtt_GetFontNameString(info, &length, + STBTT_PLATFORM_ID_MICROSOFT, + STBTT_MS_EID_UNICODE_BMP, + STBTT_MS_LANG_ENGLISH, + name_id); + + // value is big endian utf-16 i need extract only normal chars + std::string value_str; + value_str.reserve(length / 2); + for (int i = 1; i < length; i += 2) + value_str.push_back(value[i]); + + // lower case + std::transform(value_str.begin(), value_str.end(), value_str.begin(), + [](unsigned char c) { return std::tolower(c); }); + + const std::vector italics({"italic", "oblique"}); + for (const std::string &it : italics) { + if (value_str.find(it) != std::string::npos) { + return true; + } + } + return false; +} + indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d, const IProject &projection) { diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 9c63210c6f..541975d547 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -102,6 +102,14 @@ public: const char * text, const FontProp &font_prop); + /// + /// Read information from naming table of font file + /// search for italic (or oblique), bold italic (or bold oblique) + /// + /// Selector of font + /// True when the font description contains italic/obligue otherwise False + static bool is_italic(Font &font); + /// /// Project 2d point into space /// Could be plane, sphere, cylindric, ... diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp index ef58288ee4..13cdaf29c6 100644 --- a/tests/libslic3r/test_emboss.cpp +++ b/tests/libslic3r/test_emboss.cpp @@ -177,4 +177,31 @@ TEST_CASE("triangle intersection", "[]") Vec2d i = Private::get_intersection(point, dir, triangle); CHECK(abs(i.x()) < std::numeric_limits::epsilon()); CHECK(abs(i.y() - 1.) < std::numeric_limits::epsilon()); +} + +#include +#include +#include +namespace fs = std::filesystem; +TEST_CASE("Italic check", "[]") +{ + //std::string s1 = "italic"; + //std::string s2 = "italic"; + //auto pos = s1.find(s2); + //std::cout << ((pos != std::string::npos) ? "good" : "bad"); + + std::string dir_path = "C:/Windows/Fonts"; + for (const auto &entry : fs::directory_iterator(dir_path)) { + if (entry.is_directory()) continue; + const fs::path& act_path = entry.path(); + std::string ext = act_path.extension().u8string(); + std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { return std::tolower(c); }); + if (ext != ".ttf") continue; + std::string path_str = act_path.u8string(); + auto font_opt = Emboss::load_font(path_str.c_str()); + if (!font_opt.has_value()) continue; + + std::cout << ((Emboss::is_italic(*font_opt)) ? "[yes] " : "[no ] ") + << entry.path() << std::endl; + } } \ No newline at end of file diff --git a/tests/libslic3r/test_indexed_triangle_set.cpp b/tests/libslic3r/test_indexed_triangle_set.cpp index 0bb85b7ed0..b6aad9dcf4 100644 --- a/tests/libslic3r/test_indexed_triangle_set.cpp +++ b/tests/libslic3r/test_indexed_triangle_set.cpp @@ -215,50 +215,6 @@ bool is_similar(const indexed_triangle_set &from, return true; } -TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]") -{ - indexed_triangle_set its; - its.vertices = {Vec3f(-1.f, 0.f, 0.f), Vec3f(0.f, 1.f, 0.f), - Vec3f(1.f, 0.f, 0.f), Vec3f(0.f, 0.f, 1.f), - // vertex to be removed - Vec3f(0.9f, .1f, -.1f)}; - its.indices = {Vec3i(1, 0, 3), Vec3i(2, 1, 3), Vec3i(0, 2, 3), - Vec3i(0, 1, 4), Vec3i(1, 2, 4), Vec3i(2, 0, 4)}; - // edge to remove is between vertices 2 and 4 on trinagles 4 and 5 - - indexed_triangle_set its_ = its; // copy - // its_write_obj(its, "tetrhedron_in.obj"); - uint32_t wanted_count = its.indices.size() - 1; - its_quadric_edge_collapse(its, wanted_count); - // its_write_obj(its, "tetrhedron_out.obj"); - CHECK(its.indices.size() == 4); - CHECK(its.vertices.size() == 4); - - for (size_t i = 0; i < 3; i++) { - CHECK(its.indices[i] == its_.indices[i]); - } - - for (size_t i = 0; i < 4; i++) { - if (i == 2) continue; - CHECK(its.vertices[i] == its_.vertices[i]); - } - - const Vec3f &v = its.vertices[2]; // new vertex - const Vec3f &v2 = its_.vertices[2]; // moved vertex - const Vec3f &v4 = its_.vertices[4]; // removed vertex - for (size_t i = 0; i < 3; i++) { - bool is_between = (v[i] < v4[i] && v[i] > v2[i]) || - (v[i] > v4[i] && v[i] < v2[i]); - CHECK(is_between); - } - CompareConfig cfg; - cfg.max_average_distance = 0.014f; - cfg.max_distance = 0.75f; - - CHECK(is_similar(its, its_, cfg)); - CHECK(is_similar(its_, its, cfg)); -} - #include "test_utils.hpp" TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]") { @@ -282,30 +238,3 @@ TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]") CHECK(is_similar(its, mesh.its, cfg)); } -bool exist_triangle_with_twice_vertices(const std::vector& indices) -{ - for (const auto &face : indices) - if (face[0] == face[1] || - face[0] == face[2] || - face[1] == face[2]) return true; - return false; -} - -TEST_CASE("Simplify trouble case", "[its]") -{ - TriangleMesh tm = load_model("simplification.obj"); - REQUIRE_FALSE(tm.empty()); - float max_error = std::numeric_limits::max(); - uint32_t wanted_count = 0; - its_quadric_edge_collapse(tm.its, wanted_count, &max_error); - CHECK(!exist_triangle_with_twice_vertices(tm.its.indices)); -} - -TEST_CASE("Simplified cube should not be empty.", "[its]") -{ - auto its = its_make_cube(1, 2, 3); - float max_error = std::numeric_limits::max(); - uint32_t wanted_count = 0; - its_quadric_edge_collapse(its, wanted_count, &max_error); - CHECK(!its.indices.empty()); -}