تضم مجموعة الأمثلة 32 موضوعًا: 32 مشروع Delphi و 31 مشروع C++Builder و 32 مشروع Lazarus، بإجمالي 95 مشروعًا أصليًا؛ تحفظ كل منصة 22 مثال سير عمل كامل في المجلد الرئيسي؛ توجد عشرة مواضيع مركزة تحت Miscellaneous تضم 29 مشروعًا عبر المنصات الثلاث، ويتاح XfaLab لـ Delphi و Lazarus
ابدأ بسير عمل من المجلد الرئيسي أولًا: PDFViewer لجولة الميزات، وCreatePDF للتأليف الحيّ، وContentExtractionLab لجرد فوري، وFormFill للنماذج القابلة للتحرير، وStandardsLab للتحقق والتحويل، أو IntakeWorkbenchCli للاستقبال المؤتمت. نقاط الدخول الست هذه تُنتج نتائج عملية فورًا؛ والعينات المركّزة أدناه تفيد عندما تحتاج إلى فحص API بعينه بالتفصيل
| العرض | استخدمه من أجل | ما يميّزه عن العروض ذات الصلة |
|---|---|---|
PDFViewer | عرض عام وتقييم الميزات | يجمع العارض الرئيسي بين التنقل والبحث والمصغّرات وأوضاع العرض والطباعة وعرض توضيحي للميزات |
MultiPageViewer | صفحات متصلة وعروض صفحتين وتخطيطات صفحة الغلاف | مثال مركّز على التخطيط يستخدم واجهات API التحديد المدمجة في العارض؛ استخدم PDFViewer لتجربة عارض أوسع |
SplitView | مقارنة الصفحات أو المستندات في أجزاء منفصلة | يوضّح مواضع عرض مستقلة وتوجيه الأوامر إلى الجزء النشط، لا تخطيط صفحتين داخل عرض واحد |
SearchAndSelect | نتائج بحث وتحديد عبر الصفحات | قائمة نتائج وخيارات بحث تكشف سير عمل البحث مباشرةً أكثر مما يفعله شريط أدوات العارض |
PrintPDF | المعاينة ومهام الطباعة الاعتيادية | نطاقات الصفحات والتحجيم والتقدّم والإلغاء توفر سير عمل الطباعة الرئيسي |
ContentExtractionLab | فحص عدة فئات محتوى معًا | جرد TXT/JSON يصف الكائنات ويعاين النصوص؛ لكنه لا يغني عن تصدير النص الكامل أو ملفات الصور |
ExtractImages | تصدير كائنات الصور المضمَّنة | يستخرج صور bitmap بدل لقطات شاشة لصفحات كاملة؛ وتحتوي العينة المدمجة كائني صور حقيقيين في كل من الصفحتين |
TableExtractionLab | كشف الجداول وتصدير CSV/JSON | الجداول المسطّرة والمحاذاة بالفراغات والخلايا المدمجة ومجموعات الاستمرار ومفاتيح الثقة مستقلة عن استخراج النص العادي |
Attachment | قراءة المرفقات المضمَّنة وإضافتها وتصديرها | عمليات حمولة المرفقات تتجاوز سرد الأسماء والأحجام في ContentExtractionLab |
BatchExport | تصدير صور الصفحات من مستندات متعددة | المخرجات المتدفقة وحالة كل ملف والإخفاقات المعزولة توضح المعالجة الدفعية لا التحويل الفردي |
CreatePDF | إنشاء محتوى الصفحات مع معاينة حيّة | تنشئ إصدارات native الثلاثة نصًّا قابلًا للبحث وأشكالًا vector وصورة raster حقيقية وجداول وتعليقًا توضيحيًّا للمراجعة؛ وتعيد الخيارات بناء المعاينة قبل حفظ صريح |
ImageToPDF | بناء الصفحات من ملفات صور إدخال | تخطيط الصور ومطابقتها وترتيبها والتعامل مع JPEG توفر سير عمل لتحويل المستندات |
MergePDF | تجميع صفحات من عدة ملفات PDF | يوضّح استيراد المستندات والتركيب المرتّب؛ والتقسيم يعالج سير العمل العكسي |
SplitPDF | كتابة مجموعات صفحات محددة إلى ملفات PDF منفصلة | تسمية المخرجات والتحقق من مجموعات الصفحات يختلفان عن الدمج أو تصيير صور الصفحات |
WatermarkStamp | تطبيق تراكيب متكررة على صفحات قائمة | الموضع وختم الصفحات دفعةً واحدة يكمّلان واجهات API التأليف الأساسية |
FormFill | إدخال AcroForm التفاعلي والتسطيح | إدخال الحقول والمظاهر المحفوظة يختلفان عن تبادل XFDF وسلوك XFA الخاص |
AccessibilityReader | القراءة التفاعلية والنطق | القارئ الرسومي يوضّح التنقل أثناء القراءة والإبراز، لا تدقيق الامتثال |
AccessibilityWorkbenchCli | مراجعة إمكانية الوصول الدفعية وتوليد التقارير | النتائج والملخصات وبوابات المراجعة تخدم الأتمتة؛ والنتائج ليست بديلًا عن مراجعة إمكانية الوصول اليدوية |
StandardsLab | التحقق والتحويل الخاصين بالمعايير | المختبر التفاعلي يكشف العمليات والخيارات بدل الاكتفاء بتوليد تقرير مجمَّع |
PreflightReport | تقارير معايير تفاعلية | تدعم الواجهة الرسومية الفحص اليدوي وتصدير التقارير |
PreflightReportCli | تقارير معايير مؤتمتة | المدخلات الدفعية وصيغ التقارير وبوابات أكواد الخروج توفر النظير المؤتمت لـ PreflightReport |
IntakeWorkbenchCli | الاستقبال والفرز والتوجيه الدفعي | التقارير المجمَّعة وبوابات الإخفاق وقرارات التوجيه تجعل منه سير عمل معالجة يتجاوز واجهة SecurityAudit الرسومية |
افتح المشاريع من Demo\Delphi\Miscellaneous أو Demo\CBuilder\Miscellaneous أو Demo\Lazarus\Miscellaneous؛ تحفظ وصفات API ومهام تصدير ضيقة بينما يركز الرئيسي على تجارب كاملة؛ تغطي الإنشاء والاستخراج وتبادل XFDF واختبارات API فحوص Unicode الأساسية ومسار كتابة التعليقات الثابت وتعدادها، ولم تعد لها مشاريع منفصلة
| العرض | استخدمه من أجل | ما يميّزه عن العروض ذات الصلة |
|---|---|---|
SecurityAudit | فحص الوضع الأمني تفاعليًا | تركّز الواجهة الرسومية على الأذونات والسكربتات والتواقيع وتفاصيل الأمان لا على توجيه الملفات |
XfdfLab | استيراد بيانات XFDF وتصديرها | التبادل مع الحفظ الصريح لملف PDF المستورد يوضّح الاستمرارية؛ وتصدير XFDF وحده لا يحفظ ملف PDF المعدَّل |
AccessibilityLab | جولة في API القارئ داخل طرفية | جولة تنفيذية موجزة تكشف وحدات القراءة وصناديق الكلمات والبنية ومخرجات سكربت النطق |
ExtractText | تصدير النص الكامل من صفحات محددة | مخرجات طبقة النص وفواصل الصفحات والإلغاء تختلف عن معاينات الجرد وكشف الجداول؛ ولا يُنفَّذ أي OCR |
FontProperties | فحص مقاييس الخطوط والحروف | يبدأ بمقاييس الخطوط والحروف الفعلية لأول كائن نصي؛ وحدّد سطرًا آخر لمقارنة الخطوط دون تصدير حمولات المستند |
NavigationLab | العلامات المرجعية والوجهات وإجراءات التنقل | الجولة الموجزة في API تكمل عناصر التحكم بالتنقل الظاهرة في PDFViewer |
PDFtoJpg | تصيير مستند واحد إلى صور صفحات | مثال مصغّر لتصيير مستند واحد؛ يكشف إصدار Delphi نطاقات صفحات منفصلة، بينما يركّز BatchExport على مستندات إدخال متعددة |
PrintPreferences | أوراق N-up وتفضيلات طباعة مؤلف PDF | عدد النسخ وتصفية الصفحات الفردية/الزوجية والتفضيلات التي يوفرها المؤلف هي محور التعليم؛ وهو مكمّل لـ PrintPDF |
ViewerInteractionLab | تشخيص تفاعلات الفأرة ولوحة المفاتيح والإحداثيات | سجل التفاعلات والتحويل بين إحداثيات الصفحة والجهاز يجعل منه أداة لتشخيص سلوك الـ API |
XfaLab | حزم XFA الساكنة وقدرات runtime | يفتح حزمتي template وdatasets بـ runtime الاعتيادي؛ أما تصيير XFA التفاعلي فيتطلب runtime مفعَّلًا بـ XFA، مع إصدارين لـ Delphi و Lazarus |
يفتح PDFViewer ملف PDFiumDemoShowcase.pdf المرفق به، وهو مستند من ست صفحات يتضمن نصًّا قابلًا للبحث ومخططات vector وصورتين مضمَّنتين وجدولًا وأربعة حقول AcroForm وعلامات مرجعية للفصول وروابط وملاحظة مراجعة وملفين مرفقين. يوفّر شريط التجربة Restart showcase وFind live text و2-page spread وNight reading وInspect this PDF وExplore forms؛ وكل إجراء يعمل على المستند الحالي
يفتح CreatePDF معاينة حيّة لتقرير من صفحتين. عدِّل عنوان التقرير ومؤلفه أو بدِّل تفعيل الأشكال والجدول والعلامة المائية لإعادة بناء محتوى الصفحات الفعلي؛ ويضيف خيار Unicode صفحة ثالثة. لا يُكتب أي شيء قبل أن تحفظ، ويظل ملف PDF المحفوظ قابلًا للبحث
تفتح العروض MultiPageViewer وSearchAndSelect وContentExtractionLab وFormFill المستند نفسه لكل سير عمل خاص بها، مع نتائج بحث وجرد استخراج وحقول قابلة للتحرير جاهزة فورًا. ويستخدم Miscellaneous\NavigationLab نسخته المحلية الخاصة في جولة على API العلامات المرجعية والوجهات
يبدأ Attachment بملفين مضمَّنين حقيقيين. ويبدأ PrintPreferences بأربع صفحات وتفضيلات مؤلف تغطي نسختين ونطاقات صفحات محددة وتحجيمًا وطباعة على الوجهين؛ ويطبّق سير عمل الطباعة الحالي النسخ ونطاقات الصفحات، بينما تُفحَص قيم التحجيم والوجهين وتُدرَج في التقرير. ويبدأ XfaLab بحزم template وdatasets فعلية لفحص XFA الساكن؛ أما تصيير XFA التفاعلي فيتطلب runtime مناسبًا وهو قدرة منفصلة
يضم كل مشروع من مشاريع العرض والنماذج والاستخراج والتنقّل ملف PDFiumDemoShowcase.pdf الخاص به. انسخ مجلد المشروع واحتفظ بهذا الإدخال المرفق بجوار الملف التنفيذي الموزَّع؛ وتُجهِّز إصدارات Lazarus هذا الملف تلقائيًا أثناء البناء. تعمل الجولة دون اتصال، وتوفر العارضات العامة وعينات الاستخراج أيضًا محتوى احتياطيًّا مولَّدًا عندما يكون ملف PDF المحلي غير متاح
يضم كل عرض توضيحي native تنفيذًا نموذجيًّا خاصًا به. وتتضمن نقاط الدخول في Delphi و Lazarus للعروض AccessibilityLab وAccessibilityWorkbenchCli وIntakeWorkbenchCli وPreflightReportCli سير العمل كاملًا داخل مجلد المشروع، بما في ذلك التهيئة الخاصة بالمترجم وكتابة JPEG. كما تبني أمثلة المرفقات وتفضيلات الطباعة و XFA مدخلات خاصة بميزاتها محليًا. لا يلزم خارج المشروع المنسوخ سوى المكتبة وruntime الـ native المطابق وتبعيات إطار عمل المترجم الاعتيادية
اختر استخراج كائنات الصور عندما تحتاج صور bitmap مضمَّنة، وتصيير الصفحات عندما تحتاج الصفحة المرئية، واستخراج النص عندما يكون لملف PDF طبقة نص أصلًا. التقرير الذي يسرد هذه الفئات لا يصدّر حمولاتها الكاملة. هذه الحدود تبقي الأمثلة المركّزة مفيدة من دون توسيع كل عرض ليصبح عارضًا عامًّا أو workbench شاملًا آخر
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;
تعرض مشاريع Demo\Delphi\Miscellaneous\FontProperties وDemo\CBuilder\Miscellaneous\FontProperties وDemo\Lazarus\Miscellaneous\FontProperties البيانات الوصفية نفسها من خلال كل من TPdf وTPdfView
تحوّل مشاريع Demo\Delphi\ContentExtractionLab وDemo\CBuilder\ContentExtractionLab وDemo\Lazarus\ContentExtractionLab استخراج المحتوى إلى سير عمل واحد. تفتح أو تنشئ PDF، وتسمح للمستخدمين باختيار البيانات الوصفية ونص الصفحة وكائنات الصفحة والصور والمرفقات والروابط والتعليقات التوضيحية والعلامات المرجعية ومقاييس الخطوط / الحروف، ثم تولّد ملخصًا بالإضافة إلى تقرير TXT أو JSON مفصل. يتضمن المختبر أيضًا اختيار كل / لا شيء للفئات ونسخ التقرير إلى الحافظة وإجراءات حفظ PDF المصدر بحيث يمكن للمستخدمين الاحتفاظ بعينة PDF المُولَّدة بجانب تقرير استخراجها. توفر ExtractImages وAttachment سير عمل لتصدير الحمولات، بينما يحتفظ Miscellaneous\ExtractText وMiscellaneous\FontProperties بأمثلة API مركّزة؛ يدعم ExtractText خيارات نطاق الصفحات وفواصل الصفحات لإنتاج مخرجات نصية لكل صفحة عبر Delphi و C++Builder و Lazarus، بينما ContentExtractionLab هو نموذج الجرد الشامل متعدد الفئات
تحوّل مشاريع Demo\Delphi\TableExtractionLab وDemo\CBuilder\TableExtractionLab وDemo\Lazarus\TableExtractionLab كشف الجداول إلى سير عمل واحد. يبني المختبر مستندًا نموذجيًا يحتوي جدولًا مسطّرًا بخلايا رأس مدمجة، وجدولًا محاذى بالفراغات بلا تسطير، وجدولًا طويلًا ينكسر عبر حدود صفحة، ثم يشغّل ExtractTables للصفحة الحالية أو ExtractDocumentTables للمستند بأكمله، ويُبلغ الصفوف والأعمدة وقيم RowSpan و ColumnSpan وأعلام الرأس ونمط الكشف والثقة ومجموعات الاستمرار. الخيارات DetectRuledTables و DetectWhitespaceTables و DetectContinuations و DetectFilledRulings و MinConfidence قابلة للتحرير في الواجهة، ويُصدَّر الجدول المحدد عبر TPdfTable.ToCsv و TPdfTable.ToJson. كما يعالج المختبر مجلدًا كاملًا دفعةً واحدة: يشغّل Batch folder أمر ExtractDocumentTables على كل PDF، ويُبلغ أعداد الجداول لكل مستند، ويؤشر على المسوحات التي لا طبقةَ نصَّ لها، ويعيد محاولة المستندات الفارغة بضبط أعمدة مضغوطة؛ ويكتب Export all CSV كل جدول يُكشف بجوار الملفات المصدرية. يُفتح كل مستند في نظيرته من TPdf بحيث لا يستطيع ملف واحد غير مقروء أن يمس بقية الدفعة
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;
// بدون التسطيح، FormField[i] := value يكتب فقط إدخال /V —
// المظهر المرئي يأتي من stream /AP وقد لا يُحدَّث.
// GenerateFormAppearances يعيد توليد /AP لكل widget، ثم
// FlattenAllPages يثبت التعليقات التوضيحية والـ widgets على كل صفحة كمحتوى
// دائم غير قابل للتحرير.
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);
// إنشاء مستند PDF مضغوط
Pdf1.CreateDocument;
Pdf1.Compressed := True; // التأكد من أن جميع streams مضغوطة بـ FlateDecode (افتراضي)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // حجم A4
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:\NoSecurity.pdf', saRemoveSecurity); // إزالة الأمان
// الحفظ بهدف إصدار PDF محدد. مدقق إصدار PDF يرفض
// أي ميزة تم تقديمها بعد الإصدار الهدف المختار (JBIG2Decode، MarkInfo،
// تشفير AES، تعليقات 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 يعالج الحفظ الأساسي بعد ذلك بتحديث تدريجي
// يحقن مجرى بيانات XMP وصفية وOutputIntent ICC من نوع sRGB وCatalog
// مستند مُحدَّث بحيث تكون النتيجة متوافقة مع 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('Saved PDF/A-1b archive');
// 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;
// فحص خفيف بأسلوب الترويسة — يقرأ التوافق دون تكرار
// المدقق الكامل. النتيجة: 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 := 'Unknown conformance';
end;
// المدقق الكامل مع تشخيص لكل مشكلة
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;
تقوم مشاريع Demo\Delphi\StandardsLab وDemo\CBuilder\StandardsLab وDemo\Lazarus\StandardsLab بتحميل أو إنشاء PDF، وتشغيل ValidatePdfA وValidatePdfUa وValidatePdfE وValidatePdfX وValidatePdfR وValidatePdfVT، ثم تعرض كل مستوى توافق مُكتشَف وعدد المشكلات في شبكة واحدة. تستدعي أزرار الحفظ SaveAsPdfA وSaveAsPdfUa وSaveAsPdfE وSaveAsPdfX وSaveAsPdfR وSaveAsPdfVT بحيث يكون سير عمل إخراج العلامات مرئيًا دون كتابة harness مخصص
تلف الوحدة FPdfPreflightReport أدوات ValidatePdfA وValidatePdfUa وValidatePdfE وValidatePdfX وValidatePdfR وValidatePdfVT في كائن تقرير واحد قابل للاستعلام بأولوية Info / Warning / Error وتجميع الحالة والمشكلات والبحث والتصفية وبصمات SHA-256 مستقرة. يمكن إصدار التقارير كنص أو HTML أو Markdown أو JSON أو CSV أو SARIF 2.1.0 أو JUnit XML أو NDJSON أو XML أصلي. توفر Demo\Delphi\PreflightReport وDemo\Lazarus\PreflightReport وDemo\CBuilder\PreflightReport سير عمل تفاعليًا للاختيار والمعاينة، بينما تضيف Demo\Delphi\PreflightReportCli وسائط إدخال / إخراج قابلة للسكريبتة، وتصفية قياسية، وتضمينًا اختياريًا لمرفق التقرير، وبوابات رموز خروج CI، ومعالجة قوائم وأدلة دفعية، وتوجيهًا آمنًا من التصادم، وملخصات مجمعة، و manifests بتنسيق CSV. يذكر التقرير المُولَّد أن المدققات المضمنة تغطي فحوصات على مستوى العلامات وفحوصات مختارة على مستوى الملف، بحيث يظل من الممكن تفويض الفحص الكامل للمحتوى إلى محرك تحقق مخصص
// LoadCustomDocument يسمح لـ PDFium بسحب الكتل من أي TStream قابل
// للبحث عند الطلب. الـ stream لا يُنسخ إلى الذاكرة، بحيث تكون ملفات
// PDF متعددة الجيجابايت و streams استجابة 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('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Stream مملوك خارجيًا (المستدعي يحرره بعد 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 يعرض IPdfCancellationToken /
// IPdfCancellationTokenSource لدلالات الإلغاء من واجهة المستخدم التي
// تعمل عبر مسارات التصدير والعرض الطويلة.
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... ينقر المستخدم على Cancel ...
CancelSource.Cancel;
// العامل يفحص CancelToken.IsCancelled بشكل دوري، أو مسار العرض
// يستطلعه عبر callback IFSDK_PAUSE الخاص بـ PDFium.
if CancelToken.IsCancelled then
Memo1.Lines.Add('Cancelled by user');
end;
// RenderPageProgressive يسمح لعرض طويل عالي الدقة DPI بالإجهاض في منتصف
// الصفحة عندما ينقر المستخدم على Cancel، بدلاً من حجب المستدعي حتى الانتهاء.
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> يُطلق عاملاً على خيط في الخلفية ويُرسل
// مظروف TPdfFutureResult<T> عائدًا إلى الخيط الرئيسي.
//
// مهم: TPdf يُسلسل استدعاءات العرض لكل instance، لكن العامل لا يزال يمتلك
// الإرسال وعمر المستند. لا تغير TPdf أثناء جريان عرض ما؛ التصدير الدفعي
// عادةً يحتفظ بـ TPdf واحد لكل ملف.
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 يلف FS_MATRIX الخاص بـ PDFium بحيث يمكن للمستدعين بناء تحويل
// بشكل تصريحي وتمريره إلى FPDFPageObj_SetMatrix.
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // التحريك بمقدار بوصة لليمين، ~2.8 بوصة للأعلى
M.Scale(0.5, 0.5); // ختم بنصف الحجم
M.Rotate(15); // تدوير عكس عقارب الساعة بزاوية 15 درجة
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // الضرب اللاحق بمصفوفة أخرى
// التطبيق على أي كائن صفحة PDFium (نص / مسار / صورة / form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex ينسخ مصفوفة فهارس صريحة بدءًا من الصفر من
// PDF مصدر إلى هذا المستند. InsertAt = 0 يدرج قبل الصفحة 1؛
// PageCount يلحق.
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// استيراد الصفحات 0، 2، 4 (بدءًا من واحد: الصفحات 1، 3، 5) من Source
// وإلحاقها في نهاية Pdf1.
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// مصفوفة فارغة تستورد كل صفحات المصدر
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne يُرجع TPdf جديدًا تمامًا، صفحاته مركبات
// NumX*NumY من هذا المستند. OutputWidth/Height بوحدات مستخدم PDF
// (1 وحدة = 1/72 بوصة).
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// 4-up A4 أفقي: 842 x 595 pt، 2 أعمدة x 2 صفوف
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages يأخذ الفهارس بدءًا من الصفر للصفحات المراد نقلها بالإضافة إلى
// فهرس الوجهة للصفحة الأولى المنقولة بعد اكتمال النقل.
// الصفحات الأخرى تتنقل حول الكتلة المنقولة بحيث يبقى طول المستند
// كما هو.
//
// مثال: في مستند مكون من 5 صفحات مرقمة [0,1,2,3,4]،
// MovePages([2, 3], 0) يعيد الترتيب إلى [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage يصنع مقبض Form XObject قابل لإعادة الاستخدام من
// أي صفحة في أي TPdf آخر. اختم هذا المقبض على أي عدد من صفحات
// هذا المستند تريد — كل ختم هو كائن صفحة PDFium واحد
// يمكن تحديد موضعه وتحجيمه وتدويره عبر واجهة 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;
// لف الصفحة 0 من WatermarkSource كـ 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;
// توسيط العلامة المائية على الصفحة
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; // يغلق مقبض FPDF_XOBJECT
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
تحوّل مشاريع Demo\Delphi\WatermarkStamp وDemo\Lazarus\WatermarkStamp وDemo\CBuilder\WatermarkStamp هذا النمط إلى سير عمل قابل للتشغيل: تنشئ PDF هدفًا وPDF ختم قابل لإعادة الاستخدام، تلف صفحة الختم بـ CreateXObjectFromPage، تدرج نفس Form XObject على كل صفحة هدف، تطبق تحويلات TPdfMatrix للعلامات المائية الموسطة والأختام في الزاوية اليمنى العلوية، وتضيف تسميات أرقام صفحات اختيارية قبل حفظ النتيجة
// AddImage(FileName) يقبل أي تنسيق مسجل في وحدات الرسوميات VCL أو LCL
// (BMP، PNG عبر PngImage، JPG، ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) يتخطى وسيط TPicture، مثالي عندما يكون
// bitmap قد جاء بالفعل من أعمال العرض أو التوليد الدفعي.
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;
تحوّل مشاريع Demo\Delphi\ImageToPDF وDemo\CBuilder\ImageToPDF و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 match(es) on this page', [MatchCount]);
// إزالة الطبقة برمجيًا قبل تغيير الصفحة
PdfView1.ClearHighlight;
end;
// FitMode يبقي المستندات الطويلة مؤطرة أثناء Resize أو تغييرات الصفحة.
// تعيين Zoom مباشرة يلغي FitMode (يعود إلى pfmNone).
PdfView1.FitMode := pfmFitPage; // الصفحة بكاملها في منطقة العرض
// PdfView1.FitMode := pfmFitWidth; // عرض الصفحة يطابق عرض منطقة العرض
// PdfView1.FitMode := pfmActualSize; // 100%
// PageColor يفصل صفحة PDF المعروضة عن Color الخاص بعنصر التحكم المضيف
// — إعداد عارض الوضع الداكن النموذجي يبقي منطقة التمرير داكنة بينما تبقى
// صفحة PDF بيضاء ورقية.
PdfView1.Color := clBlack; // منطقة التمرير
PdfView1.PageColor := clWhite; // خلفية صفحة PDF
// ظل اختياري وحد للصفحة لرفع الصفحة عن خلفية داكنة
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
تبقي مشاريع Demo\Delphi\Miscellaneous\ViewerInteractionLab وDemo\CBuilder\Miscellaneous\ViewerInteractionLab وDemo\Lazarus\Miscellaneous\ViewerInteractionLab سطح تفاعل TPdfView الحديث في نموذج مدمج واحد: افتح أو أنشئ عينة PDF، بدّل DisplayMode، طبّق FitMode، غيّر PageColor، دوّر الصفحات، ميّز نتائج البحث في الصفحة الحالية بـ HighlightSearchText، فعّل أو عطّل تحديد نص المستخدم، افحص SelectedText، استدعِ SelectAll وCopySelectionToClipboard وClearSelection، وراقب إحداثيات DeviceToPage تتحدث في شريط الحالة بينما يتحرك الماوس فوق الصفحة
تحوّل مشاريع Demo\Delphi\SearchAndSelect وDemo\CBuilder\SearchAndSelect وDemo\Lazarus\SearchAndSelect سير عمل البحث والتحديد في العارض إلى عينات مستقلة. تفتح أو تنشئ PDF، تسرد نتائج البحث في كل الصفحات مع رقم الصفحة وفهرس الحرف ونص المعاينة، تدعم تنقل السابق / التالي والقفز إلى النتيجة بالنقر المزدوج، تميز تطابقات الصفحة الحالية بـ HighlightSearchText، تعرض خيارات مراعاة الحالة والكلمة الكاملة، تبدّل AllowUserTextSelection، تعاين SelectedText، تُشغّل SelectAll وCopySelectionToClipboard وClearSelection من الأزرار، وتسمح للمستخدمين بالتبديل بين أوضاع العرض الفردية والمنتشرة
تقرأ مشاريع Demo\Delphi\Miscellaneous\PrintPreferences وDemo\CBuilder\Miscellaneous\PrintPreferences وDemo\Lazarus\Miscellaneous\PrintPreferences تفضيلات طباعة المؤلف قبل الطباعة. تعرض PrintCopies وPrintPageRanges وPrintScaling وPrintPaperHandling، يمكنها نسخ النسخ والنطاقات المُقدَّمة من المؤلف إلى مدخلات الطباعة، وتظهر كيف يُعيِّن SetPdfPrintPaperHandlingDevMode نية Duplex لـ PDF إلى DEVMODE الخاص بـ Windows
تعرض مشاريع Demo\Delphi\PrintPDF وDemo\CBuilder\PrintPDF وDemo\Lazarus\PrintPDF سير عمل الطباعة القياسية: افتح PDF، عاين الصفحات، اختر نطاقات الصفحات والنسخ في مربع حوار الطباعة الخاص بالمنصة، احترم وضع الترتيب، اعرض كل صفحة عبر TPdf.RenderPage، واعرض تقدم الطباعة مع الإلغاء. تقبل عينة Delphi أيضًا ملفات PDF المُسحبة للتحميل السريع
تختبر مشاريع Demo\Delphi\MultiPageViewer وDemo\CBuilder\MultiPageViewer وDemo\Lazarus\MultiPageViewer العرض المستمر والمنتشر والمدرك للغلاف مع سير عمل التنقل والتكبير العادية بين الصفحات. مفيدة أيضًا لاختبار سرعة الفتح إلى الصفحة الأولى وسرعة استجابة العرض على ملفات PDF كبيرة جدًا: في اختبارات الملفات الكبيرة، يمكن للمستندات بحجم 2.x جيجابايت التي قد تجعل Acrobat أو Foxit يقضون 20-30 ثانية قبل العرض الأول أن تصبح قابلة للاستخدام تقريبًا فورًا من خلال مسار عارض PDFium Delphi Component
تعرض مشاريع Demo\Delphi\SplitView وDemo\CBuilder\SplitView وDemo\Lazarus\SplitView مراجعة PDF جنبًا إلى جنب. تركز عينات C++Builder و Lazarus على مقارنة لوحتين أو ثلاث لوحات، واختيار العرض النشط، وأوامر التنقل المتزامنة الاختيارية، وإعدادات تكبير مشتركة، وتدوير للعرض المحدد أو جميع العروض المُحمَّلة. استخدم هذه العينات لمقارنة المستندات الكبيرة مع الحفاظ على عرض أول قابل للاستخدام وعرض الصفحات اللاحق سريع الاستجابة؛ نفس ملفات PDF بحجم 2.x جيجابايت التي قد تستغرق Acrobat أو Foxit 20-30 ثانية لفتحها يمكن أن تصبح قابلة للاستخدام تقريبًا فورًا في مسار عارض PDFium Delphi Component
تفتح مشاريع Demo\Delphi\Miscellaneous\SecurityAudit و Demo\CBuilder\Miscellaneous\SecurityAudit و Demo\Lazarus\Miscellaneous\SecurityAudit PDF للقراءة فقط، وتسرد الأذونات والمرفقات و JavaScript وروابط URI و Launch وروابط الويب وملخصات التوقيع وحالة XFA وإتاحة V8 و callbacks غير المدعومة؛ تُحفظ أو تُنسخ صفوف الملخص والنتائج كـ TXT أو تُحفظ JSON؛ هي لوحات مخاطر للتطبيق المضيف وليست كشف برمجيات ضارة
// LinkOptions يتحكم في المعالجة التلقائية لأنواع إجراءات روابط PDF الأربعة.
// الافتراضيات تُمكّن goto و URI فقط؛ launch (تشغيل برنامج) و
// embedded GotoR (الانتقال إلى ملف آخر) يبقيان معطلين بحيث لا
// تستطيع نقرة شاردة تشغيل كود اعتباطي.
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // افتراضيات آمنة
// 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; // قمع المعالجة التلقائية
end;
end;
// OnWebLinkClick يُطلق لسلاسل URI التي اكتشفها ماسح روابط الويب الخاص بـ
// PDFium (URLs المُكتشفة تلقائيًا في stream النص، حتى بدون
// تعليق /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;
// على عنصر AcroForm widget المركّز، ست طرق جديدة تشغّل سجل تحرير نموذج
// PDFium. جميع الستة تنتهي بأمان إذا لم يكن هناك widget مركّز أو
// المستند لا يحمل 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;
// كلها الثلاثة بقيمة افتراضية True بحيث ترقى التطبيقات الموجودة دون تغيير
// في السلوك. اقلبها إلى False للأكشاك أو ألواح المعاينة أو التضمينات
// للقراءة فقط دون subclassing لـ TPdfView.
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // قفزات العجلة للأعلى/للأسفل
PdfView1.AllowUserTextSelection := False; // تحديد النص بالماوس/لوحة المفاتيح
// Ctrl+wheel محجوز للتكبير ويتم تخطيه بواسطة معالج التنقل
// بغض النظر عن ChangePageOnMouseScrolling.
// TPdfThumbnailView (وحدة FPdfThumbnail) يعرض صورة مصغرة لصفحة واحدة لكل
// صف في لوحة جانبية قابلة للتمرير.
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.PdfView1PageNumberChanged(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// النمط المستخدم في Demo\Delphi\BatchExport و Demo\CBuilder\BatchExport
// و Demo\Lazarus\BatchExport. TPdf واحد لكل ملف، IPdfCancellationToken
// للإلغاء من واجهة المستخدم، 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('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 هو فحص Catalog خفيف — True عندما يوجد /StructTreeRoot.
// StructureElements يجسّد الشجرة كمصفوفة مسطحة من سجلات
// TPdfStructureElement مع النوع والعنوان والنص البديل والنص
// الفعلي ونص التوسع واللغة والمستوى وفهرس الأصل وعدد الأبناء /
// المحتوى الموسوم / السمات.
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 هي دالة عامة تعيّن إلى FPDF_SetPrintMode
// الخاص بـ PDFium. استخدم قيمة TPdfPrintMode المطابقة لمشغل الطابعة
// المستخدم.
SetPdfPrintMode(pmEmf); // GDI EMF (افتراضي)
// SetPdfPrintMode(pmTextOnly); // عرض نص فقط
// SetPdfPrintMode(pmPostScript2); // PostScript Level 2
// SetPdfPrintMode(pmPostScript3); // PostScript Level 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + أقنعة صور
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + خطوط Type 42
// PrintCopies و PrintPageRanges و PrintScaling و PrintPaperHandling هي
// إدخالات قاموس تفضيلات العارض — تكوّن ما أراد مؤلف المستند
// أن تكون عليه القيم الافتراضية لقارئات 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;
// JavaScript على مستوى المستند مخزن في شجرة أسماء
// /Names /JavaScript. JavaScriptAction[i] يُرجع إدخالاً واحدًا؛
// JavaScriptActions يُرجع المصفوفة الكاملة.
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;
// مسار العرض بدون نسخ (افتراضي منذ v1.21.0): RenderPage يكتب
// مباشرة في مخزن DIB الخاص بـ TBitmap الوجهة عندما يمرر المستدعون
// bitmap مُخصصًا مسبقًا، متجنبًا نسخة width * height * 4 بايتات واحدة.
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;