Aller au contenu

Les polices : la partie difficile

Evidence: Mixed evidence

Les polices sont l’endroit où un PDF peut sembler tout à fait correct tout en étant discrètement cassé. Une page peut afficher les bons glyphes, mais rester impossible à rechercher, impossible à copier comme texte et non conforme à un profil d’archivage. Tout cela peut se produire en même temps, sans aucun signal visible pour t’alerter. Cette page présente les trois aspects qui doivent fonctionner — intégration, sous-ensemble, encodage — et ce que NextPDF fait pour chacun.

« Ça a l’air correct » est la phrase la plus dangereuse quand on travaille sur des PDF, et c’est avec les polices qu’elle fait le plus de dégâts. Trois éléments indépendants doivent tenir :

  1. Intégration — le programme de police voyage dans le fichier, ce qui garantit le même affichage sur une machine où la police n’est pas installée.
  2. Sous-ensemble — seuls les glyphes réellement utilisés sont transportés, pour éviter qu’une police CJK de 20 Mo fasse gonfler chaque document.
  3. Encodage — il existe une correspondance correcte qui ramène les codes de caractères de la page vers l’Unicode, de sorte que le texte puisse être recherché, copié, indexé et lu par une technologie d’assistance.

Le rendu visuel ne prouve que le premier point, et encore, seulement en partie. Un document peut afficher des glyphes parfaits et échouer complètement sur le troisième : le texte est alors une image de mots, pas des mots. C’est le type d’échec qui passe toutes les revues fondées sur « ça a l’air correct », puis fait échouer un audit de conformité ou une demande de communication de pièces.

  • Dans un PDF, une police est un dictionnaire auquel s’ajoute, le plus souvent, un flux de programme de police intégré.
  • Le sous-ensemble réécrit ce programme pour qu’il ne contienne que les glyphes utilisés. Le nom d’une police en sous-ensemble reçoit une balise de six lettres majuscules et un + afin que les lecteurs la traitent comme distincte.
  • L’encodage est le problème distinct de la mise en correspondance des codes de caractères avec l’Unicode. Une CMap /ToUnicode rend le texte recherchable et copiable — et elle est indépendante du fait que les glyphes aient l’air corrects.
  • Un texte à l’apparence correcte sans /ToUnicode (ou avec une mauvaise CMap) est l’échec silencieux classique : parfait à l’écran, impossible à rechercher en pratique.
  • NextPDF sous-ensemble les polices TrueType, préserve l’identité des glyphes pour un rendu correct et émet une CMap /ToUnicode pour que l’extraction fonctionne — et peut imposer la règle d’intégration de PDF 2.0 au lieu de se contenter d’avertir.

Sous-ensemble. FontSubsetter (src/Typography/FontSubsetter.php) analyse le répertoire de tables TrueType d’origine et lit la cmap pour faire correspondre les points de code Unicode aux identifiants de glyphes. Il prend en charge à la fois le format 4 du BMP et le format 12 plein-Unicode, nécessaire au CJK. Ensuite, il effectue l’étape que les sous-ensembleurs naïfs ratent : il résout les dépendances de glyphes composites par fermeture transitive. Un glyphe accentué construit à partir d’une lettre de base et d’une marque combinante référence d’autres glyphes comme composants. Si ces composants sont supprimés, le glyphe s’affiche mal. Le sous-ensembleur parcourt ce graphe jusqu’à ce qu’aucun nouveau composant n’apparaisse, avec une protection contre les cycles afin qu’une police malformée ne puisse pas boucler indéfiniment.

Deux choix d’ingénierie dans ce fichier méritent d’être explicités. D’abord, les identifiants de glyphes sont préservés, non remappés — les emplacements inutilisés sont remplis de zéros dans glyf/loca, de sorte que les indices de glyphes d’origine du flux de contenu restent valides sous CIDToGIDMap /Identity. Le remappage produirait un fichier plus petit, mais exigerait de réécrire chaque référence de glyphe. Préserver l’identité est correct par construction. Ensuite, le parcours est trié (par identifiant de glyphe croissant) afin que le sous-ensemble soit déterministe à l’octet près : la même police et les mêmes glyphes utilisés produisent les mêmes octets de sous-ensemble, ce qu’exigent les compilations reproductibles. Si le sous-ensemble faisait économiser moins d’environ 10 % du fichier, l’original est renvoyé inchangé. La surcharge ne vaut pas ce gain marginal.

Intégration. Une politique explicite décide si un programme de police est transporté ou non — jamais à l’appréciation du moteur. Pdf20FontEmbeddingPolicy (src/Writer/Pdf20FontEmbeddingPolicy.php) propose deux modes. Sous le profil PDF 2.0, Strict rejette une référence à une police Type 1 standard non intégrée (« Base14 ») avec une exception typée — le comportement conforme. AllowBase14 conserve l’ancien chemin qui se limite à avertir. Comme fenêtre de migration, il émet le descripteur de police minimal que la norme exige encore et déclenche un avertissement plutôt qu’une exception. L’appelant fait ce choix explicitement sur le document ; il n’est jamais déduit de la police.

Encodage. Pour les polices composites (Type 0), EmbeddedTtfFontDictBuilder (src/Writer/EmbeddedTtfFontDictBuilder.php) émet le descendant CIDFontType2, le parent Type0 et un flux de CMap /ToUnicode afin que les codes de caractères se résolvent en Unicode. Le flux /ToUnicode n’est légitimement absent que dans un seul cas : lorsqu’une CMap CJK prédéfinie et auto-descriptive fournit déjà au lecteur la correspondance caractère-vers-Unicode. Dans ce cas, la CMap est l’encodage ; le profil ordinaire omet donc un flux /ToUnicode redondant pour économiser des octets. En dehors de ce cas, le flux /ToUnicode est ce qui fait que le texte reste du texte.

PréoccupationCe qu’elle garantitCe qu’elle ne garantit pasÉchec silencieux en cas d’erreur
IntégrationMême rendu sans la police installéeQue le texte est recherchablePolice substituée ; métriques erronées sur une autre machine
Sous-ensembleFichier léger ; uniquement les glyphes utilisésQuoi que ce soit concernant l’encodageComposants composites manquants → glyphes accentués cassés
Encodage (/ToUnicode)Texte recherchable, copiable, accessibleQue les glyphes s’affichent correctementPage à l’apparence parfaite, impossible à rechercher / illisible à la copie

Les trois préoccupations liées aux polices sont indépendantes. L’intégration et le sous-ensemble concernent l’apparence et la taille ; l’encodage concerne le sens. Une page peut réussir les deux premières et échouer sur la troisième sans rien de visible pour le montrer.

La règle de nommage des sous-ensembles est normative et précise. Spec: ISO 32000-2, §9.9.2 exige que le nom PostScript du sous-ensemble d’une police — le BaseFont et le FontName du descripteur — commence par une balise de six lettres majuscules exactement, puis un signe plus, puis le nom PostScript de la police d’origine. Elle exige aussi que différents sous-ensembles de la même police dans un fichier utilisent des balises différentes. C’est cette règle qui permet à un lecteur de distinguer deux sous-ensembles et de fusionner correctement les documents. Evidence: Standard-backed

L’encodage est une clause distincte du rendu. Spec: ISO 32000-2, §9.10.3 définit /ToUnicode comme un flux contenant une CMap qui fait correspondre les codes de caractères à des valeurs Unicode, et la procédure d’extraction de texte de Spec: ISO 32000-2, §9.10.2 utilise cette CMap pour convertir les codes de caractères en Unicode aux fins de recherche et d’indexation. Rien dans la machinerie de tracé des glyphes ne touche à /ToUnicode — c’est précisément pourquoi un texte peut avoir l’air correct tout en s’extrayant de travers.

Sur l’intégration, la norme indique que la plupart des dictionnaires de police portent un descripteur de police dont le flux de fichier de police intégré est facultatif mais fortement recommandé. PDF 2.0 resserre cette règle pour les quatorze polices Type 1 standard en particulier. La politique Strict de NextPDF correspond à la lecture conforme de ce resserrement. AllowBase14 est l’échappatoire de rétrocompatibilité explicite et optionnelle — le moteur ne dégrade jamais silencieusement.

Strict PDF 2.0 font-embedding enforcement — edition availability
Edition Availability
Core

Disponible. Le sous-ensemble, l’émission de /ToUnicode et la politique d’intégration explicite Strict / AllowBase14 sont des comportements du moteur de base.

Pro

Ajoute une application et un signalement de conformité plus poussés autour de l’intégration des polices au niveau du profil.

Enterprise

Ajoute la même application de conformité sous la surface opérationnelle entreprise.

Voici les deux moitiés d’une police composite correctement intégrée, sous-ensemblée et recherchable. La balise de sous-ensemble applique la règle des six lettres de la norme ; la référence /ToUnicode est ce qui garde le texte extractible.

% The Type 0 (composite) font dictionary
20 0 obj
<< /Type /Font /Subtype /Type0
/BaseFont /ABCDEF+NotoSans % six-letter subset tag + '+'
/Encoding /Identity-H
/DescendantFonts [21 0 R]
/ToUnicode 23 0 R >> % the map that makes text searchable
endobj
% The descendant CIDFontType2 (carries the subsetted program)
21 0 obj
<< /Type /Font /Subtype /CIDFontType2
/BaseFont /ABCDEF+NotoSans
/CIDToGIDMap /Identity % glyph IDs preserved, not remapped
/FontDescriptor 22 0 R >>
endobj

Le /ToUnicode 23 0 R de l’objet 20 fait la différence entre un document recherchable et une image de document. Supprime-le (en dehors du cas de la CMap prédéfinie) et chaque glyphe se trace toujours parfaitement, mais une recherche d’un mot quelconque sur la page ne trouve rien.

Le piège, dit simplement : le fait que les glyphes s’affichent correctement ne dit rien sur le fait que le texte soit du texte. Le rendu suit le chemin encodage-vers-glyphe. La recherche et la copie suivent le chemin code-vers-Unicode (/ToUnicode). Ce sont des mécanismes différents, qui lisent des parties différentes du dictionnaire de police. Ainsi, un document peut avoir une sortie visuelle impeccable et un /ToUnicode absent ou erroné. Le résultat est une page qui a l’air officielle et qui est fonctionnellement impossible à rechercher — l’échec qui survit à toute revue visuelle, car par définition il n’y a rien à voir.

Un piège connexe : supposer que « la police est intégrée, donc nous sommes prêts pour l’archivage. » L’intégration est nécessaire, mais pas suffisante. Un profil tel que PDF/A attend aussi des sous-ensembles nommés selon la règle des six lettres et un encodage correct. Intégré mais impossible à rechercher échoue quand même.

Le sous-ensembleur de NextPDF est spécifiquement un sous-ensembleur TrueType. Il requiert les tables TrueType essentielles et renvoie la police d’origine inchangée lorsqu’elles manquent ou que le gain est inférieur au seuil d’environ 10 %. Le sous-ensemble et une CMap /ToUnicode rendent le texte extractible, mais ils ne peuvent pas sauver une police source qui ne contient pas l’information nécessaire pour faire correspondre un glyphe à un caractère porteur de sens. Là où aucune valeur Unicode ne peut être déterminée, aucune émission de CMap n’en invente une.

Cette page traite de la production d’une structure de police correcte dans les documents que NextPDF écrit. Ce n’est pas un outil de réparation de polices pour des PDF entrants arbitraires. Et l’émission d’un sous-ensemble et d’un encodage conformes ne suffit pas, à elle seule, à certifier un document par rapport à un profil d’archivage complet — c’est une vérification distincte et plus large.

Pourquoi la balise de six lettres — pourquoi pas le nom de la police ? Pour qu’un lecteur puisse distinguer deux sous-ensembles différents de la même police et fusionner des documents sans que leurs jeux de glyphes entrent en collision. Sous-ensembles différents, balises différentes, par règle.

Quand est-il acceptable de n’avoir aucun /ToUnicode ? Lorsqu’une CMap CJK prédéfinie et auto-descriptive fournit déjà la correspondance caractère-vers-Unicode. Dans ce cas, la CMap est l’encodage. Un /ToUnicode séparé serait redondant. En dehors de cela, son absence est un défaut.

Le sous-ensemble peut-il parfois nuire ? Seulement s’il est mal fait. Supprimer des composants de glyphes composites casse les glyphes accentués. Remapper les identifiants de glyphes sans réécrire les références casse le rendu. NextPDF évite les deux en résolvant la fermeture des composants et en préservant l’identité des glyphes.

  • Flux et filtres — les programmes de police intégrés sont des objets de flux filtrés, avec leur propre contrat de décodage.
  • Ce qu’est réellement un PDF — le modèle d’objets dans lequel vivent les dictionnaires de police et les flux de programme.
  • PDF 2.0 : ce qui a changé — y compris les attentes resserrées de la base 2.0 en matière d’intégration des polices.
  • Programme de police intégré — le fichier de police réel (TrueType/CFF/Type 1) transporté à l’intérieur du PDF comme un flux, de sorte que le rendu ne dépende pas des polices installées chez le lecteur.
  • Sous-ensemble — réécriture d’un programme de police pour qu’il ne contienne que les glyphes utilisés par le document, afin d’en réduire la taille.
  • Balise de sous-ensemble — le préfixe obligatoire de six lettres majuscules suivi de + sur le nom d’une police en sous-ensemble (par exemple, ABCDEF+NotoSans).
  • /ToUnicode — un flux de CMap faisant correspondre les codes de caractères à des valeurs Unicode ; ce qui rend le texte d’un PDF recherchable, copiable et accessible.
  • Glyphe composite — un glyphe construit en référençant d’autres glyphes comme composants ; ses composants doivent être conservés lors du sous-ensemble.
  • CIDToGIDMap /Identity — le mode où les indices de glyphes du flux de contenu sont les identifiants de glyphes propres à la police, inchangés ; NextPDF préserve l’identité des glyphes pour garder cela valide.
  • Base14 — les quatorze polices Type 1 standard ; PDF 2.0 attend que les polices soient intégrées plutôt que référencées par leur nom.