Анотації

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

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

Підтримка анотацій обмежена можливістю ліцензії 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, включаючи кнопку, що відкриває 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) =>
{
    // Прив’язано до розмірів сторінки відкритої сесії
    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 і
    // рендерер вбудовує їх у експорт зображень/PDF.
    viewer.LoadAnnotationData(token, manager);
    return Results.Ok();
});

Типи анотацій

Усі типи знаходяться в Doconut.Annotations і успадковуються від BaseAnnotation (номер сторінки + обмежувальний Rectangle):

TypeNotes
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

MemberPurpose
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 всіх сторінок з вбудованими анотаціями
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");
});

Експорти використовують той самий процес вбудовування, що й рендеринг на екрані, тому те, що бачать користувачі, міститься у файлі.

Робочий процес збереження

  1. Відкрийте документ і отримайте його токен.
  2. Завантажте раніше збережений XML або закодовані дані у цей токен.
  3. Дайте віджету прочитати та редагувати анотації сесії.
  4. Отримайте XML за допомогою GetAnnotationXML(token), коли ваш застосунок вирішить зберегти.
  5. Експортуйте PDF/PNG, коли потрібен сплощений результат.
  6. Закрийте сесію документа.

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

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

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

Усунення проблем

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

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