Анотації

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

Анотації в 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 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: '/',
        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 всіх сторінок з відрендереними анотаціями
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/дані поза сесією переглядача, потім завантажте їх у новий токен

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