Version 3 of How to use new fonts without installing'em

Updated 2009-01-19 22:30:34 by lars_h

ABU 19-Jan-2009

I like to give a distinctive look to my applications using uncommon fonts.

http://web.tiscali.it/irrational/fonts/sampleScriptina.PNG

The (old) problem with fonts is that they should be installed before you can use them and, if you want to distribute your application, you should distribute and install your special fonts, too !

On Windows, installing a new font "by program" is not a trivial task, but I don't like to fill the system font-table with all the special fonts used by some useless apps ...

Here is a way to deploy an application with new fonts. The new fonts will be "installed" just for running your (tcl) application. Only your current app can see and use this font. When the application terminates, the new fonts disappear from the font-table.

We need to link the win32-api. We will use Ffidl for this purpose.

Also, we need some new font-file. Here's an uncommon free font named Scriptina [L1 ] downloaded from www.dafont.com

Just for a quick test save the font-file in c:/tmp" folder. You can preview it but DO NOT install it !

Here is the code with some comments:

 # win32 api from gdi32.dll
 #int AddFontResourceEx(
 #  LPCTSTR lpszFilename, // font file name
 #  DWORD fl,             // font characteristics
 #  PVOID pdv             // reserved
 #);
 #
 # fl can be:
 # FR_PRIVATE (0x10)
 #  Specifies that only the process that called the AddFontResourceEx function can use this font.
 #  When the font name matches a public font, the private font will be chosen.
 #  When the process terminates, the system will remove all the 'temporary' fonts.
 # FR_NOT_ENUM (0x20)
 #   Specifies that no process, including the process that called the AddFontResourceEx function.
 #   can enumerate this font.
 #
 # pd is reserved. Must be zero.

  # create a tcl proc named 'dll_AddFontResourceEx'
 package require Ffidl
 ffidl::callout dll_AddFontResourceEx { pointer-utf16 int pointer} int \
  [ffidl::symbol gdi32.dll AddFontResourceExW ]

  # load a new font-file just for the current session.
  # Of course you can change the pathname ...
 set fontFile c:/tmp/SCRIPTIN.TTF  ; #  "c:\\tmp\\SCRIPTIN.TTF" is valid, too 

  # Here is the core !  Load the new font and check for errors ..
 set res [dll_AddFontResourceEx $fontFile 0x10 0]
 if { $res == 0 } {
    puts "ERROR loading $fontFile"
 }

  # Finally, show something with the new font !

  # The new font-name is "Scriptina"  (Note: font-names are case-insensitive)
 label .lab1 -text "Abu works!" -font {Scriptina 20}
 pack .lab1

Note that the new font is now visible in your font-table, e.g.

 [font families] now includes "Scriptina"

but this font is not visible to other apps (try to open notepad.exe and open the font panel ... ).

Limitations

  • It's for Windows platforms only.
    Do you want to add a method for X and/or Aqua ?
  • There's no a programmatic way to determine the font-name just installed
    • You should know that SCRIPTIN.TTF holds a font named "Scriptina".
    • AFAIK there's nothing in win32 API able to return font-name, even if the "AddFontResource" function DO add the font-name to the system font-table ! Lars H: In principle, one should be able to discover this from the font file without asking the system for help; the relevant entry appears to be one with nameID=4 in the name table. Locating that datum takes some work, though.
  • Starkit won't work
    If you include your fonts in a starkit (.kit), the 'dll_AddFontResourceEx' won't be able to locate your font-files 'zipped' in a starkit.
    Uhm ..., a solution could be to add some startup-code for copying the font-files in a temp directory ...
  • what about a new TIP ?