التعليقات التوضيحية

Add annotation support to the viewer

التعليقات التوضيحية في Doconut تعمل في اتجاهين: يرسمها المستخدمون في ودجت المتصفح ويقوم الخادم بحفظها لكل صفحة، أو يبنيها الكود برمجياً ويحمّلها في جلسة مفتوحة. في كلتا الحالتين تُعرض على الصفحات ويمكن دمجها في تصديرات PDF/PNG.

دعم التعليقات التوضيحية محكوم بميزة الترخيص Annotation (تُمنح تلقائياً تحت ترخيص مؤقت نشط).

تمكين واجهة المستخدم للتعليقات التوضيحية

التعليق التوضيحي هو وحدة Viewer، وليس شريط أدوات مستقل. يجب أن تشمل الصفحة الكاملة موارد Viewer، شريط أدوات Viewer، تثبيت Viewer، وتهيئة objViewer؛ ثم يتم تثبيت شريط التعليقات التوضيحية وربطه بنفس المثيل.

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

html
@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 الكامل مرئياً في العلامة:

html
<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 فقط عندما يؤكد الخادم أن التعليقات التوضيحية مرخصة:

html
<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 مملوك للمضيف:

javascript
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):

csharp
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).

التصدير مع دمج التعليقات التوضيحية

csharp
// 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");
});

التصديرات تستخدم نفس آلية الدمج المستخدمة في العرض على الشاشة، لذا ما يراه المستخدمون هو ما يحتويه الملف.

سير عمل الاستمرارية

  1. افتح المستند واحصل على رمزه المميز.
  2. حمّل XML أو البيانات المشفرة المخزنة مسبقاً في ذلك الرمز.
  3. دع الودجت يقرأ ويحرّر تعليقات الجلسة.
  4. استرجع XML باستخدام GetAnnotationXML(token) عندما يقرر تطبيقك حفظه.
  5. صدّر PDF/PNG عندما تكون نسخة مسطحة مطلوبة.
  6. أغلق جلسة المستند.

لا تستخدم الرمز المميز للعارض كمعرف دائم للتعليقات. اربط بيانات التعليقات المخزنة بمعرفات المستند والإصدار الخاصة بك.

ملاحظات الأمان والعرض

  • طلبات التعليقات تستخدم نفس أمان الجلسة/الرمز المميز كما في طلبات الصفحات.
  • عنوان URL النسبي لـ ImageAnnotation يُحلّ من مضيف الطلب ويجب أن يبقى قابلاً للوصول من الخادم عند الدمج.
  • تحقق من أي عنوان URL للصور يقدمه المستخدم وتَحكم فيه لتجنب تزوير طلبات الخادم.
  • التصديرات تطبق نفس قرار الترخيص/العلامة المائية المخصصة كما في عرض الصفحات على الشاشة.
  • الأحمال الكبيرة للخط الحر والتصديرات عالية الدقة تزيد من استهلاك الذاكرة؛ اختبر المستندات والقيم الواقعية للتكبير.

استكشاف الأخطاء وإصلاحها

العَرَضالفحص
شريط الـ Ribbon مفقودالتأكد من وجود ميزة Annotation وعلامات CSS/Script الأربعة للتعليقات
استدعاء الحفظ يُبلغ عن خطأانتهاء صلاحية الرمز/الجلسة وإعداد BasePath في الطبقة الوسيطة
تعليقات C# لا تظهرترقيم الصفحات يبدأ من الواحد والبيانات تم تحميلها إلى الرمز النشط
صورة التعليق تظهر على الشاشة لكنها لا تظهر في التصديريجب أن يتمكن الخادم من الوصول إلى عنوان URL للصورة أثناء الدمج
المستند المعاد فتحه لا يحتوي على تعليقاتاحفظ XML/البيانات خارج جلسة العارض، ثم حمّلها في الرمز الجديد

هل كانت هذه الصفحة مفيدة؟