مقالة تقنية

تصدير واستيراد XFDF في دلفي مع مكون PDFium

يقوم مكون PDFium لدلفي ولازاروس بتبادل بيانات النماذج والتعليقات التوضيحية من خلال XFDF، وهو تنسيق تبادل XML المحدد بواسطة معيار ISO 19444-1. وتقوم TPdf.ExportXFDF بمسلسلة كل قيمة حقل نموذج وكل تعليق توضيحي مدعوم في المستند المحمل إلى ملف XFDF أو TStream; وتقرأ TPdf.ImportXFDF مستند XFDF رجوعاً، مع إعادة إنشاء التعليقات التوضيحية على صفحاتها وتطبيق قيم الحقول. وتغطي تلك الرحلة الدائرية الواحدة تدفقي عمل يحتاجهما كل تطبيق مستندات في النهاية: مراجع يعلم على PDF في Acrobat ويرسل لك التعليقات لدمجها، أو قاعدة امتثال تنص على أن بيانات النموذج يجب أن تعيش في ملف منفصل وقابل للمقارنة والمراجعة بدلاً من خبزها في ملف PDF نفسه

هل يدعم PDFium استيراد وتصدير XFDF؟

مكتبة PDFium نفسها لا تدعم ذلك. حيث لا تحتوي واجهة برمجة تطبيقات C الأصلية على وظائف XFDF أو FDF على الإطلاق — ولا يقرأ أي شيء في ترويساتها العامة أي من التنسيقين أو يكتبهما، لذا فإن أي قدر من التغليف لن يوصلك إلى هناك. لذلك، يقوم مكون PDFium بتنفيذ محرك XFDF بأكمله في باسكال، في وحدة مخصصة تبني وتحلل XML مباشرة فوق نموذج بيانات حقل النموذج والتعليقات التوضيحية لـ TPdf الحالي. ويصدر الكاتب XML يدوياً والقارئ عبارة عن محلل آلة حالة مكتوب يدوياً، لذا فإن الميزة لا تضيف أي اعتماد على Delphi XMLDoc أو وحدات FPC DOM وتتصرف بشكل متطابق في دلفي ولازاروس

اختيار التصميم هذا يهم عندما تقيم البدائل. إذا كنت تستدعي وظائف FPDF_* الخام من باسكال، فإن XFDF يمثل جداراً: فالقدرة ببساطة ليست في DLL. ويعبر المكون هذا الجدار بمعاملة XFDF كمسألة مسلسلة بحتة — جمع قيم الحقول وسجلات التعليقات التوضيحية التي يعرف الغلاف بالفعل كيفية قراءتها، وكتابتها كـ XML قياسي، وعكس العملية عند الاستيراد

ماذا يحتوي ملف XFDF؟

يحدد معيار ISO 19444-1 ملف XFDF كتمثيل XML لـ FDF، وتنقسم حمولته إلى كتلتين على المستوى الأعلى. ويحمل عنصر <fields> أسماء حقول النماذج الهرمية وقيمها — كل ما كتبه المستخدم أو اختاره أو حدده في AcroForm. ويحمل عنصر <annots> التعليقات التوضيحية: تصدر TPdf.ExportXFDF ‏18 نوعاً فرعياً — النص، والتظليل، والتسطير، والتشطيب، والخط المتعرج، والخط، والدائرة، والمربع، وعلامة الإقحام، والمضلع، وخط المضلع، والختم، والحبر، والنص الحر، ومرفق الملف، والصوت، والرابط، والتعتيم (redact). وتغيب تعليقات الـ Widget التوضيحية عمداً من <annots> لأن بياناتها تنتقل في <fields>، ولا تعد الأنواع الفرعية الداخلية للعارض مثل Popup جزءاً من مفردات XFDF

لجعل الرحلة الدائرية أمينة، تم تمديد سجل TPdfAnnotation بالبيانات الوصفية التي يتوقعها XFDF: ‏Name (معرّف NM الفريد)، وSubject، وModificationDate، وCreationDate، وIcon، وOpacity، ونقاط نهاية السطر، ورؤوس المضلعات وخطوط المضلعات، ومسارات إيماءات الحبر. ويقترن كل حقل جديد بحارس منطقي Has*، بحيث يستمر الكود الذي بنى تعليقات توضيحية ضد الإصدارات السابقة في الترجمة ويستمر في إنتاج نفس القواميس — فالحقل غير المعين لا يكتب أبداً. وإذا كنت يقوم بالفعل بإنشاء علامات برمجياً، فإن السجل نفسه الذي تستخدمه لـ التعليقات التوضيحية لعلامات النص بنقاط رباعية يحمل الآن كل ما يحتاجه XFDF

كيف تقوم بتصدير بيانات النماذج والتعليقات التوضيحية إلى XFDF؟

TPdf.ExportXFDF(FileName) (أو التدفق) هو مسار استدعاء واحد: فهو يتصفح كل صفحة، ويجمع قيم الحقول والتعليقات التوضيحية، ويكتب XML. والقيمة المعادة هي عدد بايتات UTF-8 المكتوبة، مما يجعل فحص الصحة رخيصاً في السجلات

var
  Pdf: TPdf;
  Bytes: Integer;
begin
  Pdf := TPdf.Create(Self);
  Pdf.FormFill := True;            // needed so field values are live
  Pdf.FileName := 'expense-report.pdf';
  Pdf.Active := True;
  Bytes := Pdf.ExportXFDF('expense-report.xfdf');
  ShowMessage(Format('%d bytes of XFDF written', [Bytes]));
end;

كلا الاتجاهين لهما حمولة زائدة (overload) لـ TStream، لذا لا شيء يفرض ملفاً مؤقتاً على القرص. والتصدير إلى TMemoryStream هو الشكل الطبيعي عندما يتجه XFDF إلى استجابة HTTP، أو blob لقاعدة البيانات، أو إدخال أرشيف موقع

var
  Buffer: TMemoryStream;
begin
  Buffer := TMemoryStream.Create;
  try
    Pdf.ExportXFDF(Buffer);        // same XML, no file involved
    Buffer.Position := 0;
    // hand the stream to a web response, blob column, or zip entry
  finally
    Buffer.Free;
  end;
end;

كيف تقوم ImportXFDF بدمج التعليقات رجوعاً في المستند؟

جانب الاستيراد هو المكان الذي ينغلق فيه تدفق عمل المراجع. حيث يقوم زميل بتعليق العقد في Acrobat، ويصدر التعليقات كـ XFDF، ويرسل لك بضع كيلوبايتات من XML بدلاً من نسخة ثانية من PDF. وتقوم TPdf.ImportXFDF بتحليل هذا الملف، وتنشئ كل تعليق توضيحي على الصفحة التي تسميها سمة page الخاصة به، وتكتب قيم الحقول في تعليقات الـ widget المطابقة. وتعيد الوظيفة العدد المشترك للحقول بالإضافة إلى التعليقات التوضيحية المطبقة، بحيث يمكن لوراجهة المستخدم تأكيد الكمية التي وصلت بدقة

var
  Applied: Integer;
begin
  Applied := Pdf.ImportXFDF('review-comments.xfdf');
  StatusBar.SimpleText :=
    Format('%d fields and annotations merged', [Applied]);
end;

المحلل عبارة عن ماسح علامات مكتوب يدوياً مبني على التسامح بدلاً من الصرامة: حيث يتم تخطي العناصر غير المعروفة، وتجاهل تعليمات المعالجة وإعلانات DOCTYPE والتعليقات، وإسقاط أسماء العلامات غير المعترف بها، وإلغاء هروب قيم السمات من خلال المجموعة الكاملة لكيانات XML ومراجع الأحرف الرقمية، بما في ذلك أزواج بدائل UTF-16. ويندمج XFDF الذي ينتجه Acrobat، أو عارض ويب، أو أداة أخرى دون مراسم. وبمجرد وجود التعليقات التوضيحية في المستند، تستمر دورة المراجعة مع آلية الرد والحالة الموصوفة في بناء تدفق عمل مراجعة التعليقات التوضيحية باستخدام مكون PDFium، وتشارك قيم الحقول المستوردة في منطق ترتيب علامات التبويب العادي المغطى في الملاحة في حقول النموذج

لماذا تهم فواصل العشري لـ XFDF?

يتم تحديد موضع كل تعليق توضيحي في XFDF بواسطة سلاسل الإحداثيات — rect="70.5,540,200,560" وأخواتها — ويتطلب معيار ISO 19444-1 النقطة كفاصل عشري. ويتبع تنسيق Delphi العائم الافتراضي الإعدادات المحلية لـ Windows، لذلك في النظام الألماني أو الفرنسي، يقوم FloatToStr الساذج بتحويل 70.5 إلى 70,5، مما يؤدي إلى إفساد قائمة الإحداثيات المفصولة بفاصلة إلى قمامة ترفضها المعالجات الأخرى أو تسيء قراءتها. ويقوم مكون PDFium بتطبيع كل رقم يكتبه: يتم إعادة كتابة الفاصل العشري المحلي إلى نقطة ويتم تقليم الأصفار الزائدة، بحيث يكون الملف المصدر متطابقاً بالبايت سواء تم إنتاجه على جهاز en-US أو de-DE. وإذا سبق لك تصحيح أخطاء أداة PDF كانت تعمل في المكتب وفشلت في موقع عميل أوروبي، فقد قابلت فئة الأخطاء هذه بالضبط — ومن الجدير بالذكر أن المكون يتعامل معها من أجلك

ما هي حدود الرحلة الدائرية؟

هناك حدان يجدر ذكرهما بوضوح. أولاً، ينقل XFDF بيانات التعليقات التوضيحية، وليس المظاهر المعروضة — فتدفقات المظهر ليست جزءاً من التنسيق، لذا يعيد العارض المتلقي إنشاء كل مظهر تعليق توضيحي من خصائصه. وسيعرض التظليل أو المربع بشكل صحيح في كل مكان؛ وسيتراجع الختم ذو المظهر المخصص إلى ما يرسمه العارض المستهدف لاسم الختم هذا. ثانياً، تحتوي واجهة برمجة تطبيقات PDFium الأساسية على واضعي قيم (setters) للسلاسل النصية ولكن ليس لأرقام التعليقات التوضيحية أو هندسة المسار، لذا فإن Opacity، ونقاط نهاية الخط، والرؤوس، وإيماءات الحبر هي للتصدير فقط: حيث يحافظ عليها المكون بأمانة عند كتابة XFDF، ولكنه لا يستطيع كتابتها مرة أخرى في ملف PDF عند الاستيراد. وقيم الحقول والمحتويات والألوان والمستطيلات والنقاط الرباعية والتواريخ والبيانات الوصفية للهوية جميعها تقوم بالرحلة الدائرية في كلا الاتجاهين

للبدء العملي، تُشحن عينة XfdfLab في مجموعات عروض دلفي وC++Builder ولازاروس وتوصل كلا الاستدعاءين بأزرار فوق أي ملف PDF تفتحه. ويتم تضمين دعم XFDF في الإصدار الحالي من مكون PDFium Component، إلى جانب واجهات برمجة تطبيقات التعليقات التوضيحية والنماذج التي يبني عليها