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

ليس في صفحة PDF فقرات ولا مربعات نص. فيها قائمة تعليمات: في هذا الموضع، بهذا الخط وهذا الحجم، ارسم هذه الحروف المرسومة (glyphs). وتغيير النص يعني حذف التعليمات التي ترسم ذلك السطر وكتابة تعليمات جديدة في الموضع نفسه، بالخط نفسه والحجم نفسه واللون نفسه. ولهذا تحرّر أداة تحرير PDF سطراً واحداً في كل مرة ولا تستطيع التفاف النص إلى السطر التالي: فهذا نتيجة مباشرة لطريقة تخزين النص.
كيف يبدو سطر نص واحد داخل الملف
يقع محتوى الصفحة في تدفق محتوى، وهو برنامج صغير مكوّن من عوامل. أربعة عوامل تؤدي معظم عمل النص: BT وET يحيطان بكتلة نص، وTf يختار الخط وحجمه، وTd ينتقل إلى الموضع التالي، وTj يرسم سلسلة. ومع خط قياسي تبدو أبسط حالة هكذا:
BT /F1 18 Tf 20 150 Td (Hello World) Tj ET
ومعناها: اختر الخط F1 بحجم 18 نقطة، وانتقل إلى x 20 وy 150، وارسم Hello World. أما ملف PDF المطبوع من Chrome فيبدو عادةً مختلفاً: لم تعد الأقواس تحوي محارف بل أرقام الحروف المرسومة من الخط، ويضبط Tm الموضع مرة واحدة. وفيما يلي السطر Hello World from Georgia من صفحة صدّرها Chrome، حيث كل أربع خانات ست عشرية رقم حرف مرسوم واحد:
BT /F4 24 Tf 1 0 0 -1 30 52 Tm <002b0048004f004f00520003003a00520055004f0047000300490055005200500003002a004800520055004a004c0044> Tj ET
002b هو H، و0048 هو e، و004f هو l، و0003 فراغ، و003a هو W، وهكذا. هذه الأرقام لا معنى لها إلا داخل هذا الخط وحده؛ وليست Unicode. وحين تنسخ النص يحوّل العارض الأرقام إلى محارف بجدول بحث مخزّن في موضع آخر من الملف.
وينتج عن ذلك أمران. الأول أنه لا شيء في تدفق المحتوى يقول «هذه فقرة»: فنهاية السطر ليست إلا Td أو Tm آخر ينقل الموضع إلى السطر التالي، وعدد أسطر الفقرة يجب أن يُستنتج من المواضع. والثاني أن كتابة محرف جديد في سطر تتطلب رقم ذلك المحرف في ذلك الخط، وكثيراً ما لا يحوي الخط إلا الحروف المرسومة التي استُعملت عند كتابة الملف. وهذا أثر تجزئة الخطوط.
ويمكنك توسيع التدفقات بـ qpdf:
qpdf --qdf --object-streams=disable in.pdf out.pdf
افتح out.pdf في محرّر نصوص وابحث عن Tj لترى كل سلسلة تُرسم على الصفحة. ولمعرفة ما يحويه ملف PDF غير ذلك، انظر ما بداخل ملف PDF: الكائنات والتدفقات والجدول المرجعي التبادلي.
كيف يعيد المحرّر بناء «سطر» من الحروف المرسومة
على المحرّر أولاً أن يجمع الحروف المرسومة المتفرقة في سطر يستطيع المستخدم النقر عليه. الحروف المرسومة التي لها الخط والحجم واللون نفسها، والتي لا تزيد المسافة بينها وبين الحرف المرسوم السابق على حجم خط واحد، تنتمي إلى القطعة النصية نفسها، أي مجموعة من الحروف المرسومة المتجاورة؛ وتنهيها نهاية السطر أو خط جديد أو لون جديد. أما النص الذي يمتد من اليمين إلى اليسار، أو عمودياً، فلا يُجمَّع ولا يمكن فتحه للتحرير.
ويمكن ملاحظة نتيجتين مباشرة. فالسطر الذي يخلط خطين، مثل سطر صيني فيه كلمة إنجليزية، يُقسَّم إلى قطعتين نصيتين متجاورتين يُنقر عليهما كلٌّ على حدة. ويحدث الأمر نفسه بعد التحرير: إذا استخدم النص الجديد خطاً آخر صار السطر قطعتين، ويترك تحرير أحدهما الآخر دون تغيير.
تحرير سطر: احذف النص القديم ثم اكتب الجديد
يستخدم الحذف الصيغة الخاصة بالنص وحده من أداة «تسويد النص»: تُزال الحروف المرسومة الواقعة في منطقة السطر من تدفق المحتوى، وتُترك الصور وخطوط الرسم، ولا يُرسم مربع ملوّن فوق النص القديم، ولذلك لا يجده النسخ ولا البحث بعد ذلك. وهو يغيّر محتوى الصفحة فقط؛ فإذا ظهر النص نفسه أيضاً في تعليق توضيحي أو في خصائص المستند فلا يتأثر.
وتُلحق الكتابة تعليمة نص جديدة في نهاية تدفق محتوى الصفحة، بادئةً من موضع خط الأساس للسطر الأصلي وبإعادة استخدام حجمه ولونه. وبعد تغيير السطر أعلاه إلى Hello World 2، يكون ما يُلحق في نهاية الصفحة:
q 1 0 0 1 22.5 148.92 cm 0 0 0 rg
/Span <</ActualText <feff00480065006c006c006f00200057006f0072006c006400200032>>> BDC
BT /F4 18 Tf 0 0 Td <002b0048004f004f00520003003a00520055004f00470003> Tj ET
BT /F9 18 Tf 102.18 0 Td (2) Tj ET
EMC
Q
يستخدم أول BT الخط الأصلي F4 وأرقام الحروف المرسومة الأصلية، فيُعاد استخدام Hello World تماماً كما كان. أما «2» فليس في المجموعة الفرعية للخط الأصلي، ولذلك يبدأ BT الثاني خط Helvetica قياسياً جديداً (F9) ليرسمه. ويحصر q وQ تحويل الإحداثيات واللون لهذه الكتلة داخلها؛ ويلفّ المحرّر المحتوى الأصلي أيضاً بزوج q/Q، كي لا تؤثر حالة تُركت غير متوازنة في نهاية الصفحة الأصلية في النص الجديد. هذا ما بدت عليه قطعة نصية واحدة؛ وتختلف الأرقام من ملف إلى آخر.
وللإلحاق في النهاية ثلاث نتائج:
- يُرسم النص الجديد أخيراً، فوق كل ما في الصفحة. والنص الذي كان تحت صورة أو كتلة ملوّنة يظهر فوقها بعد التحرير.
- الأداة التي تستخرج النص بترتيب تدفق المحتوى (مثل
pdftotext -raw) تقرأ السطر المحرَّر أخيراً في تلك الصفحة، بينما لا يُظهر الاستخراج بحسب الموضع (pdftotext -layout) أي تغيير. تبدو الصفحة كما هي، لكن ترتيب القراءة تغيّر. - يُرفق المحرّر بالنص الجديد ActualText، وهو يخبر العارض بالمحارف الحقيقية التي تمثلها الحروف المرسومة. فقد يقابل الحرف المرسوم الواحد عدة محارف، وقد يعيد البحث برقم الحرف المرسوم وحده أحياناً محرفاً توافقياً (مثل قراءة 文 على أنه جذر كانغشي ⽂)؛ ويضمن ActualText أن يكون ما تنسخه هو ما كتبته.
أي خط يرسم النص الجديد
إعادة استخدام الخط الأصلي أسلم خيار، لأن أشكال الحروف المرسومة والوزن والعرض تطابق ما يجاورها. وتتوقف إمكانية إعادة استخدامه على قدرة المحرّر على معرفة الرمز الذي يحمله المحرف في ذلك الخط:
- خط مركّب مثل الخط أعلاه (Type0، أرقام حروف مرسومة من بايتين، ترميز Identity-H): يُبحث عن المحرف في الخط لمعرفة رقم حرفه المرسوم، ويُستخدم إن وُجد. وإن لم يوجد فالمحرف ليس في المجموعة الفرعية.
- خط بسيط ببايت واحد لكل محرف (TrueType، Type1) بترميز WinAnsi أو MacRoman: التقابل بين المحرف والبايت ثابت، وتأتي العروض من جدول العروض في الملف.
- خط بترميز مخصّص (Differences) أو يعتمد على الترميز المدمج في الخط: لا يوجد تقابل موثوق، فلا يخمّن المحرّر ويلجأ إلى خط احتياطي، وإلا خرج النص مشوّهاً.
وحين لا يكون المحرف في الخط الأصلي يُستخدم خط احتياطي. فالحروف اللاتينية العادية تستخدم الأقرب من Helvetica وTimes وCourier، وهي خطوط قياسية موجودة عند كل عارض، فلا حاجة إلى تضمين شيء. وكل ما عداها، مثل المحارف الصينية والكانا والهانغول والتايلاندية واللاتينية المشكَّلة والسيريلية واليونانية، يستخدم خط Noto مفتوح المصدر: يأخذ الخادم المحارف الواردة في الطلب ويقصّ تلك الحروف المرسومة وحدها من الخط الكامل بمكتبة التجزئة المفتوحة المصدر HarfBuzz، وغالباً بضعة KB، ويضمّنها المتصفح في ملفك. ويتبع الشكل الإقليمي للمحرف الصيني لغة الواجهة: المبسّط أو التقليدي أو الياباني أو الكوري.
وتُضمَّن الحروف المرسومة بدل كتابة اسم الخط فقط لأن الخط المشار إليه بالاسم وحده يستبدله كل عارض بما يختاره من خط احتياطي، وقد يختلف الوزن بين العارضين؛ أما بعد التضمين فيعرض كل عارض الأشكال نفسها.
لماذا سطر واحد في كل مرة
ليس للمحرّر محرك تخطيط. فكل موضع حرف مرسوم ثابت في الملف؛ ويُرتَّب النص الجديد ببساطة نحو اليمين من نقطة البدء بعروض الخط، دون منطق «التفاف عند الحافة»، ولا يُنقل شيء بعده. وإذا أطلت سطراً استمرت المحارف الزائدة نحو اليمين، وما يتجاوز حافة الصفحة لا يُرى. أما إعادة كتابة فقرة أو إضافة صفوف إلى جدول فتتطلب تخطيطاً جديداً، أي العودة إلى الملف المصدر الذي صُنع منه ملف PDF.
والعروض أيضاً هي عروض التقدّم التي يحددها الخط نفسه، أي المسافة التي يخصصها لكل حرف مرسوم، دون تقارب حروف (kerning) ودون استبدال حروف مرسومة. والنص الذي لا يحتاج إلى تشكيل النص (text shaping)، أي اختيار الحروف المرسومة وتموضعها بحسب السياق، مثل اللاتينية والسيريلية واليونانية والمحارف الصينية، يُرتَّب صحيحاً. وعلامات النغمة في التايلاندية تحتاج إلى تموضع الحروف المرسومة لتستقر في مكانها الصحيح، وهذا ما لا يفعله المحرّر، فقد تنحرف. والعربية تحتاج إلى أشكال حروف مرسومة تعتمد على السياق وتخطيط من اليمين إلى اليسار، والعبرية تحتاج إلى تخطيط من اليمين إلى اليسار، والكتابات الهندية تحتاج إلى دمج الحروف الصامتة وعلامات الحركات في حروف مرسومة؛ وكل ذلك يتطلب تشكيل نص كاملاً لا يقوم به المحرّر الآن، ولذلك يُرفض إدخالها بدل إنتاج محارف خاطئة.
وهناك حدّان آخران يأتيان من الملف نفسه. فمحتوى الصفحة الممسوحة ضوئياً صورة واحدة بلا عوامل نص، فلا شيء يُحذف أو يُغيَّر. وبعد تحرير ملف عليه توقيع رقمي يتغير المحتوى الأصلي الذي كان التوقيع يحميه، ولا يعود التوقيع صالحاً.
تحقق بنفسك
يمكنك رؤية التغييرات الموصوفة أعلاه في ملف نزّلته بثلاثة أوامر:
pdftotext -raw edited.pdf - # استخراج بترتيب تدفق المحتوى: النص القديم اختفى، والسطر المحرَّر يأتي أخيراً
pdffonts edited.pdf # قائمة الخطوط: الخطوط الأصلية التي أُعيد استخدامها، والمجموعة الفرعية الجديدة المضمّنة
qpdf --qdf --object-streams=disable edited.pdf edited.qdf # توسيع تدفق المحتوى؛ كتلة BT ... ET المُلحقة في النهاية
تابع القراءة
- لماذا تكسر تجزئة الخطوط التحرير لا القراءة: لماذا قد يفتقر الخط الأصلي إلى محرف، وماذا يحدث حين يفتقر إليه.
- ما بداخل ملف PDF: الكائنات والتدفقات والجدول المرجعي التبادلي: الصورة الكاملة لتدفقات المحتوى والكائنات وبنية الملف.
- تحرير النص في ملف PDF عبر الإنترنت: صحّحه دون الملف المصدر: كيفية الاستخدام وما يناسبه ومتى تعود إلى الملف المصدر.