مقال تقني

إضافة حقول AcroForm إلى ملف PDF محمّل في Delphi

لديك قالب فاتورة من جهة خارجية، أو عقد مؤرشف أنشأه أحدهم قبل سنوات في برنامج لم يعد أحد يستطيع العثور عليه، والمطلوب جعله تفاعليًا: ضع مربع توقيع في الزاوية، وأضف بضعة حقول نصية، وحوّل قائمة تحقق مسطحة إلى مربعات اختيار حقيقية. المشكلة أنك لا تؤلف هذا الـ PDF من الصفر. فهو موجود بالفعل، ويحتوي بالفعل على صفحات وتدفقات محتوى وخطوط لا تسيطر عليها، وتحتاج إلى إلحاق عناصر AcroForm التفاعلية بذلك الرسم البياني للكائنات من دون إعادة بنائه. هذه مشكلة مختلفة عن إنشاء نموذج على مستند جديد، والجزء الذي يربك الناس لا يظهر إلا عندما تفتح النتيجة في عارض فتجد الحقول التي كتبتها للتو غير موجودة على الصفحة

HotPDF هو مكوّن PDF أصلي لـ VCL في Delphi وC++Builder، وابتداءً من v2.247.0 يوفّر عائلة مخصصة من الطرق لهذا الغرض تحديدًا: بناء الأنواع القياسية الستة للحقول مباشرة على مستند محمّل باستخدام LoadFromFile. تشرح هذه المقالة ما تفعله تلك الطرق، وقاموس ISO 32000-1 الذي تنشئه، والعلم الوحيد الذي من دونه ينتج هذا العمل كله ملفًا يبدو فارغًا بصمت

لماذا يُعد إنشاء الحقول على مستند محمّل مسارًا برمجيًا مستقلًا

عندما تنشئ PDF من لا شيء، يمتلك HotPDF نموذج الكائنات بالكامل. كل صفحة هي غلاف قابل للكتابة من نوع THPDFPage، وإضافة حقل نصي عبر AddTextField تربط الودجت الجديد بكائن التعليق الخاص بالصفحة، وكائن الصفحة، ومجموعة حقول النموذج، ثم تولّد تدفق مظهر من موارد الخطوط في المستند. تدفق المظهر هو السطح المرئي للودجت، أي الصندوق والحد وأي نص افتراضي، مرسومًا كأوامر رسم PDF يطبعها العارض كما هي

غير أن المستند المحمّل لا يمنحك أيًا من هذه البنية. فقد وصلت الصفحات كقواميس خام، ولا يوجد غلاف THPDFPage قابل للكتابة لتعليق الودجت عليه، والأهم من ذلك أنه لا توجد سلسلة موارد خطوط جاهزة لرسم تدفقات المظهر. لذلك يسلك المسار المحمّل طريقًا مختلفًا. فهو يكتب قواميس الحقول مباشرة فوق الرسم البياني للكائنات الذي جرى تحليله، ويخاطب الصفحات بفهرس يبدأ من الصفر بدلًا من كائن الصفحة. أنواع الحقول وبتات الأعلام تطابق مسار الإنشاء من الصفر تمامًا، لذا يبقى حقل Text حقل Text في الحالتين، لكن ما يتغيّر هو السباكة تحتها، وعلى نحو أهم، الطريقة التي يُرسم بها سطح الودجت

علامة /NeedAppearances ليست اختيارية هنا

هذه هي الحقيقة الوحيدة التي تحدد ما إذا كان عملك سيظهر أم لا. لأن المسار المحمّل لا يولد تدفقات مظهر، يصل الودجت المضاف حديثًا إلى العارض من دون /AP إدخال /AP: حقل بلا سطح موصوف. كثير من العارضات، عندما يُطلب منها عرض وودجت بلا مظهر ومن دون تعليمات لإنشاء واحد، لا ترسم شيئًا على الإطلاق. يكون الحقل موجودًا في الملف، صالحًا بنيويًا، قابلًا للوصول عبر أداة تعبئة النماذج، لكنه غير مرئي تمامًا للبشر

المخرج من هذا الوضع محدد في ISO 32000-1 §12.7.3: يحمل قاموس AcroForm قيمة منطقية /NeedAppearances، وعندما تكون true فإن القارئ المطابق للمواصفة يكون مطالبًا بإنشاء تدفقات المظهر المفقودة بنفسه من سلسلة /DA (default appearance) string and value. HotPDF يضبط هذا نيابةً عنك. في أول مرة تضيف فيها أي حقل إلى مستند محمّل، EnsureLoadedAcroFormيعمل EnsureLoadedAcroForm: إذا كان catalog لا يحتوي على /AcroForm فإنه ينشئ واحدًا، وإذا لم تكن هناك /Fields مصفوفة /NeedAppearances true فإنه ينشئها، ويجبر /NeedAppearances وما زالت لا تعرض شيئًا. بالنسبة إلى القرّاء السائدين تؤدي العلامة وظيفتها، لكن إذا كان جمهورك يستخدم عارضًا مضمنًا غير مألوف، فاختبره هناك قبل أن تعد بأي شيء

إضافة الأنواع الستة من الحقول

كل طريقة تتبع النمط نفسه. تمرر فهرس الصفحة الذي يبدأ من الصفر، والزوايا الأربع لمستطيل الودجت بإحداثيات مساحة المستخدم في PDF، واسم الحقل، وأي وسائط إضافية يحتاجها النوع. يكون المستطيل X1, Y1, X2, Y2 مع أصل PDF في أسفل يسار الصفحة، لذا تكون قيم Y الأكبر أعلى؛ هذه هي اتفاقية الإحداثيات في تنسيق الملف، لا اتفاقية الشاشة ذات الأصل في أعلى اليسار، والخلط بينها هو ثاني أكثر الأخطاء شيوعًا بعد نسيان العلامة. وتعيد كل استدعاء فهرس الحقل الجديد الذي يبدأ من الصفر، أو -1 إذا كان فهرس الصفحة خارج النطاق أو تعذّر حل كائن الصفحة

var
  Pdf: THotPDF;
  Idx: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('contract.pdf') <= 0 then Exit;

    // Text field: name, initial value, max length (0 = unlimited)
    Idx := Pdf.AddLoadedTextField(0, 72, 680, 320, 700, 'FullName', '', 0);

    // CheckBox: export value, initial checked state
    Pdf.AddLoadedCheckBox(0, 72, 640, 90, 658, 'AgreeTerms', 'Yes', False);

    // Signature field: just a name and a rectangle
    Pdf.AddLoadedSignatureField(0, 360, 72, 540, 132, 'ApproverSig');

    if Idx >= 0 then
      Pdf.SaveLoadedDocument('contract-interactive.pdf');
  finally
    Pdf.Free;
  end;
end;

وسيطا السلسلة الثالث والرابع في حقل النص هما اسم الحقل وقيمة /V الابتدائية؛ والعدد الصحيح هو /MaxLen، ولا يُكتب إلا إذا كان أكبر من الصفر. يمنح HotPDF كل حقل قابل للتحرير سلسلة مظهر افتراضية هي /Helv 12 Tf 0 0 0 rg، وهي ما يقرأه العارض الذي يحترم /NeedAppearances ليقرر الخط واللون الذي يرسم به القيمة. يقبل مربع الاختيار قيمة تصدير، أي السلسلة التي يرسلها النموذج عندما يُحدَّد المربع، بالإضافة إلى قيمة منطقية للحالة الابتدائية؛ وداخليًا يكتب الإدخالات المطابقة /V, /AS، و/DV إدخالات الأسماء بحيث تكون حالة التشغيل والإيقاف متسقة في اللحظة التي يُفتح فيها الملف. وتكون قيمة التصدير الفارغة افتراضيًا Yes، وهو الاسم المعتاد للحالة المفعلة

حقول الاختيار وأعلام البت /Ff

ComboBox وListBox كلاهما من حقول الاختيار، ونوع الحقل /Ch في ISO 32000-1 §12.7.4. الفرق بين قائمة منسدلة وقائمة تمرير هو بت واحد في عدد أعلام الحقل /Ff: البت 18، وهو علم Combo، وقيمته $40000. يضبط HotPDF ذلك البت في AddLoadedComboBox ويتركه غير مضبوطة في AddLoadedListBox؛ وإلا فهما متطابقان، وكلاهما يأخذ خياراته كمصفوفة مفتوحة من السلاسل تُكتب في إدخال /Opt

// Dropdown (Combo flag set internally) with an initial selection
Pdf.AddLoadedComboBox(0, 72, 600, 300, 620, 'Country', 'Canada',
  ['United States', 'Canada', 'Mexico']);

// Scrolling list, no initial value
Pdf.AddLoadedListBox(0, 72, 520, 300, 590, 'Priority', '',
  ['Low', 'Normal', 'High']);

// Push button with a caption drawn through /MK
Pdf.AddLoadedPushButton(0, 360, 600, 480, 626, 'SubmitBtn', 'Submit');

ملاحظتان على قائمة الخيارات/Optيكتب HotPDF كل [export display] إدخال على هيئة سلسلة عادية، حيث تكون قيمة التصدير والتسمية المعروضة النص نفسه. كما يجيز ISO 32000-1 §12.7.4.4 الشكل ثنائي العناصر

عندما تحتاج إلى أن تختلف القيمة المرسلة عما يقرأه المستخدم؛ وتستخدم طرق الإنشاء المحمّلة الصيغة الأبسط ذات السلسلة الواحدة، لذا إذا احتجت إلى اختلاف قيم التصدير والعرض فستضبطها في القاموس الناتج بنفسك. والقيمة التي تمررها بوصفها التحديد الحالي للحقل ينبغي أن تكون إحدى الخيارات التي وفرتها، لأن العارض يطابقها مع القائمة./Btnزر الضغط هو الحالة الأخرى التي يحكمها العلم: نوع الحقل $10000 مع البت 17، علم PushButton، وقيمته /Btn. هذا البت هو ما يفصل الزر القابل للنقر عن مربع الاختيار، وهو أيضًا /MK حقل دون هذا البت. وتُكتب التسمية التي تمررها في قاموس خصائص المظهر /CA كتسمية عادية . ومن المهم أن نكون صريحين بشأن النطاق هنا: يُنشأ الزر مع تسميته ومستطيله، لكن طريقة الإنشاء للمستند المحمّل لا تربطه بأي إجراء، لذا فهو بمفرده زر يبدو صحيحًا ولا يفعل شيئًا عند النقر. ربط إجراءات الإرسال أو إعادة الضبط أو JavaScript موضوع منفصل؛ وعلى جانب الإنشاء من الصفر، فإن سير العمل الذي يجمع الحقل مع الإجراء مشروح في بناء حقول AcroForm والإجراءات في Delphi

القاموس المشترك بين كل الحقول

تحت الطرق الست كلها يوجد منشئ واحد مشترك يبني تعليق الودجت ويسجله في موضعين. فهو يكتب /Type /Annotتحت الطرق الست كلها يوجد منشئ واحد مشترك يبني تعليق الودجت ويسجله في موضعين. فهو يكتب /Subtype /Widget و/Rect، و/F 4مصفوفة /T التي تضبط علم Print كي يظهر الحقل على الورق كما يظهر على الشاشة، واسم الحقل /FT، ونوع الحقل /Ff، والأعلام /P، ومرجعًا عكسيًا /Fields إلى كائن الصفحة. ثم يضيف الحقل الجديد إلى مصفوفة AcroForm الخاصة بـ /Annots وإلى مصفوفة تلك الصفحة

، مع حل المراجع غير المباشرة على طول الطريق حتى يوسّع المصفوفات الحقيقية بدلًا من ترك الودجت يتيمًا./Fieldsذلك التسجيل المزدوج مهم لأن ويدجتًا يعيش في إحدى القائمتين فقط يكون معطوبًا بطريقة خفية. فحقل موجود في /Annots لكنه مفقود من

بعض الحدود الصريحة

ضع التوقعات قبل أن تبني عليها سير عمل. يعتمد سلوك التسطيح وإعادة الإنشاء على التزام العارض بـ /NeedAppearancesضع التوقعات قبل أن تبني عليها سير عمل. يعتمد سلوك التسطيح وإعادة الإنشاء على التزام العارض بـ /AP، وهو ما يشمل Acrobat ومحركات PDF في المتصفحات الحديثة والقارئات المكتبية الشائعة، لكنه ليس ضمانًا صارمًا عبر كل عارض موجود. إذا كان لا بد من إنتاج ملف تعرض حقوله بشكل متطابق في كل مكان، بما في ذلك العارضات التي تتجاهل العلم، فأنت تدخل في مجال تدفقات المظهر، والمسار الذي ينشئها لك من الصفر ويطبع

هو الأنسب. وبالمثل، يُنشأ حقل التوقيع على هيئة ويدجت توقيع فارغ جاهز للتوقيع؛ فمجرد وضع الحقل ليس هو نفسه تطبيق توقيع تشفيري.عندما تريد تغيير الموجود بدلًا من إضافة جديد إليه، فالعملية المرتبطة هي تسطيح النماذج، حيث تعيد دمج الحقول التفاعلية داخل محتوى الصفحة الثابتة بحيث تصبح القيم دائمة وغير قابلة للتحرير؛ وذلك الانتقال ذهابًا وإيابًا، بما في ذلك كيفية التعامل مع النماذج التي تحتوي على XFA، مشروح في تسطيح حقول XFA وAcroForm في Delphi

. إضافة الحقول وتسطیح الحقول هما طرفا دورة حياة واحدة: هذه المقالة تشرح كيف تجلب التفاعلية إلى مستند كان يفتقر إليها، والتسطيح هو كيف تزيلها مرة أخرى بعد أن يؤدي النموذج غرضه.واجهة برمجة تطبيقات النماذج الخاصة بالمستندات المحمّلة المعروضة هنا تأتي ضمن HotPDF Component