mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 04:59:01 +08:00
add is italic check for font file
This commit is contained in:
parent
82ee1c5e4a
commit
b1b8eee3c9
@ -45,12 +45,12 @@ std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::Font &font)
|
|||||||
{
|
{
|
||||||
int font_offset = stbtt_GetFontOffsetForIndex(font.buffer.data(), font.index);
|
int font_offset = stbtt_GetFontOffsetForIndex(font.buffer.data(), font.index);
|
||||||
if (font_offset < 0) {
|
if (font_offset < 0) {
|
||||||
std::cerr << "Font index("<<font.index<<") doesn't exist.";
|
std::cerr << "Font index("<<font.index<<") doesn't exist." << std::endl;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
stbtt_fontinfo font_info;
|
stbtt_fontinfo font_info;
|
||||||
if (stbtt_InitFont(&font_info, font.buffer.data(), font_offset) == 0) {
|
if (stbtt_InitFont(&font_info, font.buffer.data(), font_offset) == 0) {
|
||||||
std::cerr << "Can't initialize font.";
|
std::cerr << "Can't initialize font." << std::endl;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return font_info;
|
return font_info;
|
||||||
@ -437,7 +437,7 @@ std::optional<Emboss::Font> Emboss::load_font(std::vector<unsigned char> data)
|
|||||||
--index; // last one is bad
|
--index; // last one is bad
|
||||||
// at least one font must be inside collection
|
// at least one font must be inside collection
|
||||||
if (index < 1) {
|
if (index < 1) {
|
||||||
std::cerr << "There is no font collection inside data.";
|
std::cerr << "There is no font collection inside data." << std::endl;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
// select default font on index 0
|
// select default font on index 0
|
||||||
@ -457,18 +457,18 @@ std::optional<Emboss::Font> Emboss::load_font(const char *file_path)
|
|||||||
{
|
{
|
||||||
FILE *file = fopen(file_path, "rb");
|
FILE *file = fopen(file_path, "rb");
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
std::cerr << "Couldn't open " << file_path << " for reading.";
|
std::cerr << "Couldn't open " << file_path << " for reading." << std::endl;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// find size of file
|
// find size of file
|
||||||
if (fseek(file, 0L, SEEK_END) != 0) {
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
size_t size = ftell(file);
|
size_t size = ftell(file);
|
||||||
if (size == 0) {
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
rewind(file);
|
rewind(file);
|
||||||
@ -476,7 +476,7 @@ std::optional<Emboss::Font> Emboss::load_font(const char *file_path)
|
|||||||
std::vector<unsigned char> buffer(size);
|
std::vector<unsigned char> buffer(size);
|
||||||
size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file);
|
size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file);
|
||||||
if (count_loaded_bytes != size) {
|
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 {};
|
||||||
}
|
}
|
||||||
return load_font(std::move(buffer));
|
return load_font(std::move(buffer));
|
||||||
@ -488,7 +488,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
|
|||||||
{
|
{
|
||||||
HDC hdc = ::CreateCompatibleDC(NULL);
|
HDC hdc = ::CreateCompatibleDC(NULL);
|
||||||
if (hdc == 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 {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +506,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (size == 0 || size == GDI_ERROR) {
|
if (size == 0 || size == GDI_ERROR) {
|
||||||
std::cerr << "HFONT doesn't have size.";
|
std::cerr << "HFONT doesn't have size." << std::endl;
|
||||||
::DeleteDC(hdc);
|
::DeleteDC(hdc);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -515,7 +515,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
|
|||||||
size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer.data(), size);
|
size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer.data(), size);
|
||||||
::DeleteDC(hdc);
|
::DeleteDC(hdc);
|
||||||
if (size != loaded_size) {
|
if (size != loaded_size) {
|
||||||
std::cerr << "Different loaded(from HFONT) data size.";
|
std::cerr << "Different loaded(from HFONT) data size." << std::endl;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,6 +601,43 @@ ExPolygons Emboss::text2shapes(Font & font,
|
|||||||
return Private::dilate_to_unique_points(result);
|
return Private::dilate_to_unique_points(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Emboss::is_italic(Font &font) {
|
||||||
|
std::optional<stbtt_fontinfo> 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<std::string> 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,
|
indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
|
||||||
const IProject &projection)
|
const IProject &projection)
|
||||||
{
|
{
|
||||||
|
@ -102,6 +102,14 @@ public:
|
|||||||
const char * text,
|
const char * text,
|
||||||
const FontProp &font_prop);
|
const FontProp &font_prop);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read information from naming table of font file
|
||||||
|
/// search for italic (or oblique), bold italic (or bold oblique)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="font">Selector of font</param>
|
||||||
|
/// <returns>True when the font description contains italic/obligue otherwise False</returns>
|
||||||
|
static bool is_italic(Font &font);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Project 2d point into space
|
/// Project 2d point into space
|
||||||
/// Could be plane, sphere, cylindric, ...
|
/// Could be plane, sphere, cylindric, ...
|
||||||
|
@ -177,4 +177,31 @@ TEST_CASE("triangle intersection", "[]")
|
|||||||
Vec2d i = Private::get_intersection(point, dir, triangle);
|
Vec2d i = Private::get_intersection(point, dir, triangle);
|
||||||
CHECK(abs(i.x()) < std::numeric_limits<double>::epsilon());
|
CHECK(abs(i.x()) < std::numeric_limits<double>::epsilon());
|
||||||
CHECK(abs(i.y() - 1.) < std::numeric_limits<double>::epsilon());
|
CHECK(abs(i.y() - 1.) < std::numeric_limits<double>::epsilon());
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -215,50 +215,6 @@ bool is_similar(const indexed_triangle_set &from,
|
|||||||
return true;
|
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"
|
#include "test_utils.hpp"
|
||||||
TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]")
|
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));
|
CHECK(is_similar(its, mesh.its, cfg));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool exist_triangle_with_twice_vertices(const std::vector<stl_triangle_vertex_indices>& 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<float>::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<float>::max();
|
|
||||||
uint32_t wanted_count = 0;
|
|
||||||
its_quadric_edge_collapse(its, wanted_count, &max_error);
|
|
||||||
CHECK(!its.indices.empty());
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user