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

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

حاشیه‌نویسی‌ها در 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 را در نشانه‌گذاری (markup) قابل مشاهده نگه دارید:

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: '/',
        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()بازگرداندن نوار Ribbon به حالت بسته و غیر ویرایشی
isOpen() / annotating()خواندن وضعیت نوار Ribbon / وضعیت ویرایش حاشیه‌نویسی 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 relative نسبت به میزبان درخواست هنگام افزودن حاشیه‌نویسی حل می‌شود (فقط دریافت تصویر در زمان سوزاندن انجام می‌شود) — باید از سرور قابل دسترس باشد (مثلاً فایلی زیر wwwroot که توسط UseStaticFiles سرو می‌شود)

API مدیریت حاشیه‌نویسی

عضوهدف
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 از میزبان درخواست حل می‌شود و باید در زمان پردازش (burn) برای سرور قابل دسترسی بماند.
  • URL تصویر ارائه‌شده توسط کاربر را اعتبارسنجی و کنترل کنید تا از جعل درخواست سمت سرور جلوگیری شود.
  • خروجی‌ها همان تصمیم مجوز/آب‌نشان سفارشی را که برای رندرینگ صفحه روی‑صفحه اعمال می‌شود، به‌کار می‌برند.
  • بارهای آزاد بزرگ و خروجی‌های با وضوح بالا مصرف حافظه را افزایش می‌دهند؛ اسناد واقعی و مقادیر زوم را تست کنید.

عیب‌یابی

علامتبررسی
نوار حاشیه‌نویسی موجود نیستقابلیت Annotation و چهار پرچم CSS/اسکریپت حاشیه‌نویسی
Callback ذخیره‌سازی خطا گزارش می‌دهدانقضای توکن/جلسه و میانی‌افزار BasePath
حاشیه‌نویسی‌های C# نمایش داده نمی‌شوندشماره‌گذاری صفحات از یک شروع می‌شود و داده‌ها در توکن فعال بارگذاری شده‌اند
حاشیه‌نویسی تصویر روی صفحه نمایش داده می‌شود اما در خروجی نیستسرور می‌تواند در زمان پردازش (burn‑in) به URL تصویر دسترسی داشته باشد
سند باز شده مجدداً حاشیه‌نویسی نداردXML/داده‌ها را خارج از جلسه نمایشگر ذخیره کنید، سپس در توکن جدید بارگذاری کنید

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