Aller au contenu
getnextpdf.com

Pro édition

Font Tools — référence approfondie

Cette page est la référence de niveau contrat pour NextPDF Pro Font Tools. La surface se compose d’un seul scanner, NextPDF\Pro\FontTools\FontDesubsetter, et de deux objets-valeurs immuables, SubsetInfo et DesubsetPlan. Le scanner lit les octets bruts du PDF, signale chaque entrée /BaseFont distincte et marque les entrées qui suivent la convention de nommage de sous-ensemble d’ISO 32000-2:2020 §9.9.2. Un plan agrège les sous-ensembles marqués et estime le coût en octets de la restauration des programmes de police complets. Le module se contente d’analyser et d’estimer ; il ne réécrit jamais un programme de police intégré. Cette page énonce l’API publique, le contrat de comportement observable et les modes de défaillance.

Cette fonctionnalité est livrée dans NextPDF Pro (nextpdf/pro) et s’active avec une enveloppe de licence de niveau Pro. Un déploiement dépourvu de ce droit ne charge pas les classes de la fonctionnalité. Compare les éditions et obtiens une licence.

Aucun indicateur de licence propre à la fonctionnalité ne conditionne ce module. Les classes Font Tools sont disponibles dès que nextpdf/pro est installé.

SymboleParamètresComportement par défautRetourneLève ou échoue avecNotes
FontDesubsetteraucunScanner sans état sur les octets bruts du PDFfinal ; réutilisable sans risque entre documents
FontDesubsetter::analyzeSubsets()string $pdfDataSignale chaque entrée /BaseFont distincte, sous-ensemble ou non, marquée par isSubsetlist<SubsetInfo>InvalidArgumentException lorsqu’une estimation de sous-ensemble dérivée des largeurs dépasse l’estimation du décompte complet dérivée du nomAnalyse au niveau de l’octet ; les flux d’objets compressés ne sont pas décodés
FontDesubsetter::isSubsetFont()string $baseFontNameCorrespond à la convention de préfixe « six lettres majuscules plus + »boolAncré au début du nom
FontDesubsetter::extractSubsetPrefix()string $baseFontNameRetourne l’étiquette de sous-ensemble de six lettresstringChaîne vide pour les noms qui ne sont pas des sous-ensembles
FontDesubsetter::generateDesubsetPlan()list<SubsetInfo> $subsetsCollecte les entrées dont isSubset vaut true et additionne l’estimation de tailleDesubsetPlanNe lève pasLes entrées qui ne sont pas des sous-ensembles sont ignorées silencieusement
SubsetInfoconstructeur : $fontName, $baseFont, $subsetGlyphCount, $fullGlyphCount, $isSubset, $encodingDescription immuable d’une entrée /BaseFontInvalidArgumentException sur un décompte de glyphes négatif, ou un décompte de sous-ensemble supérieur au décompte completfinal readonly ; toutes les propriétés sont publiques
SubsetInfo::subsetPrefix()aucunExtrait l’étiquette de six lettres de fontNamestringChaîne vide lorsqu’il ne s’agit pas d’un sous-ensemble ou que le + ne se trouve pas en position six
SubsetInfo::coveragePercent()aucunPart du sous-ensemble dans l’ensemble complet des glyphesfloat dans [0.0, 100.0]Retourne 0.0 lorsque fullGlyphCount vaut 0
DesubsetPlanconstructeur : list<SubsetInfo> $targets, int $estimatedSizeIncreasePlan de dé-sous-ensemble immuablefinal readonly ; toutes les propriétés sont publiques
DesubsetPlan::count()aucunNombre de polices cibléesintÉgal à la longueur de targets
DesubsetPlan::totalGlyphsNeeded()aucunGlyphes manquants additionnés sur toutes les ciblesintSomme de fullGlyphCount - subsetGlyphCount par cible
public function analyzeSubsets(string $pdfData): array
public function isSubsetFont(string $baseFontName): bool
public function extractSubsetPrefix(string $baseFontName): string
public function generateDesubsetPlan(array $subsets): DesubsetPlan
public function __construct(
public string $fontName,
public string $baseFont,
public int $subsetGlyphCount,
public int $fullGlyphCount,
public bool $isSubset,
public string $encoding,
)
public function subsetPrefix(): string
public function coveragePercent(): float
public function __construct(
public array $targets,
public int $estimatedSizeIncrease,
) {}
public function count(): int
public function totalGlyphsNeeded(): int

analyzeSubsets() extrait les jetons de nom /BaseFont des octets bruts au moyen d’une correspondance de motif au niveau de l’octet. Les noms en double sont fusionnés en une seule entrée ; l’ordre suit la première apparition. Chaque nom distinct produit un SubsetInfo, qu’il s’agisse ou non d’un sous-ensemble. Un nom est un sous-ensemble lorsqu’il commence par exactement six lettres majuscules ASCII suivies de +, la convention du §9.9.2. Pour les noms de sous-ensemble, baseFont est le nom débarrassé du préfixe de sept caractères. Pour les noms ordinaires, baseFont est égal à fontName. Chaque nom de sous-ensemble distinct est signalé comme sa propre entrée, conformément à la recommandation du §9.9.2 de traiter les sous-ensembles comme des entités indépendantes.

Pour chaque police, le scanner examine une fenêtre d’octets bornée après l’occurrence de /BaseFont. Une entrée de nom /Encoding présente dans la fenêtre l’emporte. À défaut, une sous-chaîne Identity-H ou Identity-V présente dans la fenêtre est signalée. À défaut des deux, l’entrée signale Unknown. Les valeurs d’encodage contenues dans des dictionnaires ou atteintes via des références indirectes signalent Unknown.

Les deux décomptes de glyphes sont des estimations. subsetGlyphCount dérive des tableaux de largeurs visibles près de l’entrée de police : un tableau /W de CIDFont produit environ un glyphe par triplet de largeur, et un tableau /Widths de police simple produit un glyphe par entrée numérique. Lorsqu’aucun des deux tableaux n’est visible dans la fenêtre, une petite valeur par défaut fixe s’applique. Lorsque l’occurrence de /BaseFont ne peut pas être retrouvée pour la recherche dans la fenêtre, le décompte est 0. fullGlyphCount dérive d’heuristiques fondées sur le nom de famille : une table de familles latines bien connues, un ensemble d’indicateurs de nom de famille CJK, et un plancher générique sinon. Le programme de police intégré n’est jamais analysé. Les tables, tailles de fenêtre et constantes précises relèvent du détail d’implémentation, ne sont pas publiées et peuvent changer d’une version à l’autre.

generateDesubsetPlan() filtre l’entrée pour ne conserver que les entrées dont isSubset vaut true. Chaque cible contribue à estimatedSizeIncrease par son décompte de glyphes manquants, multiplié par une constante fixe d’octets moyens par glyphe. Le plan est une projection destinée aux décisions de capacité, non un delta mesuré. Exécuter un plan — réécrire les programmes de police — sort du périmètre de ce module.

L’ensemble de la surface est une fonction pure de son entrée. Des octets identiques produisent des résultats identiques. Il n’y a aucune part d’aléatoire, aucun appel réseau et aucun accès au système de fichiers.

  • La construction de SubsetInfo rejette les états invalides : un décompte de glyphes négatif, ou un décompte de sous-ensemble supérieur au décompte complet, lève InvalidArgumentException.
  • analyzeSubsets() peut propager cette exception dans un cas particulier : une police dont le nom correspond à une famille connue mais dont le tableau de largeurs visible produit une estimation de sous-ensemble plus grande que le chiffre du décompte complet de la famille.
  • La détection opère sur la représentation en octets. Les entrées /BaseFont sérialisées dans des flux d’objets compressés sont invisibles ; décompresse ces flux avant de balayer.
  • Les entrées dont la clé et la valeur /BaseFont sont séparées par un espace autre qu’une simple espace sont tout de même détectées, mais la recherche par fenêtre propre à chaque police ne parvient pas à les retrouver. De telles entrées signalent l’encodage Unknown et un décompte de glyphes de sous-ensemble de 0.
  • Les noms PDF utilisant des octets échappés par # sont signalés sous leur forme échappée brute ; les échappements ne sont pas décodés.
  • Les noms /BaseFont en double sont fusionnés en une seule entrée. Deux objets de police distincts partageant un même nom sont indiscernables pour ce scanner.
  • generateDesubsetPlan() n’échoue jamais sur une entrée qui n’est pas un sous-ensemble ; les entrées dont isSubset vaut false sont simplement exclues de targets.
  • Tous les décomptes et estimatedSizeIncrease sont des heuristiques. Ne les traite pas comme des valeurs mesurées ; utilise-les uniquement pour le triage et la planification de capacité.
  • Aucune opération cryptographique n’a lieu dans ce module, il n’y a donc aucun comportement propre au mode FIPS.
AffirmationNormeClause
La détection de sous-ensemble correspond à la convention de nommage de sous-ensemble : une étiquette de six lettres majuscules suivie de + préfixée à la valeur BaseFont.ISO 32000-2:2020§9.9.2
Chaque nom de sous-ensemble distinct est signalé indépendamment, suivant la recommandation de traiter plusieurs sous-ensembles comme des entités distinctes.ISO 32000-2:2020§9.9.2

Toutes les clauses sont paraphrasées ; NextPDF ne reproduit pas le texte normatif. Il s’agit de déclarations de capacité, non de certifications. NextPDF ne détient aucune certification et n’en accorde aucune. Le module affirme la détection de la convention de nommage et un signalement déterministe ; il n’affirme pas l’exactitude des estimations de décompte de glyphes ou de taille.

  • Installe avec composer require nextpdf/pro:^3. Disponible depuis nextpdf/pro 1.9.0 ; actuel dans nextpdf/pro 3.1.0.
  • FontDesubsetter est sans état. Construis-le une fois et réutilise-le entre les documents et les fils de travail.
  • Fournis à analyzeSubsets() des octets décompressés lorsque la couverture des sous-ensembles compte ; sinon, les dictionnaires de police empaquetés dans des flux d’objets sont manqués.
  • Aiguille sur SubsetInfo::isSubset avant d’agir ; la liste de résultats inclut intentionnellement les polices qui ne sont pas des sous-ensembles à des fins d’inventaire.
  • Utilise DesubsetPlan::totalGlyphsNeeded() et estimatedSizeIncrease pour décider si le dé-sous-ensemble vaut le coût en taille de fichier avant de te procurer les programmes de police complets.
  • Le balayage est linéaire en fonction de la longueur de l’entrée, avec des recherches par fenêtre bornées pour chaque police. Le module ne stocke rien et n’émet aucune télémétrie.

Cette page documente uniquement le comportement observable de l’extérieur et la surface d’API publique prise en charge. Les chemins d’espaces de noms internes, les classes utilitaires, les tables de mécanismes, les noms de fichiers de runbook et les préfixes de ticket sont hors périmètre.