كيفية العمل مع تعليقات PDF في C++
Aspose.PDF FOSS لـ C++ يمثل كل تعليقة PDF كفئة فرعية من الفئة الأساسية المشتركة Annotation، ويكشف التعليقات على الصفحة عبر AnnotationCollection الذي تُعيده Page::Annotations(). يضيف هذا الدليل تعليقة ملاحظة نصية عادية وتعليقة منسقة إلى صفحة باستخدام TextAnnotation، يحفظ المستند، ثم يفتحه مرة أخرى لقراءة التعليقات وإزالة واحدة. يتم دمج المكتبة في مشروع CMake كاعتماد فرعي — لا توجد خطوة تثبيت عبر سجل الحزم.
دليل خطوة بخطوة
الخطوة 1: تثبيت الحزمة
أضف المكتبة كدليل فرعي في CMake واربط هدف المكتبة الثابتة:
add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)تحقق من أن سلسلة الأدوات وخطوة الربط تحلان بشكل صحيح باستخدام برنامج بسيط:
#include <aspose/pdf/document.hpp>
#include <iostream>
int main() {
Aspose::Pdf::Document doc;
std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}بناء ناجح يطبع pages: 0 يؤكد أن المكتبة مرتبطة.
الخطوة 2: استيراد الفئات المطلوبة
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/page_collection.hpp>
#include <aspose/pdf/rectangle.hpp>
#include <aspose/pdf/color.hpp>
#include <aspose/pdf/annotations/annotation.hpp>
#include <aspose/pdf/annotations/annotation_collection.hpp>
#include <aspose/pdf/annotations/annotation_type.hpp>
#include <aspose/pdf/annotations/annotation_flags.hpp>
#include <aspose/pdf/annotations/border.hpp>
#include <aspose/pdf/annotations/border_style.hpp>
#include <aspose/pdf/annotations/text_annotation.hpp>
using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Annotations;الخطوة 3: إنشاء مستند وإضافة صفحة
أنشئ مستندًا جديدًا وأضف صفحة إليه. PageCollection::Add() يعيد الـ Page المضاف حديثًا:
Document doc;
Page page = doc.Pages().Add();الخطوة 4: إضافة تعليق نصي إلى الصفحة
TextAnnotation يُعرض كتعليق على نمط الملاحظات اللاصقة. أنشئه من الـ Document المالك، عيّن موقعه باستخدام Rect() ورسالةه باستخدام Contents()، ثم أضفه إلى AnnotationCollection الخاص بالصفحة:
TextAnnotation note{doc};
note.Rect(Rectangle(100.0, 700.0, 200.0, 720.0, false));
note.Contents("Reviewed and approved.");
page.Annotations().Add(note);الخطوة 5: تنسيق التعليق الثاني باللون، والحد، والأعلام
Annotation يكشف أيضًا عن Color() وBorder() وFlags(). Flags() يأخذ حقل بتات AnnotationFlags — اجمع القيم باستخدام OR البتية لتحديد أكثر من علم في وقت واحد:
TextAnnotation flagged{doc};
flagged.Rect(Rectangle(100.0, 600.0, 300.0, 650.0, false));
flagged.Contents("Needs follow-up");
flagged.Color(Color::FromRgb(220, 20, 20));
flagged.Flags(AnnotationFlags::Print | AnnotationFlags::ReadOnly);
flagged.Border().Width(2);
flagged.Border().Style(BorderStyle::Dashed);
page.Annotations().Add(flagged);الخطوة 6: حفظ المستند
لا يتم كتابة أي شيء إلى القرص حتى يتم تشغيل Save():
doc.Save("annotated.pdf");الخطوة 7: إعادة فتح ملف PDF وقراءة تعليقاته التوضيحية
أعد فتح الملف المحفوظ واقرأ AnnotationCollection للصفحة الأولى مرة أخرى. AnnotationCollection يبدأ من الصفر، وCount() يوضح عدد التعليقات التوضيحية التي تحتويها الصفحة:
Document reopened("annotated.pdf");
auto& annots = reopened.Pages()[1].Annotations();
std::cout << "Annotation count: " << annots.Count() << "\n";
for (int i = 0; i < annots.Count(); ++i) {
const auto& a = annots[i];
if (a.AnnotationType() == AnnotationType::Text) {
std::cout << "Text annotation: " << a.Contents() << "\n";
}
}الخطوة 8: إزالة تعليق توضيحي وإعادة الحفظ
AnnotationCollection::Delete(index) يزيل تعليقًا توضيحيًا وفقًا لموقعه الذي يبدأ من الصفر. احذف أول تعليق توضيحي واحفظ النتيجة في ملف جديد:
annots.Delete(0);
reopened.Save("annotated-cleaned.pdf");المشكلات الشائعة والإصلاحات
لا يحدث أي تغيير في ملف PDF المحفوظ بعد الاستدعاء Annotations().Add()
شئان غالبًا ما يخطئان هنا. أولاً، PageCollection يعتمد على الفهرسة من 1 (doc.Pages()[1] هي الصفحة الأولى) بينما AnnotationCollection يعتمد على الفهرسة من 0 (annots[0] هو التعليق الأول) — خلط نظامي الفهرسة يؤدي إلى العمل على الكائن الخطأ. ثانيًا، تأكد من أن Document::Save() يتم تشغيله فعليًا بعد إضافة التعليق؛ لا شيء يُكتب إلى القرص حتى ذلك الحين.
AnnotationCollection الفهرسة أو Delete(index) throws std::out_of_range
المؤشرات الصالحة تتراوح من 0 إلى Count() - 1. تمرير مؤشر سالب أو مؤشر يساوي أو أكبر من Count() يُلقي std::out_of_range عن قصد. استدعِ Count() أولاً لتحديد حدود أي حلقة أو بحث.
Remove() returns false المرة الثانية التي أستدعيه فيها على نفس التعليق التوضيحي
هذا ليس خطأ. Remove() يبلّغ ما إذا تم العثور على التعليق وإزالته كـ bool; استدعاؤه مرة أخرى على تعليق تم حذفه بالفعل لا يؤدي إلى أي عملية ويُعيد false. تحقق من قيمة الإرجاع بدلاً من الافتراض أن Remove() ينجح دائمًا.
تعيين جديد AnnotationFlags القيمة تمسح العلامات التي كنت قد ضبطتها بالفعل
Flags(value) يستبدل مجموعة العلامات بالكامل — لا يدمج مع القيمة السابقة. لإضافة أو مسح علامة واحدة، اقرأ العلامات الحالية أولاً ودمجها باستخدام عوامل البت، على سبيل المثال a.Flags(a.Flags() | AnnotationFlags::Print) لإضافة علامة، أو a.Flags(a.Flags() & ~AnnotationFlags::Print) لمسح علامة واحدة مع ترك البقية دون تغيير.
الأسئلة المتكررة
ما هي العلاقة بين Annotation، TextAnnotation، وأنواع التعليقات التوضيحية الأخرى؟
Annotation هي الفئة الأساسية المشتركة. TextAnnotation وأنواع التعليقات التوضيحية الملموسة الأخرى كل منها يخصصها لنوع فرعي واحد من تعليقات PDF التوضيحية، مع مشاركة وصولات Rect()، Contents()، Color()، Flags()، وBorder() الخاصة بالفئة الأساسية.
هل يتم تحديد نطاق التعليقات التوضيحية للوثيقة بأكملها أم لصفحة واحدة؟
كل صفحة لديها AnnotationCollection الخاصة بها، والتي تُرجِعها طريقة Annotations() لتلك الصفحة. تكون التعليقات التوضيحية دائمًا محصورة في الصفحة التي أضيفت إليها، لا في الوثيقة ككل.
كيف أحسب عدد التعليقات التوضيحية الموجودة في صفحة؟
استدعِ Count() على AnnotationCollection التي تُرجِعها Page::Annotations().
هل يمكن أن تكون التعليق التوضيحي قابلة للطباعة وقراءة فقط في نفس الوقت؟
نعم. AnnotationFlags هو حقل بت، لذا يمكنك دمج القيم باستخدام OR البتية، على سبيل المثال AnnotationFlags::Print | AnnotationFlags::ReadOnly.
هل يؤدي حذف التعليق التوضيحي من AnnotationCollection إلى إزالته من ملف PDF على القرص؟
فقط بعد تشغيل Document::Save(). Delete() وRemove() وClear() تعدل فقط المجموعة في الذاكرة — يبقى ملف PDF على القرص دون تغيير حتى يتم حفظ المستند.