Technical Article

بنية ملف PDF: كيف يعمل التنسيق فعليًا

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

نموذج الكائنات

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

قاموس الفهرس هو الجذر. وهو يشير إلى شجرة الصفحات، التي تنظم قواميس الصفحات في بنية شجرية متوازنة بدلًا من قائمة مسطحة، حتى لا يتطلب التنقل إلى الصفحة 5000 من مستند من 10000 صفحة اجتياز كل واصف صفحة سابق. تشير كل قاموس صفحة إلى تيارات المحتوى الخاصة بها ‏(واحدة أو أكثر من سلاسل معاملات وصف الصفحة)، وإلى قاموس الموارد الخاص بها ‏(الذي يشير بدوره إلى واصفات الخطوط ومساحات الألوان و XObjects الخاصة بالصور)، وإلى مربع الوسائط الخاص بها ‏(فضاء الإحداثيات الذي تعيش فيه الصفحة). أصل الإحداثيات يقع في الزاوية السفلية اليسرى، مع ارتفاع المحور Y إلى الأعلى، بوحدة 1/72 inch.

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

تيارات المحتوى ونموذج الرسومات

يعيش المحتوى المرئي للصفحة في تيار محتوى واحد أو أكثر. كل تيار هو تسلسل من معاملات PDF تتخللها معاملاتُها. يبدأ معامل النص BT كائن نص، ويختار Tf خطًا وحجمًا من قاموس الموارد، ويضع Td مؤشر النص، ويرسم Tj أو TJ سلسلة، ويغلق ET كائن النص. ويتبع الرسم المتجهي نمطًا مشابهًا: يحدد m نقطة بداية مسار، ويضيف l مقطعًا مستقيمًا، ويضيف c منحنى Bezier، ويملا f أو يرسم S المسار.

تحكم حالة الرسومات كل ما يحدث بين المعاملات: مصفوفة التحويل الحالية، وعرض الخط، وفضاء اللون، ولون التعبئة، ولون الرسم، ومسار القص. المعاملات مثل q و Q تدفع حالة الرسومات إلى مكدس وتسحبها منه، وهذا هو كيف ينفذ PDF التحويلات المحلية للإحداثيات وتجاوزات الحالة المؤقتة من دون التأثير في السياق المحيط بها. تعمم Form XObjects هذا المفهوم: تيار محتوى مستقل ذاتيًا له قاموس موارد خاص به يمكن رسمه على الصفحة في مواضع ومقاييس عشوائية باستخدام معامل Do واحد.

تضمين الخطوط واستخراج النص

يمكن لـ PDF أن يشير إلى الخطوط بالاسم ويعتمد على العارض لاستبدال شيء ما، لكن عمليًا يجب أن يضمّن أي مستند تنوي مشاركته بيانات الخط. يحمل خط Type 1 أو TrueType/OpenType المضمّن في PDF قاموس واصف خط يشير إلى تيار ملف خط. بالنسبة إلى خطوط TrueType، يحتوي ذلك التيار على برنامج الخط الثنائي؛ وبالنسبة إلى Type 1 فهو بيانات PFB. أما التقليم، وهو ما تفعله كل مولدات PDF الجادة، فيزيل الأشكال غير المشار إليها في المستند، مما يبقي أحجام الملفات معقولة حتى في الخطوط Unicode الكبيرة.

استخراج النص هو المكان الذي يعود فيه تضمين الخطوط ليضغط عليك. التمثيل المرئي للحرف تحدده صورة glyph في برنامج الخط المضمّن. أما قيمة Unicode لذلك الحرف فتحددها تيار ToUnicode CMap ملحق بقاموس الخط. عندما يكون ToUnicode CMap مفقودًا أو غير صحيح، يمكن لعارض PDF أن يعرض النص مقروءًا لكنه لا يستطيع استخراجه بوصفه Unicode ذا معنى، وهذا هو سبب كون النسخ واللصق من بعض ملفات PDF ينتج هراءً. يضيف Tagged PDF (ISO 32000 §14.8) طبقة ثانية: شجرة بنية منطقية تربط محتوى الصفحة بأدوار دلالية للمستند مثل الفقرات والعناوين وخلايا الجدول. تستخدم قارئات الشاشة ومحركات إعادة التدفق شجرة البنية بدل ترتيب تيار المحتوى الخام، وهذا يفسر كيف يمكن لملف PDF موضوع بصريًا بشكل جيد أن يظل غير قابل للوصول إذا كان الوسم غائبًا أو خاطئًا.

التحديثات التراكمية والتواقيع الرقمية

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

أولًا، يكبر الملف مع كل دورة حفظ. المستند الذي يُعدّل ويحفظ مرارًا يتراكم فيه عدد من طبقات الكائنات القديمة. يمكن لأدوات مثل QPDF أن تعيد تنظيم الملف أو تضغطه وتعيد كتابته لاستعادة تلك المساحة، لكن السلوك الافتراضي هو التراكم. ثانيًا، تعتمد التواقيع الرقمية على التحديثات التراكمية في نموذج سلامتها. يغطي توقيع ISO 32000 نطاقًا من بايتات الملف، عادةً كل شيء باستثناء العنصر النائب لقيمة التوقيع نفسها. أي تغييرات بعد التوقيع تظهر كتحديثات تراكمية إضافية يراها القارئ الذي يحقق التوقيع على أنها تعديلات حدثت بعد التوقيع، وهذا هو سجل التدقيق الذي تريده بالضبط. لكن هذا يعني أيضًا أن بعض التعديلات، مثل إضافة توقيع موافقة أو تعبئة حقول نموذج، مسموح بها صراحة في المعيار من دون إبطال التوقيع الأصلي، بشرط أن تتوافق التغييرات مع إعدادات الأذونات في المستند (ISO 32000-2 §12.7.6). أما التعديل الذي يقع خارج تلك الأذونات فيُعلّم على أنه غير مصرح به. فهم هذا الفرق مهم عندما تولد مستندات سيوقعها طرف لاحقًا.

مستويات المطابقة وسلسلة ISO 32000

بدأ PDF كتنسق Adobe مملوكًا في 1993، واستوعب نموذج التصوير من PostScript، وعلى مدار خمسة عشر إصدارًا تراكمت فيه الميزات: التشفير في 1.1، والنماذج التفاعلية في 1.2، والتواقيع الرقمية والبنية المنطقية في 1.3، والشفافية في 1.4، وتيارات الكائنات في 1.5، وتشفير AES في 1.6. قدمت Adobe PDF 1.7 إلى ISO في 2007، وكانت النتيجة ISO 32000-1:2008. يغطي ISO 32000-2:2020 PDF 2.0، الذي شدد بعض المناطق غير المحددة جيدًا، وراجع اشتقاق مفتاح AES-256 ‏(revision 6 بدلًا من revision 5)، وأضاف دعمًا صريحًا للملفات المرتبطة والوسائط الغنية.

تشتق المعايير الفرعية من الأساس نفسه. يتخلى PDF/A ‏(ISO 19005) عن بعض الميزات لصالح الاستقرار الأرشيفي: لا تشفير، ولا تبعيات لمحتوى خارجي، وكل الخطوط مضمّنة، ومساحات الألوان مستقلة عن الجهاز، وبيانات XMP مطلوبة. PDF/A-1 مبني على PDF 1.4، وPDF/A-2 على PDF 1.7، وPDF/A-3 يسمح بملفات مضمّنة بأي صيغة. PDF/X ‏(ISO 15930) هو مجموعة الطباعة: نوايا الإخراج، ومربعات النزف والقص، ولا شفافية في مستويات المطابقة الأقدم. PDF/UA ‏(ISO 14289) يفرض بنية موسومة، وتعيينات Unicode، وبيانات اللغة من أجل سهولة الوصول. هذه ليست صيغًا متنافسة؛ إنها مجموعات من القيود الإضافية فوق PDF الأساسي، ويمكن لملف واحد أن يطابق أكثر من واحدة منها في الوقت نفسه ما دامت القيود لا تتعارض.

بالنسبة إلى أي شخص يكتب شفرة تولد PDF أو تعالجه، فإن الأساس العملي هو ISO 32000-2 مع الانتباه الدقيق إلى الأقسام التي تغطي نموذج الإسناد المرجعي (§7.5)، وحالة الرسومات (§8.4)، ومعاملات حالة النص (§9.3)، وواصفات الخطوط و ToUnicode (§9.6 و §9.10)، والنماذج التفاعلية (§12.7)، والتواقيع الرقمية (§12.8). المعيار طويل، لكن معظم العمل البرمجي على PDF يلمس شريحة ضيقة منه مرارًا. فهم نموذج الكائنات وآلية الإسناد المرجعي هو نقطة الدخول؛ وما عدا ذلك تخصص ينطلق من هناك.