Comment l'application de retouche d'images vectorielles Boxy SVG utilise l'API Local Font Access pour permettre aux utilisateurs de choisir leurs polices locales préférées

L'API Local Font Access fournit un mécanisme permettant d'accéder aux données de police installées localement par l'utilisateur, y compris des détails de niveau supérieur tels que les noms, les styles et les familles, ainsi qu'aux octets bruts des fichiers de police sous-jacents. Découvrez comment l'application d'édition SVG Boxy utilise cette API.

Introduction

(Cet article est également disponible sous forme de vidéo.)

Le SVG Boxy est un éditeur de graphiques vectoriels. Son principal cas d'utilisation consiste à modifier des dessins au format SVG, afin de créer des illustrations, des logos, des icônes et d'autres éléments de conception graphique. Il a été développé par le développeur polonais Jarosław Foksa et est sorti le 15 mars 2013. Jarosław tient un blog Boxy SVG dans lequel il annonce les nouvelles fonctionnalités qu'il ajoute à l'application. Le développeur est un fervent défenseur du projet Fugu de Chromium et a même ajouté une balise Fugu dans l'outil de suivi des idées de l'application.

L'application SVG Boxy modifiant l'icône SVG de Project Fugu.

API Local Font Access dans le SVG Boxy

Jarosław a mentionné un ajout de fonctionnalité : l'API Local Font Access. L'API Local Font Access permet aux utilisateurs d'accéder aux polices installées localement, y compris aux détails de niveau supérieur tels que les noms, les styles et les familles, ainsi qu'aux octets bruts des fichiers de police sous-jacents. Dans la capture d'écran suivante, vous pouvez voir comment j'ai autorisé l'application à accéder aux polices installées localement sur mon MacBook et à choisir la police Marker Felt pour mon texte.

Application SVG Boxy modifiant l'icône du fichier SVG de l'icône du projet Fugu, en ajoutant le texte "Project Fugu rocks" défini dans la police Marker Felt, qui est sélectionnée dans le sélecteur de police.

Le code sous-jacent est assez simple. Lorsque l'utilisateur ouvre le sélecteur de famille de polices pour la première fois, l'application vérifie d'abord si le navigateur Web prend en charge l'API Local Font Access.

Il recherche également l'ancienne version expérimentale de l'API et l'utilise, le cas échéant. Depuis 2023, vous pouvez ignorer l'ancienne API en toute sécurité, car elle n'était disponible que pendant une courte période grâce aux indicateurs Chrome expérimentaux, mais il est possible que certains dérivés de Chromium l'utilisent encore.

let isLocalFontsApiEnabled = (
  // Local Font Access API, Chrome >= 102
  window.queryLocalFonts !== undefined ||
  // Experimental Local Font Access API, Chrome < 102
  navigator.fonts?.query !== undefined
);

Si l'API Local Font Access n'est pas disponible, l'outil de sélection de famille de polices devient gris. Un espace réservé s'affichera pour l'utilisateur à la place de la liste des polices:

if (isLocalFontsApiEnabled === false) {
  showPlaceholder("no-local-fonts-api");
  return;
}

Sélecteur de police affichant le message &quot;Votre navigateur n&#39;est pas compatible avec l&#39;API Local Font Access&quot;.

Sinon, l'API Local Font Access est utilisée pour récupérer la liste de toutes les polices du système d'exploitation. Notez le bloc try…catch, qui est nécessaire pour gérer correctement les erreurs d'autorisation.

let localFonts;

if (isLocalFontsApiEnabled === true) {
  try {
    // Local Font Access API, Chrome >= 102
    if (window.queryLocalFonts) {
      localFonts = await window.queryLocalFonts();
    }
    // Experimental Local Font Access API, Chrome < 102
    else if (navigator.fonts?.query) {
      localFonts = await navigator.fonts.query({
        persistentAccess: true,
      });
    }
  } catch (error) {
    showError(error.message, error.name);
  }
}

Une fois la liste des polices locales récupérée, une fontsIndex simplifiée et normalisée est créée à partir de celle-ci:

let fontsIndex = [];

for (let localFont of localFonts) {
  let face = "400";

  // Determine the face name
  {
    let subfamily = localFont.style.toLowerCase();
    subfamily = subfamily.replaceAll(" ", "");
    subfamily = subfamily.replaceAll("-", "");
    subfamily = subfamily.replaceAll("_", "");

    if (subfamily.includes("thin")) {
      face = "100";
    } else if (subfamily.includes("extralight")) {
      face = "200";
    } else if (subfamily.includes("light")) {
      face = "300";
    } else if (subfamily.includes("medium")) {
      face = "500";
    } else if (subfamily.includes("semibold")) {
      face = "600";
    } else if (subfamily.includes("extrabold")) {
      face = "800";
    } else if (subfamily.includes("ultrabold")) {
      face = "900";
    } else if (subfamily.includes("bold")) {
      face = "700";
    }

    if (subfamily.includes("italic")) {
      face += "i";
    }
  }

  let descriptor = fontsIndex.find((descriptor) => {
    return descriptor.family === localFont.family);
  });

  if (descriptor) {
    if (descriptor.faces.includes(face) === false) {
      descriptor.faces.push(face);
    }
  } else {
    let descriptor = {
      family: localFont.family,
      faces: [face],
    };

    fontsIndex.push(descriptor);
  }
}

for (let descriptor of fontsIndex) {
  descriptor.faces.sort();
}

L'index des polices normalisées est ensuite stocké dans la base de données IndexedDB afin d'être facilement interrogé, partagé entre les instances d'application et conservé d'une session à l'autre. Le SVG Boxy utilise Dexie.js pour gérer la base de données:

let database = new Dexie("LocalFontsManager");
database.version(1).stores({cache: "family"}).
await database.cache.clear();
await database.cache.bulkPut(fontsIndex);

Section &quot;Stockage des outils pour les développeurs Chrome&quot; affichant la table &quot;IndexedDB&quot; avec le cache des polices

Une fois la base de données renseignée, le widget de sélection de police peut l'interroger et afficher les résultats à l'écran:

Sélecteur de polices rempli de polices.

Notez que le SVG Boxy affiche la liste dans un élément personnalisé nommé <bx-fontfamilypicker> et applique un style à chaque élément de la liste de polices pour qu'il s'affiche dans la famille de polices concernée. Pour isoler le contenu du reste de la page, le SVG Boxy utilise le Shadow DOM dans cet élément et dans d'autres éléments personnalisés.

Panneau &quot;Éléments des outils pour les développeurs Chrome&quot; montrant le sélecteur de police inspecté: un élément personnalisé nommé &quot;bx-fontfamiliypicker&quot;.

Conclusions

La fonctionnalité de police locale est très populaire, et les utilisateurs apprécient d'avoir accès à leurs polices locales pour leurs conceptions et leurs créations. Lorsque la forme de l'API a changé et que la fonctionnalité a cessé de fonctionner brièvement, les utilisateurs en ont immédiatement noté l'existence. Jarosław a rapidement remplacé le code par le schéma défensif de l'extrait ci-dessus, qui fonctionne avec les toutes dernières versions de Chrome et d'autres versions dérivées de Chromium qui n'ont peut-être pas encore adopté la dernière version. Essayez le SVG Boxy et assurez-vous de vérifier les polices installées localement. Vous découvrirez peut-être des classiques oubliés depuis longtemps, comme Zapf Dingbats ou Webdings.