Анотації

Додайте підтримку анотацій у переглядач

Анотації в Doconut працюють у двох напрямках: користувачі малюють їх у віджеті браузера, а сервер зберігає їх по сторінках, або ваш код створює їх програмно і завантажує у відкриту сесію. У будь‑якому випадку вони відображаються на сторінках і можуть бути вбудовані у PDF/PNG експорти.

Підтримка анотацій обмежена можливістю ліцензії Annotation (надається автоматично при активній тимчасовій ліцензії).

Увімкнення інтерфейсу анотацій

Annotation — це модуль Viewer, а не окрема панель інструментів. Повна сторінка повинна включати ресурси Viewer, панель інструментів Viewer, монтування Viewer та ініціалізований objViewer; потім стрічка Annotation монтується і приєднується до того ж екземпляра.

Виводьте пакети анотацій разом з пакетами переглядача — вони обмежені ліцензією, тому теги з’являються лише коли можливість доступна:

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>

Пакет Annotation генерує DOM стрічки всередині annBarMount; вам не потрібно копіювати його кнопки чи розмітку діалогових вікон. Спочатку ініціалізуйте docViewer, а потім створюйте стрічку лише коли сервер підтвердить, що Annotation ліцензовано:

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>

Збереження зі стрічки надсилає дані через проміжне ПЗ (AnnSave), яке зберігає їх у сесії документа по сторінках. Завантаження (AnnLoad) відбувається автоматично, коли сторінка з анотаціями відображається. Чотири зворотні виклики onAnn* підтримують синхронізацію стрічки з життєвим циклом переглядача.

Відкрийте та закрийте її з будь‑якої панелі інструментів Viewer, що належить хосту:

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

Публічний API стрічки:

МетодПризначення
attach(objViewer)Підключити стрічку до ініціалізованого переглядача; потрібно один раз
open() / close()Розпочати або завершити редагування анотацій
reset()Повернути стрічку у закрите, не‑редагувальне стан
isOpen() / annotating()Прочитати стан стрічки / стан редагування анотацій у переглядачі
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. Закрийте сесію документа.

Не використовуйте непрозорий токен переглядача як постійний ідентифікатор анотації. Пов’язуйте збережені дані анотацій зі своїми ідентифікаторами документу та версії.

Примітки щодо безпеки та рендерингу

  • Запити анотацій використовують ту ж безпеку сесії/токену, що й запити сторінок.
  • Відносний URL ImageAnnotation розв’язується від хоста запиту і має залишатися доступним серверу під час вбудовування.
  • Перевіряйте та контролюйте будь‑які URL зображень, надані користувачем, щоб уникнути підробки запитів на стороні сервера.
  • Експорти застосовують ті ж рішення щодо ліцензії/кастомного водяного знаку, що й відображення сторінок на екрані.
  • Великі об’єми даних вільного малювання та експорти високої роздільної здатності збільшують використання пам’яті; тестуйте реальні документи та значення масштабу.

Усунення неполадок

СимптомПеревірка
Стрічка анотацій відсутняAnnotation можливість та чотири прапорці CSS/скриптів анотацій
Зворотний виклик збереження повідомляє про помилкуТермін дії токену/сесії та проміжне ПЗ BasePath
Анотації C# не відображаютьсяНумерація сторінок починається з 1, і дані були завантажені в активний токен
Зображення анотації відображається на екрані, але не в експортіСервер може досягти URL зображення під час вбудовування
Перевідкритий документ не має анотаційЗбережіть XML/дані поза сесією переглядача, потім завантажте їх у новий токен

Чи була ця сторінка корисною?