روابط PDF التشعبية هي تعليقات توضيحية من نوع URI: مستطيل يغطي جزءا من الصفحة ويطلب من العارض فتح URL عند النقر عليه. التعليق والنص الموجود تحته كائنان مستقلان تماما. تجمع PrintHyperlink في HotPDF الأمرين في استدعاء واحد، إذ ترسم النص وتحسب مستطيل التعليق من مقاييس النص المعروض. هذه السهولة تخفي تفصيلا يستحق الفهم قبل كتابة شيفرة الإنتاج
كيف تعمل PrintHyperlink
PrintHyperlink تتوفر في THPDFPage وتقبل أربع وسائط: إحداثيات X وY (بوحدة النقاط، مع أصل في الزاوية السفلية اليسرى وازدياد Y إلى الأعلى)، وسلسلة التسمية المراد رسمها، وهدف URL. داخليا تستدعي TextOut بلون الارتباط الحالي، ثم تحسب مباشرة مستطيل التعليق من TextWidth وTextHeight وفقا لمقاييس الخط الحالية. هذا يعني أن الخط والحجم يجب ضبطهما قبل الاستدعاء، وألا يتغيرا بين رسم التسمية ووضع التعليق، لأنهما يُحسَمان في الاستدعاء نفسه
اللون الافتراضي هو clBlue. تغيّر SetRGBHyperlinkColor هذا اللون للاستدعاءات اللاحقة فقط، ولا تحدّث التعليقات التوضيحية المكتوبة سابقا بأثر رجعي. إذا احتجت ألوانا مختلفة لمجموعات روابط مختلفة في الصفحة نفسها، فاستدعِ SetRGBHyperlinkColor قبل كل مجموعة وأعد الضبط بعدها
فيما يلي مستند بسيط يكتب ثلاثة روابط بلونين مختلفين
procedure CreateLinkedReport(const FileName: string);
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := FileName;
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
// Default blue for informational links
Pdf.CurrentPage.TextOut(50, 750, 0, 'Reference links:');
Pdf.CurrentPage.PrintHyperlink(50, 720, 'Product page', 'https://www.loslab.com/en-us/pdf-library/delphi-pdf-component.html');
Pdf.CurrentPage.PrintHyperlink(50, 695, 'Online manual', 'https://www.loslab.com/en-us/pdf-library/documentation.html');
// Red for the action link
Pdf.CurrentPage.SetRGBHyperlinkColor(clRed);
Pdf.CurrentPage.PrintHyperlink(50, 660, 'Purchase license', 'https://www.loslab.com/en-us/order/');
Pdf.CurrentPage.SetRGBHyperlinkColor(clBlue); // restore default
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
فخ الإحداثيات
يستخدم HotPDF أصل الإحداثيات في الزاوية السفلية اليسرى مع ازدياد Y إلى الأعلى، بوحدة النقاط (1/72 بوصة). صفحة A4 قياسها 595 × 842 pt، وصفحة US Letter قياسها 612 × 792 pt. يقع Y=750 قرب أعلى صفحة A4، بينما يقع Y=50 قرب الهامش السفلي. من يأتي من رسومات الشاشة أو HTML يفترض العكس ويضع أول سطر رابط خارج المنطقة المرئية تماما
يستخدم مستطيل التعليق الذي تحسبه PrintHyperlink نظام الإحداثيات نفسه. إذا قمت لاحقا بتدوير الصفحة أو تحجيمها أو تغيير حجمها من دون إعادة حساب قيم X/Y، فسيتباعد النص المرئي والمستطيل القابل للنقر. قد يبدو الرابط وكأنه يعمل، لأن النقر قرب النص يطلق URL، لكن المنطقة القابلة للنقر لم تعد تطابق ما يراه القارئ. اختبره على حجم الصفحة الفعلي ومستوى التكبير الذي ستشحنه، لا على جهاز التطوير فقط عند 100%
أحد الحالات التي يكون فيها هذا الانحراف مؤكدا: إذا استدعيت PrintHyperlink بإحداثيات مناسبة لصفحة A4 ثم انتقلت إلى صفحة مخصصة ضيقة من دون تعديل قيم X/Y، فقد ينتهي التعليق خارج الصفحة تماما. يظل كائن التعليق مكتوبا داخل PDF، لكن معظم عارضي PDF يقصونه بصمت، فيختفي الرابط ببساطة من دون أي خطأ
نص التسمية مقابل هدف URL
الوسيطان Text وLink مستقلان. يمكنك رسم "Download invoice PDF" بينما يكون الهدف URL HTTPS كاملا مع معاملات استعلام. هذا الفصل مقصود، فالتسمية المرئية يجب أن تكون مقروءة للبشر، بينما يمكن أن يكون URL طويلا أو مولدا ديناميكيا
تبدأ المشكلة عندما تكون التسمية هي URL الخام نفسه، ولا سيما إذا كان طويلا. إذا التف URL بصريا على سطرين بينما حُسب مستطيل التعليق لسلسلة من سطر واحد، فلن يكون قابلا للنقر إلا السطر الأول. لا تتعامل PrintHyperlink مع التدفق متعدد الأسطر؛ فاجعل التسمية قصيرة بما يكفي لتناسب سطرا واحدا عند حجم الخط وعرض الصفحة الحاليين، أو استخدم تسمية وصفية قصيرة مع URL الكامل كهدف
في المستندات التي ستؤرشف أو توزع من دون اتصال نشط بالإنترنت، فكّر أيضا في ما إذا كان ينبغي أن يظهر URL نفسه مطبوعا في موضع ما داخل متن المستند، لا كبيانات وصفية للتعليق فقط. القارئ الذي يطبع PDF على الورق لا يستفيد شيئا من تعليق URI توضيحي
مثال كامل على توليد مستند
النمط التالي يعرض سيناريو أكثر واقعية: توليد تقرير قصير يحتوي على قسم رأس ونص رئيسي ووصف روابط في التذييل، وكل ذلك من الشفرة لا من نموذج يحوي حقول TEdit
procedure GenerateProductSheet(
const FileName, ProductName, ProductURL, SupportURL: string);
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := FileName;
Pdf.Compression := cmFlateDecode;
Pdf.BeginDoc;
// Header
Pdf.CurrentPage.SetFont('Arial', [fsBold], 16);
Pdf.CurrentPage.TextOut(50, 750, 0, WideString(ProductName));
// Body paragraph placeholder
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 710, 0, 'See the links below for full documentation.');
// Footer links
Pdf.CurrentPage.SetFont('Arial', [], 10);
Pdf.CurrentPage.TextOut(50, 80, 0, 'Links:');
Pdf.CurrentPage.PrintHyperlink(50, 60, 'Product page', ProductURL);
Pdf.CurrentPage.PrintHyperlink(200, 60, 'Support', SupportURL);
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
لاحظ أن SetFont يستدعى قبل كل مجموعة من استدعاءات النص. لا يظل الخط محفوظا عبر AddPage، وإذا نسيت ضبطه قبل PrintHyperlink على صفحة جديدة، فسيُحسب مستطيل التعليق وفقا لأي مقاييس افتراضية تملكها الصفحة، وقد تختلف عما تتوقعه
أين يختلف التعامل مع التعليقات التوضيحية بين عارضي PDF
تُعرَّف تعليقات PDF URI التوضيحية في ISO 32000-1 §12.6.4.7، ويجب أن يلتزم بها كل عارض مطابق للمواصفة. عمليا، تختلف بعض السلوكيات من عارض إلى آخر. يعرض Adobe Acrobat مطالبة أمان عند أول نقرة على URLs غير الموجودة في قائمة النطاقات الموثوقة، بينما لا تفعل العديد من المتصفحات والقارئات الخفيفة ذلك. بعض عارضي PDF المؤسسيين في البيئات المقيدة يعطلون تعليقات URI بالكامل وفقا للسياسة، فتفشل النقرات من دون أي رسالة ظاهرة. وتختلف تطبيقات PDF على الهاتف المحمول في ما إذا كانت تفتح الروابط داخل عرض الويب الخاص بالتطبيق أم تسلمها إلى متصفح النظام
لا شيء من ذلك خطأ يمكنك إصلاحه من جهة التوليد؛ إنها قرارات تتعلق بسياسة العارض. ما يمكنك فعله هو كتابة تسميات روابط تجعل URL مرئيا أيضا داخل متن المستند، حتى يتمكن القارئ في بيئة مقيدة من نسخ العنوان يدويا. التعليق التوضيحي هو وسيلة الراحة، أما النص فهو البديل الاحتياطي
وثمة تفصيل آخر يستحق المعرفة: تعليقات PDF URI التوضيحية لا تتضمن أي خط سفلي مرئي افتراضيا. فالخط السفلي الذي تراه في معظم العارضات يرسمه العارض نفسه استنادا إلى نوع التعليق، لا محرف في تيار المحتوى. إذا كنت تحتاج إلى خط سفلي فعلي ينجو من الطباعة إلى عارض غير تفاعلي أو من التحويل من PDF إلى صورة، فارسمه صراحة باستخدام LineTo وStroke عند إزاحة Y المناسبة أسفل خط أساس النص. هذا إجراء رسم منفصل، وليس شيئا تتكفل به PrintHyperlink
واجهة برمجة تطبيقات الارتباط التشعبي المعروضة هنا جزء من مكوّن HotPDF لـ Delphi و C++Builder