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;
Projekten Demo\Delphi\FontProperties, Demo\CBuilder\FontProperties och Demo\Lazarus\FontProperties visar samma metadata via både TPdf och TPdfView.
Projekten Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab och Demo\Lazarus\ContentExtractionLab gör innehållsextraktion till ett enda arbetsflöde. De öppnar eller skapar en PDF, låter användare välja metadata, sidtext, sidobjekt, bilder, bilagor, länkar, annoteringar, bokmärken samt typsnitts- / teckenmått, och genererar sedan en sammanfattning plus en detaljerad TXT- eller JSON-rapport. Labbet inkluderar också val av alla / inga kategorier, kopiering av rapport till urklipp och åtgärder för att spara käll-PDF så att användare kan behålla den genererade exempel-PDF:en bredvid sin extraktionsrapport. De äldre demoerna ExtractText, ExtractImages, Attachment och FontProperties är kvar som fokuserade exempel; ExtractText stöder alternativ för sidintervall och sidseparator för att producera textutdata per sida över Delphi, C++Builder och Lazarus, medan ContentExtractionLab är det tvärgående inventeringsexemplet.
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;
// Utan plattläggning skriver FormField[i] := value endast /V-posten —
// den synliga utseendet kommer från /AP-strömmen och kan komma att inte uppdateras.
// GenerateFormAppearances regenererar /AP för varje widget, sedan
// bakar FlattenAllPages in varje sidas annoteringar och widgetar i
// permanent, icke-redigerbart innehåll.
Pdf1.FileName := 'C:\Application.pdf';
Pdf1.Active := True;
Pdf1.FormField[0] := 'John Smith';
Pdf1.FormField[1] := 'john@example.com';
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);
// Skapa ett komprimerat PDF-dokument
Pdf1.CreateDocument;
Pdf1.Compressed := True; // säkerställ att alla strömmar är FlateDecode-komprimerade (standard)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // A4-storlek
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// Spara med alternativ
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // inkrementellt sparande
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // ta bort säkerhet
// Spara till ett specifikt PDF-versionsmål. PDF-versionsvalideraren avvisar
// alla funktioner som introducerats efter det valda målet (JBIG2Decode, MarkInfo,
// AES-kryptering, Polygon / Caret / Watermark / Redact-annoteringar, ...).
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('Save rejected: document contains features newer than PDF 1.5');
// SaveAsPdfA efterbehandlar grundsparandet med en inkrementell uppdatering som
// injicerar en XMP-metadataström, en sRGB ICC OutputIntent och en uppdaterad
// dokumentkatalog så att resultatet är PDF/A-1b-konformt. Den medföljande
// sRGB IEC61966-2.1-profilen används automatiskt när ingen anpassad profil
// tillhandahålls.
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 med en anpassad ICC-profil (t.ex. CMYK-utskriftspipelines)
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;
// PDF/A-utdata i minnet
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;
// Billig sond i header-stil — läser konformansen utan att iterera
// den fullständiga valideraren. Resultat: pacNone, pac1a, pac1b, pac2b, pac3b eller
// 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;
// Fullständig validerare med per-problem-diagnostik
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;
Projekten Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab och Demo\Lazarus\StandardsLab läser in eller skapar en PDF, kör ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR och ValidatePdfVT, och visar sedan varje detekterad konformansnivå och antal problem i ett enda rutnät. Deras sparknappar anropar SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR och SaveAsPdfVT så att arbetsflödet för markörutdata är synligt utan att skriva ett anpassat ramverk.
Enheten FPdfPreflightReport omsluter ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR och ValidatePdfVT till ett rapportobjekt. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport och Demo\CBuilder\PreflightReport låter användare välja standarder, generera en sammanfattning, inspektera status, prioritet, problemkategorier, kategoriantal, nästa åtgärder, problemkoder och rekommenderade åtgärder, växla förhandsgranskningen mellan text, Markdown, JSON och CSV, samt exportera TXT-, HTML-, Markdown-, JSON- eller CSV-rapporter. Delphi GUI-exemplet lägger också till en Action Plan-förhandsgranskning som kondensar ej godkända standarder, prioriteringar, problemmarkeringar och rekommendationer till en åtgärdslista för korrigering. Demo\Delphi\PreflightReportCli exponerar samma rapportväg som ett konsolarbetsflöde med argument för in- / utdata, valfritt lösenord, val av utdataformat inklusive plan / actionplan, standardfiltrering, valfri enkelfilsrapport-inbäddning attach=output.pdf, utgångskoder för CI-grindning failon=, bearbetning av batch=list.txt, katalogskanning batchdir=folder med valfri rekursion och stabil sökvägssorterad bearbetning, rapportruttning outdir=reports, kollisionssäkra rapportnamn för duplicerade indatafilnamn, TXT- / JSON- / HTML-sammanfattningar med aggregerade och standardstatus-totaler, CSV-radmanifest med körningsinställningar som upprepas per objekt, samt ett argumentlöst exempelläge för skript och CI-jobb. Den genererade rapporten anger att de inbyggda validerarna täcker kontroller på markör- och utvalda filnivåer, så att fullständig preflight på innehållsnivå fortfarande kan delegeras till en dedikerad valideringsmotor.
// LoadCustomDocument låter PDFium hämta block från valfri sökbar TStream on-
// demand. Strömmen kopieras INTE in i minnet, så multi-GB-PDF:er, fjärr-
// HTTP-bodyströmmar och databasbaserade källor är alla genomförbara utan
// en buffert i förväg.
var
FileStream: TFileStream;
begin
// Strömmande från fil (ingen minneskopia)
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ ägandeskap överfört — Pdf1 frigör FileStream vid UnloadDocument.
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Externt ägd ström (anroparen frigör den efter 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 exponerar IPdfCancellationToken /
// IPdfCancellationTokenSource för avbrytning-från-UI-semantik som fungerar
// över de långvariga export- och renderingsvägarna.
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... användaren klickar på Avbryt ...
CancelSource.Cancel;
// Workern kontrollerar periodvis CancelToken.IsCancelled, eller renderingen
// pollar den via PDFiums IFSDK_PAUSE-callback.
if CancelToken.IsCancelled then
Memo1.Lines.Add('Cancelled by user');
end;
// RenderPageProgressive låter en lång rendering med hög DPI avbryta mitt i sidan när
// användaren klickar på Avbryt, istället för att blockera anroparen tills klar.
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> startar en worker på en bakgrundstråd och postar tillbaka ett
// TPdfFutureResult<T>-kuvert till huvudtråden.
//
// Viktigt: TPdf serialiserar renderingsanrop per instans, men workern äger fortfarande
// dispatch och dokumentets livstid. Mutera inte en TPdf medan en rendering pågår;
// batch-export håller vanligtvis en TPdf per fil.
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 omsluter PDFiums FS_MATRIX så att anropare kan bygga en transformation
// deklarativt och överlämna den till FPDFPageObj_SetMatrix.
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // flytta 1in höger, ~2.8in upp
M.Scale(0.5, 0.5); // halvstorleksstämpel
M.Rotate(15); // 15-grader CCW rotation
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // post-multiplicera med en annan matris
// Tillämpa på valfritt PDFium-sidobjekt (text / sökväg / bild / form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex kopierar en explicit nollbaserad indexarray från en
// käll-PDF in i detta dokument. InsertAt = 0 infogar före sida 1;
// PageCount lägger till på slutet.
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Importera sidor 0, 2, 4 (ettbaserat: sidor 1, 3, 5) från Source
// och lägg till dem i slutet av Pdf1.
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Tom array importerar alla källsidor
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne returnerar en helt ny TPdf vars sidor är NumX*NumY
// kompositioner av DETTA dokument. OutputWidth/Height är PDF-användarenheter
// (1 enhet = 1/72 in).
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// 4-up A4 liggande: 842 x 595 pt, 2 kolumner x 2 rader
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages tar de nollbaserade indexen för de sidor som ska flyttas plus
// destinationsindexet för den första flyttade sidan efter att flyttningen är klar.
// Andra sidor förskjuts runt det flyttade blocket så att dokumentlängden förblir
// densamma.
//
// Exempel: i ett 5-sidigt dokument med sidor numrerade [0,1,2,3,4],
// MovePages([2, 3], 0) omordnar till [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage tillverkar ett återanvändbart Form XObject-handle från
// valfri sida av valfri annan TPdf. Stämpla det handlet på så många sidor av
// DETTA dokument du vill — varje stämpel är ett enda PDFium-sidobjekt
// som kan positioneras, skalas och roteras via matris-API:et.
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;
// Omslut sida 0 av WatermarkSource som ett återanvändbart XObject
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;
// Centrera vattenstämpeln på sidan
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; // stänger FPDF_XOBJECT-handlet
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
Projekten Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp och Demo\CBuilder\WatermarkStamp gör detta mönster till ett körbart arbetsflöde: de skapar en mål-PDF och en återanvändbar stämpel-PDF, omsluter stämpelsidan med CreateXObjectFromPage, infogar samma Form XObject på varje målsida, tillämpar TPdfMatrix-transformationer för centrerade vattenstämplar och hörnstämplar uppe till höger, och lägger till valfria sidnummeretiketter innan resultatet sparas.
// AddImage(FileName) accepterar alla format registrerade med VCL- eller LCL-
// grafikenheter (BMP, PNG via PngImage, JPG, ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) hoppar över TPicture-mellansteget, idealt när
// bitmappen redan kommer från renderings- eller batch-genereringsarbete.
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;
Projekten Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF och Demo\Lazarus\ImageToPDF gör detta till ett fullständigt batch-arbetsflöde: välj flera bildfiler, förhandsgranska det valda objektet, skapa en PDF-sida per bild, skala varje bild till en A4 stående eller liggande sida, spara resultatet och öppna den genererade PDF:en.
var
MatchCount: Integer;
begin
// Måla en clYellow-mask över varje träff på vyns aktuella sida.
// Byte till en annan sida rensar markeringen automatiskt.
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d match(es) on this page', [MatchCount]);
// Programmatiskt ta bort överlägget innan sidan ändras
PdfView1.ClearHighlight;
end;
// FitMode håller långa dokument inramade under Resize eller sidbyten.
// Att sätta Zoom direkt avbryter FitMode (det återgår till pfmNone).
PdfView1.FitMode := pfmFitPage; // hela sidan i viewporten
// PdfView1.FitMode := pfmFitWidth; // sidbredden matchar viewportbredden
// PdfView1.FitMode := pfmActualSize; // 100%
// PageColor separerar den renderade PDF-sidan från värdkontrollens Color
// — typisk inställning för visare i mörkt läge håller rullningsområdet mörkt medan
// PDF-sidan förblir pappersvit.
PdfView1.Color := clBlack; // rullningsområde
PdfView1.PageColor := clWhite; // PDF-sidans bakgrund
// Valfri skuggeffekt och sidram för att lyfta sidan från en mörk bakgrund
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
Projekten Demo\Delphi\ViewerInteractionLab, Demo\CBuilder\ViewerInteractionLab och Demo\Lazarus\ViewerInteractionLab håller den moderna interaktionsytan för TPdfView i ett kompakt formulär: öppna eller skapa en exempel-PDF, växla DisplayMode, tillämpa FitMode, ändra PageColor, rotera sidor, markera sökträffar på aktuell sida med HighlightSearchText, aktivera eller inaktivera användartextmarkering, inspektera SelectedText, anropa SelectAll, CopySelectionToClipboard och ClearSelection, och se DeviceToPage-koordinater uppdateras i statusraden medan musen rör sig över sidan.
Projekten Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect och Demo\Lazarus\SearchAndSelect gör sök-och-markera-arbetsflödet i visaren till fristående exempel. De öppnar eller skapar en PDF, listar sökresultat över alla sidor med sidnummer, teckenindex och förhandsvisningstext, stödjer Föregående / Nästa-navigering och dubbelklicksresultatshopp, markerar träffar på aktuell sida med HighlightSearchText, exponerar alternativ för match-case och hela ord, växlar AllowUserTextSelection, förhandsvisar SelectedText, driver SelectAll, CopySelectionToClipboard och ClearSelection från knappar, och låter användare växla mellan enkel- och uppslagsvisningslägen.
Projekten Demo\Delphi\PrintPreferences, Demo\CBuilder\PrintPreferences och Demo\Lazarus\PrintPreferences läser författarens utskriftsinställningar innan utskrift. De visar PrintCopies, PrintPageRanges, PrintScaling och PrintPaperHandling, kan kopiera författarspecificerade kopior och intervall in i utskriftsindata, och visar hur SetPdfPrintPaperHandlingDevMode mappar PDF-duplex-avsikt till en Windows DEVMODE.
Projekten Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF och Demo\Lazarus\PrintPDF visar standardutskriftsarbetsflödet: öppna en PDF, förhandsgranska sidor, välj sidintervall och kopior i plattformens utskriftsdialog, hedra kollationeringsläge, rendera varje sida via TPdf.RenderPage och exponera utskriftsprogress med avbrytning. Delphi-exemplet accepterar också släppta PDF-filer för snabb inläsning.
Projekten Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer och Demo\Lazarus\MultiPageViewer övar kontinuerlig, uppslags- och omslagsmedveten visning med vanliga sidnavigerings- och zoomarbetsflöden. De är också användbara för att testa öppna-till-första-sida-hastighet och renderingsresponsivitet på mycket stora PDF:er: i tester med stora filer kan 2,x GB-dokument som kan få Acrobat eller Foxit att spendera 20-30 sekunder innan första vy bli användbara nästan omedelbart via PDFiumPas-visarvägen.
Projekten Demo\Delphi\SplitView, Demo\CBuilder\SplitView och Demo\Lazarus\SplitView visar sida-vid-sida-PDF-granskning. C++Builder- och Lazarus-exemplen fokuserar på två- eller trefönsterjämförelse, val av aktiv vy, valfria synkroniserade navigeringskommandon, delade zoomförinställningar och rotation för den valda vyn eller alla inlästa vyer. Använd dessa exempel för att jämföra stora dokument samtidigt som första användbara vy och efterföljande sidrendering förblir responsiv; samma 2,x GB PDF-filer som kan ta Acrobat eller Foxit 20-30 sekunder att öppna kan bli användbara nästan omedelbart i PDFiumPas-visarvägen.
Projekten Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit och Demo\Lazarus\SecurityAudit öppnar en PDF skrivskyddat och listar rättighetsstatus, inbäddade bilagor, dokument-JavaScript-åtgärder, URI- och Launch-länkannoteringar, webblänkar, signatursammanfattningar, XFA-status, V8-hjälpartillgänglighet och callbacks för funktioner som inte stöds. Samma sammanfattning och fyndrader kan sparas eller kopieras som en TXT-revisionsrapport eller sparas som strukturerad JSON. De är avsedda som riskpaneler för värdapplikationer, inte som malware-detektering.
// LinkOptions kontrollerar automatisk hantering av de fyra PDF-länkåtgärds-
// typerna. Standardvärden aktiverar endast goto och URI; launch (kör ett program) och
// inbäddad GotoR (hoppa till en annan fil) förblir AVSTÄNGDA så att ett oavsiktligt klick inte kan
// köra godtycklig kod.
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // säkra standardvärden
// OnAnnotationLinkClick aktiveras för dokumentinterna destinationer (sidhopp,
// namngivna destinationer, åtgärdskedjor). Markera Handled = True för att förhindra
// att vyn auto-följer länken.
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; // undertryck auto-hantering
end;
end;
// OnWebLinkClick aktiveras för URI-strängar som upptäckts av PDFiums webblänk-
// skanner (auto-detekterade URL:er i textströmmen, även utan en
// /A <</S/URI...>>-annotering).
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
WebLinkIndex: Integer; const Url: WString;
var Handled: Boolean);
begin
Log.Add('Web link clicked: ' + string(Url));
end;
// På den fokuserade AcroForm-widgeten driver sex nya metoder PDFiums
// formulärredigeringshistorik. Alla sex kortsluter säkert om ingen widget är fokuserad eller
// dokumentet inte bär något 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;
// Alla tre är som standard True så att befintliga appar uppgraderas utan beteende-
// ändring. Vänd dem till False för kiosker, förhandsgranskningsfält eller skrivskyddade
// integrationer utan att underklassa TPdfView.
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // hjul upp/ned-hopp
PdfView1.AllowUserTextSelection := False; // mus/tangentbord textmarkering
// Ctrl+hjul är reserverat för zoom och hoppas över av navigerings-
// hanteraren oavsett ChangePageOnMouseScrolling.
// TPdfThumbnailView (enhet FPdfThumbnail) renderar en sidminiatyrbild per
// rad i en rullbar sidopanel.
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // varm markering
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex är nollbaserad
end;
procedure TForm1.PdfView1PageNumberÄndrat(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Mönster som används av Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport
// och Demo\Lazarus\BatchExport. En TPdf per fil, IPdfCancellationToken
// för avbrytning-från-UI, TPdfStreamAdapter för buffrad filinläsning.
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 är en billig katalogsond — True när /StructTreeRoot existerar.
// StructureElements materialiserar trädet till en plan array av
// TPdfStructureElement-poster med typ, titel, alternativ text, faktisk
// text, expansionstext, språk, nivå, förälderindex och antal barn / märkta
// innehåll / attribut.
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 är en global funktion som mappar till PDFiums
// FPDF_SetPrintMode. Använd matchande TPdfPrintMode-värde för
// skrivardrivrutinen som används.
SetPdfPrintMode(pmEmf); // GDI EMF (standard)
// SetPdfPrintMode(pmTextOnly); // endast text-rendering
// SetPdfPrintMode(pmPostScript2); // PostScript Level 2
// SetPdfPrintMode(pmPostScript3); // PostScript Level 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + image masks
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + Type 42-typsnitt
// PrintCopies, PrintPageRanges, PrintScaling och PrintPaperHandling är
// poster i visningsinställningsordboken — de kodar vad
// dokumentförfattaren ville att PDF-läsare skulle använda som standard.
var
Ranges: TPrintPageRanges;
Range: TPrintPageRange;
begin
ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
Ord(Pdf1.PrintScaling)));
Ranges := Pdf1.PrintPageRanges; // ettbaserade intervall
for Range in Ranges do
Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// JavaScript på dokumentnivå lagras i namnträdet /Names /JavaScript.
// JavaScriptAction[i] returnerar en post; JavaScriptActions returnerar
// den fullständiga arrayen.
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;
// Zero-copy-renderingsväg (standard sedan v1.21.0): RenderPage skriver
// direkt till destinationens TBitmap-DIB-buffert när anropare skickar en
// förallokerad bitmap, vilket undviker en width * height * 4 bytes-kopia.
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;