التعليقات التوضيحية
Add annotation support to the viewer
التعليقات التوضيحية في Doconut تعمل في اتجاهين: يرسمها المستخدمون في ودجت المتصفح ويقوم الخادم بحفظها لكل صفحة، أو يبنيها الكود برمجياً ويحمّلها في جلسة مفتوحة. في كلتا الحالتين تُعرض على الصفحات ويمكن دمجها في تصديرات PDF/PNG.
دعم التعليقات التوضيحية محكوم بميزة الترخيص Annotation (تُمنح تلقائياً تحت ترخيص مؤقت نشط).
تمكين واجهة المستخدم للتعليقات التوضيحية
التعليق التوضيحي هو وحدة Viewer، وليس شريط أدوات مستقل. يجب أن تشمل الصفحة الكاملة
موارد Viewer، شريط أدوات Viewer، تثبيت Viewer، وتهيئة 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
}))احتفظ بتركيب Viewer الكامل مرئياً في العلامة:
<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: '/doconut',
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 مع
دورة حياة العارض.
افتحه وأغلقه من أي شريط أدوات Viewer مملوك للمضيف:
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؛ التحكمات التي لا تُعطى نقطة نهاية تبقى مخفية.
لسلسلة بدء تشغيل Viewer المدمج مع البحث والتعليقات التوضيحية، راجع
البدء السريع(Quick Start).
حزمة التعليقات التوضيحية تضيف أدوات التأليف في المتصفح، لكن البيانات لا تزال تخص جلسة المستند على الخادم المحددة بالرمز المميز. إعادة فتح المصدر تُنشئ جلسة جديدة؛ احفظ الـ 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 المحدد):
| النوع | ملاحظات |
|---|---|
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
| العضو | الغرض |
|---|---|
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 للصور يقدمه المستخدم وتَحكم فيه لتجنب تزوير طلبات الخادم.
- التصديرات تطبق نفس قرار الترخيص/العلامة المائية المخصصة كما في عرض الصفحات على الشاشة.
- الأحمال الكبيرة للخط الحر والتصديرات عالية الدقة تزيد من استهلاك الذاكرة؛ اختبر المستندات والقيم الواقعية للتكبير.
استكشاف الأخطاء وإصلاحها
| العَرَض | الفحص |
|---|---|
| شريط الـ Ribbon مفقود | التأكد من وجود ميزة Annotation وعلامات CSS/Script الأربعة للتعليقات |
| استدعاء الحفظ يُبلغ عن خطأ | انتهاء صلاحية الرمز/الجلسة وإعداد BasePath في الطبقة الوسيطة |
| تعليقات C# لا تظهر | ترقيم الصفحات يبدأ من الواحد والبيانات تم تحميلها إلى الرمز النشط |
| صورة التعليق تظهر على الشاشة لكنها لا تظهر في التصدير | يجب أن يتمكن الخادم من الوصول إلى عنوان URL للصورة أثناء الدمج |
| المستند المعاد فتحه لا يحتوي على تعليقات | احفظ XML/البيانات خارج جلسة العارض، ثم حمّلها في الرمز الجديد |
هل كانت هذه الصفحة مفيدة؟