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"