Pdf1.FileName := 'C:\MyDocument.pdf';
Pdf1.Active := True;
ShowMessage('דפים: ' + IntToStr(Pdf1.PageCount));
ShowMessage('כותרת: ' + Pdf1.Title);
ShowMessage('מחבר: ' + Pdf1.Author);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromFile('C:\MyDocument.pdf');
Pdf1.LoadDocument(Stream, True);
Pdf1.Active := True;
ShowMessage('ה-PDF נטען מזרם');
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('טקסט במלבן: ' + RectText);
end;
var
Position: Integer;
begin
Position := Pdf1.FindFirst('Hello', [seCaseSensitive]);
while Position >= 0 do
begin
ShowMessage('נמצא בתו: ' + IntToStr(Position));
Position := Pdf1.FindNext;
end;
end;
Pdf1.PageNumber := 1;
Pdf1.AddText('כותרת המסמך', 'Times New Roman', 16, 100, 750, clBlue);
Pdf1.AddText('זהו תוכן המסמך', '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('אובייקט ' + IntToStr(I));
Memo1.Lines.Add('שם בסיס: ' + Pdf1.FontBaseName[I]);
Memo1.Lines.Add('משפחה: ' + Pdf1.FontFamilyName[I]);
Memo1.Lines.Add('מוטמע: ' + BoolToStr(Pdf1.FontIsEmbedded[I], True));
Memo1.Lines.Add('משקל: ' + IntToStr(Pdf1.FontWeight[I]));
Memo1.Lines.Add('זווית נטויה: ' + IntToStr(Pdf1.FontItalicAngle[I]));
Memo1.Lines.Add('עלייה: ' + FloatToStr(Pdf1.FontAscent[I, MetricSize]));
Memo1.Lines.Add('ירידה: ' + FloatToStr(Pdf1.FontDescent[I, MetricSize]));
Memo1.Lines.Add('בתים של נתוני גופן: ' + IntToStr(Length(FontBytes)));
end;
if Pdf1.CharacterCount > 0 then
begin
Memo1.Lines.Add('גודל התו הראשון: ' + FloatToStr(Pdf1.CharacterFontSize[0]));
Memo1.Lines.Add('משקל התו הראשון: ' + IntToStr(Pdf1.CharacterFontWeight[0]));
Memo1.Lines.Add('זווית התו הראשון: ' + FloatToStr(Pdf1.CharacterAngle[0]));
end;
end;
הפרויקטים Demo\Delphi\FontProperties, Demo\CBuilder\FontProperties ו-Demo\Lazarus\FontProperties מציגים את אותם מטא-נתונים דרך TPdf וגם דרך TPdfView
הפרויקטים Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab ו-Demo\Lazarus\ContentExtractionLab הופכים חילוץ תוכן לזרימת עבודה אחת. הם פותחים או יוצרים PDF, מאפשרים למשתמשים לבחור metadata, טקסט עמוד, אובייקטי עמוד, images, attachments, links, annotations, bookmarks ומדדי גופן / תו, ואז מייצרים סיכום יחד עם דוח TXT או JSON מפורט. המעבדה כוללת גם בחירה של all / none categories, העתקת הדוח ללוח, ופעולות שמירת PDF המקור כדי שהמשתמשים יוכלו לשמור את ה-PDF לדוגמה שנוצר לצד דוח החילוץ שלו. הדגמות ExtractText, ExtractImages, Attachment ו-FontProperties הישנות נשארות דוגמאות ממוקדות; ExtractText תומכת באפשרויות טווח-עמודים ומפריד-עמודים כדי להפיק פלט טקסט לכל עמוד ב-Delphi, C++Builder ו-Lazarus, בעוד ContentExtractionLab היא דגימת המלאי החוצה-חתכים.
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;
// Without flattening, FormField[i] := value writes only the /V entry —
// the visible appearance comes from the /AP stream and may not refresh
// GenerateFormAppearances regenerates /AP for each widget, then
// FlattenAllPages bakes all annotations and widgets on each page into
// fixed content that cannot be edited
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('הערה ' + 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);
// יצירת מסמך PDF דחוס
Pdf1.CreateDocument;
Pdf1.Compressed := True; // לוודא שכל הזרמים דחוסים ב-FlateDecode (ברירת המחדל)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // A4 size
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// שמירה עם אפשרויות
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // שמירה מצטברת
Pdf1.SaveAs('C:\Noאבטחה.pdf', saRemoveSecurity); // הסרת אבטחה
// שמירה ליעד גרסת PDF מסוים. מאמת גרסת ה-PDF דוחה
// כל תכונה שהתווספה אחרי היעד שנבחר (JBIG2Decode, MarkInfo,
// AES encryption, Polygon / Caret / Watermark / Redact annotations, ...)
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('השמירה נדחתה: המסמך מכיל תכונות חדשות יותר מ-PDF 1.5');
// SaveAsPdfA מבצע עיבוד אחרי השמירה הבסיסית עם עדכון מצטבר שמחדיר
// זרם מטא-נתונים XMP, ICC OutputIntent מסוג sRGB, וקטלוג מסמך מעודכן
// כך שהתוצאה תואמת ל-PDF/A-1b. פרופיל sRGB IEC61966-2.1 המצורף
// משמש אוטומטית כאשר לא מסופק פרופיל מותאם אישית
Pdf1.FileName := 'C:\Report.pdf';
Pdf1.Active := True;
if Pdf1.SaveAsPdfA('C:\Report.pdfa.pdf', pac1b) then
ShowMessage('נשמר ארכיון PDF/A-1b');
// PDF/A עם פרופיל ICC מותאם אישית (לדוגמה צינורות הדפסה CMYK)
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 בזיכרון
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;
// בדיקת כותרת זולה בסגנון probe — קוראת את התאימות בלי להריץ
// את המאמת המלא. תוצאה: pacNone, pac1a, pac1b, pac2b, pac3b, או
// 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 := 'תאימות לא ידועה';
end;
// מאמת מלא עם אבחון לכל בעיה
Validation := Pdf1.ValidatePdfA;
Memo1.Lines.Add('תאימות: ' + GetEnumName(TypeInfo(TPdfAConformance),
Ord(Validation.Conformance)));
for Issue in Validation.Issues do
Memo1.Lines.Add('- ' + Issue.Description);
end;
The Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab, and Demo\Lazarus\StandardsLab projects load or create a PDF, run ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR, and ValidatePdfVT, then show each detected conformance level and issue count in one grid. Their save buttons call SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR, and SaveAsPdfVT so the marker-output workflow is visible without writing a custom harness.
יחידת FPdfPreflightReport עוטפת את ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR ו-ValidatePdfVT לאובייקט דוח אחד. הפרויקטים Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport ו-Demo\CBuilder\PreflightReport מאפשרים למשתמשים לבחור תקנים, ליצור סיכום, לבדוק מצב, עדיפות, קטגוריות בעיות, ספירות קטגוריות, פעולות הבאות, קודי בעיות ופעולות מומלצות, להחליף את התצוגה המקדימה בין text, Markdown, JSON ו-CSV, ולייצא דוחות TXT, HTML, Markdown, JSON או CSV. דוגמת ה-GUI של Delphi מוסיפה גם תצוגת Action Plan שמרכזת תקנים שנכשלו, עדיפויות, קודי בעיות והמלצות לרשימת תיקון. Demo\Delphi\PreflightReportCli חושפת את אותו נתיב דוח כזרימת קונסול עם ארגומנטים של קלט / פלט, סיסמה אופציונלית, בחירת תבנית פלט כולל plan / actionplan, סינון תקנים, הטמעת דוח בקובץ יחיד אופציונלי attach=output.pdf, קודי יציאה של CI דרך failon=, עיבוד batch=list.txt, סריקת תיקיות batchdir=folder עם רקורסיה אופציונלית ועיבוד יציב לפי נתיב, ניתוב דוחות באמצעות outdir=reports, שמות דוח בטוחים להתנגשות עבור שמות קלט כפולים, סיכומי TXT / JSON / HTML עם סיכומי סטטוס מצטברים ולפי תקן, manifests של שורות CSV עם הגדרות ריצה החוזרות לכל פריט, ומצב דוגמה ללא ארגומנטים עבור סקריפטים ומשימות CI. הדוח שנוצר מציין שהמאמתים המובנים מכסים בדיקות ברמת marker וברמת קובץ נבחר, כך שבדיקת preflight מלאה ברמת תוכן עדיין יכולה להיות מנותבת למנוע אימות ייעודי
// LoadCustomDocument lets PDFium pull blocks from any seekable TStream on
// לפי דרישה. הזרם אינו מועתק לזיכרון, כך ש-PDFs בני כמה GB, זרמי
// body של HTTP ומקורות מבוססי מסד נתונים כולם אפשריים בלי
// חיץ מקדים
var
FileStream: TFileStream;
begin
// סטרימינג מקובץ ללא עותק בזיכרון
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ הבעלות הועברה — Pdf1 משחרר את FileStream ב-UnloadDocument
Pdf1.Active := True;
ShowMessage('דפים: ' + IntToStr(Pdf1.PageCount));
end;
// Externally-owned stream (caller frees it after 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 exposes IPdfCancellationToken /
// IPdfCancellationTokenSource for cancel-from-UI semantics that work
// across the long-running export and render paths.
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... user clicks Cancel ...
CancelSource.Cancel;
// The worker periodically checks CancelToken.IsCancelled, or the render
// קורא אותו דרך הקריאה החוזרת IFSDK_PAUSE של PDFium
if CancelToken.IsCancelled then
Memo1.Lines.Add('בוטל על ידי המשתמש');
end;
// RenderPageProgressive lets a long high-DPI render abort mid-page when
// the user clicks Cancel, instead of blocking the caller until done.
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('הרינדור בוטל — תוצאה חלקית זמינה');
prsFailed: Memo1.Lines.Add('PDFium reported FPDF_RENDER_FAILED');
end;
finally
Bitmap.Free;
end;
end;
// TPdfFuture<T> spins up a worker on a background thread and posts a
// TPdfFutureResult<T> envelope back to the main thread.
//
// Important: TPdf serializes render calls per instance, but the worker still
// owns dispatch and document lifetime. Do not mutate a TPdf while a render is
// in flight; batch export usually keeps one TPdf per file.
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('בוטל');
pfsFailed: Log.Add('העובד נכשל: ' + AResult.ErrorMessage);
end;
end);
end;
// FPdfMatrix wraps PDFium's FS_MATRIX so callers can build a transform
// declaratively and hand it to FPDFPageObj_SetMatrix.
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // move 1in right, ~2.8in up
M.Scale(0.5, 0.5); // half-size stamp
M.Rotate(15); // 15-degree CCW rotation
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // post-multiply with another matrix
// Apply to any PDFium page object (text / path / image / form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex copies an explicit zero-based index array from a
// PDF המקור לתוך מסמך זה. InsertAt = 0 מוסיף לפני דף 1;
// PageCount מצרף בסוף
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Import pages 0, 2, 4 (one-based: pages 1, 3, 5) from Source
// and append them at the end of Pdf1.
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Empty array imports every source page
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne returns a brand-new TPdf whose pages are NumX*NumY
// composites of THIS document. OutputWidth/Height are PDF user units
// (1 unit = 1/72 in).
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// 4-up A4 landscape: 842 x 595 pt, 2 columns x 2 rows
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages takes the zero-based indices of the pages to move plus the
// אינדקס היעד של הדף שהוזז ראשון לאחר השלמת ההזזה
// דפים אחרים זזים סביב הבלוק שהוזז כך שאורך המסמך נשאר
// the same.
//
// דוגמה: in a 5-page document with pages numbered [0,1,2,3,4],
// MovePages([2, 3], 0) reorders to [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage manufactures a reusable Form XObject handle from
// כל דף של TPdf אחר. הטביעו את הידית הזו על כמה שיותר דפים של
// מסמך זה שתרצו — כל חותמת היא אובייקט דף יחיד של PDFium
// שאפשר למקם, להגדיל ולהקטין ולסובב דרך ה-Matrix API
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;
// Wrap page 0 of WatermarkSource as a reusable 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;
// Centre the watermark on the 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; // closes the FPDF_XOBJECT handle
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
The Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp, and Demo\CBuilder\WatermarkStamp הפרויקטים הופכים את התבנית הזו לזרימת עבודה ניתנת להרצה: הם יוצרים PDF יעד ו-PDF חותמת לשימוש חוזר, עוטפים את דף החותמת עם CreateXObjectFromPage, מחדירים את אותו Form XObject לכל דף יעד, מפעילים טרנספורמציות TPdfMatrix עבור watermarks ממורכזים וחותמות בפינה הימנית העליונה, ומוסיפים תוויות מספרי עמוד אופציונליות לפני שמירת התוצאה
// AddImage(FileName) accepts any format registered with the VCL or LCL
// יחידות גרפיקה (BMP, PNG דרך PngImage, JPG, ...)
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) skips the TPicture intermediary, ideal when the
// bitmap already comes from rendering or batch generation work.
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;
The Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF, and Demo\Lazarus\ImageToPDF הפרויקטים הופכים זאת לזרימת עבודה קבוצתית מלאה: בוחרים כמה קובצי תמונה, מציגים תצוגה מקדימה של הפריט שנבחר, יוצרים דף PDF אחד לכל תמונה, מתאימים כל תמונה לדף A4 לאורך או לרוחב, שומרים את התוצאה ופותחים את ה-PDF שנוצר
var
MatchCount: Integer;
begin
// צבעו מסכת clYellow מעל כל התאמה בדף הנוכחי של הצופה
// מעבר לדף אחר מנקה את ההדגשה באופן אוטומטי
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d התאמות בדף הזה', [MatchCount]);
// Programmatically remove the overlay before the page changes
PdfView1.ClearHighlight;
end;
// FitMode keeps long documents framed during Resize or page changes.
// Setting Zoom directly cancels FitMode (it reverts to pfmNone).
PdfView1.FitMode := pfmFitPage; // whole page in viewport
// PdfView1.FitMode := pfmFitWidth; // page width matches viewport width
// PdfView1.FitMode := pfmActualSize; // 100%
// PageColor decouples the rendered PDF page from the host control's Color
// — typical dark-mode viewer setup keeps the scroll area dark while the
// PDF page stays paper-white.
PdfView1.Color := clBlack; // scroll area
PdfView1.PageColor := clWhite; // PDF page background
// Optional drop shadow and page border to lift the page off a dark bg
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
The Demo\Delphi\ViewerInteractionLab, Demo\CBuilder\ViewerInteractionLab, and Demo\Lazarus\ViewerInteractionLab projects keep the modern TPdfView interaction surface in one compact form: open or create a sample PDF, switch DisplayMode, apply FitMode, change PageColor, rotate pages, highlight current-page search hits with HighlightSearchText, enable or disable user text selection, inspect SelectedText, call SelectAll, CopySelectionToClipboard, and ClearSelection, and watch DeviceToPage קואורדינטות מתעדכנות בשורת המצב בזמן שהעכבר נע מעל הדף
הפרויקטים Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect ו-Demo\Lazarus\SearchAndSelect הופכים את זרימת העבודה של חיפוש ובחירה במציג לדוגמאות עצמאיות. הם פותחים או יוצרים PDF, מציגים תוצאות חיפוש בכל הדפים עם מספר דף, אינדקס תו וטקסט תצוגה מקדימה, תומכים בניווט Previous / Next ובקפיצה לתוצאה בלחיצה כפולה, מדגישים התאמות בדף הנוכחי בעזרת HighlightSearchText, חושפים אפשרויות match-case ו-whole-word, מחליפים את AllowUserTextSelection, מציגים SelectedText, מפעילים את SelectAll, CopySelectionToClipboard ו-ClearSelection מכפתורים, ומאפשרים למשתמשים לעבור בין מצבי תצוגה single ו-spread
הפרויקטים Demo\\Delphi\\PrintPreferences, Demo\\CBuilder\\PrintPreferences ו-Demo\\Lazarus\\PrintPreferences קוראים העדפות הדפסה של המחבר לפני ההדפסה. הם מציגים את PrintCopies, PrintPageRanges, PrintScaling ו-PrintPaperHandling, יכולים להעתיק עותקים וטווחים שסופקו על ידי המחבר אל שדות ההדפסה, ומראים כיצד SetPdfPrintPaperHandlingDevMode ממפה כוונת duplex של PDF אל DEVMODE של Windows
הפרויקטים Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF ו-Demo\Lazarus\PrintPDF מציגים את זרימת ההדפסה הסטנדרטית: פתיחת PDF, תצוגה מקדימה של דפים, בחירת טווחי עמודים ועותקים בתיבת הדו-שיח של ההדפסה, שמירה על מצב collate, עיבוד כל דף דרך TPdf.RenderPage, וחשיפת התקדמות ההדפסה עם אפשרות ביטול. דוגמת Delphi גם מקבלת קובצי PDF שנגררו אליה לטעינה מהירה
The Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer, and Demo\Lazarus\MultiPageViewer הפרויקטים מתרגלים תצוגה רציפה, spread ותצוגה מודעת-כריכה עם ניווט עמודים רגיל וזרימות זום. הם גם שימושיים לבדיקת מהירות פתיחה-לדף-הראשון ותגובתיות הרינדור על PDFs גדולים מאוד: בבדיקות קובצי ענק, מסמכים בני 2.x GB שיכולים לגרום ל-Acrobat או ל-Foxit להשקיע 20-30 שניות לפני התצוגה הראשונה, יכולים להפוך לשמישים כמעט מיד דרך נתיב הצופה של PDFiumPas
The Demo\Delphi\SplitView, Demo\CBuilder\SplitView, and Demo\Lazarus\SplitView הפרויקטים מציגים סקירת PDF זה לצד זה. הדגימות של C++Builder ו-Lazarus מתמקדות בהשוואה של שתי חלוניות או שלוש, בבחירת view פעיל, בפקודות ניווט מסונכרנות אופציונליות, בפריסות זום משותפות ובסיבוב של התצוגה שנבחרה או של כל התצוגות שנטענו. השתמשו בדגימות האלה כדי להשוות מסמכים גדולים תוך שמירה על התצוגה השימושית הראשונה ועל תגובתיות רינדור העמודים הבאים; אותם קובצי PDF בני 2.x GB שיכולים להצריך מ-Acrobat או Foxit 20-30 שניות לפתוח, יכולים להפוך לשמישים כמעט מיד בנתיב הצופה של PDFiumPas
The Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit, and Demo\Lazarus\SecurityAudit הפרויקטים פותחים PDF לקריאה בלבד ומציגים מצב הרשאות, קבצים מוטמעים מצורפים, פעולות JavaScript של המסמך, annotations של קישורי URI ו-Launch, קישורי web, סיכומי חתימות, מצב XFA, זמינות helper של V8 ו-callbacks עבור תכונות שאינן נתמכות. את אותן שורות סיכום וממצאים אפשר לשמור או להעתיק כדוח audit ב-TXT או לשמור כ-JSON מובנה. הם מיועדים כלוחות סיכון של היישום המארח, לא לזיהוי malware
// LinkOptions שולט בטיפול האוטומטי בארבעת סוגי פעולות הקישור של PDF
// הסוגים. ברירות המחדל מפעילות goto ו-URI בלבד; launch (הרצת תוכנית) ו-
// GotoR מוטמע (קפיצה לקובץ אחר) נשארים כבויים כך שלחיצה מקרית לא תוכל
// להפעיל קוד שרירותי
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // safe defaults
// OnAnnotationLinkClick מופעל עבור יעדים בתוך המסמך (קפיצות דף,
// יעדים בעלי שם, שרשראות פעולות). סמנו Handled = True כדי למנוע מה
// מציג לעקוב אחר הקישור אוטומטית
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; // suppress auto-handling
end;
end;
// OnWebLinkClick מופעל עבור מחרוזות URI שזוהו על ידי סורק ה-web-link של PDFium
// סורק (כתובות URL שזוהו אוטומטית בזרם הטקסט, גם בלי
// /A <</S/URI...>> annotation).
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
WebLinkIndex: Integer; const Url: WString;
var Handled: Boolean);
begin
Log.Add('קישור אינטרנט נלחץ: ' + string(Url));
end;
// On the focused AcroForm widget, six new methods drive PDFium's form
// היסטוריית העריכה. כל ששתם יוצאים מוקדם בבטחה אם אין widget ממוקד או
// שלמסמך אין AcroForm
procedure TForm1.btnSelectAllClick(Sender: TObject);
begin
PdfView1.SelectAllFormText;
EditMenuCopy.Caption := 'העתק: ' + 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;
// All three default to True so existing apps upgrade with no behaviour
// שינוי. הפכו אותם ל-False עבור קיוסקים, חלוניות תצוגה מקדימה או
// הטמעות לקריאה בלבד בלי ליצור תת-מחלקה של TPdfView
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+דף הבית/End
PdfView1.ChangePageOnMouseScrolling := False; // wheel up/down jumps
PdfView1.AllowUserTextSelection := False; // mouse/keyboard text selection
// Ctrl+wheel שמור לזום ונעקף על ידי
// מטפל הניווט ללא תלות ב-ChangePageOnMouseScrolling.
// TPdfThumbnailView (unit FPdfThumbnail) renders one page thumbnail per
// שורה בחלונית צד נגללת
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // הדגשה חמימה
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex הוא מבוסס אפס
end;
procedure TForm1.PdfView1PageNumberשונה(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Pattern used by Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport,
// ו-Demo\Lazarus\BatchExport. TPdf אחד לכל קובץ, IPdfCancellationToken
// לביטול מה-UI, TPdfStreamAdapter לטעינת קובץ עם חיץ
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('דף %d, X %.2f, Y %.2f, תו %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 is a cheap catalog probe — True when /StructTreeRoot exists.
// StructureElements מממש את העץ למערך שטוח של
// רשומות TPdfStructureElement עם type, title, alternate text, actual
// text, expansion text, language, level, parent index, ו-child / marked
// content / attribute counts
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 is a global function that maps to PDFium's
// FPDF_SetPrintMode. השתמשו בערך TPdfPrintMode המתאים עבור
// מנהל ההתקן של המדפסת שבשימוש
SetPdfPrintMode(pmEmf); // GDI EMF (default)
// SetPdfPrintMode(pmTextOnly); // רינדור טקסט בלבד
// 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 fonts
// PrintCopies, PrintPageRanges, PrintScaling ו-PrintPaperHandling הם
// רשומות viewer-preference dictionary — הן מקודדות מה
// שהמחבר רצה שקוראי 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; // טווחים מבוססי אחת
for Range in Ranges do
Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// Document-level JavaScript is stored in the /Names /JavaScript name
// tree. JavaScriptAction[i] returns one record; JavaScriptActions returns
// את כל המערך
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;
// Copy-free render path (default since v1.21.0): RenderPage writes
// directly into the target TBitmap DIB buffer when callers pass
// a preallocated bitmap, avoiding one copy of width * height * 4 bytes
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;