Анотації

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

Анотації в 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">
    <!-- Елементи управління переглядачем, включаючи кнопку, що відкриває 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):

ТипПримітки
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 усіх сторінок з анотаціями, накладеними на них
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/script анотації
Зворотний виклик збереження повідомляє про помилкуТермін дії токену/сесії закінчився та middleware BasePath
Анотації C# не відображаютьсяНумерація сторінок починається з одиниці, і дані були завантажені в активний токен
Зображення анотації відображається на екрані, але не в експортіСервер може досягти URL-адреси зображення під час обробки
Повторно відкритий документ не містить анотаційЗберігайте XML/дані поза сесією переглядача, потім завантажте їх у новий токен

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