حاشیه‌نویسی‌ها

افزودن پشتیبانی از حاشیه‌نویسی به نمایشگر

حاشیه‌نویسی‌ها در Doconut به دو جهت کار می‌کنند: کاربران آن‌ها را در ویجت مرورگر می‌کشند و سرور برای هر صفحه ذخیره می‌کند، یا کد شما به‌صورت برنامه‌نویسی آن‌ها را می‌سازد و در یک جلسه باز بارگذاری می‌کند. به هر دو صورت، آن‌ها روی صفحات رندر می‌شوند و می‌توانند در خروجی‌های PDF/PNG سوزانده شوند.

پشتیبانی از حاشیه‌نویسی توسط قابلیت مجوز Annotation کنترل می‌شود (به‌صورت خودکار تحت یک مجوز موقت فعال اعطا می‌شود).

فعال‌سازی رابط کاربری حاشیه‌نویسی

حاشیه‌نویسی یک ماژول Viewer است، نه یک نوار ابزار مستقل. صفحه کامل باید شامل منابع Viewer، نوار ابزار Viewer، نقطهٔ نصب Viewer، و objViewer مقداردهی اولیه شده باشد؛ نوار Ribbon حاشیه‌نویسی سپس نصب و به همان نمونه متصل می‌شود.

باندل‌های حاشیه‌نویسی را همراه با باندل‌های Viewer بارگذاری کنید — آن‌ها تحت مجوز هستند، بنابراین برچسب‌ها فقط زمانی ظاهر می‌شوند که قابلیت موجود باشد:

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>

باندل حاشیه‌نویسی، DOM نوار 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 همگام می‌سازند.

از هر نوار ابزار Viewer متعلق به میزبان می‌توانید آن را باز یا بسته کنید:

javascript
annBar.open();
annBar.close();

API عمومی نوار Ribbon به صورت زیر است:

متدهدف
attach(objViewer)اتصال نوار Ribbon به Viewer مقداردهی‌شده؛ یک‌بار لازم است
open() / close()ورود یا خروج از حالت ویرایش حاشیه‌نویسی
reset()بازگرداندن نوار به حالت بسته و غیر ویرایشی
isOpen() / annotating()خواندن وضعیت نوار / وضعیت ویرایش حاشیه‌نویسی Viewer
reopenEditable()بارگذاری مجدد حاشیه‌نویسی‌های صفحهٔ فعلی به‌صورت اشیای ویرایشی
updateActionState()تازه‌سازی در دسترس بودن کنترل‌های ذخیره/حذف پس از تغییرات میزبان
headerSlot()دریافت اسلات اختیاری سرصفحه برای کنترل‌های متعلق به میزبان

onStatus، onToast، onLayout، onEditStart و onEditEnd کال‌بک‌های اختیاری میزبان هستند. شیء endpoints می‌تواند به‌علاوهٔ exportPdf، exportPng، imageUpload و imageList را فراهم کند؛ کنترل‌هایی که نقطهٔ انتهایی پیکربندی‌شده ندارند مخفی می‌مانند. برای توالی راه‌اندازی ترکیبی Viewer، Search و Annotation، به شروع سریع مراجعه کنید.

باندل حاشیه‌نویسی ابزارهای نویسندگی مرورگر را اضافه می‌کند، اما داده‌ها همچنان متعلق به جلسهٔ سمت‑سرور هستند که با توکن شناسایی می‌شود. بازگشایی منبع یک جلسهٔ جدید ایجاد می‌کند؛ 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 سرو می‌شود)

API 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. جلسه سند را ببندید.

از توکن شفاف Viewer به‌عنوان شناسهٔ دائمی حاشیه‌نویسی استفاده نکنید. دادهٔ حاشیه‌نویسی ذخیره‌شده را با شناسه‌ها و نسخه‌های سند خودتان مرتبط کنید.

نکات امنیتی و رندرینگ

  • درخواست‌های حاشیه‌نویسی از همان امنیت جلسه/توکن همانند درخواست‌های صفحه استفاده می‌کنند.
  • یک URL ImageAnnotation نسبی از میزبان درخواست حل می‌شود و باید در زمان سوزاندن برای سرور قابل دسترسی باشد.
  • هر URL تصویری که توسط کاربر ارائه می‌شود را اعتبارسنجی و کنترل کنید تا از جعل درخواست سمت سرور جلوگیری شود.
  • خروجی‌ها همان تصمیم مجوز/آب‌نشان سفارشی را که برای رندر صفحه روی‑صفحه اعمال می‌شود، به‌کار می‌برند.
  • بارگذاری‌های آزاد بزرگ و خروجی‌های با وضوح بالا مصرف حافظه را افزایش می‌دهند؛ اسناد واقعی و مقادیر زوم را تست کنید.

عیب‌یابی

علامتبررسی
نوار Ribbon حاشیه‌نویسی موجود نیستقابلیت Annotation و چهار پرچم CSS/اسکریپت حاشیه‌نویسی
کال‌بک ذخیره‌سازی خطا می‌دهدانقضای توکن/جلسه و میدل‌ویر BasePath
حاشیه‌نویسی‌های C# ظاهر نمی‌شوندشماره‌گذاری صفحات از یک شروع می‌شود و داده‌ها به توکن فعال بارگذاری شده‌اند
حاشیه‌نویسی تصویر روی صفحه می‌نماید اما در خروجی نیستسرور باید در زمان سوزاندن به URL تصویر دسترسی داشته باشد
سند بازگشایی‌شده حاشیه‌نویسی نداردXML/داده را خارج از جلسه Viewer حفظ کنید، سپس در توکن جدید بارگذاری کنید

آیا این صفحه مفید بود؟