Анотації

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

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

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