Closed NanoMichael closed 2 years ago
So I did some digging, and believe I now know why this is the case. When implementing the fontsense algorithm, I was unaware of the importance of the FontSrc "name" in order to do styling. In lib/unimath/uni_font.cpp: FontFamily::fontStyleOf
the "name" gets matched with a static map to determine the font style.
since the name determined by fontsense is "Charter {Regular,Bold,Italic,Bold Italic}" (or whatever, applies to every font) the returned FontStyle is always FontStyle::none
. Instead of using names for styles, I think it'd be better to get and include the correct style in the clm file and then match against that.
If I understand the fontforge python doc correct, the only way of doing this is taking the <font>.macstyle
parameter, which seems to be a bitflag style short.However the docs doesn't seem to specify whether its big or low endian 🙃 .
Hmm, at least neither Charter nor Latin Modern Math supports macstyle (just returns -1). Fontforge itself is able to detect the correct style under Font Information > OS/2 > Misc. > Style Map, however I fail to understand how to access that from python :/
Ok, it seems to not be documented, but <font>.os2_stylemap could work: similar to this: fontforge/sfd.c:8112
but I don't know what the best way forward is with including this in the clm file, given that preferably we unify macstyle/os2_stylemap
Well, I've also noticed this problem...
A modern font has these meta properties:
italic
(namely oblique
), other styles are rarely used, see hereserif
, sans-serif
, monospace
For convenience, we put these properties together into one flag:
We can read its style and weight via font.sfnt_names or font.os2_stylemap
(not documented though), the problem is it seems we can not get its generic family. A solution is to let users specify these properties when generate clm data, e.g. bf, bfit, sfbf, sfbfit
, and if not specified we treat it as a serif font.
Would something like this work?
diff --git a/prebuilt/otf2clm.py b/prebuilt/otf2clm.py
index ce325e4..53d487f 100755
--- a/prebuilt/otf2clm.py
+++ b/prebuilt/otf2clm.py
@@ -587,7 +587,62 @@ def write_glyphs(f, glyphs, glyph_name_id_map, is_math_font, have_glyph_path):
write_path(glyph[3])
-def parse_otf(file_path, have_glyph_path, output_file_path):
+def parse_fontstyle(font, userstyle):
+ NONE = 0b00000000
+ RM = 0b00000001
+ BF = 0b00000010
+ IT = 0b00000100
+ CAL = 0b00001000
+ FRAK = 0b00010000
+ BB = 0b00100000
+ SF = 0b01000000
+ TT = 0b10000000
+
+ style = NONE
+
+ if (userstyle == None or userstyle == ""):
+ if (font.os2_weight >= 700):
+ style |= BF
+
+ if (font.os2_stylemap == 0x40):
+ style |= RM
+ if (font.os2_stylemap == 0x21):
+ style |= (BF | IT)
+ if (font.os2_stylemap == 0x20):
+ style |= BF
+ if (font.os2_stylemap == 0x01):
+ style |= IT
+
+ if (font.macstyle != -1):
+ if (font.macstyle & 0b01 == 0b01):
+ style |= BF
+ if (font.macstyle & 0b10 == 0b10):
+ style |= IT
+
+ if (font.fullname.upper().__contains__("MONO")):
+ style |= TT
+ else:
+ userstyles = userstyle.split(",")
+ if ("rm" in userstyles):
+ style |= RM
+ if ("bf" in userstyles):
+ style |= BF
+ if ("it" in userstyles):
+ style |= IT
+ if ("cal" in userstyles):
+ style |= CAL
+ if ("frak" in userstyles):
+ style |= FRAK
+ if ("bb" in userstyles):
+ style |= BB
+ if ("sf" in userstyles):
+ style |= SF
+ if ("tt" in userstyles):
+ style |= TT
+
+ return style
+
+def parse_otf(file_path, have_glyph_path, output_file_path, userstyle = ""):
print("parsing font " + file_path + ", please wait...")
font = fontforge.open(file_path)
@@ -633,6 +688,7 @@ def parse_otf(file_path, have_glyph_path, output_file_path):
name = font.fullname
family = font.familyname
+ style = parse_fontstyle(font, userstyle)
em = font.em
xheight = font.xHeight
ascent = font.ascent
@@ -649,6 +705,7 @@ def parse_otf(file_path, have_glyph_path, output_file_path):
f.write(struct.pack(str(len(name)+1) + 's', bytes(name, 'utf-8')))
f.write(struct.pack(str(len(family)+1) + 's', bytes(family, 'utf-8')))
f.write(struct.pack('?', is_math_font))
+ f.write(struct.pack('!H', style))
f.write(struct.pack('!H', em))
f.write(struct.pack('!H', int(xheight)))
f.write(struct.pack('!H', ascent))
@@ -710,10 +767,14 @@ def main():
sys.argv[4]
)
else:
+ userstyle = ""
+ if (len(sys.argv) > 5):
+ userstyle = sys.argv[5]
parse_otf(
sys.argv[2],
sys.argv[3] == 'true',
- sys.argv[4]
+ sys.argv[4],
+ userstyle
)
print("The generated clm data file was saved into file: " + sys.argv[4])
Would something like this work?
Excellent 🎉 🎉 🎉 , that is exactly what I mean. Could you please make a PR for this?
See #99