حاشیهنویسیها
افزودن پشتیبانی از حاشیهنویسی به نمایشگر
حاشیهنویسیها در Doconut به دو جهت کار میکنند: کاربران آنها را در ویجت مرورگر میکشند و سرور برای هر صفحه ذخیره میکند، یا کد شما بهصورت برنامهنویسی آنها را میسازد و در یک جلسه باز بارگذاری میکند. به هر دو صورت، آنها روی صفحات رندر میشوند و میتوانند در خروجیهای PDF/PNG سوزانده شوند.
پشتیبانی از حاشیهنویسی توسط قابلیت مجوز Annotation کنترل میشود (بهصورت خودکار تحت یک مجوز موقت فعال اعطا میشود).
فعالسازی رابط کاربری حاشیهنویسی
حاشیهنویسی یک ماژول Viewer است، نه یک نوار ابزار مستقل. صفحه کامل باید شامل
منابع Viewer، نوار ابزار Viewer، نقطهٔ نصب Viewer، و objViewer مقداردهی اولیه شده باشد؛
نوار Ribbon حاشیهنویسی سپس نصب و به همان نمونه متصل میشود.
باندلهای حاشیهنویسی را همراه با باندلهای Viewer بارگذاری کنید — آنها تحت مجوز هستند، بنابراین برچسبها فقط زمانی ظاهر میشوند که قابلیت موجود باشد:
@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>باندل حاشیهنویسی، DOM نوار 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 همگام میسازند.
از هر نوار ابزار Viewer متعلق به میزبان میتوانید آن را باز یا بسته کنید:
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):
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).
خروجی با حاشیهنویسیهای سوزاندهشده
// 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 را زمانی که یک تحویل مسطح لازم است، خروجی بگیرید.
- جلسه سند را ببندید.
از توکن شفاف Viewer بهعنوان شناسهٔ دائمی حاشیهنویسی استفاده نکنید. دادهٔ حاشیهنویسی ذخیرهشده را با شناسهها و نسخههای سند خودتان مرتبط کنید.
نکات امنیتی و رندرینگ
- درخواستهای حاشیهنویسی از همان امنیت جلسه/توکن همانند درخواستهای صفحه استفاده میکنند.
- یک URL
ImageAnnotationنسبی از میزبان درخواست حل میشود و باید در زمان سوزاندن برای سرور قابل دسترسی باشد. - هر URL تصویری که توسط کاربر ارائه میشود را اعتبارسنجی و کنترل کنید تا از جعل درخواست سمت سرور جلوگیری شود.
- خروجیها همان تصمیم مجوز/آبنشان سفارشی را که برای رندر صفحه روی‑صفحه اعمال میشود، بهکار میبرند.
- بارگذاریهای آزاد بزرگ و خروجیهای با وضوح بالا مصرف حافظه را افزایش میدهند؛ اسناد واقعی و مقادیر زوم را تست کنید.
عیبیابی
| علامت | بررسی |
|---|---|
| نوار Ribbon حاشیهنویسی موجود نیست | قابلیت Annotation و چهار پرچم CSS/اسکریپت حاشیهنویسی |
| کالبک ذخیرهسازی خطا میدهد | انقضای توکن/جلسه و میدلویر BasePath |
| حاشیهنویسیهای C# ظاهر نمیشوند | شمارهگذاری صفحات از یک شروع میشود و دادهها به توکن فعال بارگذاری شدهاند |
| حاشیهنویسی تصویر روی صفحه مینماید اما در خروجی نیست | سرور باید در زمان سوزاندن به URL تصویر دسترسی داشته باشد |
| سند بازگشاییشده حاشیهنویسی ندارد | XML/داده را خارج از جلسه Viewer حفظ کنید، سپس در توکن جدید بارگذاری کنید |
آیا این صفحه مفید بود؟