PDF Library for Delphi (PDFlibPas) écrit les métadonnées de commandes Web Capture dans le catalogue du document via AddWebCaptureCommand, en remplissant le dictionnaire /SpiderInfo défini dans ISO 32000-1 §14.10. Chaque commande enregistre l'URL récupérée, la profondeur en niveaux de la collecte et un petit jeu de drapeaux. Elle enregistre l'intention — elle ne récupère rien
C'est précisément cette distinction qui rend cette API facile à mal lire. Un ingénieur du support vous tend un PDF assemblé depuis la documentation en ligne d'un fournisseur et demande d'où vient la page 40. Si le producteur a rempli /SpiderInfo, la réponse se trouve dans le catalogue : une URL, une profondeur de collecte, peut-être le corps POST qui a produit la page. Si le producteur ne l'a pas fait, aucune lecture du flux de contenu ne vous le dira. Écrire cette provenance est peu coûteux, structurellement délicat, et presque toujours omis
Que contient vraiment le dictionnaire /SpiderInfo du catalogue ?
/SpiderInfo est un dictionnaire d'informations Web Capture accroché au catalogue du document, et il contient exactement deux choses qui intéressent PDF Library for Delphi : /V, un numéro de version numérique de la base de données Web Capture que la bibliothèque écrit toujours comme 1.0, et /C, un tableau de dictionnaires de commandes. Le numéro de version n'est pas la version du PDF — il identifie le modèle de données Web Capture lui-même, et 1.0 est la seule valeur que définit ISO 32000-1 §14.10. Tout ce qui compte se trouve dans /C. Chaque dictionnaire de commande porte /URL (l'adresse qui a été demandée), /L (le nombre de niveaux de liens suivis depuis elle) et /F (les drapeaux de traversée). Trois clés optionnelles décrivent la requête elle-même quand ce n'était pas un simple GET : /P pour les données POST, /CT pour le type de contenu de ces données et /H pour les en-têtes de requête supplémentaires. PDF Library for Delphi projette les six sur un seul enregistrement, TPDFlibWebCaptureCommand, dont les champs sont URL, Levels, Flags, PostData, ContentType et Headers, tous en AnsiString sauf les deux compteurs Integer. La présence de /SpiderInfo pousse aussi la version minimale du document : AddWebCaptureCommand appelle EnsureMinVersion('1.3', 'Catalog /SpiderInfo Web Capture command'), et les règles de détection de version de PDF Library for Delphi enregistrent une règle PDF 1.3 correspondante pour qu'un document relu plus tard signale le même plancher
Pourquoi une commande Web Capture doit être un objet indirect
La seule règle structurelle qui fait trébucher : un dictionnaire de commande doit être enregistré comme objet indirect avant d'entrer dans /C, parce que ISO 32000-1 §14.10 spécifie /C comme un tableau de références indirectes vers des dictionnaires de commandes, pas comme un tableau de dictionnaires. Pousser un dictionnaire direct dans ce tableau produit quelque chose qui se parse comme un PDF valide et ne vaut rien comme enregistrement Web Capture — une visionneuse ou un outil d'archivage qui parcourt la liste de commandes trouve un objet inline là où une référence devrait se trouver, et l'entrée n'est tout simplement pas une commande. PDF Library for Delphi gère cela à l'intérieur de AddWebCaptureCommand : elle construit le dictionnaire, le confie à OnNewIndObj pour obtenir un numéro d'objet et un numéro de génération, enveloppe la paire dans une référence indirecte et ajoute la référence au tableau. Si OnNewIndObj ne produit pas de numéro d'objet positif, la fonction renvoie 0 et le tableau reste intact. La raison pour laquelle la spec insiste sur l'indirection est qu'une commande unique peut être partagée — la même collecte peut être référencée depuis plus d'un endroit dans une structure Web Capture — et les objets partagés dans un PDF sont, par définition, indirects
Comment ajouter une commande Web Capture depuis Delphi ?
Remplissez l'enregistrement entièrement, puis appelez AddWebCaptureCommand, qui renvoie l'index 1-based de la nouvelle commande ou 0 si la validation l'a rejetée. L'exhaustivité compte ici plus que d'habitude. Delphi initialise les champs AnsiString gérés d'un enregistrement local à vide, mais les champs Integer — Levels et Flags — ne reçoivent aucun traitement de ce genre, donc un enregistrement que vous oubliez de remplir arrive portant ce qui traînait sur la pile. AddWebCaptureCommand exige que Levels vaille au moins 1 et que Flags soit non négatif, et une valeur de déchet de pile sera soit rejetée d'emblée, soit, pire, acceptée silencieusement comme une profondeur plausible
var
Lib: TPDFlib;
Command: TPDFlibWebCaptureCommand;
Index: Integer;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile('captured-site.pdf', '') = 1 then
begin
// Affectez chaque champ : Levels et Flags sont des Integer bruts et
// portent des déchets de pile si vous les sautez.
Command.URL := 'https://example.com/docs/index.html';
Command.Levels := 2;
Command.Flags := PDF_WEB_CAPTURE_SAME_SITE or PDF_WEB_CAPTURE_SAME_PATH;
Command.PostData := '';
Command.ContentType := '';
Command.Headers := '';
// Renvoie le nouvel index de commande 1-based, ou 0 en cas de rejet.
Index := Lib.AddWebCaptureCommand(Command);
if Index = 0 then
raise Exception.Create('Web Capture command rejected');
Lib.SaveToFile('captured-site.pdf');
end;
finally
Lib.Free;
end;
end;
La première appel réussie est aussi ce qui crée la structure. AddWebCaptureCommand demande le tableau de commandes à l'helper interne WebCaptureCommands(True), et cet helper crée /SpiderInfo avec son entrée /V puis un tableau /C vide seulement s'ils manquent. Il est délibérément conservateur sur ce qu'il trouve : si le catalogue a déjà une clé /SpiderInfo dont la valeur n'est pas un dictionnaire, ou une clé /C dont la valeur n'est pas un tableau, l'helper renvoie nil plutôt que d'écraser l'objet existant. Une structure héritée malformée fait échouer l'ajout ; elle ne fait pas détruire à PDF Library for Delphi ce que le producteur précédent a écrit
La liste blanche de drapeaux : trois bits définis et rien d'autre
AddWebCaptureCommand valide Flags contre une liste blanche et rejette toute valeur avec un bit posé hors des trois constantes que définit PDF Library for Delphi : PDF_WEB_CAPTURE_SAME_SITE = 1 (suivre seulement les liens qui restent sur le même site), PDF_WEB_CAPTURE_SAME_PATH = 2 (suivre seulement les liens sous le même chemin) et PDF_WEB_CAPTURE_SUBMIT = 4 (cette requête était une soumission de formulaire plutôt qu'une simple récupération). Passez 8, ou 16, ou un -1 accidentel, et l'appel renvoie 0 sans toucher au document
C'est plus strict que ne le sont d'habitude les parseurs PDF, et c'est voulu. /F est un champ de bits sans structure auto-descriptive, donc un bit non défini est indiscernable d'un bit corrompu, et un consommateur qui relit la valeur plus tard n'a aucun moyen de distinguer une extension future d'une coquille. Refuser à l'écriture garde l'ambiguïté complètement hors du fichier. Notez aussi que /P, /CT et /H ne sont écrits que quand leurs champs d'enregistrement correspondants sont non vides, donc un GET ordinaire produit un dictionnaire de commande à trois clés — /URL, /L, /F — sans placeholders de chaîne vide qui l'encombrent, ce qu'attend un lecteur qui parse le fichier pour une requête sans corps
// Une soumission de formulaire : corps POST plus son type de contenu.
Command.URL := 'https://example.com/search';
Command.Levels := 1;
Command.Flags := PDF_WEB_CAPTURE_SUBMIT; // 4
Command.PostData := 'q=iso32000&scope=all';
Command.ContentType := 'application/x-www-form-urlencoded';
Command.Headers := 'Accept-Language: en-US';
if Lib.AddWebCaptureCommand(Command) = 0 then
raise Exception.Create('submission command rejected');
// Même site plus même chemin est une combinaison légale : 1 ou 2 = 3.
Command.Flags := PDF_WEB_CAPTURE_SAME_SITE or PDF_WEB_CAPTURE_SAME_PATH;
// Le bit 3 n'est pas défini par la spec, donc celui-ci n'atteint jamais le fichier.
Command.Flags := 8;
if Lib.AddWebCaptureCommand(Command) <> 0 then
raise Exception.Create('undefined flag bit should have been refused');
Relire les commandes : une clé, deux représentations légales
GetWebCaptureCommand renvoie 1 en cas de succès et 0 sinon, et il doit être plus tolérant que l'écrivain, parce qu'il lit des fichiers écrits par d'autres producteurs. Deux asymétries comptent. D'abord, le lecteur accepte une entrée de commande qu'elle soit une référence indirecte ou un dictionnaire direct, en déréférençant quand c'est nécessaire — PDF Library for Delphi écrit toujours la forme indirecte qu'exige la spec, mais refuser de lire un fichier bâclé n'aide personne. Ensuite, /P est autorisé à être soit une chaîne soit un flux, et cela se généralise bien au-delà de Web Capture. ISO 32000-1 laisse à plusieurs reprises une clé unique tenir soit une chaîne soit un flux quand la valeur peut être arbitrairement grande — les corps POST ici, et le même motif réapparaît ailleurs dans le format pour les métadonnées et les charges embarquées. L'helper interne ReadString dans GetWebCaptureCommand prend donc un drapeau AllowStream, et seule la lecture de /P passe True : une valeur de flux est décodée à travers sa chaîne de filtres et renvoyée comme champ PostData, tandis que /URL, /CT et /H restent chaînes uniquement parce que la spec ne leur offre pas l'alternative flux. Si vous écrivez votre propre code de lecture PDF, c'est l'habitude à voler — vérifiez dans la spec quelles clés sont doublement typées plutôt que de supposer une chaîne
var
Lib: TPDFlib;
Command: TPDFlibWebCaptureCommand;
I, Total, Removed: Integer;
begin
Total := Lib.GetWebCaptureCommandCount;
// L'indexation publique est 1-based, comme le reste de PDF Library for Delphi.
for I := 1 to Total do
if Lib.GetWebCaptureCommand(I, Command) = 1 then
Writeln(Format('%s levels=%d flags=%d post=%d bytes',
[Command.URL, Command.Levels, Command.Flags, Length(Command.PostData)]));
// Supprime tout le dictionnaire /SpiderInfo et rapporte combien de
// commandes ont été abandonnées ; renvoie 0 quand il n'y avait rien à effacer.
Removed := Lib.ClearWebCaptureCommands;
Writeln(Format('cleared %d command(s)', [Removed]));
end;
ClearWebCaptureCommands compte les commandes, puis purge la clé /SpiderInfo entière du catalogue plutôt que de simplement vider /C. Laisser un /SpiderInfo avec un tableau de commandes vide affirmerait que le document a une provenance Web Capture et que rien n'a été collecté, ce qui est une affirmation différente et fausse par rapport à n'avoir aucune provenance enregistrée. Le même instinct s'applique généralement aux métadonnées de catalogue — un dictionnaire coquille vide est une déclaration, pas un résidu neutre. Si vous auditez ce qu'un document prétend déjà avant de le réécrire, le motif d'introspection dans lire les actions d'outline et d'annotation d'un PDF existant se marie naturellement avec une passe lire-puis-effacer ici
Écrire des métadonnées n'est pas implémenter Web Capture
Soyez franc avec vous-même sur le périmètre : AddWebCaptureCommand sauvegarde un enregistrement d'une collecte prévue ou terminée, et c'est tout ce qu'il fait. PDF Library for Delphi n'exécute pas de requêtes HTTP, ne suit pas les liens que décrit votre valeur Levels et n'honore pas les drapeaux SAME_SITE ou SAME_PATH — ces drapeaux documentent le comportement d'un crawler, ce ne sont pas des instructions que la bibliothèque exécute. Votre propre code de collecte, quel qu'il soit, reste entièrement votre affaire
Deux autres morceaux d'ISO 32000-1 §14.10 sont aussi hors de cette API. Web Capture définit des ensembles de contenu — les structures /Contents qui rattachent des morceaux de page individuels à la source dont ils proviennent — et un name tree qui projette des identifiants numériques vers ces ensembles. PDF Library for Delphi ne maintient ni l'un ni l'autre. Ce que vous obtenez, c'est la liste de commandes : la réponse de premier niveau à « d'où ce document a-t-il été collecté, et à quelle profondeur la collecte est-elle allée », ce qui pour la provenance, l'audit et l'entrée en archivage est d'habitude la partie que tout le monde demande réellement. Si vous voulez que les URL soient cliquables pour les lecteurs plutôt que seulement enregistrées pour les auditeurs, c'est un travail séparé — voir construire les actions GoToR, GoToE et Launch pour le côté action, et les déclencheurs d'actions de cycle de vie de document et de page pour le comportement au moment d'ouvrir ou fermer. Les métadonnées de commandes Web Capture du catalogue /SpiderInfo comme décrites ici font partie de PDF Library for Delphi, la bibliothèque PDF native pour Delphi et C++Builder