Utiliser une fonte TTF sous Windows

Aujourd'hui, je termine la série concernant l'utilisation de fontes personnalisées dans les applications Firemonkey, mais l'aventure ne se terminera probablement pas là pour FMX. En effet d'autres plateformes seront ajoutées à Firemonkey selon le succès des différents systèmes d'exploitation et certains auront une interface graphique permettant également d'embarquer des fontes de caractères dans nos programmes. Quand ce sera possible je complèterai donc cette série, mais en attendant occupons-nous donc de Windows.

Avec Firemonkey ou la VCL, Delphi a toujours permis d'accéder aux API de Windows. Elles sont disponibles dans les unités commençant tout simplement par Winapi. La documentation, en revanche, reste celle de Microsoft disponible sur MSDN. Pas de greffon particulier fourni avec Delphi.

Dans le cas qui nous occupe nous aurons besoin de deux unités : Winapi.Windows et Winapi.Messages. La première contient les déclarations permettant d'accéder aux fonctions système. La seconde contient les déclarations des messages utilisables pour demander à Windows d'effectuer certaines opérations.

Vous vous en doutez : Microsoft a prévu des API pour ajouter et retirer des fontes au système.

En pratique il y a même plusieurs façons de faire :

  • ajouter un fichier de police de caractères dans le dossier des fontes système et la déclarer dans la base de registres : la fonte est ainsi disponible pour toutes les applications même après redémarrage de l'ordinateur.
  • utiliser AddFontResource() qui permet d'activer le chargement d'une fonte pour la session de travail en cours. La fonte est utilisable par les autres applications du système. Ce changement ne persiste pas après reboot.
  • utiliser AddFontResourceEx() qui permet d'activer une fonte de façon privée pour le programme en cours. Ce changement ne persiste pas après reboot de l'ordinateur.

Si nous désirons une fonte juste pour un programme et ne voulons pas qu'elle soit utilisable ailleurs, en dehors du programme, on peut déjà éliminer la première possibilité. En revanche si on désire laisser cette fonte exploitable en permanence c'est la solution à choisir et de préférence à gérer à partir du programme d'installation de votre logiciel.

Sous Firemonkey, la troisième option ne fonctionne pas. Cela pourrait changer dans l'avenir car il y a eu des demandes en ce sens sur le bugtracker de la communauté.

Il reste donc la seconde option qui permet à d'autres programme d'accéder à la fonte personnalisée, mais uniquement lorsque notre programme a été lancé et a ajouté la police de caractères aux fontes système de la session. Et si on veut vraiment limiter les accès, on peut n'activer une fonte que pour le moment où on s'en sert et la retirer juste après.

Comme pour les autres plateformes vous devrez également joindre la fonte à votre exécutable, soit en ressource interne qui sera ensuite enregistrée sur le disque dur, soit à l'aide de votre programme d'installation.

Côté programme, vous devez donc commencer par ajouter les deux unités utiles pour accéder à l'API. Je fais généralement toutes ces opérations dans la fiche principale de l'application. C'est la première à être affichée et à priori la dernière à être désactivée.

{$IFDEF MSWINDOWS}

uses
  winapi.windows, winapi.messages;

{$ENDIF}

Si vous avez besoin d'autres unités, pensez à ne conditionner que ces deux là, comme par exemple ici :

uses
{$IFDEF MSWINDOWS}
  winapi.windows, winapi.messages,
{$ENDIF}
  System.IOUtils;

Le chargement de la fonte de caractères se fait avec deux lignes de code :

  AddFontResource(starTrekFutureFontFilename);
  SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);

La première ajoute la fonte à la liste des fontes du système. La seconde envoit un message à toutes les applications (dont la nôtre) pour lui signaler un changement dans la liste des fontes et lui demander ainsi de prendre en compte les nouveautés.

Si on charge une fonte il faut impérativement penser à la décharger. Si on oublie, elle restera active jusqu'au prochain reboot de l'ordinateur. Le déchargement de la fonte se fait de cette façon :

  RemoveFontResource(starTrekFutureFontFilename);
  SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);

Pour me simplifier les choses, j'ai déclaré une constante starTrekFutureFontFilename qui contient le chemin d'accès absolu vers le fichier TTF à charger :

const
  starTrekFutureFontFilename =
    'C:\Users\PATRICK PREMARTIN\Documents\Embarcadero\Studio\Projets\fonte-ttf\Star_Trek_future.ttf';

Ceci n'est valable que dans le cadre de mon exemple et ne doit jamais être utilisé en production. Même si vous êtes un professionnel de la cascade, vous vous devez de mettre des chemins d'accès relatifs à votre programme ou trouver une méthode de paramétrage plus efficace pour que le programme trouve le fichier TTF utilisé sur les ordinateurs de vos utilisateurs et non par rapport à la configuration sur le vôtre.

Le chargement d'une fonte peut se faire dans la méthode Create() de la fiche principale puis son déchargement dans la méthode Destroy(). Vous pouvez aussi, comme ici, le faire directement au niveau d'une unité du programme qui serait chargée du chargement/déchargement des fontes liées à l'application :

implementation

{$IFDEF MSWINDOWS}

uses
  winapi.windows, winapi.messages;

const
  starTrekFutureFontFilename =
    'C:\Users\PATRICK PREMARTIN\Documents\Embarcadero\Studio\Projets\fonte-ttf\Star_Trek_future.ttf';
{$ENDIF}

initialization

{$IFDEF MSWINDOWS}
  AddFontResource(starTrekFutureFontFilename);
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
{$ENDIF}

finalization

{$IFDEF MSWINDOWS}
  RemoveFontResource(starTrekFutureFontFilename);
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
{$ENDIF}

end.

Comme pour les autres plateformes l'utilisation de la fonte se fait en modifiant la propriété Font.Family d'un composant affichant du texte.

Ainsi s'achève donc cette série consacrée aux fontes et à Firemonkey, mais il reste à voir comment faire avec la VCL, histoire d'être complet sur le sujet. A très bientôt donc.


Mug Pascal case in AlexandrieMug carte postale Sydney