Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Lookup font in text render based on family and style name #4509

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 106 additions & 5 deletions src/libOpenImageIO/imagebufalgo_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <limits>
#include <set>
#include <unordered_map>
#include <unordered_set>

#include <OpenImageIO/half.h>

Expand Down Expand Up @@ -744,6 +745,12 @@ static const char* font_dir_suffixes[]
"share/fonts", "share/Fonts", "share/fonts/OpenImageIO" };
// static const char* font_extensions[] = { "", ".ttf", ".ttc", ".pfa", ".pfb" };

// list of available font families
static std::vector<std::string> s_font_families;
// available font styles per families
static std::unordered_map<std::string, std::vector<std::string>> s_font_styles;
// font filenames per family and style (e.g. "Arial Italic")
static std::unordered_map<std::string, std::string> s_font_filename_per_family;


// Add one dir to font_search_dirs, if the dir exists.
Expand Down Expand Up @@ -921,6 +928,86 @@ text_size_from_unicode(cspan<uint32_t> utext, FT_Face face, int fontsize)
}


// Read available font families and styles.
static void
init_font_families()
{
// skip if already initialized
if (!s_font_families.empty())
return;

// If we know FT is broken, don't bother trying again
if (ft_broken)
return;

// If FT not yet initialized, do it now.
if (!ft_library) {
if (FT_Init_FreeType(&ft_library)) {
ft_broken = true;
return;
}
}

// read available fonts
std::unordered_set<std::string> font_family_set;
std::unordered_map<std::string, std::unordered_set<std::string>>
font_style_set;
const std::vector<std::string>& font_files = pvt::font_file_list();
for (const std::string& filename : font_files) {
// Load the font.
FT_Face face;
int error = FT_New_Face(ft_library, filename.c_str(),
0 /* face index */, &face);
if (error)
continue;

// Ignore if the font fmaily name is not defined.
if (!face->family_name) {
FT_Done_Face(face);
continue;
}

// Store the font family.
std::string family = std::string(face->family_name);
font_family_set.insert(family);

// Store the font style.
std::string style = face->style_name ? std::string(face->style_name)
: std::string();
if (!style.empty()) {
std::unordered_set<std::string>& styles = font_style_set[family];
styles.insert(style);
}

// Store the filename. Use the family and style as the key (e.g. "Arial Italic").
std::string font_name = family;
if (!style.empty())
font_name += " " + style;
s_font_filename_per_family[font_name] = filename;

// Store regular fonts also with the family name only (e.g. "Arial Regular" as "Arial").
if (style == "Regular")
s_font_filename_per_family[family] = filename;

FT_Done_Face(face);
}

// Sort font families.
s_font_families = std::vector<std::string>(font_family_set.begin(),
font_family_set.end());
std::sort(s_font_families.begin(), s_font_families.end());

// Sort font styles.
for (auto it : font_style_set) {
const std::string& family = it.first;
std::unordered_set<std::string>& styles_set = it.second;
std::vector<std::string> styles(styles_set.begin(), styles_set.end());
std::sort(styles.begin(), styles.end());
s_font_styles[family] = styles;
}
}


// Given font name, resolve it to an existing font filename.
// If found, return true and put the resolved filename in result.
// If not found, return false and put an error message in result.
Expand Down Expand Up @@ -959,12 +1046,26 @@ resolve_font(string_view font_, std::string& result)
result = "Could not set default font face";
return false;
}
}
if (!Filesystem::is_regular(font)) {
} else if (Filesystem::is_regular(font)) {
// directly specified filename -- use it
} else {
// A font name was specified but it's not a full path, look for it
auto f = font_file_map.find(font);
if (f != font_file_map.end()) {
font = f->second;
std::string f;

// first look for a font with the given family and style
init_font_families();
if (s_font_filename_per_family.find(font)
!= s_font_filename_per_family.end())
f = s_font_filename_per_family[font];

// then look for a font with the given filename
if (f.empty()) {
if (font_file_map.find(font) != font_file_map.end())
f = font_file_map[font];
}

if (!f.empty()) {
font = f;
} else {
result = Strutil::fmt::format("Could not find font \"{}\"", font);
return false;
Expand Down
Binary file added testsuite/oiiotool-text/ref/fontbyfamily.tif
Binary file not shown.
2 changes: 2 additions & 0 deletions testsuite/oiiotool-text/ref/out.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ Comparing "textshadowed.tif" and "ref/textshadowed.tif"
PASS
Comparing "textalpha.tif" and "ref/textalpha.tif"
PASS
Comparing "fontbyfamily.tif" and "ref/fontbyfamily.tif"
PASS
Comparing "unicode.tif" and "ref/unicode.tif"
PASS
7 changes: 6 additions & 1 deletion testsuite/oiiotool-text/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,13 @@
"--text:x=20:y=120:color=.5,.5,.5,.5:size=50 \"Hello, world\" "
"-d uint8 -o textalpha.tif")

# test lookup font by family and style name
command += oiiotool ("--create 320x240 3 "
"\"--text:x=25:y=120:font=Droid Serif Bold:size=40\" \"Hello, world\" "
"-d uint8 -o fontbyfamily.tif")

# Outputs to check against references
outputs = [ "text.tif", "aligned.tif", "textshadowed.tif", "textalpha.tif" ]
outputs = [ "text.tif", "aligned.tif", "textshadowed.tif", "textalpha.tif", "fontbyfamily.tif" ]

# Test Unicode characters. But only when not on Windows, because I just
# can't figure out how to get Unicode chars on the command line properly
Expand Down
Loading