مقال تقني

استيراد وتصدير تعليقات PDF التوضيحية كـ XFDF في Delphi

يقوم HotPDF بتصدير واستيراد تعليقات الـ PDF التوضيحية (annotations) كـ XFDF من خلال دالتين تعملان على المستند المحمل حاليًا: ExportLoadedAnnotationsToXFDF و ImportLoadedAnnotationsFromXFDF؛ وتعد صيغة XFDF هي تنسيق XML لتبادل التعليقات التوضيحية والمعياري بالمواصفة ISO 19444-1، ويتيح هذا الزوج لبرنامج Delphi أو C++Builder تسليم تعليقاته إلى Acrobat أو أداة مراجعة تابعة لجهة خارجية واستعادة النتائج المحددة، كل ذلك دون إعادة كتابة محتوى الصفحة الذي تقع عليه هذه التعليقات

تخيل الاتجاهين اللذين يحل هذا المسار مشكلتهما؛ حيث يفتح المراجع تقريرك الذي تم إنشاؤه في Acrobat، ويضع سهمًا أحمر على رسم بياني غير محاذٍ بشكل صحيح، ويضع دائرة حول إجمالي خاطئ ويكتب ملاحظة في الهامش، ثم يصدر التعليقات إلى ملف XFDF صغير؛ أو العكس: ينتج برنامجك العلامات التوضيحية بنفسه، وتحتاج إلى شحنها إلى شخص لا يمتلك أداة HotPDF؛ وفي كلتا الحالتين، تنتقل التعليقات التوضيحية كـ XML يفهمه كلا الجانبين، وتبقى صفحات الـ PDF بايتًا ببايت كما كانت

ما الفرق بين FDF و XFDF؟

تحمل FDF و XFDF نفس الحمولة بأسلوبين مختلفين، ويصبح التمييز مهمًا لحظة تحديد الملف الذي ستسلمه لأداة أخرى؛ حيث إن FDF هي تنسيق بيانات النماذج القديم المحدد داخل مواصفات الـ PDF نفسها: فهي تستخدم صيغة كائنات PDF، ولذلك يبدو ملف FDF كنسخة مجردة من PDF ويحتاج إلى محلل متوافق مع PDF لقراءته؛ أما XFDF فهو تعبير XML عن نفس تلك البيانات، والمعياري بشكل مستقل كمواصفة ISO 19444-1، مما يعني أن أي مكتبة XML على أي منصة يمكنها فتحه أو مقارنته أو إنشاؤه؛ وتستطيع كلتا الصيغتين حمل قيم حقول النماذج في شجرة <fields>، وهو ما تحكمه الفقرة 6.3 من مواصفة ISO 19444-1، وحمل التعليقات في شجرة <annots>؛ ويقسم HotPDF هذه المسؤوليات، فيوجه بيانات النموذج من خلال ExportLoadedFormToXFDF ويحجز ExportLoadedAnnotationsToXFDF لجانب <annots>؛ وعندما تتبادل التعليقات مع خدمة ويب، أو خادم مراجعة جافا، أو نص برمجي، فإن XFDF هو التنسيق الذي لا يجبر الجانب الآخر على تضمين محلل PDF

كيف تقوم بتصدير تعليقات PDF التوضيحية كـ XFDF في Delphi؟

يقوم HotPDF بتصدير التعليقات التوضيحية بالمرور عبر كل صفحة من المستند المحمل، ومصدرًا عنصر XFDF واحدًا لكل تعليق مدعوم، ويرجع عدد التعليقات المكتوبة؛ فقم بتحميل ملف PDF أولاً، ثم استدعِ ExportLoadedAnnotationsToXFDF مع تحديد مسار الهدف؛ والنتيجة الصحيحة هي عدد التعليقات التي تم تسلسلها، والنتيجة الصفرية أو الأقل تعني أنه لم يتم تصدير أي شيء ولم يتم كتابة أي ملف، وهو ما يشير إلى أن المستند لا يحمل تعليقات توضيحية من الأنواع الفرعية المدعومة

var
  Pdf: THotPDF;
  Written: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report-reviewed.pdf', '') > 0 then
    begin
      // كتابة عنصر XFDF واحد لكل تعليق مدعوم في كل صفحة
      Written := Pdf.ExportLoadedAnnotationsToXFDF('comments.xfdf');
      if Written <= 0 then
        ShowMessage('No supported annotations were found');
    end;
  finally
    Pdf.Free;
  end;
end;

ملف XFDF الناتج هو عبارة عن XML بسيط وقابل للقراءة؛ حيث يكتب HotPDF جذر <xfdf> في مساحة أسماء ISO 19444-1، وحاوية <annots>، وطفلًا واحدًا لكل تعليق مع فهرس صفحته المبني على الصفر ولونه وهندسته كسمات أو عناصر فرعية؛ وسطر ذو تعبئة صفراء ورأس سهم مفتوح، يقبع بجوار مضلع معبأ، يتسلسل بهذا الشكل

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/">
  <annots>
    <line page="0" start="72,700" end="220,700"
          color="#FF0000" interior-color="#FFFF00"
          head="OpenArrow" tail="None">
      <contents-richtext>Baseline looks off</contents-richtext>
    </line>
    <polygon page="0" color="#0000FF" interior-color="#CCE5FF">
      <vertices>72,120;180,120;180,200;72,200</vertices>
    </polygon>
  </annots>
</xfdf>

كيف تطابق الأنواع الفرعية للتعليقات مع عناصر XFDF

يطابق كل نوع فرعي للتعليقات عنصرًا محددًا بمواصفة ISO 19444-1 مع اتفاقية هندسية خاصة به، ويتبع HotPDF تلك الهياكل بدلاً من ابتكار هياكله الخاصة؛ حيث تحمل تعليقات الخطوط سمة start و end تحمل إحداثيات نقطتي النهاية، مأخوذة مباشرة من مصفوفة L للتعليق، بينما تصبح أنماط نهاية السطور LE سمات head و tail؛ وتنقل تعليقات المضلع والخطوط المتعددة قائمة نقاطها إلى عنصر فرعي <vertices> كأزواج x,y مفصولة بفاصلة منقوطة، وليس كسمة، لأن القارئ الذي يتوقع العنصر الفرعي سيسقط بصمت النقاط المخفية في أي مكان آخر؛ وتعليقات الحبر، والتي يمكن أن تحمل عدة ضربات منفصلة، تعشش عنصر <inklist> مع طفل <gesture> واحد لكل ضربة، بحيث تنجو التوقيعات متعددة الضربات كإيماءات مميزة بدلاً من كتلة واحدة مدمجة

وينجو النص المنسق وتنسيقات الألوان والحدود جنبًا إلى جنب مع الهندسة؛ حيث يُكتب متن النص المنسق للملاحظة كعنصر فرعي <contents-richtext>؛ وتأتي التعبئة الداخلية التي يخزنها الـ PDF في مصفوفة IC، والطلاء داخل دائرة أو مربع أو مضلع أو رأس سهم والملء لصندوق التحرير، كسمة interior-color بصيغة #RRGGBB؛ وتطابق سمات عرض الحدود، ونمط الشرطات، وتأثير الحدود السحابية مع سمات width و dashes و style و intensity، بحيث يظل التعليق التوضيحي ذو الحدود السحابية مقروءًا كسحابة على الطرف الآخر؛ ويحافظ HotPDF أيضًا على النافذة المنبثقة المرفقة بالتعليق التوضيحي، مستوردًا هندسة النافذة وحالتها المفتوحة أو الغلقة في قاموس Popup للتعليق التوضيحي، ويحمل حالات الفتح والمراجعة لتعليقات النصوص، بحيث يحتفظ المستند المراجع ليس فقط بأشكاله بل ببيانات تدفق العمل التي يعتمد عليها المراجعون

استيراد XFDF مرة أخرى إلى مستند محمل

يقوم HotPDF باستيراد XFDF عن طريق تحليل XML، وإنشاء تعليق توضيحي جديد لكل عنصر من خلال NewLoadedAnnotation، وإرفاقه بالصفحة التي يسميها العنصر، وإرجاع عدد التعليقات التي أضافها؛ وسير العمل متماثل مع التصدير: قم بتحميل ملف PDF الأساسي، واستدعِ ImportLoadedAnnotationsFromXFDF مع ملف المراجع، ثم احفظ المستند المحمل للاحتفاظ بالعلامات الجديدة؛ وإذا كان الملف مفقودًا أو تعذر تحليل XML، فإن الدالة ترجع صفرًا ويُترك المستند دون تغيير

var
  Pdf: THotPDF;
  Added: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report.pdf', '') > 0 then
    begin
      Added := Pdf.ImportLoadedAnnotationsFromXFDF('comments.xfdf');
      if Added > 0 then
        Pdf.SaveLoadedDocument('report-annotated.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

لأن كل عنصر XFDF يسمي فهرس صفحته الخاصة، تهبط التعليقات على الصفحات التي تم تأليفها ضدها حتى عند استيراد عدة ملفات متتالية، مما يجعله من الآمن جمع التعليقات من أكثر من مراجع على نفس المستند المحمل قبل حفظ واحد؛ ويوضح المثال أدناه دمج مراجعين في نسخة مدمجة واحدة؛ ولبناء وتعديل كائنات التعليقات التوضيحية نفسها في التعليمات البرمجية بدلاً من تبادلها كملفات، انظر كيف يقوم HotPDF بإنشاء وتعديل كائنات تعليقات PDF التوضيحية مباشرة من Delphi

var
  Pdf: THotPDF;
  Total, I: Integer;
  Files: array[0..1] of string;
begin
  Files[0] := 'alice-comments.xfdf';
  Files[1] := 'bob-comments.xfdf';
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('master.pdf', '') > 0 then
    begin
      Total := 0;
      for I := Low(Files) to High(Files) do
        Inc(Total, Pdf.ImportLoadedAnnotationsFromXFDF(Files[I]));
      if Total > 0 then
        Pdf.SaveLoadedDocument('master-merged.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

ما الذي يدور دورة كاملة بنظافة، وما الذي لا يدور

يقوم HotPDF بتدوير الأنواع الفرعية للتعليقات التي توفر لها مواصفة ISO 19444-1 مسكنًا، ويتخطى الباقي عمدًا بدلاً من إصدار شيء قد يفسره القارئ بشكل خاطئ؛ وتغطي المجموعة المدعومة أنواع العلامات التوضيحية التي تهيمن على أعمال المراجعة الحقيقية: الملاحظات النصية، النصوص الحرة، الخطوط، المربعات، الدوائر، المضلعات، الخطوط المتعددة، الأنواع الأربعة لعلامات النصوص (التمييز، والتسطير، والتشطيب، والخط المتعرج)، والأختام، والحبر، وعلامات الإقحام (caret)، بالإضافة إلى مرفقات الملفات، والصوت، والتحرير (redaction)، والروابط — وثمانية عشر نوعًا فرعيًا في المجموع؛ ويتم تخطي أي تعليق يقع نوعه الفرعي خارج هذه القائمة عند التصدير، ولأنه يتم تخطيه بدلاً من كتابته فارغًا، فإنه لا يزيد من العدد الذي ترجعه الدالة

النص المنسق هو التنبيه الحقيقي هنا؛ حيث يحافظ HotPDF على جسم <contents-richtext> بحيث يقوم النص المنسق والمحتويات البسيطة بالرحلة، ولكن XFDF يحمل نص التعليق ووسوم نمطه، وليس دفق مظهر معروض، لذا يعيد التطبيق المستلم رسم النافذة المنبثقة بخطوطه وتخطيطه الخاص بدلاً من إعادة إنتاج بكسلات HotPDF الدقيقة؛ وعامل الدورة الكاملة كأمانة للمحتوى والقصد، وليس للعرض على الشاشة وصولاً إلى البكسل؛ وإذا كان محتواك المنسق يعيش في بيانات نماذج XFA بدلاً من دفق التعليقات، فإن القواعد تختلف، ويغطي المقال المصاحب كيفية تعامل HotPDF مع بيانات XFA exData والنصوص المنسقة والروابط التشعبية هذا المسار المنفصل

إن المعالجة على مستوى الأحرف أكثر صرامة مما تبدو، وهو بالضبط ما تريده؛ حيث يطبق HotPDF قواعد الهروب للفقرة 5.8.2 من مواصفة ISO 19444-1 عندما يكتب النصوص، ويرمز الأحرف المهمة في XML وبايتات التحكم بحيث ينتج تعليق يحتوي على علامة ampersand أو قوس زاوية أو فاصل أسطر لغة XML جيدة التكوين يقبلها أي محلل متوافق، ويعكس نفس القواعد عند الاستيراد؛ ولهذا السبب تعود الملاحظة المنسوخة من جدول بيانات، بعلامات ترقيمها وكل شيء، سليمة بدلاً من إفساد الملف

تبادل التعليقات التوضيحية هو جزء واحد مما تفعله واجهة برمجة تطبيقات المستندات المحملة، وهو يمتزج مع البقية: استيراد ملف XFDF للمراجع، أو ضبط الصفحات أو تعديل بيانات تعريف المستند، أو تسطيح الملف أو إعادة أذوناته، ثم تصدير ملف XFDF جديد للجولة التالية؛ ويتم شحن كل هذا في مكون HotPDF القياسي لـ Delphi و C++Builder، الذي يوثق مرجعه التغطية الكاملة للأنواع الفرعية للتعليقات ودوال XFDF المصاحبة لبيانات النماذج