Anotasi
Tambahkan dukungan anotasi ke penampil
Anotasi di Doconut berfungsi dalam dua arah: pengguna menggambarnya di widget peramban dan server menyimpannya per halaman, atau kode Anda membuatnya secara programatik dan memuatnya ke dalam sesi terbuka. Bagaimanapun, mereka ditampilkan pada halaman dan dapat dibakar ke dalam ekspor PDF/PNG.
Dukungan anotasi dibatasi oleh kemampuan lisensi Annotation (diberikan secara otomatis di bawah lisensi Sementara yang aktif).
Aktifkan UI anotasi
Anotasi adalah modul Viewer, bukan toolbar mandiri. Halaman lengkap harus menyertakan sumber daya Viewer, toolbar Viewer, mount Viewer, dan objViewer yang diinisialisasi; Ribbon Anotasi kemudian dipasang dan dilampirkan ke instance yang sama.
Keluarkan paket anotasi bersamaan dengan paket penampil — mereka dibatasi lisensi, sehingga tag hanya muncul ketika kemampuan tersedia:
@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
}))Pertahankan komposisi Viewer lengkap terlihat dalam markup:
<nav id="toolbar" aria-label="Document viewer controls">
<!-- Kontrol penampil, termasuk tombol yang membuka Anotasi -->
</nav>
<div id="annBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>Bundle Anotasi menghasilkan DOM Ribbon di dalam annBarMount; Anda tidak perlu menyalin tombol atau markup dialognya. Inisialisasi docViewer terlebih dahulu, kemudian buat Ribbon hanya ketika server mengonfirmasi bahwa Anotasi berlisensi:
<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>Menyimpan dari Ribbon mengirim data melalui middleware (AnnSave), yang menyimpannya dalam sesi dokumen per halaman. Memuat (AnnLoad) terjadi secara otomatis ketika halaman dengan anotasi ditampilkan. Empat callback onAnn* menjaga Ribbon tetap sinkron dengan siklus hidup penampil.
Buka dan tutup dari toolbar Viewer milik host mana pun:
annBar.open();
annBar.close();API Ribbon publik adalah:
| Metode | Tujuan |
|---|---|
attach(objViewer) | Menghubungkan Ribbon ke penampil yang diinisialisasi; diperlukan satu kali |
open() / close() | Masuk atau keluar dari penyuntingan anotasi |
reset() | Mengembalikan Ribbon ke keadaan tertutup, tidak dalam penyuntingan |
isOpen() / annotating() | Membaca status Ribbon / status penyuntingan anotasi penampil |
reopenEditable() | Memuat ulang anotasi halaman saat ini sebagai objek yang dapat disunting |
updateActionState() | Menyegarkan ketersediaan kontrol simpan/hapus setelah perubahan host |
headerSlot() | Mendapatkan slot ekstensi header opsional untuk kontrol milik host |
onStatus, onToast, onLayout, onEditStart, dan onEditEnd adalah callback host opsional. Objek endpoints dapat tambahan menyediakan exportPdf, exportPng, imageUpload, dan imageList; kontrol tanpa endpoint yang dikonfigurasi tetap tersembunyi. Untuk urutan startup gabungan Viewer, Search, dan Annotation, lihat Panduan Cepat.
Paket anotasi menambahkan alat authoring di peramban, tetapi data tetap milik sesi dokumen sisi server yang diidentifikasi oleh token. Membuka kembali sumber menciptakan sesi baru; simpan XML atau envelope anotasi yang terenkode dalam aplikasi Anda jika anotasi harus bertahan melampaui masa hidup sesi.
Membuat anotasi di C#
Dapatkan manager yang terikat pada sesi terbuka, tambahkan anotasi, dan muat mereka (dengan using Doconut.Annotations; untuk tipe dan using System.Drawing; untuk Rectangle/Color):
app.MapPost("/api/annotations/load-sample", (string token, Viewer viewer) =>
{
// Terikat pada dimensi halaman sesi terbuka
var manager = viewer.GetAnnotationManager(token);
var pageCount = viewer.GetPageCount(token);
// Satu stempel per halaman
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));
// Muat ke dalam sesi — widget mengambilnya melalui AnnLoad dan
// renderer menempelkan mereka ke dalam ekspor gambar/PDF.
viewer.LoadAnnotationData(token, manager);
return Results.Ok();
});Tipe Anotasi
Semua tipe berada di Doconut.Annotations dan mewarisi dari BaseAnnotation (nomor halaman + Rectangle pembatas):
| Type | Catatan |
|---|---|
StampAnnotation | Stempel teks dengan ukuran font, batas, warna; mendukung Opacity, Rotate |
NoteAnnotation | Catatan tempel dengan teks, warna latar belakang, ukuran font, TitleColor |
RectangleAnnotation | Warna batas + isi, Title/ShowTitle |
CircleAnnotation | Batas + isi, ShowBorder |
EllipseAnnotation | Batas + isi, ShowBorder |
TriangleAnnotation | Warna batas, BackColor, ShowBorder |
LineAnnotation | Garis lurus dengan lebar dan warna |
ArrowAnnotation | Garis dengan kepala panah; dapat diatur Direction (tipe ArrowDirection, arah kompas, default E) |
FreehandAnnotation | Garis bebas dari titik FreehandData yang terenkode |
ImageAnnotation | Gambar dari URL. URL relatif diresolusikan terhadap host permintaan saat anotasi ditambahkan (hanya pengambilan gambar yang terjadi pada saat pembakaran) — harus dapat dijangkau dari server (misalnya file di bawah wwwroot yang disajikan oleh UseStaticFiles) |
API AnnotationManager
| Anggota | Tujuan |
|---|---|
Add(BaseAnnotation) | Antri anotasi |
GetAnnotations() / GetAnnotations(int page) | Periksa apa yang dimiliki manager |
ClearAnnotations() / ClearAnnotations(int page) | Hapus semua / per halaman |
GetAnnotationData() / GetAnnotationData(int page) | String data anotasi terenkode — sebuah envelope wire Base64 (yang dikonsumsi widget) |
GetAnnotationXml() | Bentuk XML |
Viewer mencerminkan operasi muat/baca terhadap sebuah sesi: LoadAnnotationData(token, manager) atau LoadAnnotationData(token, encodedData) (envelop wire Base64 dari GetAnnotationData()), LoadAnnotationXML(token, xml), GetAnnotationXML(token).
Ekspor dengan anotasi dibakar
// PDF semua halaman dengan anotasi yang dirender di atasnya
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");
});
// Atau ZIP dari PNG per halaman
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");
});Ekspor menggunakan pembakar yang sama seperti rendering di layar, sehingga apa yang dilihat pengguna adalah apa yang terdapat dalam file.
Alur kerja Persistensi
- Buka dokumen dan dapatkan tokennya.
- Muat XML atau data terenkode yang sebelumnya disimpan ke dalam token tersebut.
- Biarkan widget membaca dan mengedit anotasi sesi.
- Ambil XML dengan
GetAnnotationXML(token)ketika aplikasi Anda memutuskan untuk menyimpan. - Ekspor PDF/PNG ketika diperlukan deliverable yang telah diratakan.
- Tutup sesi dokumen.
Jangan gunakan token viewer yang tidak transparan sebagai pengidentifikasi anotasi permanen. Kaitkan data anotasi yang disimpan dengan pengidentifikasi dokumen dan versi Anda sendiri.
Keamanan dan catatan rendering
- Permintaan anotasi menggunakan keamanan sesi/token yang sama seperti permintaan halaman.
- URL
ImageAnnotationrelatif diselesaikan dari host permintaan dan harus tetap dapat dijangkau oleh server pada saat proses burn. - Validasi dan kontrol setiap URL gambar yang diberikan pengguna untuk menghindari pemalsuan permintaan sisi server.
- Ekspor menerapkan keputusan lisensi/watermark khusus yang sama seperti rendering halaman di layar.
- Payload bebas tangan yang besar dan ekspor resolusi tinggi meningkatkan penggunaan memori; uji dokumen realistis dan nilai zoom.
Pemecahan Masalah
| Gejala | Periksa |
|---|---|
| Pita anotasi tidak muncul | Annotation kapabilitas dan empat flag CSS/script anotasi |
| Callback penyimpanan melaporkan error | Kedaluwarsa token/sesi dan middleware BasePath |
| Anotasi C# tidak muncul | Penomoran halaman berbasis satu dan data dimuat ke dalam token aktif |
| Anotasi gambar muncul di layar tetapi tidak dalam ekspor | Server dapat menjangkau URL gambar selama proses burn-in |
| Dokumen yang dibuka kembali tidak memiliki anotasi | Simpan XML/data di luar sesi viewer, lalu muat ke dalam token baru |
Apakah halaman ini membantu?