Knowing if a font exists
-
hi there,
i'd like to know if there is any way to know if the font i entered is valid / exists on the pc of the user.
i can set the font 'Arial', but if i set a non existing font like 'Whatever', there will be a fallback to the default font. i tried to get some feedback, if this has happend, but i can not figure out how.this is my current code in a python generator:
import c4d doc: c4d.documents.BaseDocument op: c4d.BaseObject def main() -> c4d.BaseObject: text = op[c4d.ID_USERDATA,2] # temp doc # ---------------------------------------------------------- temp_doc: c4d.documents.BaseDocument = c4d.documents.BaseDocument() temp_doc.SetName("temp_doc") temp_null = c4d.BaseObject( c4d.Onull ) temp_doc.InsertObject( temp_null ) # create text spline # ---------------------------------------------------------- text_spline = c4d.BaseObject( c4d.Osplinetext ) text_spline[c4d.PRIM_TEXT_TEXT] = text text_spline[c4d.PRIM_TEXT_ALIGN] = 1 text_spline[c4d.PRIM_TEXT_HEIGHT] = 1 text_spline[c4d.PRIM_PLANE] = 2 bc_font = c4d.BaseContainer() #bc_font.SetString(500, 'Arial') bc_font.SetString(500, 'Consolasssss') bc_font.SetInt32(502, 700) # weight fontdata = c4d.FontData() fontdata.SetFont( bc_font ) text_spline[c4d.PRIM_TEXT_FONT] = fontdata # font check in temp doc # ---------------------------------------------------------- text_spline.GetClone().InsertUnder( temp_null ) temp_doc.ExecutePasses( c4d.threading.GeGetCurrentThread(), True, True, True, c4d.BUILDFLAGS_NONE ) text_spline_2 = temp_null.GetDown() fontdata_check = text_spline_2[c4d.PRIM_TEXT_FONT] font_check = fontdata_check.GetFont() print( font_check[500] ) # will print the non existing font name, not the fallback default font return text_spline
-
Hey @datamilch,
Thank you for reaching out to us. We recently had a very similar topic, where I gave an answer which is probably also relevant for you.
In short, GetFontDescription is one of the ways to do this. What I would absolutely advise against, is browsing all font data to look for your font, because that can be very slow.
The approach I showed in the linked topic requires that you can accurately predict the name of a font. E.g., predict that the font you are looking for will have the postscript name
"ArialMT-Regular"
. This stands in contrast to just browsing all font data - for example via EnumerateFonts - and then checking one by one if one of the font labels contains the string"Arial"
. This latter approach will be very slow, because these browse functions all load the actual fonts to access their meta data.Cheers,
Ferdinand -
hi @ferdinand exactly what i needed , thanks!
the fontchek seems solid so far.did a bid of testing, the check with c4d.bitmaps.GeClipMap.GetFontDescription()
seems only to work for the c4d.GE_FONT_NAME_POSTSCRIPT parameter. not with c4d.GE_FONT_NAME_FAMILY or c4d.GE_FONT_NAME_DISPLAY ... maybe because they could be ambiguous?then it was a bit unclear how the postscript names are constructed. i created a font-selector-user-data to print the ps-names of the selected font. these names could then be used to check if a font exists on another system. i just hope, these names are consistent across platfoms.
the fontdata definiton still feels a bit unclear to me in respect to which values are needed or not. the ps-name alone will not work to define a fontdata. a single name in font[500] might work. ... in my test i used the bc returned by c4d.bitmaps.GeClipMap.GetFontDescription().
here is some test code i used in a python generator:
import c4d doc: c4d.documents.BaseDocument # The document the object `op` is contained in. op: c4d.BaseObject # The Python generator object holding this code. def main() -> c4d.BaseObject: fontdata = op[c4d.ID_USERDATA,1] # font selector data field font: c4d.BaseContainer = fontdata.GetFont() print( "==============================" ) print( font[500] ) print( font[501] ) print( font[502] ) print( font[503] ) print( font[508]," <- ps name" ) print( font[509] ) print( "------------" ) # store the ps name for later font_ps_name = font[508] # we are testing the font, that we just selected in the user data - so it should always exist check_bc: c4d.BaseContainer | None = c4d.bitmaps.GeClipMap.GetFontDescription(font[508], c4d.GE_FONT_NAME_POSTSCRIPT) if not check_bc: print(f"508 nope") else: print(f"508 exists" ) print( "------------" ) print( check_bc[500] ) print( check_bc[502] ) print( check_bc[503] ) print( check_bc[504] ) print( check_bc[509] ) print( "------------" ) # testing with spline text # -------------------------------------------------------- # defing a font only with its ps-name will not work - yields default font bc_font = c4d.BaseContainer() bc_font.SetString(508, font_ps_name) # using the data returned by GetFontDescription() works fontdata = c4d.FontData() fontdata.SetFont( check_bc ) text_spline = c4d.BaseObject( c4d.Osplinetext ) text_spline[c4d.PRIM_TEXT_TEXT] = "Text 0123" text_spline[c4d.PRIM_TEXT_FONT] = fontdata return text_spline
-
for my use case i will probably have a fallback solution with web-save or system fonts like this:
import platform system_name = platform.system() if system_name == "Windows": font_name = "Consolas" elif system_name == "Darwin": font_name = "Menlo" elif system_name == "Linux": font_name = "DejaVu Sans Mono"