مقال تقني

تحويل PDF إلى Markdown وDOCX في Delphi باستخدام PDFlibPas

تحوّل PDFlibPas محتوى PDF إلى صيغتين قابلتين للتحرير دون الحاجة إلى أتمتة Office. تُعيد ExportPageMarkdown وExportDocumentMarkdown نص Markdown دلالي بعناوين مستنتَجة، وقوائم مرقّمة وغير مرقّمة، وجداول بخط عمودي فاصل، بينما تكتب SaveDOCXToFile وSaveDOCXToStream حزمة WordprocessingML تحتوي على فقرات وعناوين وترقيم قوائم أصلي وجداول مكتشَفة وتنسيق خطوط وفواصل صفحات وصور PNG موضوعة في أماكنها

تعمل كلتا الوظيفتين بالكامل بلغة Pascal، على خادم، دون تثبيت Word ودون COM. هذا القيد هو سبب وجود هذه الميزة في مكتبة PDF بدلاً من أداة سطح مكتب

لماذا يُعد «تحويل PDF إلى Word» صعباً حقاً؟

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

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

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

تصدير Markdown، صفحة واحدة في كل مرة

مسار Markdown هو ما تلجأ إليه عندما تكون الوجهة خط أنابيب نصياً: موقع توثيق، فهرس بحث، أو مجموعة استرجاع لمساعد ذكي. الخيارات هي قناع بتّي: PDF_MARKDOWN_INCLUDE_PAGE_MARKERS وPDF_MARKDOWN_DETECT_HEADINGS وPDF_MARKDOWN_PRESERVE_STYLES، مع PDF_MARKDOWN_DEFAULT التي تجمع الخيارات الثلاثة معاً

var
  Pdf: TPDFlib;
  Md: WideString;
begin
  Pdf := TPDFlib.Create;
  try
    Pdf.LoadFromFile('handbook.pdf', '');

    // صفحة واحدة، كسلسلة نصية
    Md := Pdf.ExportPageMarkdown(1, PDF_MARKDOWN_DEFAULT);

    // نطاق صفحات، مكتوب بشكل متدفق إلى القرص بترميز UTF-8 دون BOM
    Pdf.SaveMarkdownToFile('1-40',
      PDF_MARKDOWN_DETECT_HEADINGS or PDF_MARKDOWN_PRESERVE_STYLES,
      'handbook.md');
  finally
    Pdf.Free;
  end;
end;

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

نقاط الدخول المتدفقة مهمة للمستندات الكبيرة. تكتب SaveMarkdownToStream وSaveMarkdownToFile بترميز UTF-8 صفحة واحدة في كل مرة ولا تخزّن الإخراج الكامل مؤقتاً، بحيث لا يتحول دليل من 900 صفحة إلى سلسلة نصية من 900 صفحة في الذاكرة أولاً. غياب علامة ترتيب البايت متعمَّد أيضاً: فوجود BOM في ملف Markdown يربك عدداً مفاجئاً من مولّدات المواقع الثابتة وأدوات مقارنة الفروق

DOCX دون تثبيت Office على الجهاز

تُنتج كاتبة DOCX الحزمة بنفسها: مدخلات ZIP مكتوبة بضغط Deflate خام مع فحوصات CRC، وأجزاء WordprocessingML، والعلاقات التي تربطها معاً. لا شيء يستدعي Word، مما يعني أن التحويل يعمل على خادم بلا واجهة رسومية، داخل حساب خدمة، في حاوية، في كل الأماكن التي تكون فيها أتمتة Office إما غير مرخّصة أو غير مستقرة أو محظورة

var
  Pdf: TPDFlib;
  Target: TFileStream;
begin
  Pdf := TPDFlib.Create;
  Target := TFileStream.Create('handbook.docx', fmCreate);
  try
    Pdf.LoadFromFile('handbook.pdf', '');
    Pdf.SaveDOCXToStream('1-40',
      PDF_DOCX_INCLUDE_IMAGES or PDF_DOCX_DETECT_HEADINGS or
      PDF_DOCX_PRESERVE_STYLES or PDF_DOCX_PRESERVE_PAGE_BREAKS,
      Target);
  finally
    Target.Free;
    Pdf.Free;
  end;
end;

تُكتب بيانات الصور أثناء معالجة كل صفحة بدلاً من تجميعها وإلحاقها في النهاية، بحيث تتبع ذروة استهلاك الذاكرة صفحة واحدة بدلاً من المستند بأكمله. يُحافَظ على ترتيب الصفحات الصريح، وتُستعاد صفحة PDF المحددة بعد ذلك، وهو أمر مهم عندما يكون التصدير خطوة واحدة ضمن مهمة أطول كانت قد حددت صفحة لأسباب أخرى

ماذا يمنحك التغليف الحتمي؟

قابلية إعادة الإنتاج بايتاً ببايت. تحويلان للإدخال نفسه بالخيارات نفسها ينتجان الحزمة نفسها، مما يعني أنه يمكنك تجزئة الإخراج لاكتشاف التغيير، ومقارنة نسختين من مستند مولَّد، والتخزين المؤقت بقوة دون القلق من أن إدخالاً متطابقاً أنتج قطعة أثرية مختلفة

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

أين يكون الإخراج جيداً، وأين لا يكون كذلك

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

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

بالنسبة لخطوط أنابيب المساعدات الذكية والاسترجاع، عادة ما يكون مسار Markdown هو الهدف الأفضل: تصبح العناوين حدوداً للأجزاء، وتبقى الجداول قابلة للقراءة كجداول بخط فاصل، وتمنح علامات الصفحات كل جزء موقعاً قابلاً للاستشهاد. أما بالنسبة للتحرير البشري، فإن DOCX هو الإجابة، لأن ما يريده المستخدم ليس النص بل القدرة على تغييره

PDFlibPas هي مكتبة PDF لـ Delphi و C++Builder و Lazarus، مزودة بواجهات DLL وActiveX مطابقة، بحيث تتوفر استدعاءات التصدير نفسها من C# أو C++ أو مضيفات البرمجة النصية. التوثيق الكامل ونسخة تجريبية متاحان على صفحة مكتبة PDFlibPas لـ Delphi