ما حقيقة ملف PDF
ISO 32000-2 §7 Evidence: Standard-backed
لمحة سريعة
قسم بعنوان «لمحة سريعة»ملف PDF ليس وصفًا لصفحة صادف أن وُضع داخل ملف. إنه قاعدة بيانات رسومية صغيرة مقترنة بطابعة. تصف هذه الصفحة الأجزاء الأربعة التي يتكوّن منها كل ملف PDF — الترويسة، والجسم، وجدول المراجع المتقاطعة، والذيل — وكيف يكتبها NextPDF بحيث يستطيع القارئ العثور على كل كائن دون تخمين.
لماذا يهم هذا
قسم بعنوان «لماذا يهم هذا»معظم عيوب PDF ليست عيوب عرض. إنها عيوب بنية: إزاحة بايت تشير إلى موضع يبتعد حرفًا واحدًا عن الكائن الذي يُفترض أن تشير إليه، أو ذيل يسمّي الجذر الخطأ، أو مدخل في المراجع المتقاطعة لا يطابق الموضع الفعلي للكائن. لا يغيّر أيٌّ من ذلك شكل الصفحة إلى أن يسلك القارئ مسارًا مختلفًا عبر الملف فيتجاوز نهايته.
إذا تعاملت مع PDF بوصفه صندوقًا مغلقًا، بدت تلك الإخفاقات عشوائية. وإذا عرفت نموذج الكائنات، ظهرت كما هي فعلًا: رقم لا يطابق موضعًا. فهم التنسيق هو الفارق بين “ملف PDF تالف” و”إزاحة الكائن 14 قديمة لأن الكاتب قاسها قبل إنهاء طول الدفق.”
النسخة المختصرة
قسم بعنوان «النسخة المختصرة»يتألف ملف PDF من أربعة أجزاء، بترتيب الملف:
- ترويسة — سطر واحد يسمّي الإصدار (
%PDF-2.0). - جسم — تسلسل من الكائنات غير المباشرة المرقّمة: قواميس، ودفقات، ومصفوفات، وأرقام، وسلاسل نصية، وأسماء.
- جدول مراجع متقاطعة (أو، في PDF 2.0، دفق مراجع متقاطعة) — بحث يربط رقم الكائن بإزاحة البايت، بحيث يمكن الوصول إلى أي كائن دون مسح الملف.
- ذيل — قاموس صغير يسمّي الكائن الجذر للمستند ويشير إلى موضع بدء قسم المراجع المتقاطعة.
لا يقرأ القارئ ملف PDF من بدايته إلى نهايته. بل يقرأ السطر الأخير أولًا، ويعثر على startxref، ويقفز إلى قسم المراجع المتقاطعة، ثم يستخدمه فهرسًا للجسم. لقد صُمّم التنسيق ليُقرأ من نهايته. وهذه الحقيقة وحدها تفسّر معظم تصميمه.
كيف يتعامل NextPDF معه
قسم بعنوان «كيف يتعامل NextPDF معه»يبني NextPDF ملف PDF بالطريقة التي يُقرأ بها التنسيق: الكائن أولًا، ثم تسجيل الإزاحة بعده، ثم كتابة الجدول أخيرًا.
يُخصَّص لكل كائن غير مباشر رقمٌ من سجلّ واحد (src/Core/ObjectRegistry.php). يوزّع السجلّ أرقامًا متتالية عبر allocate()، ويسجّل إزاحة البايت — بعد كتابة بايتات الكائن إلى مخزن الإخراج — عبر register(). لا تُخمَّن الإزاحات مسبقًا أبدًا، بل تُلتقط من BinaryBuffer::getOffset() لحظة إصدار ترويسة الكائن. ولهذا لا يمكن لمدخل المراجع المتقاطعة في NextPDF أن ينحرف عن الكائن الذي يصفه: فالإزاحة هي موضع المخزن الفعلي كما هو.
عند اكتمال الجسم، تتولى استراتيجية تسلسل خاصة بالإصدار (src/Writer/PdfSerializationStrategy.php) كتابة قسم المراجع المتقاطعة والذيل:
- يُصدِر
Pdf20StreamStrategyدفق مراجع متقاطعة مضغوطًا (/Type /XRef) — وهو السلوك الافتراضي في PDF 2.0. - يُصدِر
Pdf17TableStrategyوPdf14TableStrategyجدول مراجع متقاطعة تقليديًّا بحجم 20 بايت إضافة إلى قاموس ذيل منفصل — وهو ما تتطلبه ملفات تعريف PDF/A التي تفرض بنية ملف أقدم.
تُختار الاستراتيجية بحسب ملف الإخراج، لا بالاستنتاج. وأيًّا كانت الاستراتيجية، فإن البايتات النهائية تأخذ الشكل ذاته: قسم المراجع المتقاطعة، ثم startxref، ثم إزاحة البايت، ثم %%EOF. وهذا الذيل هو ما يجده القارئ أولًا.
- Step 1 of 4: ISO 32000-2 §7.5.5 — %%EOF and startxref at the file end
- Step 2 of 4: ISO 32000-2 §7.5.4 / §7.5.8 — the cross-reference section maps object number to offset
- Step 3 of 4: ISO 32000-2 §7.5.5 — the trailer names /Root, the document catalog
- Step 4 of 4: ISO 32000-2 §7.3.10 — each indirect object is reached at its recorded offset
ما تقوله الأدلة
قسم بعنوان «ما تقوله الأدلة»البنية رباعية الأجزاء ليست عُرفًا خاصًّا بـNextPDF؛ بل هي جزء من بنية الملف في Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 . يعرّف المعيار ملف PDF بأنه ترويسة، وجسم من الكائنات، وجدول مراجع متقاطعة، وذيل، وينصّ على أن القارئ ينبغي أن يحلّل الملف من نهايته. السطر الأخير هو %%EOF، والسطران السابقان له هما الكلمة المفتاحية startxref وإزاحة البايت إلى قسم المراجع المتقاطعة.
يُعرَّف الكائن غير المباشر بأنه رقم كائن ورقم جيل، يفصل بينهما فراغ، تليهما قيمة الكائن محصورة بين الكلمتين المفتاحيتين obj وendobj. يحدّد الجمع بين رقم الكائن ورقم الجيل الكائنَ على نحو فريد؛ وتُكتب الإشارة غير المباشرة إليه برقم الكائن، ورقم الجيل، والكلمة المفتاحية R. يحاكي ObjectRegistry الخاص بـNextPDF هذا تمامًا: رقم متتالٍ، والجيل 0 للكائنات المكتوبة حديثًا، وإزاحة مسجَّلة.
يسمح PDF 1.5 فما بعده أيضًا بأن توجد الكائنات داخل دفق كائنات، حيث تُخزَّن من دون الكلمتين المفتاحيتين obj/endobj ويجب أن يكون جيلها صفرًا. إن دفق المراجع المتقاطعة (/Type /XRef،
Spec: ISO 32000-2, §7.5.8 ISO 32000-2 §7.5.8 ) هو آلية PDF 2.0
التي تفهرس الكائنات العادية وهذه الكائنات المضغوطة معًا.
يبني CrossReferenceStream الخاص بـNextPDF ذلك باستخدام مصفوفة عرض حقول /W و
ضغط FlateDecode.
مثال عملي
قسم بعنوان «مثال عملي»هذا هو شكل أبسط جسم PDF مع ذيله. الأرقام في قسم المراجع المتقاطعة هي إزاحات بايت. يجب أن تكون صحيحة تمامًا، ولهذا يسجّلها NextPDF من المخزن بدلًا من حسابها.
%PDF-2.01 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj2 0 obj<< /Type /Pages /Kids [3 0 R] /Count 1 >>endobj3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] >>endobjxref0 40000000000 65535 f0000000009 00000 n0000000058 00000 n0000000122 00000 ntrailer<< /Size 4 /Root 1 0 R >>startxref196%%EOFيفتح القارئ هذا الملف من الأسفل: %%EOF، ثم startxref 196، ثم يقفز إلى البايت 196 حيث يبدأ xref، فيقرأ أن الكائن 1 يقع عند البايت 9، ويتبع /Root 1 0 R إلى الفهرس، ثم يسير في شجرة الصفحات من هناك. الكائن 0 هو دائمًا رأس قائمة الكائنات الحرة بالجيل 65535 — وهي خصوصية موروثة من أقدم تصاميم التنسيق، تُعاد بأمانة لأن القرّاء يتوقعونها.
مفهوم خاطئ شائع
قسم بعنوان «مفهوم خاطئ شائع»الفخّ هو الاعتقاد بأن ملف PDF يُقرأ من الأعلى إلى الأسفل كالشيفرة المصدرية. لكنه لا يُقرأ بهذه الطريقة. يمكن أن يرتّب الجسم الكائنات بأي تسلسل. لا يلزم أن تكون أرقام الكائنات متتالية في الملف، ولا يعتمد القارئ مطلقًا على كونها كذلك. الفهرس الموثوق الوحيد هو قسم المراجع المتقاطعة، والطريق الوحيد للعثور عليه هو الذيل في النهاية. ملف PDF بجسم سليم تمامًا ورقم واحد خاطئ في startxref غير قابل للقراءة. وملف PDF بكائنات مكتوبة بترتيب مشوّش لكن بجدول مراجع متقاطعة صحيح هو ملف سليم. الموضع لا معنى له؛ الموضع المسجَّل هو كل شيء.
الحدود والقيود
قسم بعنوان «الحدود والقيود»تصف هذه الصفحة بنية الملف، لا محتوى الصفحة. أما كيفية وصول العلامات إلى الصفحة — دفقات المحتوى، ومُعامِلات الرسومات، وعرض النص — فهي موضوع منفصل. كما لا تتناول ما يحدث عندما يُغيَّر ملف بعد كتابته. فتلك مهمة التحديثات التزايدية، حيث يُلحق الكاتب قسم مراجع متقاطعة ثانيًا ويتسلسل الذيل إلى الوراء.
NextPDF هو كاتب. والسلوك الموصوف هنا هو كيفية تسلسله لمستند بناه. إنه ليس محلّل PDF عام الأغراض ولا أداة إصلاح. وهو لا يَعِد بقراءة ملف عشوائي من طرف ثالث بجدول مراجع متقاطعة تالف أو إعادة بنائه أو إنقاذه. الضمان ضيّق ومقصود. الملفات التي يكتبها NextPDF لها إزاحات متطابقة، لأنها مقاسة لا متوقعة.
أسئلة شائعة موجزة
قسم بعنوان «أسئلة شائعة موجزة»لماذا أرقام الأجيال إذا كانت الملفات الجديدة تستخدم 0 دائمًا؟ توجد أرقام الأجيال لإعادة استخدام الكائنات عبر التحديثات. في الملف المكتوب حديثًا يكون كل كائن عند الجيل 0. ولا تظهر الأجيال غير الصفرية إلا عندما يُحدَّث ملف تزايديًّا ويُعاد تدوير رقم كائن.
هل يمكن لكائنين أن يحملا الرقم نفسه؟ ضمن قسم مراجع متقاطعة واحد، لا. وعبر التحديثات التزايدية يمكن أن يحتوي الملف فعليًّا على عدة نسخ من رقم الكائن نفسه. ويُعتمد أحدث مدخل في المراجع المتقاطعة. وذلك موضوع الصفحة التالية.
هل يهم ترتيب الكائنات في الملف بالنسبة إلى الإخراج؟ لا. يكتب NextPDF الكائنات بترتيب حتمي لبناءات قابلة لإعادة الإنتاج، لكن القارئ يحلّ كل شيء عبر قسم المراجع المتقاطعة، لذلك لا يحمل الترتيب الفعلي معنى دلاليًّا.
مستندات ذات صلة
قسم بعنوان «مستندات ذات صلة»- التحديثات التزايدية ولماذا تهم — ما يحدث عندما يُغيَّر ملف PDF مكتوب: أقسام مُلحقة وذيل متسلسل إلى الوراء.
- الدفقات والمرشّحات — كيف تُضغط كائنات الدفق في الجسم وتُرمَّز.
- PDF 2.0: ما الذي تغيّر — كيف تختلف بنية الملف بين 1.7 وخط أساس 2.0 الذي يستهدفه NextPDF.
مسرد المصطلحات
قسم بعنوان «مسرد المصطلحات»- الكائن غير المباشر — كائن مرقّم في الجسم، يُكتب على هيئة
N G obj … endobj، حيثNرقم الكائن وGرقم الجيل. - الإشارة غير المباشرة — مؤشّر إلى كائن غير مباشر، يُكتب
N G R. - جدول المراجع المتقاطعة (xref) — الفهرس من رقم الكائن إلى إزاحة البايت. في PDF 2.0 يكون هذا عادةً دفق مراجع متقاطعة (
/Type /XRef) بدلًا من الجدول النصي الكلاسيكي بحجم 20 بايت لكل مدخل. - الذيل — القاموس في نهاية قسم المراجع المتقاطعة الذي يسمّي
/Root(فهرس المستند) و/Size، ويُعثَر عليه عبر إزاحةstartxref. - دفق الكائنات — كائن دفق يحتوي بنفسه على كائنات غير مباشرة أخرى (مضغوطة معًا)؛ ليس لأعضائه
obj/endobjوجيلها صفر. - فهرس المستند — الكائن الذي يسمّيه
/Root؛ نقطة الدخول إلى شجرة الصفحات وسائر أجزاء المستند.