حاشیهنویسیها
افزودن پشتیبانی از حاشیهنویسی به نمایشگر
حاشیهنویسیها در 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 را در نشانهگذاری (markup) قابل مشاهده نگه دارید:
<nav id="toolbar" aria-label="Document viewer controls">
<!-- کنترلهای Viewer، شامل دکمهای که 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() | بازگرداندن نوار 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):
app.MapPost("/api/annotations/load-sample", (string token, Viewer viewer) =>
{
// متصل به ابعاد صفحهٔ جلسهٔ باز
var manager = viewer.GetAnnotationManager(token);
var pageCount = viewer.GetPageCount(token);
// یک مهر برای هر صفحه
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));
// بارگذاری در جلسه — ویجت آنها را از طریق AnnLoad دریافت میکند و
// renderer آنها را در خروجیهای تصویر/PDF میسوزاند.
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 تمام صفحات با حاشیهنویسیهای رندر شده روی آنها
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");
});
// یا یک ZIP از PNGهای هر صفحه
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 را خروجی بگیرید وقتی یک تحویل مسطح (flattened) مورد نیاز است.
- جلسه سند را ببندید.
از توکن شفاف Viewer به عنوان شناسه دائمی حاشیهنویسی استفاده نکنید. دادههای حاشیهنویسی حفظشده را با شناسههای سند و نسخه خودتان مرتبط کنید.
نکات امنیتی و رندرینگ
- درخواستهای حاشیهنویسی از همان امنیت جلسه/توکن همانند درخواستهای صفحه استفاده میکنند.
- یک URL نسبی
ImageAnnotationاز میزبان درخواست حل میشود و باید در زمان پردازش برای سرور قابل دسترسی بماند. - هر URL تصویری که توسط کاربر ارائه میشود را اعتبارسنجی و کنترل کنید تا از جعل درخواست سمت سرور جلوگیری شود.
- خروجیها همان تصمیمگیری دربارهٔ لایسنس/آبنشان سفارشی را که در رندر صفحه روی صفحه نمایش اعمال میشود، به کار میبرند.
- بارهای بزرگ دستنویس و خروجیهای با وضوح بالا مصرف حافظه را افزایش میدهند؛ اسناد واقعی و مقادیر زوم را تست کنید.
عیبیابی
| علامت | بررسی |
|---|---|
| نوار حاشیهنویسی گم شده است | قابلیت Annotation و چهار پرچم CSS/اسکریپت حاشیهنویسی |
| بازگشتتابع ذخیره خطایی گزارش میدهد | انقضای توکن/جلسه و میانیافزار BasePath |
| حاشیهنویسیهای C# ظاهر نمیشوند | شمارهگذاری صفحات از یک شروع میشود و دادهها به توکن فعال بارگذاری شدهاند |
| حاشیهنویسی تصویر روی صفحه نمایش ظاهر میشود اما در خروجی نیست | سرور میتواند در زمان پردازش به URL تصویر دسترسی داشته باشد |
| سند بازگشایی شده حاشیهنویسی ندارد | XML/دادهها را خارج از جلسه نمایشگر ذخیره کنید، سپس آن را به توکن جدید بارگذاری کنید |
آیا این صفحه مفید بود؟