التعليقات التوضيحية
إضافة دعم التعليقات التوضيحية إلى العارض
تعمل التعليقات التوضيحية في Doconut في اتجاهين: يرسمها المستخدمون في أداة المتصفح ويقوم الخادم بحفظها لكل صفحة، أو يبنيها الكود الخاص بك برمجياً ويحمّلها في جلسة مفتوحة. في كلتا الحالتين تُعرض على الصفحات ويمكن دمجها في تصديرات PDF/PNG.
يتم التحكم في دعم التعليقات التوضيحية عبر قدرة الترخيص Annotation (تُمنح تلقائياً بموجب ترخيص مؤقت نشط).
تمكين واجهة المستخدم للتعليقات التوضيحية
التعليق التوضيحي هو وحدة في العارض، وليس شريط أدوات مستقل. يجب أن تشمل الصفحة الكاملة موارد العارض، شريط أدوات العارض، تثبيت العارض، وobjViewer المُهيأ؛ ثم يتم تثبيت شريط التعليقات التوضيحية وربطه بنفس المثيل.
قم بإصدار حزم التعليقات التوضيحية جنباً إلى جنب مع حزم العارض — فهي محكومة بالترخيص، لذا تظهر العلامات فقط عندما تكون القدرة متاحة:
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeViewerCss = true,
IncludeAnnotationCss = true // jquery-ui.min.css + annotationBar.css
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeViewerScripts = true,
IncludeAnnotationScripts = true, // jquery-ui, raphael.js, annotation.js
IncludeAnnotationBar = true // the embedded annotation ribbon
}))احفظ تركيبة العارض الكاملة مرئية في العلامات:
<nav id="toolbar" aria-label="Document viewer controls">
<!-- Viewer controls, including the button that opens Annotation -->
</nav>
<div id="annBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>تُنشئ حزمة التعليقات التوضيحية شريط الـ Ribbon داخل annBarMount؛ لا تحتاج إلى نسخ أزراره أو علامات الحوار. قم بتهيئة docViewer أولاً، ثم أنشئ الـ Ribbon فقط عندما يؤكد الخادم أن التعليق التوضيحي مرخص:
<script>
let annBar = null;
let currentToken = '';
const objViewer = $('#div_ctlDoc').docViewer({
BasePath: '/',
ResPath: 'doconut-res/images',
onAnnLoaded: () => annBar?.handleAnnLoaded(),
onAnnSaved: () => annBar?.handleAnnSaved(),
onAnnSaveError: () => annBar?.handleAnnSaveError(),
onAnnClosed: () => annBar?.handleAnnClosed(),
onError: (message) => console.error('Viewer error:', message)
});
@if (Viewer.IsAnnotationEnabled)
{
<text>
annBar = $('#annBarMount').doconutAnnotationBar({
docId: 'ctlDoc',
getRequestParams: () => ({ token: currentToken }),
onStatus: (message) => console.log(message),
onToast: (message, type) => console.log(type, message),
onLayout: () => requestAnimationFrame(() => objViewer.Refit())
});
annBar.attach(objViewer);
</text>
}
</script>يقوم الحفظ من الـ Ribbon بإرسال البيانات عبر الطبقة الوسيطة (AnnSave)، التي تخزنها في جلسة المستند لكل صفحة. يتم التحميل (AnnLoad) تلقائياً عندما يتم عرض صفحة تحتوي على تعليقات توضيحية. تحافظ الاستدعاءات الأربعة onAnn* على تزامن الـ Ribbon مع دورة حياة العارض.
افتحه وأغلقه من أي شريط أدوات عارض مملوك للمضيف:
annBar.open();
annBar.close();واجهة برمجة التطبيقات العامة للـ Ribbon هي:
| الطريقة | الغرض |
|---|---|
attach(objViewer) | ربط الـ Ribbon بالعارض المُهيأ؛ مطلوب مرة واحدة |
open() / close() | دخول أو الخروج من تحرير التعليقات التوضيحية |
reset() | إعادة الـ Ribbon إلى حالته المغلقة غير القابلة للتحرير |
isOpen() / annotating() | قراءة حالة الـ Ribbon / حالة تحرير التعليقات التوضيحية في العارض |
reopenEditable() | إعادة تحميل تعليقات الصفحة الحالية ككائنات قابلة للتحرير |
updateActionState() | تحديث توفر عناصر التحكم بالحفظ/الحذف بعد تغييرات المضيف |
headerSlot() | الحصول على فتحة التوسيع الاختيارية في الرأس للتحكمات المملوكة للمضيف |
onStatus، onToast، onLayout، onEditStart، وonEditEnd هي استدعاءات اختيارية من المضيف. يمكن لكائن endpoints أن يوفر إضافياً exportPdf، exportPng، imageUpload، وimageList؛ تظل عناصر التحكم التي لا تملك نقطة نهاية مُكوَّنة مخفية. لسلسلة بدء تشغيل العارض المشترك مع البحث والتعليقات التوضيحية، راجع البدء السريع.
تضيف حزمة التعليقات التوضيحية أدوات التأليف في المتصفح، لكن البيانات لا تزال تابعة لجلسة المستند على الخادم المحددة بالرمز المميز. إعادة فتح المصدر تُنشئ جلسة جديدة؛ احفظ ملف XML أو الغلاف المشفر للتعليقات التوضيحية في تطبيقك إذا كان يجب أن تبقى التعليقات بعد انتهاء مدة الجلسة.
بناء التعليقات التوضيحية في C#
احصل على مدير مرتبط بالجلسة المفتوحة، أضف التعليقات التوضيحية، وحمّلها (باستخدام using Doconut.Annotations; للأنواع و using System.Drawing; لـ Rectangle/Color):
app.MapPost("/api/annotations/load-sample", (string token, Viewer viewer) =>
{
// Bound to the open session's page dimensions
var manager = viewer.GetAnnotationManager(token);
var pageCount = viewer.GetPageCount(token);
// One stamp per page
for (int page = 1; page <= pageCount; page++)
{
manager.Add(new StampAnnotation(page, new Rectangle(30, 20, 240, 90),
$"PAGE {page}", 28, 4, Color.Maroon)
{
Opacity = 60,
Rotate = -8
});
}
manager.Add(new NoteAnnotation(1, new Rectangle(420, 150, 220, 120),
"Loaded from C# code.", Color.FromArgb(255, 255, 255, 170), 14));
// Load into the session — the widget fetches them via AnnLoad and the
// renderer burns them into image/PDF exports.
viewer.LoadAnnotationData(token, manager);
return Results.Ok();
});أنواع التعليقات التوضيحية
جميع الأنواع موجودة في Doconut.Annotations وتورّث من BaseAnnotation (رقم الصفحة + Rectangle المحدد):
| Type | Notes |
|---|---|
StampAnnotation | ختم نصي مع حجم الخط، الحدود، اللون؛ يدعم Opacity، Rotate |
NoteAnnotation | ملاحظة لاصقة مع نص، لون خلفية، حجم خط، TitleColor |
RectangleAnnotation | ألوان الحدود والملء، Title/ShowTitle |
CircleAnnotation | حدود + تعبئة، ShowBorder |
EllipseAnnotation | حدود + تعبئة، ShowBorder |
TriangleAnnotation | لون الحدود، BackColor، ShowBorder |
LineAnnotation | خط مستقيم بعرض ولون |
ArrowAnnotation | خط مع رأس سهم؛ يمكن ضبط Direction (من نوع ArrowDirection، نقاط البوصلة، الافتراضي E) |
FreehandAnnotation | ضربة حرة من نقاط FreehandData المشفرة |
ImageAnnotation | صورة من عنوان URL. يتم حل عنوان URL نسبي بالنسبة لمضيف الطلب عند إضافة التعليق التوضيحي (يتم جلب الصورة فقط عند الحرق) — يجب أن يكون قابلًا للوصول من الخادم (مثلاً ملف تحت wwwroot يُقدم بواسطة UseStaticFiles) |
واجهة برمجة تطبيقات AnnotationManager
| Member | Purpose |
|---|---|
Add(BaseAnnotation) | إضافة تعليق توضيحي إلى قائمة الانتظار |
GetAnnotations() / GetAnnotations(int page) | فحص ما يحتفظ به المدير |
ClearAnnotations() / ClearAnnotations(int page) | إزالة جميع التعليقات / حسب الصفحة |
GetAnnotationData() / GetAnnotationData(int page) | سلسلة بيانات التعليقات المشفرة — غلاف Base64 (ما يستهلكه الودجت) |
GetAnnotationXml() | صيغة XML |
Viewer يعكس عمليات التحميل/القراءة مقابل جلسة: LoadAnnotationData(token, manager) أو LoadAnnotationData(token, encodedData) (غلاف Base64 من GetAnnotationData())، LoadAnnotationXML(token, xml)، GetAnnotationXML(token).
تصدير مع دمج التعليقات التوضيحية
// PDF of all pages with annotations rendered onto them
app.MapGet("/api/annotations/export-pdf", async (string token, Viewer viewer) =>
{
byte[] pdf = await viewer.ExportAnnotationsToPdfAsync(token, zoom: 100);
return Results.File(pdf, "application/pdf", "export.pdf");
});
// Or a ZIP of per-page PNGs
app.MapGet("/api/annotations/export-png-zip", async (string token, Viewer viewer) =>
{
byte[] zip = await viewer.ExportAnnotationsToPngZipAsync(token, zoom: 100);
return Results.File(zip, "application/zip", "annotations-png.zip");
});تستخدم عمليات التصدير نفس آلية الحرق كما في العرض على الشاشة، لذا ما يراه المستخدمون هو ما يحتويه الملف.
سير عمل الحفظ
- افتح المستند واحصل على رمزه.
- حمّل XML أو البيانات المشفرة المخزنة مسبقًا إلى ذلك الرمز.
- اسمح للودجت بقراءة وتعديل تعليقات الجلسة.
- استرجع XML باستخدام
GetAnnotationXML(token)عندما يقرر تطبيقك حفظ البيانات. - صدّر PDF/PNG عندما يكون التسليم المسطح مطلوبًا.
- أغلق جلسة المستند.
لا تستخدم رمز المشاهد الغامض كمعرّف دائم للتعليق التوضيحي. اربط بيانات التعليقات المحفوظة بمعرفات المستند والإصدار الخاصة بك.
ملاحظات الأمان والعرض
- تستخدم طلبات التعليقات التوضيحية نفس أمان الجلسة/الرمز المميز مثل طلبات الصفحات.
- يتم حل عنوان URL النسبي لـ
ImageAnnotationمن مضيف الطلب ويجب أن يظل قابلاً للوصول إلى الخادم عند وقت الحرق. - تحقق وتحقق من أي عنوان URL للصور مقدم من المستخدم لتجنب تزوير طلبات الخادم.
- تُطبق الصادرات نفس قرار الترخيص/العلامة المائية المخصصة كما في عرض الصفحة على الشاشة.
- الأحمال الكبيرة للرسومات الحرة والصادرات عالية الدقة تزيد من استهلاك الذاكرة؛ اختبر المستندات الواقعية وقيم التكبير.
استكشاف الأخطاء وإصلاحها
| العَرَض | التحقق |
|---|---|
| شريط التعليقات التوضيحية مفقود | ميزة Annotation وأربع علامات CSS/سكريبت للتعليقات التوضيحية |
| إبلاغ استدعاء الحفظ بوجود خطأ | انتهاء صلاحية الرمز المميز/الجلسة والوسيط BasePath |
| التعليقات التوضيحية بلغة C# لا تظهر | ترقيم الصفحات يبدأ من واحد وتم تحميل البيانات إلى الرمز المميز النشط |
| تظهر تعليقات الصور على الشاشة ولكن ليس في التصدير | يمكن للخادم الوصول إلى عنوان URL للصورة أثناء عملية الحرق |
| المستند المعاد فتحه لا يحتوي على تعليقات توضيحية | احفظ XML/البيانات خارج جلسة العارض، ثم حمّلها إلى الرمز المميز الجديد |
هل كانت هذه الصفحة مفيدة؟