المحتوى الموسوم هو الآلية التي يُعرِّف بها ISO 32000-1 §14.6 لوسم محتوى الصفحة، ومبنيٌّ عليها PDF الموسوم وPDF/UA كلاهما. يكشفها مكوّن PDFium مباشرة: PageObjectMarks يقرأ كل وسم BDC وقائمة خصائصه من كائن صفحة، AddPageObjectMark يكتب واحدًا، RemovePageObjectMark يحذف واحدًا، وPageObjectMarkedContentID يُبلِّغ عن MCID الذي يربط المحتوى بشجرة البنية
حتى تستطيع شجرة البنية أن تُربَط بالمحتوى الذي تصفه، أدوات الوصول مجرد تخمين. تقول شجرة البنية «هذا عنوان»؛ MCID يقول أي وسوم على أي صفحة هو ذلك العنوان فعلًا. يجب أن يكون النصفان قابلين للقراءة كلاهما قبل أن يستطيع تطبيق أن يتحقق من الوسم أو يُصلحه أو يُبلِّغ عنه
ما هو الوسم، بالبايتات؟
عامل تشغيل BDC مع اسم وسم وقائمة خصائص اختيارية، يُغلَق بـ EMC. في دفق المحتوى يبدو كـ /P <</MCID 3>> BDC ... EMC: يسمّي الوسم /P الدور، يحمل القاموس الخصائص، وكل شيء بين العاملين هو المحتوى الموسوم. كائن صفحة داخل ذلك الامتداد يحمل الوسم، وهذا ما يُعيده PDFium وما يحوّله مكوّن PDFium إلى سجل
يحمل TPdfContentMark مقبضًا، والوسم Name، ومصفوفة من TPdfContentMarkParam. لكل وسيط Key وKind وحقل قيمة ذو معنى واحد يُختار بذلك النوع: pmpInt أو pmpFloat أو pmpString أو pmpBlob. يأتي النوع من تقرير نوع PDFium الخاص لا من أي getter نجح، وهذا هو الفرق بين قراءة قائمة خصائص والتخمين عن واحدة
var
Marks: TPdfContentMarks;
M: TPdfContentMark;
P: TPdfContentMarkParam;
I: Integer;
begin
Pdf.PageNumber := 1; // PageNumber is 1-based
for I := 0 to Pdf.ObjectCount - 1 do // page object indexes are 0-based
begin
Marks := Pdf.PageObjectMarks(I);
for M in Marks do
begin
Memo1.Lines.Add('mark ' + M.Name +
' (MCID ' + IntToStr(Pdf.PageObjectMarkedContentID(I)) + ')');
for P in M.Params do
case P.Kind of
pmpInt: Memo1.Lines.Add(' ' + P.Key + ' = ' + IntToStr(P.IntValue));
pmpString: Memo1.Lines.Add(' ' + P.Key + ' = ' + P.StringValue);
pmpFloat: Memo1.Lines.Add(' ' + P.Key + ' = ' + FloatToStr(P.FloatValue));
pmpBlob: Memo1.Lines.Add(' ' + P.Key + ' = ' +
IntToStr(Length(P.BlobValue)) + ' bytes');
end;
end;
end;
end;
لماذا يعني pmpUnknown شيئين مختلفين
يُعاد pmpUnknown حين يُبلِّغ PDFium عن FPDF_OBJECT_UNKNOWN، ويعيد PDFium ذلك أيضًا لمفتاح غير موجود. لا يمكن تمييز الحالتين عند هذه الطبقة، والادعاء بغير ذلك أسوأ من قول ذلك
النتيجة العملية لكودك: تعامل مع pmpUnknown كـ «لا قيمة قابلة للاستخدام هنا» لا كنوع قد تفك شفرته على أي حال. إن كانت خاصية تهم سير عملك، تحقق من وجودها بنوع تعرفه، ولا تستنتج الغياب من واحد مجهول — وسم قائمة خصائصه لا تستطيع قراءته وسم ينبغي أن تُبلِّغ عنه، لا أن تقبله بصمت
سجل الوسم لقطة، لا مقبض تملكه
حقل Handle يخص المكتبة. يصبح باليًا لحظة يُزال فيها الوسم، أو يُدمَّر كائن الصفحة، أو تُفرَّغ الصفحة، فالسجل لقطة قراءة فقط بعمر قصير. خزّنه عبر تبديل صفحة وأنت تمسك مؤشرًا إلى ذاكرة استعادها المحرّك
هذا هو الانضباط نفسه الذي ينطبق على مقابض كائن الصفحة عمومًا في PDFium، ويصطاد الناس في المكان نفسه: قائمة تحكم عُمرت بسجلات وسوم، مستخدم يتنقل إلى صفحة أخرى، وانهيار يبدو غير مرتبط بالتنقل. انسخ القيم التي تحتاجها — الاسم، والمفاتيح، والأرقام — ودع المقبض يذهب. تغطي ملاحظات مقابض كائن الصفحة التي تصبح بالية بعد تحويل القاعدة العامة وكيف تعض في مكان آخر
إضافة وسم، وخطوة الحفظ السهل تفويتها
يأخذ AddPageObjectMark فهرس كائن الصفحة، واسم وسم، ومجموعة وسيطات كاملة. تُكتَب الوسائط كمجموعة لا يُرقَّع مفتاح واحد في كل مرة، ولهذا لا توجد Has* حراس على TPdfContentMarkParam — حالة «تحديث حقل واحد من سجل قائم» التي تحرسها تلك لا تنشأ
الجزء الذي يستحق البيان صراحةً: إضافة وسم يعيد بناء دفق محتوى الصفحة كي ينجو الوسم من الحفظ. كان هذا لزامًا صريحًا لأن SaveAs لا يُولِّد المحتوى بنفسه — تغيير عاش في نموذج الكائن فقط يُهمَل، ويبدو الملف المحفوظ تمامًا كالذي بدأت به. إن أضفت شيئًا يومًا إلى صفحة PDFium ووجدته مفقودًا من الإخراج، فهذا عادةً السبب
var
Params: TPdfContentMarkParams;
begin
SetLength(Params, 1);
Params[0].Key := 'MCID';
Params[0].Kind := pmpInt;
Params[0].IntValue := NextMcid;
Pdf.AddPageObjectMark(ObjectIndex, 'P', Params); // rebuilds the content stream
Pdf.UpdatePage;
Pdf.SaveAs('tagged-out.pdf');
end;
ماذا يفعل هذا وماذا لا يجعل المستند
الوسوم وحدها لا تصنع PDF موسومًا. مستند موسوم مطابق يحتاج شجرة بنية عناصرها تشير إلى هذه MCIDs، ومدخل /MarkInfo يصرّح بأن المستند موسوم، وأسماء أدوار تعني ما يقوله المعيار. كتابة وسم /P مع MCID لا يشير إليه عنصر بنية تمنحك محتوى يدّعي أنه موسوم وشجرة بنية لا تذكره إطلاقًا
حيث يكسب المحتوى الموسوم رزقه فعلًا عند هذا المستوى هو الفحص والإصلاح: تدقيق أي كائنات صفحة موسومة، إيجاد عناصر زخرفية كان ينبغي أن تُعلَّم كذلك، أو مطابقة MCIDs مقابل شجرة بنية لإيجاد اليتامى. لنصف شجرة البنية من ذلك العمل، انظر شرح تحقق شجرة بنية PDF/UA، ولتجربة القراءة التي الوسوم من أجلها في النهاية، ملاحظات بناء قارئ PDF قابل للوصول في Delphi
يمنح مكوّن PDFium تطبيقات Delphi وC++Builder وLazarus واجهة VCL عالية المستوى فوق محرّك PDFium، مع المحتوى الموسوم وأشجار البنية والتحقق من الوصول قابلة للوصول من كود Pascal عادي — انظر صفحة منتج مكوّن PDFium لسطح API الكامل