La collection de démos couvre 32 sujets : 32 projets Delphi, 31 projets C++Builder et 32 projets Lazarus, soit 95 projets natifs au total ; chaque plateforme conserve 22 démos de traitements complets dans son répertoire principal ; dix sujets ciblés se trouvent sous Miscellaneous, avec 29 projets natifs sur les trois plateformes ; XfaLab est disponible pour Delphi et Lazarus
Ouvrez d'abord un workflow du répertoire principal : PDFViewer pour un tour d'horizon des fonctionnalités, CreatePDF pour la création en direct, ContentExtractionLab pour un inventaire instantané, FormFill pour des formulaires modifiables, StandardsLab pour la validation et la conversion, ou IntakeWorkbenchCli pour l'intake automatisé. Ces six points d'entrée produisent immédiatement un résultat concret ; les exemples ciblés ci-dessous servent quand vous devez inspecter une API en détail
| Démo | À quoi elle sert | En quoi elle diffère des démos associées |
|---|---|---|
PDFViewer | Visualisation générale et évaluation des fonctionnalités | La visionneuse principale combine navigation, recherche, vignettes, modes d'affichage, impression et tour d'horizon des fonctionnalités |
MultiPageViewer | Pages continues, doubles pages et mises en page avec couverture | Un exemple ciblé de mise en page appuyé sur les API de sélection intégrées de la visionneuse ; utilisez PDFViewer pour l'expérience de visionneuse la plus large |
SplitView | Comparer des pages ou des documents dans des panneaux séparés | Démontre des positions de vue indépendantes et le routage des commandes vers le panneau actif, plutôt qu'une disposition deux pages dans une seule vue |
SearchAndSelect | Résultats de recherche multi-pages et sélection | Une liste de résultats et des options de recherche exposent le workflow de recherche plus directement qu'une barre d'outils de visionneuse |
PrintPDF | Prévisualisation et travaux d'impression ordinaires | Plages de pages, mise à l'échelle, progression et annulation fournissent le workflow d'impression principal |
ContentExtractionLab | Inspecter plusieurs catégories de contenu ensemble | Les inventaires TXT/JSON décrivent les objets et prévisualisent le texte ; ils ne remplacent pas l'export complet du texte ou des fichiers image |
ExtractImages | Exporter les objets image intégrés | Extrait des bitmaps d'images plutôt que des captures de pages entières ; le document d'exemple intégré contient deux vrais objets image sur chacune de ses deux pages |
TableExtractionLab | Détecter les tableaux et exporter en CSV/JSON | Tableaux à filets et alignés par espaces, cellules fusionnées, groupes de continuation et contrôles de confiance sont indépendants de l'extraction en texte brut |
Attachment | Lire, ajouter et exporter les pièces jointes intégrées | Les opérations sur les charges utiles des pièces jointes vont au-delà du listage de noms et de tailles dans ContentExtractionLab |
BatchExport | Exporter des images de pages depuis plusieurs documents | Sortie en flux, statut par fichier et échecs isolés démontrent le traitement par lots plutôt qu'une conversion unique |
CreatePDF | Créer du contenu de page avec un aperçu en direct | Les trois variantes natives créent du texte recherchable, des formes vectorielles, une vraie image raster, des tableaux et une annotation de revue ; les options reconstruisent l'aperçu avant un enregistrement explicite |
ImageToPDF | Construire des pages à partir de fichiers image en entrée | Disposition, ajustement, ordre des images et gestion JPEG fournissent un workflow de conversion de documents |
MergePDF | Assembler des pages de plusieurs PDF | Démontre l'import de documents et la composition ordonnée ; le découpage résout le workflow inverse |
SplitPDF | Écrire des groupes de pages sélectionnées dans des PDF séparés | Le nommage des sorties et la validation des groupes de pages diffèrent de la fusion ou du rendu en images de pages |
WatermarkStamp | Appliquer des surimpressions répétées à des pages existantes | Le placement et le tamponnage de pages par lots complètent les API de création de base |
FormFill | Saisie AcroForm interactive et aplatissement | La saisie de champs et les apparences enregistrées se distinguent de l'interchange XFDF et du comportement propre à XFA |
AccessibilityReader | Lecture interactive et synthèse vocale | Le lecteur graphique démontre la navigation en lecture et le surlignage plutôt qu'un audit de conformité |
AccessibilityWorkbenchCli | Revue d'accessibilité par lots et génération de rapports | Anomalies, synthèses et critères de blocage de revue servent l'automatisation ; les anomalies ne remplacent pas une revue d'accessibilité manuelle |
StandardsLab | Validation et conversion propres aux normes | Le lab interactif expose les opérations et options au lieu de se contenter de générer un rapport agrégé |
PreflightReport | Rapports de normes interactifs | L'interface graphique prend en charge l'inspection manuelle et l'export de rapports |
PreflightReportCli | Rapports de normes automatisés | Entrées par lots, formats de rapports et blocages par code de sortie fournissent la contrepartie automatisée de PreflightReport |
IntakeWorkbenchCli | Intake par lots, triage et routage | Rapports agrégés, blocages sur échec et décisions de routage en font un workflow de traitement au-delà de l'interface graphique SecurityAudit |
Ouvrez ces projets depuis Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous ou Demo\Lazarus\Miscellaneous ; ils conservent des recettes API utiles et des exports ciblés, le répertoire principal se concentrant sur les traitements complets ; les vérifications Unicode de base et le parcours fixe d’écriture puis d’énumération d’annotations sont couverts par la création, l’extraction, les échanges XFDF et les tests API ; ils n’ont plus de projets de démo distincts
| Démo | À quoi elle sert | En quoi elle diffère des démos associées |
|---|---|---|
SecurityAudit | Inspecter la posture de sécurité de façon interactive | L'interface graphique met l'accent sur les permissions, les scripts, les signatures et les détails de sécurité plutôt que sur le routage de fichiers |
XfdfLab | Importer et exporter des données XFDF | L'interchange et l'enregistrement explicite du PDF importé démontrent la persistance ; exporter XFDF seul n'enregistre pas le PDF modifié |
AccessibilityLab | Parcourir les API de lecture dans une console | Une visite guidée exécutable compacte expose les unités de lecture, les boîtes de mots, la structure et la sortie du script de synthèse vocale |
ExtractText | Exporter le texte complet de pages sélectionnées | Sortie de la couche de texte, séparateurs de pages et annulation se distinguent des prévisualisations d'inventaire et de la détection de tableaux ; aucun OCR n'est effectué |
FontProperties | Inspecter les métriques de police et de caractère | S'ouvre avec les métriques réelles de police et de caractère du premier objet texte ; sélectionnez une autre ligne pour comparer les polices sans exporter les charges utiles du document |
NavigationLab | Signets, destinations et actions de navigation | La visite guidée compacte des API complète les contrôles de navigation visibles dans PDFViewer |
PDFtoJpg | Rendre un document en images de pages | Un exemple compact de rendu mono-document ; Delphi expose des plages de pages discrètes, tandis que BatchExport se concentre sur plusieurs documents en entrée |
PrintPreferences | Feuilles N-up et préférences d'impression de l'auteur du PDF | Copies, filtrage pages impaires/paires et préférences fournies par l'auteur sont au cœur de la démonstration ; c'est un compagnon de PrintPDF |
ViewerInteractionLab | Diagnostiquer les interactions souris, clavier et coordonnées | Le journal d'interactions et la conversion de coordonnées page/périphérique en font un outil de diagnostic d'API |
XfaLab | Paquets XFA statiques et capacités du runtime | Ouvre les paquets template et datasets avec le runtime ordinaire ; le rendu XFA interactif requiert un runtime avec XFA activé, avec des variantes Delphi et Lazarus |
PDFViewer ouvre son PDFiumDemoShowcase.pdf embarqué, un document de six pages avec du texte recherchable, des graphiques vectoriels, deux images intégrées, un tableau, quatre champs AcroForm, des signets de chapitres, des liens, une note de revue et deux pièces jointes. La barre d'expérience propose Restart showcase, Find live text, 2-page spread, Night reading, Inspect this PDF et Explore forms ; chaque action agit sur le document courant
CreatePDF ouvre un aperçu de rapport en direct sur deux pages. Modifiez son titre et son auteur, ou basculez les formes, le tableau et le filigrane pour reconstruire le contenu réel des pages ; l'option Unicode ajoute une troisième page. Rien n'est écrit tant que vous n'enregistrez pas, et le PDF enregistré reste recherchable
MultiPageViewer, SearchAndSelect, ContentExtractionLab et FormFill ouvrent le même document pour leurs propres workflows, avec des résultats de recherche, un inventaire d'extraction et des champs modifiables prêts immédiatement. Miscellaneous\NavigationLab utilise sa propre copie locale pour une visite guidée des API de signets et de destinations
Attachment démarre avec deux vrais fichiers intégrés. PrintPreferences démarre avec quatre pages et des préférences d'auteur pour deux copies, des plages de pages sélectionnées, la mise à l'échelle et le recto verso ; le workflow d'impression actuel applique les copies et les plages de pages, tandis que la mise à l'échelle et le recto verso sont inspectés et rapportés. XfaLab démarre avec de vrais paquets template et datasets pour l'inspection XFA statique ; le rendu XFA interactif requiert un runtime approprié et constitue une capacité distincte
Chaque projet de visualisation, de formulaire, d'extraction et de navigation contient son propre PDFiumDemoShowcase.pdf. Copiez le répertoire du projet et conservez ce fichier embarqué à côté de l'exécutable distribué ; les builds Lazarus le placent automatiquement. Le tour d'horizon fonctionne hors ligne, et les visionneuses généralistes et les exemples d'extraction fournissent aussi du contenu de repli généré quand le PDF local n'est pas disponible
Chaque démo native contient sa propre implémentation d'exemple. Les points d'entrée Delphi et Lazarus de AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli et PreflightReportCli incluent le workflow complet dans le répertoire du projet, avec l'initialisation propre au compilateur et l'écriture JPEG. Les exemples Attachment, de préférences d'impression et XFA construisent aussi localement leurs propres données d'entrée spécifiques à chaque fonctionnalité. Seuls la bibliothèque, le runtime natif correspondant et les dépendances de framework habituelles du compilateur sont nécessaires en dehors du projet copié
Choisissez l'extraction d'objets image quand vous avez besoin des bitmaps intégrés, le rendu de page quand vous avez besoin de la page visible, et l'extraction de texte quand le PDF a déjà une couche de texte. Un rapport qui liste ces catégories n'exporte pas leurs charges utiles complètes. Ces frontières gardent les exemples ciblés utiles sans transformer chaque démo en une visionneuse ou un workbench généraliste de plus
Pdf1.FileName := 'C:\MyDocument.pdf';
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
ShowMessage('Title: ' + Pdf1.Title);
ShowMessage('Author: ' + Pdf1.Author);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromFile('C:\MyDocument.pdf');
Pdf1.LoadDocument(Stream, True);
Pdf1.Active := True;
ShowMessage('PDF loaded from stream');
finally
Stream.Free;
end;
end;
Pdf1.CreateDocument;
Pdf1.Active := True;
Pdf1.AddPage(0, 612, 792);
Pdf1.PageNumber := 1;
Pdf1.AddText('Hello World!', 'Arial', 12, 100, 700, clBlack, $FF, 0.0);
Pdf1.UpdatePage;
Pdf1.SaveAs('C:\NewDocument.pdf');
Pdf1.Active := False;
var
PageText: WString;
RectText: WString;
begin
Pdf1.PageNumber := 1;
PageText := Pdf1.Text;
Memo1.Text := PageText;
RectText := Pdf1.TextInRectangle(100, 100, 500, 200);
ShowMessage('Text in rectangle: ' + RectText);
end;
var
Position: Integer;
begin
Position := Pdf1.FindFirst('Hello', [seCaseSensitive]);
while Position >= 0 do
begin
ShowMessage('Found at character: ' + IntToStr(Position));
Position := Pdf1.FindNext;
end;
end;
Pdf1.PageNumber := 1;
Pdf1.AddText('Document Title', 'Times New Roman', 16, 100, 750, clBlue);
Pdf1.AddText('This is the document content.', 'Arial', 12, 100, 700, clBlack);
Pdf1.UpdatePage;
var
I: Integer;
MetricSize: Single;
FontBytes: TBytes;
begin
Pdf1.PageNumber := 1;
for I := 0 to Pdf1.ObjectCount - 1 do
if Pdf1.ObjectType[I] = otText then
begin
MetricSize := 12.0;
FontBytes := Pdf1.FontData[I];
Memo1.Lines.Add('Object ' + IntToStr(I));
Memo1.Lines.Add('Base name: ' + Pdf1.FontBaseName[I]);
Memo1.Lines.Add('Family: ' + Pdf1.FontFamilyName[I]);
Memo1.Lines.Add('Embedded: ' + BoolToStr(Pdf1.FontIsEmbedded[I], True));
Memo1.Lines.Add('Weight: ' + IntToStr(Pdf1.FontWeight[I]));
Memo1.Lines.Add('Italic angle: ' + IntToStr(Pdf1.FontItalicAngle[I]));
Memo1.Lines.Add('Ascent: ' + FloatToStr(Pdf1.FontAscent[I, MetricSize]));
Memo1.Lines.Add('Descent: ' + FloatToStr(Pdf1.FontDescent[I, MetricSize]));
Memo1.Lines.Add('Font data bytes: ' + IntToStr(Length(FontBytes)));
end;
if Pdf1.CharacterCount > 0 then
begin
Memo1.Lines.Add('First character size: ' + FloatToStr(Pdf1.CharacterFontSize[0]));
Memo1.Lines.Add('First character weight: ' + IntToStr(Pdf1.CharacterFontWeight[0]));
Memo1.Lines.Add('First character angle: ' + FloatToStr(Pdf1.CharacterAngle[0]));
end;
end;
Les projets Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties et Demo\Lazarus\Miscellaneous\FontProperties montrent les mêmes métadonnées via TPdf et TPdfView
Les projets Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab et Demo\Lazarus\ContentExtractionLab transforment l'extraction de contenu en un workflow unique. Ils ouvrent ou créent un PDF, permettent aux utilisateurs de choisir les métadonnées, le texte de page, les objets de page, les images, les pièces jointes, les liens, les annotations, les signets et les métriques de police / caractère, puis génèrent une synthèse plus un rapport TXT ou JSON détaillé. Le lab inclut également la sélection toutes / aucune catégorie, la copie de rapport vers le presse-papiers et les actions d'enregistrement du PDF source afin que les utilisateurs puissent conserver le PDF d'exemple généré à côté de son rapport d'extraction. ExtractImages et Attachment fournissent des workflows d'export de charges utiles, tandis que Miscellaneous\ExtractText et Miscellaneous\FontProperties conservent des exemples d'API ciblés ; ExtractText prend en charge les options de plage de pages et de séparateur de pages pour produire une sortie texte par page sous Delphi, C++Builder et Lazarus, tandis que ContentExtractionLab est l'exemple d'inventaire transversal
Les projets Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab et Demo\Lazarus\TableExtractionLab transforment la détection de tableaux en un flux de travail unique. Le laboratoire construit un document d'exemple contenant un tableau à filets avec cellules d'en-tête fusionnées, un tableau aligné par espaces sans filets et un long tableau qui se coupe à la frontière d'une page, puis exécute ExtractTables pour la page courante ou ExtractDocumentTables pour tout le document et rapporte les lignes, les colonnes, les valeurs RowSpan et ColumnSpan, les indicateurs d'en-tête, le mode de détection, la confiance et les groupes de continuation. Les options DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings et MinConfidence sont modifiables dans l'interface, et le tableau sélectionné s'exporte via TPdfTable.ToCsv et TPdfTable.ToJson. Le laboratoire traite aussi un dossier entier par lots : Batch folder exécute ExtractDocumentTables sur chaque PDF, rapporte le nombre de tableaux par document, signale les scans dépourvus de couche de texte et retente les documents vides avec un préréglage de colonnes compactes ; Export all CSV écrit chaque tableau détecté à côté des fichiers sources. Chaque document s'ouvre dans sa propre instance de TPdf, afin qu'un fichier illisible ne puisse pas affecter le reste du lot
var
I: Integer;
FieldInfo: TPdfFormFieldInfo;
begin
Pdf1.FormField[0] := 'John';
for I := 0 to Pdf1.FormFieldCount - 1 do
begin
FieldInfo := Pdf1.FormFieldInfo[I];
ShowMessage(FieldInfo.Name + ': ' + Pdf1.FormField[I]);
end;
end;
// Sans aplatissement, FormField[i] := value écrit uniquement l'entrée /V —
// l'apparence visible provient du flux /AP et peut ne pas se rafraîchir.
// GenerateFormAppearances régénère /AP pour chaque widget, puis
// FlattenAllPages intègre les annotations et widgets de chaque page dans
// du contenu permanent et non modifiable.
Pdf1.FileName := 'C:\Application.pdf';
Pdf1.Active := True;
Pdf1.FormField[0] := 'John Smith';
Pdf1.FormField[1] := '[email protected]';
Pdf1.GenerateFormAppearances;
if Pdf1.FlattenAllPages then
Pdf1.SaveAs('C:\Application.flat.pdf');
Pdf1.Active := False;
var
I: Integer;
Bitmap: TBitmap;
begin
for I := 0 to Pdf1.BitmapCount - 1 do
begin
Bitmap := Pdf1.Bitmap[I];
try
Bitmap.SaveToFile('C:\ExtractedImage' + IntToStr(I) + '.bmp');
finally
Bitmap.Free;
end;
end;
end;
var
JpegStream: TFileStream;
begin
JpegStream := TFileStream.Create('C:\MyImage.jpg', fmOpenRead or fmShareDenyWrite);
try
Pdf1.AddJpegImage(JpegStream, 100, 500, 200, 150);
finally
JpegStream.Free;
end;
Pdf1.AddPicture(Image1.Picture, 100, 300, 150, 100);
Pdf1.UpdatePage;
end;
var
I: Integer;
Annotation: TPdfAnnotation;
begin
for I := 0 to Pdf1.AnnotationCount - 1 do
begin
Annotation := Pdf1.Annotation[I];
ShowMessage('Annotation ' + IntToStr(I) + ': ' + Annotation.ContentsText);
end;
end;
Pdf1.CreatePath(100, 100, 200, 150, fmAlternate, clYellow, $FF, True, clBlack, $FF, 2.0);
Pdf1.AddPath;
Pdf1.CreatePath(100, 100, fmNone, clBlack, $FF, True, clRed, $FF, 3.0);
Pdf1.LineTo(200, 100);
Pdf1.LineTo(150, 200);
Pdf1.ClosePath;
Pdf1.AddPath;
Pdf1.UpdatePage;
var
I: Integer;
Bookmarks: TBookmarks;
begin
Bookmarks := Pdf1.Bookmarks;
for I := 0 to Length(Bookmarks) - 1 do
ShowMessage(Bookmarks[I].Title + ' -> Page ' + IntToStr(Bookmarks[I].PageNumber));
end;
var
I: Integer;
Destination: TDestination;
begin
for I := 0 to Pdf1.DestinationCount - 1 do
begin
Destination := Pdf1.Destination[I];
if Destination.Name = 'Chapter1' then
begin
Pdf1.PageNumber := Destination.PageNumber;
Break;
end;
end;
end;
var
I: Integer;
AttachmentData: TBytes;
AttachmentName: WString;
FileStream: TFileStream;
begin
for I := 0 to Pdf1.AttachmentCount - 1 do
begin
AttachmentName := Pdf1.AttachmentName[I];
AttachmentData := Pdf1.Attachment[I];
FileStream := TFileStream.Create('C:\Extracted_' + string(AttachmentName), fmCreate);
try
if Length(AttachmentData) > 0 then
FileStream.WriteBuffer(AttachmentData[0], Length(AttachmentData));
finally
FileStream.Free;
end;
end;
if Pdf1.CreateAttachment('MyFile.txt') then
Pdf1.Attachment[Pdf1.AttachmentCount - 1] := TFile.ReadAllBytes('C:\MyFile.txt');
end;
Pdf1.AddPage(Pdf1.PageCount + 1, 612, 792);
Pdf1.AddPage(Pdf1.PageCount + 1, 595, 842);
Pdf1.AddPage(Pdf1.PageCount + 1, 400, 600);
var
SourcePdf: TPdf;
begin
SourcePdf := TPdf.Create(nil);
try
SourcePdf.FileName := 'C:\SourceDocument.pdf';
SourcePdf.Active := True;
Pdf1.ImportPages(SourcePdf, '1', Pdf1.PageCount + 1);
finally
SourcePdf.Free;
end;
end;
if Pdf1.PageCount > 1 then
Pdf1.DeletePage(Pdf1.PageCount);
// Créer un document PDF compressé
Pdf1.CreateDocument;
Pdf1.Compressed := True; // garantir que tous les flux sont compressés FlateDecode (défaut)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // format A4
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// Enregistrer avec options
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // enregistrement incrémentiel
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // suppression de la sécurité
// Enregistrer vers une cible de version PDF spécifique. Le validateur de
// version PDF rejette toute fonctionnalité introduite après la cible
// choisie (JBIG2Decode, MarkInfo, chiffrement AES, annotations Polygon /
// Caret / Watermark / Redact, ...).
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('Save rejected: document contains features newer than PDF 1.5');
// SaveAsPdfA post-traite l'enregistrement de base avec une mise à jour
// incrémentielle qui injecte un flux de métadonnées XMP, un OutputIntent
// ICC sRGB et un catalogue de document mis à jour, de sorte que le résultat
// soit conforme PDF/A-1b. Le profil sRGB IEC61966-2.1 intégré est utilisé
// automatiquement lorsqu'aucun profil personnalisé n'est fourni.
Pdf1.FileName := 'C:\Report.pdf';
Pdf1.Active := True;
if Pdf1.SaveAsPdfA('C:\Report.pdfa.pdf', pac1b) then
ShowMessage('Saved PDF/A-1b archive');
// PDF/A avec un profil ICC personnalisé (pipelines d'impression CMYK par exemple)
var
Opts: TPdfASaveOptions;
begin
Opts := Default(TPdfASaveOptions);
Opts.Conformance := pac1b;
Opts.IccProfileData := TFile.ReadAllBytes('C:\Profiles\Coated_GRACoL_2006.icc');
Pdf1.SaveAsPdfA('C:\Report.cmyk.pdfa.pdf', Opts);
end;
// Sortie PDF/A en mémoire
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Opts := Default(TPdfASaveOptions);
Opts.Conformance := pac1b;
if Pdf1.SaveAsPdfAToStream(Stream, Opts) then
UploadToArchive(Stream);
finally
Stream.Free;
end;
end;
var
Validation: TPdfAValidationResult;
Issue: TPdfAValidationIssue;
begin
Pdf1.FileName := 'C:\Incoming\report.pdf';
Pdf1.Active := True;
// Sonde de style header bon marché — lit la conformité sans itérer
// le validateur complet. Résultat : pacNone, pac1a, pac1b, pac2b, pac3b ou
// pacUnknown.
case Pdf1.PdfAConformance of
pac1b: Status.Caption := 'PDF/A-1b';
pac2b: Status.Caption := 'PDF/A-2b';
pacNone: Status.Caption := 'Not PDF/A';
else
Status.Caption := 'Unknown conformance';
end;
// Validateur complet avec diagnostics par problème
Validation := Pdf1.ValidatePdfA;
Memo1.Lines.Add('Conformance: ' + GetEnumName(TypeInfo(TPdfAConformance),
Ord(Validation.Conformance)));
for Issue in Validation.Issues do
Memo1.Lines.Add('- ' + Issue.Description);
end;
Les projets Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab et Demo\Lazarus\StandardsLab chargent ou créent un PDF, exécutent ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR et ValidatePdfVT, puis affichent chaque niveau de conformité détecté et le nombre de problèmes dans une seule grille. Leurs boutons d'enregistrement appellent SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR et SaveAsPdfVT afin que le workflow de sortie avec marqueurs soit visible sans écrire de harnais personnalisé
L'unité FPdfPreflightReport encapsule ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR et ValidatePdfVT dans un seul objet de rapport interrogeable avec sévérité Info / Warning / Error, agrégation des statuts et des problèmes, recherche ponctuelle, recherche, filtrage et empreintes SHA-256 stables. Les rapports peuvent être émis en texte, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON ou XML natif. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport et Demo\CBuilder\PreflightReport fournissent des workflows interactifs de sélection et de prévisualisation, tandis que Demo\Delphi\PreflightReportCli ajoute des arguments d'entrée / sortie scriptables, le filtrage par norme, l'intégration facultative d'une pièce jointe de rapport, le blocage par code de sortie CI, le traitement par lots de listes et de répertoires, le routage résistant aux collisions, les synthèses agrégées et les manifestes CSV. Le rapport généré indique que les validateurs intégrés couvrent les contrôles au niveau marqueur et certains contrôles au niveau fichier, de sorte que le contrôle complet au niveau contenu peut toujours être délégué à un moteur de validation dédié
// LoadCustomDocument permet à PDFium de récupérer les blocs depuis tout
// TStream cherchable à la demande. Le flux n'est PAS copié en mémoire, de
// sorte que les PDF de plusieurs Go, les flux de corps HTTP distants et les
// sources adossées à une base de données sont tous viables sans tampon
// préalable.
var
FileStream: TFileStream;
begin
// Streaming en lecture depuis fichier (pas de copie en mémoire)
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ propriété transférée — Pdf1 libère FileStream sur UnloadDocument.
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Flux détenu en externe (l'appelant le libère après UnloadDocument)
var
Stream: TFileStream;
begin
Stream := TFileStream.Create('C:\Live.pdf',
fmOpenRead or fmShareDenyNone);
try
Pdf1.LoadCustomDocument(Stream, False);
Pdf1.Active := True;
DoWork;
Pdf1.Active := False;
finally
Stream.Free;
end;
end;
// FPdfAsync expose IPdfCancellationToken /
// IPdfCancellationTokenSource pour une sémantique d'annulation depuis
// l'UI qui fonctionne à travers les chemins longs d'export et de rendu.
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... l'utilisateur clique sur Annuler ...
CancelSource.Cancel;
// Le worker vérifie périodiquement CancelToken.IsCancelled, ou le chemin
// de rendu l'interroge via le callback IFSDK_PAUSE de PDFium.
if CancelToken.IsCancelled then
Memo1.Lines.Add('Cancelled by user');
end;
// RenderPageProgressive permet à un long rendu haute résolution d'être
// interrompu en milieu de page lorsque l'utilisateur clique sur Annuler,
// au lieu de bloquer l'appelant jusqu'à la fin.
var
Status: TPdfProgressiveStatus;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(2480, 3508); // A4 @ 300 DPI
Status := Pdf1.RenderPageProgressive(Bitmap, 0, 0, Bitmap.Width,
Bitmap.Height, CancelToken, ro0, [reAnnotations], clWhite);
case Status of
prsDone: SaveBitmap(Bitmap);
prsCancelled: Memo1.Lines.Add('Render cancelled — partial result available');
prsFailed: Memo1.Lines.Add('PDFium reported FPDF_RENDER_FAILED');
end;
finally
Bitmap.Free;
end;
end;
// TPdfFuture<T> lance un worker sur un thread d'arrière-plan et renvoie
// une enveloppe TPdfFutureResult<T> vers le thread principal.
//
// Important : TPdf sérialise les appels de rendu par instance, mais le
// worker reste responsable de la répartition et de la durée de vie du
// document. Ne mutez pas un TPdf pendant qu'un rendu est en cours ;
// l'export par lot conserve généralement un TPdf par fichier.
type
TRenderResult = record
Bitmap : TBitmap;
PageNo : Integer;
end;
var
Future: TPdfFuture<TRenderResult>;
begin
Future := TPdfFuture<TRenderResult>.Create(
function (const ACancelToken: IPdfCancellationToken): TRenderResult
var
LocalPdf: TPdf;
begin
LocalPdf := TPdf.Create(nil);
try
LocalPdf.FileName := 'C:\Huge.pdf';
LocalPdf.Active := True;
LocalPdf.PageNumber := 1;
Result.Bitmap := LocalPdf.RenderPage(0, 0, 2480, 3508);
Result.PageNo := 1;
finally
LocalPdf.Free;
end;
end,
procedure (const AResult: TPdfFutureResult<TRenderResult>)
begin
case AResult.State of
pfsSuccess: PaintBitmapToView(AResult.Value.Bitmap);
pfsCancelled: Log.Add('Cancelled');
pfsFailed: Log.Add('Worker failed: ' + AResult.ErrorMessage);
end;
end);
end;
// FPdfMatrix encapsule FS_MATRIX de PDFium afin que les appelants puissent
// construire une transformation de manière déclarative et la passer à
// FPDFPageObj_SetMatrix.
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // déplacer 1in à droite, ~2,8in vers le haut
M.Scale(0.5, 0.5); // tampon à mi-taille
M.Rotate(15); // rotation de 15 degrés CCW
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // post-multiplier avec une autre matrice
// Appliquer à tout objet de page PDFium (text / path / image / form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex copie un tableau d'index explicite base zéro depuis
// un PDF source dans ce document. InsertAt = 0 insère avant la page 1 ;
// PageCount ajoute à la fin.
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Importer les pages 0, 2, 4 (base un : pages 1, 3, 5) depuis Source
// et les ajouter à la fin de Pdf1.
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Un tableau vide importe toutes les pages source
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne renvoie un nouveau TPdf dont les pages sont des
// composites NumX*NumY de CE document. OutputWidth/Height sont des unités
// utilisateur PDF (1 unité = 1/72 in).
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// A4 paysage 4-up : 842 x 595 pt, 2 colonnes x 2 lignes
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages prend les indices base zéro des pages à déplacer plus
// l'index de destination pour la première page déplacée après l'achèvement
// du déplacement. Les autres pages se décalent autour du bloc déplacé, de
// sorte que la longueur du document reste la même.
//
// Exemple : dans un document de 5 pages avec les pages numérotées [0,1,2,3,4],
// MovePages([2, 3], 0) réorganise en [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage fabrique un handle Form XObject réutilisable à
// partir de n'importe quelle page d'un autre TPdf. Tamponnez ce handle sur
// autant de pages de CE document que vous voulez — chaque tampon est un
// seul objet de page PDFium qui peut être positionné, mis à l'échelle et
// tourné via l'API matrice.
uses FPdfMatrix, FPdfView;
var
WatermarkSource: TPdf;
XObj: TPdfXObject;
PageObj: FPDF_PAGEOBJECT;
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
I: Integer;
begin
WatermarkSource := TPdf.Create(nil);
try
WatermarkSource.FileName := 'C:\Watermarks\Confidential.pdf';
WatermarkSource.Active := True;
// Encapsuler la page 0 de WatermarkSource en tant que XObject réutilisable
XObj := Pdf1.CreateXObjectFromPage(WatermarkSource, 0);
try
for I := 1 to Pdf1.PageCount do
begin
Pdf1.PageNumber := I;
PageObj := Pdf1.InsertFormObjectFromXObject(XObj);
if PageObj = nil then Continue;
// Centrer le filigrane sur la page
M := TPdfMatrix.Create;
try
M.Scale(0.5, 0.5);
M.Translate(0.25 * Pdf1.PageWidth, 0.5 * Pdf1.PageHeight);
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
Pdf1.UpdatePage;
end;
finally
XObj.Free; // ferme le handle FPDF_XOBJECT
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
Les projets Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp et Demo\CBuilder\WatermarkStamp transforment ce modèle en un workflow exécutable : ils créent un PDF cible et un PDF de tampon réutilisable, encapsulent la page de tampon avec CreateXObjectFromPage, insèrent le même Form XObject sur chaque page cible, appliquent des transformations TPdfMatrix pour des filigranes centrés et des tampons en haut à droite, et ajoutent des étiquettes de numéro de page facultatives avant d'enregistrer le résultat
// AddImage(FileName) accepte tout format enregistré avec les unités
// graphiques VCL ou LCL (BMP, PNG via PngImage, JPG, ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) évite l'intermédiaire TPicture, idéal lorsque le
// bitmap provient déjà du rendu ou de la génération par lot.
var
Bitmap: TBitmap;
begin
Bitmap := Pdf1.RenderPage(0, 0, 595, 842);
try
Pdf1.PageNumber := 2;
Pdf1.AddImage(Bitmap, 50, 50, 250, 350);
Pdf1.UpdatePage;
finally
Bitmap.Free;
end;
end;
Les projets Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF et Demo\Lazarus\ImageToPDF transforment cela en un workflow par lots complet : sélectionner plusieurs fichiers image, prévisualiser l'élément sélectionné, créer une page PDF par image, mettre à l'échelle chaque image dans une page A4 portrait ou paysage, enregistrer le résultat et ouvrir le PDF généré
var
MatchCount: Integer;
begin
// Peindre un masque clYellow sur chaque correspondance de la page courante
// de la vue. Passer à une autre page efface automatiquement la surbrillance.
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d match(es) on this page', [MatchCount]);
// Supprimer la superposition par programmation avant le changement de page
PdfView1.ClearHighlight;
end;
// FitMode conserve les longs documents cadrés lors d'un Resize ou d'un
// changement de page. Définir Zoom directement annule FitMode (il revient
// à pfmNone).
PdfView1.FitMode := pfmFitPage; // page entière dans la fenêtre
// PdfView1.FitMode := pfmFitWidth; // la largeur de la page correspond à la fenêtre
// PdfView1.FitMode := pfmActualSize; // 100 %
// PageColor dissocie la page PDF rendue du Color du contrôle hôte
// — configuration typique de visionneuse en mode sombre qui garde la
// zone de défilement sombre tandis que la page PDF reste blanc papier.
PdfView1.Color := clBlack; // zone de défilement
PdfView1.PageColor := clWhite; // arrière-plan de la page PDF
// Ombre portée et bordure de page facultatives pour détacher la page d'un fond sombre
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
Les projets Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab et Demo\Lazarus\Miscellaneous\ViewerInteractionLab conservent la surface d'interaction TPdfView moderne dans un formulaire compact : ouvrir ou créer un PDF d'exemple, changer de DisplayMode, appliquer FitMode, changer PageColor, faire pivoter les pages, surligner les correspondances de recherche de la page courante avec HighlightSearchText, activer ou désactiver la sélection de texte par l'utilisateur, inspecter SelectedText, appeler SelectAll, CopySelectionToClipboard et ClearSelection, et voir les coordonnées DeviceToPage se mettre à jour dans la barre d'état pendant que la souris se déplace sur la page
Les projets Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect et Demo\Lazarus\SearchAndSelect transforment le workflow de visionneuse de recherche et sélection en exemples autonomes. Ils ouvrent ou créent un PDF, listent les résultats de recherche multi-pages avec numéro de page, index de caractère et texte de prévisualisation, prennent en charge la navigation Précédent / Suivant et le saut aux résultats par double-clic, surlignent les correspondances de la page courante avec HighlightSearchText, exposent les options sensible à la casse et mot entier, basculent AllowUserTextSelection, prévisualisent SelectedText, pilotent SelectAll, CopySelectionToClipboard et ClearSelection depuis des boutons, et laissent les utilisateurs basculer entre les modes d'affichage simple et double page
Les projets Demo\Delphi\Miscellaneous\PrintPreferences, Demo\CBuilder\Miscellaneous\PrintPreferences et Demo\Lazarus\Miscellaneous\PrintPreferences lisent les préférences d'impression de l'auteur avant l'impression. Ils affichent PrintCopies, PrintPageRanges, PrintScaling et PrintPaperHandling, peuvent copier les copies et plages fournies par l'auteur dans les entrées d'impression, et montrent comment SetPdfPrintPaperHandlingDevMode mappe l'intention recto-verso PDF vers un DEVMODE Windows
Les projets Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF et Demo\Lazarus\PrintPDF montrent le workflow d'impression standard : ouvrir un PDF, prévisualiser les pages, choisir les plages de pages et les copies dans la boîte de dialogue d'impression de la plateforme, respecter le mode d'assemblage, rendre chaque page via TPdf.RenderPage, et exposer la progression de l'impression avec annulation. L'exemple Delphi accepte également les fichiers PDF déposés pour un chargement rapide
Les projets Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer et Demo\Lazarus\MultiPageViewer exercent la visualisation continue, double page et tenant compte de la couverture avec des workflows réguliers de navigation et de zoom. Ils sont également utiles pour tester la vitesse d'ouverture à la première page et la réactivité du rendu sur de très grands PDF : dans les tests sur fichiers volumineux, des documents de 2,x Go qui peuvent faire passer Acrobat ou Foxit 20-30 secondes avant le premier rendu peuvent devenir utilisables presque immédiatement via le chemin de visionneuse PDFium Delphi Component
Les projets Demo\Delphi\SplitView, Demo\CBuilder\SplitView et Demo\Lazarus\SplitView montrent une revue PDF côte à côte. Les exemples C++Builder et Lazarus se concentrent sur la comparaison à deux ou trois panneaux, la sélection de la vue active, des commandes de navigation synchronisées facultatives, des préréglages de zoom partagés et la rotation pour la vue sélectionnée ou toutes les vues chargées. Utilisez ces exemples pour comparer des documents volumineux tout en gardant le premier rendu utilisable et le rendu de page subséquent réactifs ; les mêmes fichiers PDF de 2,x Go qui peuvent prendre 20-30 secondes à Acrobat ou Foxit pour s'ouvrir peuvent devenir utilisables presque immédiatement dans le chemin de visionneuse PDFium Delphi Component
Les projets Demo\Delphi\Miscellaneous\SecurityAudit, Demo\CBuilder\Miscellaneous\SecurityAudit et Demo\Lazarus\Miscellaneous\SecurityAudit ouvrent un PDF en lecture seule et recensent permissions, pièces jointes incorporées, actions JavaScript du document, annotations de lien URI et Launch, liens web, résumés de signatures, état XFA, disponibilité des helpers V8 et callbacks de fonctionnalités non prises en charge ; les mêmes lignes de synthèse et résultats peuvent être enregistrées ou copiées en rapport TXT, ou enregistrées en JSON structuré ; ces projets servent de panneaux de risque pour l’application hôte, pas de détecteurs de logiciels malveillants
// LinkOptions contrôle la gestion automatique des quatre types d'actions
// de lien PDF. Les valeurs par défaut activent uniquement goto et URI ;
// launch (exécuter un programme) et embedded GotoR (sauter vers un autre
// fichier) restent DÉSACTIVÉS afin qu'un clic intempestif ne puisse pas
// exécuter de code arbitraire.
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // valeurs par défaut sécurisées
// OnAnnotationLinkClick se déclenche pour les destinations dans le
// document (sauts de page, destinations nommées, chaînes d'actions).
// Marquez Handled = True pour empêcher la vue de suivre automatiquement le lien.
procedure TForm1.PdfView1AnnotationLinkClick(Sender: TObject;
LinkIndex: Integer; const Action: TPdfAction;
var Handled: Boolean);
begin
if Action.Kind = paUri then
begin
if MessageDlg('Open ' + Action.Uri + '?', mtConfirmation, [mbYes, mbNo], 0)
<> mrYes then
Handled := True; // supprimer la gestion automatique
end;
end;
// OnWebLinkClick se déclenche pour les chaînes URI découvertes par le
// scanner de liens Web de PDFium (URL auto-détectées dans le flux de texte,
// même sans annotation /A <</S/URI...>>).
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
WebLinkIndex: Integer; const Url: WString;
var Handled: Boolean);
begin
Log.Add('Web link clicked: ' + string(Url));
end;
// Sur le widget AcroForm actif, six nouvelles méthodes pilotent
// l'historique d'édition de formulaire de PDFium. Les six court-circuitent
// en toute sécurité si aucun widget n'a le focus ou si le document ne porte
// pas d'AcroForm.
procedure TForm1.btnSelectAllClick(Sender: TObject);
begin
PdfView1.SelectAllFormText;
EditMenuCopy.Caption := 'Copy: ' + string(PdfView1.GetSelectedFormText);
end;
procedure TForm1.btnUndoClick(Sender: TObject);
begin
btnUndo.Enabled := PdfView1.FormCanUndo;
btnRedo.Enabled := PdfView1.FormCanRedo;
if PdfView1.FormCanUndo then
PdfView1.FormUndo;
end;
procedure TForm1.btnRedoClick(Sender: TObject);
begin
if PdfView1.FormCanRedo then
PdfView1.FormRedo;
end;
// Les trois ont pour valeur par défaut True, de sorte que les applications
// existantes se mettent à niveau sans changement de comportement. Passez-
// les à False pour les bornes interactives, panneaux de prévisualisation
// ou intégrations en lecture seule sans sous-classer TPdfView.
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // sauts molette haut/bas
PdfView1.AllowUserTextSelection := False; // sélection de texte souris/clavier
// Ctrl+molette est réservé au zoom et ignoré par le gestionnaire de
// navigation, quel que soit ChangePageOnMouseScrolling.
// TPdfThumbnailView (unité FPdfThumbnail) rend une miniature de page par
// ligne dans un panneau latéral défilant.
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // surbrillance chaude
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex est en base zéro
end;
procedure TForm1.PdfView1PageNumberChanged(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Modèle utilisé par Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport
// et Demo\Lazarus\BatchExport. Un TPdf par fichier, IPdfCancellationToken
// pour annuler depuis l'UI, TPdfStreamAdapter pour le chargement de fichier mis en tampon.
uses FPdfAsync;
procedure ExportBatch(const Files: TArray<string>;
const OutDir: string; DPI: Integer; Quality: Integer;
const ACancelToken: IPdfCancellationToken);
var
I, J: Integer;
Job: TPdf;
Bmp: TBitmap;
Jpeg: TJPEGImage;
begin
for I := 0 to High(Files) do
begin
if ACancelToken.IsCancelled then Break;
OverallProgress.Position := I;
Job := TPdf.Create(nil);
try
Job.FileName := Files[I];
Job.Active := True;
PageProgress.Max := Job.PageCount;
for J := 1 to Job.PageCount do
begin
if ACancelToken.IsCancelled then Break;
PageProgress.Position := J;
Job.PageNumber := J;
Bmp := Job.RenderPage(
0, 0,
Round(Job.PageWidth * DPI / 72),
Round(Job.PageHeight * DPI / 72));
try
Jpeg := TJPEGImage.Create;
try
Jpeg.CompressionQuality := Quality;
Jpeg.Assign(Bmp);
Jpeg.SaveToFile(Format('%s\%s.p%.3d.jpg',
[OutDir, ExtractFileName(Files[I]), J]));
finally
Jpeg.Free;
end;
finally
Bmp.Free;
end;
end;
finally
Job.Free;
end;
end;
end;
procedure FitCurrentPage;
begin
PdfView1.Zoom := PdfView1.PageZoom[PdfView1.PageNumber];
end;
procedure InspectViewerPoint(X, Y: Integer);
var
PageNo: Integer;
PageX, PageY: Double;
CharIndex: Integer;
Ch: WString;
begin
PageNo := PdfView1.PageNumber;
if not PdfView1.DeviceToPage(X, Y, PageNo, PageX, PageY) then
Exit;
CharIndex := PdfView1.CharacterIndexAtPos(X, Y, 8, 8);
if CharIndex >= 0 then
begin
Ch := PdfView1.Text(CharIndex, 1);
ShowMessage(Format('Page %d, X %.2f, Y %.2f, character %s',
[PageNo, PageX, PageY, string(Ch)]));
end;
end;
function LoadPdfSafely(const FileName: string): Boolean;
begin
Result := False;
if not FileExists(FileName) then
Exit;
try
Pdf1.FileName := FileName;
Pdf1.Active := True;
Result := Pdf1.Active;
except
Result := False;
end;
end;
function ExtractTextSafely(PageNo: Integer): WString;
begin
Result := '';
if not Pdf1.Active then
Exit;
if (PageNo < 1) or (PageNo > Pdf1.PageCount) then
Exit;
Pdf1.PageNumber := PageNo;
Result := Pdf1.Text;
end;
// IsTagged est une sonde de catalogue bon marché — True lorsque
// /StructTreeRoot existe. StructureElements matérialise l'arbre en un
// tableau plat de records TPdfStructureElement avec type, titre, texte
// alternatif, texte réel, texte d'expansion, langue, niveau, index parent
// et comptes d'enfants / contenu balisé / attributs.
var
Elements: TPdfStructureElements;
I: Integer;
begin
if not Pdf1.IsTagged then
begin
Log.Add('Document is NOT tagged — accessibility tools may struggle.');
Exit;
end;
if Pdf1.Language = '' then
Log.Add('Tagged PDF without /Lang — fails PDF/UA.');
Elements := Pdf1.StructureElements;
for I := 0 to High(Elements) do
Log.Add(StringOfChar(' ', Elements[I].Level * 2)
+ Elements[I].StructType + ' "' + Elements[I].Title + '"');
end;
// SetPdfPrintMode est une fonction globale qui mappe vers FPDF_SetPrintMode
// de PDFium. Utilisez la valeur TPdfPrintMode correspondant au pilote
// d'imprimante utilisé.
SetPdfPrintMode(pmEmf); // GDI EMF (défaut)
// SetPdfPrintMode(pmTextOnly); // rendu texte seul
// SetPdfPrintMode(pmPostScript2); // PostScript Level 2
// SetPdfPrintMode(pmPostScript3); // PostScript Level 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + masques d'image
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + polices Type 42
// PrintCopies, PrintPageRanges, PrintScaling et PrintPaperHandling sont
// les entrées du dictionnaire des préférences de visionneuse — elles
// encodent ce que l'auteur du document voulait voir comme valeurs par
// défaut des lecteurs PDF.
var
Ranges: TPrintPageRanges;
Range: TPrintPageRange;
begin
ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
Ord(Pdf1.PrintScaling)));
Ranges := Pdf1.PrintPageRanges; // plages base un
for Range in Ranges do
Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// Le JavaScript de niveau document est stocké dans l'arbre de noms
// /Names /JavaScript. JavaScriptAction[i] renvoie une entrée ;
// JavaScriptActions renvoie le tableau complet.
var
I: Integer;
Action: TPdfJavaScriptAction;
begin
for I := 0 to Pdf1.JavaScriptActionCount - 1 do
begin
Action := Pdf1.JavaScriptAction[I];
Memo1.Lines.Add('Name: ' + string(Action.Name));
Memo1.Lines.Add('Script: ' + string(Action.Script));
Memo1.Lines.Add('---');
end;
end;
procedure ProcessMultiplePages;
var
I: Integer;
PageText: WString;
begin
for I := 1 to Pdf1.PageCount do
begin
Pdf1.PageNumber := I;
PageText := Pdf1.Text;
ProcessPageText(PageText);
end;
end;
procedure SetOptimalRenderOptions;
begin
PdfView1.Options := [reAnnotations, reLcd];
end;
// Chemin de rendu sans copie (par défaut depuis v1.21.0) : RenderPage
// écrit directement dans le tampon DIB du TBitmap de destination lorsque
// les appelants passent un bitmap pré-alloué, évitant une copie de
// largeur * hauteur * 4 octets.
procedure RenderIntoCallerBitmap(Bitmap: TBitmap);
begin
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(2480, 3508); // A4 @ 300 DPI
Pdf1.RenderPage(Bitmap, 0, 0, Bitmap.Width, Bitmap.Height);
end;