アノテーション

ビューアにアノテーションサポートを追加

Doconutのアノテーションは2つの方向で機能します。ユーザーはブラウザウィジェット上で描画し、サーバーがページごとに永続化するか、またはコードでプログラム的に作成し、オープンセッションにロードします。どちらの場合もページに描画され、PDF/PNGエクスポートに焼き込むことができます。

アノテーションサポートは Annotation ライセンス機能で制御されます(有効な Temporary ライセンス下で自動的に付与されます)。

アノテーション UI を有効化

アノテーションは Viewer のモジュールであり、単体のツールバーではありません。完全なページには Viewer のリソース、Viewer ツールバー、Viewer のマウント、そして初期化された objViewer が含まれる必要があります。その後、アノテーションリボンがマウントされ、同じインスタンスに添付されます。

アノテーションバンドルを Viewer バンドルと同時に出力します — これらはライセンスで制御されるため、機能が利用可能なときだけタグが表示されます:

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">
    <!-- ビューアのコントロール、アノテーションを開くボタンを含む -->
</nav>
<div id="annBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>

アノテーションバンドルは annBarMount 内にリボンの DOM を生成します。ボタンやダイアログのマークアップをコピーする必要はありません。まず docViewer を初期化し、サーバーがアノテーションがライセンスされていることを確認したときにのみリボンを作成します:

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)はアノテーション付きページがレンダリングされると自動的に行われます。4つの onAnn* コールバックがリボンとビューアのライフサイクルを同期させます。

任意のホスト所有の Viewer ツールバーから開閉できます:

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

公開されているリボン API は次のとおりです:

メソッド目的
attach(objViewer)リボンを初期化されたビューアに接続します。1回だけ必要です
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;、Rectangle/Color には using System.Drawing; を使用します)。

csharp
app.MapPost("/api/annotations/load-sample", (string token, Viewer viewer) =>
{
    // 開いているセッションのページ寸法にバインドされます
    var manager = viewer.GetAnnotationManager(token);
    var pageCount = viewer.GetPageCount(token);

    // ページごとに1つのスタンプ
    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 ポイントからの自由なストローク
ImageAnnotationURL からの画像。相対 URL はアノテーション追加時にリクエストホストに対して解決されます(画像取得は焼き込み時にのみ行われます)— サーバーからアクセス可能である必要があります(例: UseStaticFiles で提供される wwwroot 配下のファイル)。

AnnotationManager API の概要

メンバー目的
Add(BaseAnnotation)アノテーションをキューに追加
GetAnnotations() / GetAnnotations(int page)マネージャーが保持しているアノテーションを確認
ClearAnnotations() / ClearAnnotations(int page)すべて / ページ単位で削除
GetAnnotationData() / GetAnnotationData(int page)エンコードされたアノテーションデータ文字列 — Base64 のワイヤーエンベロープ(ウィジェットが使用)
GetAnnotationXml()XML 形式

Viewer はセッションに対するロード/読み取り操作を鏡像します:LoadAnnotationData(token, manager) または LoadAnnotationData(token, encodedData)(GetAnnotationData() からの Base64 ワイヤーエンベロープ)、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");
});

// またはページごとの PNG をまとめた ZIP
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. アプリケーションが永続化を決定したときに GetAnnotationXML(token) で XML を取得します。
  5. フラットな納品物が必要な場合は PDF/PNG をエクスポートします。
  6. ドキュメントセッションを閉じます。

不透明なビューアートークンを永続的なアノテーション識別子として使用しないでください。永続化されたアノテーションデータは、独自のドキュメントおよびバージョン識別子と関連付けて管理してください。

セキュリティとレンダリングに関する注意点

  • アノテーションリクエストは、ページリクエストと同じセッション/トークンのセキュリティを使用します。
  • 相対的な ImageAnnotation URL はリクエストホストから解決され、バーン時にサーバーから到達可能である必要があります。
  • ユーザー提供の画像URLを検証・制御し、サーバー側リクエスト偽装を防止してください。
  • エクスポートは、画面上のページレンダリングと同じライセンス/カスタム透かしの設定を適用します。
  • 大きなフリーハンドペイロードや高解像度エクスポートはメモリ使用量を増加させます。実際の文書とズーム値でテストしてください。

トラブルシューティング

症状確認項目
アノテーションリボンが表示されないAnnotation 機能と4つのアノテーション CSS/スクリプト フラグ
保存コールバックがエラーを報告するトークン/セッションの有効期限切れとミドルウェア BasePath
C# アノテーションが表示されないページ番号が1から始まり、データがアクティブトークンにロードされていること
画像アノテーションが画面上には表示されるがエクスポートに含まれないバーンイン中にサーバーが画像URLに到達できること
再度開いた文書にアノテーションがないビューアセッション外でXML/データを永続化し、新しいトークンにロードする

このページは役に立ちましたか?