La découverte est arrivée six ans après le déploiement : trente-huit mille factures archivées déclaraient PDF/A-1b dans leurs métadonnées XMP, et un échantillon passé dans veraPDF échouait presque partout — RGB dépendant du périphérique sans OutputIntent, deux polices jamais incorporées, des flags d'annotation interdits par ISO 19005-1. L'application de génération avait écrit l'identifiant de conformité sans jamais valider face à la norme, et tous les systèmes aval avaient fait confiance à l'étiquette. Une conformité auto-déclarée vaut exactement ce qu'elle coûte à écrire. L'alternative durable est le preflight au moment où un fichier entre dans l'archive, et losLab PDF Library (PDFlibPas) le rend pratique pour les systèmes Delphi et C++Builder en intégrant les validateurs PDF/A et PDF/UA dans la bibliothèque elle-même, sans service externe dans la boucle.
Deux normes qui font échouer les fichiers pour des raisons opposées
ISO 19005 (PDF/A) est un contrat de reproduction : un fichier conforme doit se rendre à l'identique dans des décennies, sur un logiciel qui n'a jamais vu le système d'origine. Ses règles attaquent donc les dépendances externes — chaque police incorporée, la couleur ancrée à un OutputIntent ICC intégré ou exprimée dans des espaces indépendants du périphérique, pas de chiffrement en PDF/A-1, pas de JavaScript, des métadonnées XMP cohérentes avec le dictionnaire d'informations du document.
ISO 14289 (PDF/UA) est un contrat de sémantique : les technologies d'assistance doivent pouvoir parcourir le document de manière significative. Ses règles vivent dans une couche entièrement différente — arbre de structure complet, texte alternatif sur les figures, titre de document configuré pour l'affichage, niveaux de titres qui ne sautent jamais, relations d'en-têtes de tableau qui tiennent hors écran.
Les deux sont orthogonales, et les fichiers dangereux se trouvent au milieu. Un document parfait pour l'archivage peut être illisible pour un lecteur d'écran ; un document parfaitement balisé peut référencer une police de bureau qui n'existera plus dans dix ans. Les pipelines qui nécessitent les deux — la publication du secteur public est le cas canonique — doivent exécuter les deux contrôles et acheminer les constats vers des responsables différents, car les polices non incorporées sont un défaut du code de génération tandis que le texte alternatif manquant appartient à l'équipe qui maintient les modèles.
Le choix de partie compte autant que le verdict. PDF/A-1, figé sur PDF 1.4, rejette la transparence et JPEG2000 — des fonctionnalités que les sorties de reporting modernes utilisent librement. PDF/A-2 (ISO 19005-2, bâti sur ISO 32000-1) accepte les deux et constitue le choix par défaut raisonnable pour de nouvelles archives. PDF/A-3 autorise en plus des fichiers incorporés de tout type, ce dont dépendent les formats de facturation électronique réglementés. Une équipe qui standardise encore sur PDF/A-1b en 2026 hérite généralement d'une exigence écrite il y a quinze ans, et la correction la moins chère consiste souvent à renégocier la partie cible plutôt qu'à retirer la transparence de chaque graphique.
Constats structurés au moment de l'ingestion
Le point d'entrée de l'API flat est CheckFileCompliance, avec le sélecteur de test 1 pour PDF/A et 2 pour PDF/UA. Il renvoie un handle de liste de chaînes dont les éléments sont des constats individuels, ce qui en fait la bonne forme pour une barrière automatisée :
function GateArchiveUpload(Pdf: TPDFlib; const FileName: string): Boolean;
var
ListId, I: Integer;
begin
ListId := Pdf.CheckFileCompliance(FileName, '', 1, 0); // 1 = PDF/A
if ListId = 0 then
begin
// 0 means "no findings" OR "file unreadable" -- disambiguate before passing
Result := Pdf.LastErrorCode = 0;
Exit;
end;
for I := 0 to Pdf.GetStringListCount(ListId) - 1 do
LogFinding(FileName, Pdf.GetStringListItem(ListId, I));
Pdf.ReleaseStringList(ListId);
Result := False;
end;
Deux détails d'implémentation décident si ce mécanisme fonctionne sans surveillance. D'abord, CheckFileCompliance renvoie 0 aussi bien lorsque le fichier est entièrement conforme que lorsque le fichier n'a pas pu être ouvert — en interne, une liste de résultats vide produit 0 dans les deux cas — si bien qu'une barrière qui lit 0 comme un succès laissera entrer des uploads corrompus dans l'archive. Désambiguïsez avec LastErrorCode, comme ci-dessus. Ensuite, le contrôleur travaille sur le lecteur en flux de la bibliothèque plutôt que sur le modèle de document complet : il ouvre le fichier directement avec partage en lecture et n'a jamais besoin de LoadFromFile, ce qui explique pourquoi il gère des fichiers de plusieurs gigaoctets sans construire d'arbres d'objets — mais il échouera pendant qu'un autre processus détient encore le fichier ouvert en écriture, exactement l'état d'un upload en cours. Filtrez après la fin du transfert, pas pendant.
Le débit découle du même design. Comme chaque contrôle ouvre son entrée en lecture seule et partage le fichier pour lecture, un audit de corpus se parallélise naturellement entre workers threads ou processus, avec une instance TPDFlib par worker. Les handles de listes de chaînes sont la ressource qui demande de la discipline : tout handle non nul issu de CheckFileCompliance reste alloué jusqu'à ReleaseStringList, et une barrière longue durée qui les fuit se dégrade lentement plutôt que de casser bruyamment.
Des rapports pour les humains, des diffs pour les barrières de build
Les listes de constats sont la bonne forme pour une barrière et la mauvaise pour un e-mail à l'équipe modèles. CreatePreflightReport rend la même analyse sous forme de rapport lisible, CreatePreflightReportEx ajoute un sélecteur de format de rapport, et SavePreflightReport écrit le rapport sur disque afin qu'il puisse voyager dans le paquet documentaire — une exigence contractuelle dans beaucoup d'accords de livraison archivistique.
Le membre sous-estimé de la famille est ComparePreflightReports. Les résultats de conformité sont une surface de régression comme les autres : une modification de modèle, une nouvelle police d'entreprise ou une mise à niveau de bibliothèque peuvent introduire chacune des constats absents à la version précédente. Conservez sous contrôle de version des rapports de référence pour un corpus de documents représentatifs, régénérez-les après chaque changement, et laissez ComparePreflightReports calculer le delta. Un diff vide devient un artefact de release ; un constat inattendu fait échouer le build au lieu de faire échouer l'audit.
Générer une sortie qui réussit dès le premier passage
Le preflight gagne sa place sur les fichiers entrants ; pour les documents produits par votre propre code, réparer les constats après génération prend le problème à l'envers. PDFlibPas embarque un mode côté génération pour chaque norme, et les deux se composent :
var
Pdf: TPDFlib;
Diag: WideString;
begin
Pdf := TPDFlib.Create;
try
Pdf.NewDocument;
Pdf.SetPDFAMode(1);
Pdf.LoadOutputIntentProfile('sRGB-IEC61966-2.1.icc', 'RGB');
Pdf.SetPDFUAMode('en-US');
Pdf.SetInformation(1, 'Quarterly Statement'); // /Title: required for PDF/UA
// ... draw tagged content here ...
Diag := Pdf.GetPDFUADiagnostics;
if Diag <> '' then
Writeln('fix before shipping: ', Diag);
Pdf.SaveToFile('statement.pdf');
// the preflight that counts runs on the saved file:
Writeln(Pdf.CreatePreflightReport('statement.pdf', '', 1, 0));
finally
Pdf.Free;
end;
end;
Le piège se cache à l'enregistrement. Plusieurs réparations de conformité — forcer le flag d'impression sur les annotations, écrire la valeur par défaut AFRelationship pour les fichiers incorporés PDF/A-3, normaliser l'ordre de tabulation et les descriptions de champs de formulaire pour PDF/UA — sont appliquées pendant la sérialisation du document, pas au moment où le mode est activé. Le document en mémoire n'est pas identique, octet pour octet, à celui qui atteint le disque ; le seul verdict de preflight qui compte est donc celui calculé depuis le fichier enregistré. Validez statement.pdf ; ne déduisez jamais la conformité depuis l'objet document encore en mémoire.
Les scénarios de facture qui incorporent du XML lisible machine à côté du document visuel — le modèle ZUGFeRD et Factur-X, bâti sur PDF/A-3 — doivent définir explicitement la relation de pièce jointe via SetPDFA3DefaultAFRelationship, car ISO 19005-3 exige que chaque fichier incorporé déclare son rôle par rapport au document.
Arbitres indépendants : veraPDF et Acrobat
Ne laissez jamais un producteur noter sa propre copie. Les contrôleurs PDFlibPas donnent des verdicts rapides, structurés et in-process ; la barrière de release pour les lots d'archive doit tout de même inclure un validateur indépendant. veraPDF est l'implémentation de référence maintenue par la communauté pour la validation PDF/A et l'outil que la plupart des archives nomment dans leurs critères d'acceptation ; les profils de preflight d'Acrobat fournissent une troisième opinion utile lorsque deux outils divergent. Enregistrez le nom et la version du validateur à côté de chaque rapport stocké — prétendre « passe veraPDF » ne signifie pas grand-chose sans savoir quel veraPDF.
Lorsque les validateurs ne sont pas d'accord, ce qui arrivera parfois aux marges des normes, réduisez le fichier à un échantillon minimal et tranchez face au texte de la norme plutôt que face à l'un ou l'autre outil. L'exercice prend une heure et révèle généralement soit un bug d'outil à signaler, soit une clause mal lue à documenter dans les notes de conformité de l'équipe.
Les entrées chiffrées méritent une règle spéciale. Les deux contrôleurs acceptent un argument mot de passe, mais pour PDF/A-1 le dictionnaire de chiffrement est déjà une violation de conformité — ISO 19005-1 l'interdit purement et simplement — si bien qu'une soumission chiffrée peut être rejetée avant toute analyse plus profonde. Auditer ce qu'un dictionnaire de chiffrement autorise réellement est un exercice séparé, traité dans l'audit du chiffrement PDF et des permissions.
Les constats PDF/UA remontent presque toujours à la manière dont l'arbre de structure a été authoré ; les techniques de balisage sont couvertes dans la construction d'arbres de structure Tagged PDF en Delphi. Les archives qui exigent aussi des signatures numériques doivent associer cette barrière au flux décrit dans la signature et validation PAdES. La référence complète de l'API preflight se trouve sur la page produit losLab PDF Library pour Delphi.