Açıklamalar
Görüntüleyiciye açıklama desteği ekleyin
Doconut'taki açıklamalar iki yönde çalışır: kullanıcılar bunları tarayıcı widget'ında çizer ve sunucu sayfa başına saklar, ya da kodunuz bunları oluşturur ve açık bir oturuma yükler. Hangi yöntem olursa olsun, sayfalarda görüntülenir ve PDF veya PNG dışa aktarımlarına gömülebilir.
Açıklama desteği, Annotation lisans yeteneğiyle sınırlıdır (aktif bir Geçici lisans altında otomatik olarak verilir).
Açıklama UI'sini Etkinleştir
Annotation, bağımsız bir araç çubuğu değil, bir Viewer modülüdür. Sayfa Viewer kaynaklarını, Viewer araç çubuğunu, Viewer bağlamasını ve başlatılmış bir objViewer'ı içermelidir; ardından Annotation Ribbon aynı örneğe monte edilir ve eklenir.
Annotation dosyalarını viewer dosyalarıyla birlikte yayınlayın. Bunlar lisans kısıtlamalıdır, bu yüzden etiketleri yalnızca yetenek verildiğinde görünür. MVC 5'te, etiketleri denetleyicide oluşturun (görünümlerde @inject yoktur):
var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
ViewBag.ViewerCss = viewer.ReferenceCss(new CssConfig
{
IncludeViewerCss = true,
IncludeAnnotationCss = true // jquery-ui.min.css + annotationBar.css
});
ViewBag.ViewerScripts = viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeViewerScripts = true,
IncludeAnnotationScripts = true, // jquery-ui, raphael.js, annotation.js
IncludeAnnotationBar = true // the embedded annotation ribbon
});
ViewBag.IsAnnotationEnabled = viewer.IsAnnotationEnabled;Tam Viewer bileşimini işaretlemede tutun:
<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 dosyaları annBarMount içinde Ribbon'ı oluşturur; düğmelerini veya iletişim kutularını kopyalamanıza gerek yoktur. Önce docViewer'ı başlatın, ardından Ribbon'ı yalnızca sunucu Annotation'ın lisanslı olduğunu doğruladığında oluşturun:
@Html.Raw(ViewBag.ViewerScripts)
<script>
var annBar = null;
var currentToken = '';
var objViewer = $('#div_ctlDoc').docViewer({
BasePath: '/',
ResPath: 'doconut-res/images',
onAnnLoaded: function () { if (annBar) annBar.handleAnnLoaded(); },
onAnnSaved: function () { if (annBar) annBar.handleAnnSaved(); },
onAnnSaveError: function () { if (annBar) annBar.handleAnnSaveError(); },
onAnnClosed: function () { if (annBar) annBar.handleAnnClosed(); },
onError: function (message) { console.error('Viewer error:', message); }
});
@if ((bool)ViewBag.IsAnnotationEnabled)
{
<text>
annBar = $('#annBarMount').doconutAnnotationBar({
docId: 'ctlDoc',
getRequestParams: function () { return { token: currentToken }; },
onLayout: function () { requestAnimationFrame(function () { objViewer.Refit(); }); }
});
annBar.attach(objViewer);
</text>
}
</script>Kapasite olmadan, ReferenceScripts Ribbon betiğini dışarıda bırakır, bu yüzden sunucu tarafındaki if korumasız bir doconutAnnotationBar(...) çağrısının sayfayı kırmasını önler. Web Forms'ta aynı korumayı <% if (IsAnnotationEnabled) { %> … <% } %> şeklinde yazın.
Ribbon'dan kaydetme, verileri DocImage.axd (AnnSave) adresine gönderir ve bu, sayfa başına belge oturumunda saklanır. Yükleme (AnnLoad) ise açıklamaları olan bir sayfa render edildiğinde otomatik olarak gerçekleşir.
Kendi araç çubuğunuzdan annBar.open() ve annBar.close() ile Ribbon'ı açıp kapatın. Genel API'si:
| Yöntem | Amaç |
|---|---|
attach(objViewer) | Ribbon'ı başlatılmış görüntüleyiciye bağlar; bir kez gereklidir |
open() / close() | Açıklama düzenlemesine girer veya çıkar |
reset() | Ribbon'ı kapalı, düzenleme dışı duruma geri döndürür |
isOpen() / annotating() | Ribbon durumunu / görüntüleyicinin açıklama düzenleme durumunu okur |
reopenEditable() | Mevcut sayfanın açıklamalarını düzenlenebilir nesneler olarak yeniden yükler |
updateActionState() | Sunucu değişikliklerinden sonra kaydet ve sil kontrollerini yeniler |
headerSlot() | Sunucu sahipliğindeki kontroller için isteğe bağlı başlık yuvası |
onStatus, onToast, onLayout, onEditStart ve onEditEnd isteğe bağlı sunucu geri aramalarıdır. endpoints nesnesi ayrıca exportPdf, exportPng, imageUpload ve imageList sağlayabilir; yapılandırılmış bir uç noktası olmayan kontroller gizli kalır.
İki tür geri çağırma, iki şekilde bağlanmış
Açıklama kodu iki geri çağırma stilini kullanır ve her biri diğer şekilde bağlandığında sessizce başarısız olur:
onAnnLoaded,onAnnSaved,onAnnSaveError,onAnnCloseddocViewer({...})'nin seçenekleridir, tıpkı her görüntüleyici geri çağırması gibi.Created,Changed,DeletedvePropertiesisimle bulunan küresel fonksiyonlardır: olayın önüne görüntüleyici kimliği eklenir.#div_ctlDociçindeki görüntüleyicinin kimliğictlDocolduğundan fonksiyonlarctlDoc_Created,ctlDoc_Changed,ctlDoc_DeletedvectlDoc_Propertiesşeklindedir. Yanlış yazılmış veya yeniden adlandırılmış bir fonksiyon basitçe hiç çağrılmaz.
SaveAnnotations() kaydedip kaydetmediğini döndürmez: sonuç onAnnSaved ya da onAnnSaveError aracılığıyla gelir. Dönüş değerini okuyan kod, “kaydedilmemiş değişiklikler” bayrağını asla temizlemez.
C#'ta açıklamaları oluşturma
Açık oturuma bağlı bir yöneticiyi alın, açıklamaları ekleyin ve onları yükleyin (using Doconut.Annotations; tipler için ve using System.Drawing; Rectangle ve Color için):
// POST /Annotations/LoadSample?token=...
[HttpPost]
public ActionResult LoadSample(string token)
{
var viewer = Doconut.DoconutHost.Services.GetRequiredService<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 viewer fetches them, and the renderer burns them into
// image/PDF exports.
viewer.LoadAnnotationData(token, manager);
return new HttpStatusCodeResult(200);
}Açıklama türleri
Tüm türler Doconut.Annotations içinde bulunur ve BaseAnnotation (sayfa numarası ve sınırlayıcı Rectangle) üzerinden türetilir:
| Tür | Notlar |
|---|---|
StampAnnotation | Yazı damgası, yazı tipi boyutu, kenarlık, renk; Opacity, Rotate destekler |
NoteAnnotation | Yapışkan not, metin, arka plan rengi, yazı tipi boyutu, TitleColor |
RectangleAnnotation | Kenarlık ve dolgu renkleri, Title/ShowTitle |
CircleAnnotation | Kenarlık ve dolgu, ShowBorder |
EllipseAnnotation | Kenarlık ve dolgu, ShowBorder |
TriangleAnnotation | Kenarlık rengi, BackColor, ShowBorder |
LineAnnotation | Genişlik ve renk ile düz çizgi |
ArrowAnnotation | Ok başlığı olan çizgi; ayarlanabilir Direction (ArrowDirection, pusula yönleri, varsayılan E) |
FreehandAnnotation | Kodlanmış FreehandData noktalarından serbest çizgi |
ImageAnnotation | Bir URL'den görüntü. Göreceli bir URL, açıklama eklendiğinde geçerli isteğin sunucusuna göre çözülür — aşağıdaki dışa aktarma notuna bakın |
AnnotationManager API'si
| Üye | Amaç |
|---|---|
Add(BaseAnnotation) | Bir açıklamayı kuyruğa ekle |
GetAnnotations() / GetAnnotations(int page) | Yöneticinin ne tuttuğunu incele |
ClearAnnotations() / ClearAnnotations(int page) | Hepsini / sayfa başına kaldır |
GetAnnotationData() / GetAnnotationData(int page) | Kodlanmış açıklama verileri — widget'ın tükettiği zarf |
GetAnnotationXml() | XML biçimi |
Viewer oturuma karşı yükleme ve okuma işlemlerini yansıtır: LoadAnnotationData(token, manager) veya LoadAnnotationData(token, encodedData), LoadAnnotationXML(token, xml) ve GetAnnotationXML(token).
Açıklamaların yanarak gömülü dışa aktarımı
// PDF of all pages with annotations rendered onto them
public async Task<ActionResult> ExportPdf(string token)
{
var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
byte[] pdf = await viewer.ExportAnnotationsToPdfAsync(token, zoom: 100, ct: Response.ClientDisconnectedToken);
return File(pdf, "application/pdf", "export.pdf");
}
// Or a ZIP of per-page PNGs
public async Task<ActionResult> ExportPngZip(string token)
{
var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
byte[] zip = await viewer.ExportAnnotationsToPngZipAsync(token, zoom: 100, ct: Response.ClientDisconnectedToken);
return File(zip, "application/zip", "annotations-png.zip");
}Dışa aktarmalar, ekrandaki renderlama ile aynı yakıcıyı, aynı lisansı ve özel filigran kararını kullanır.
İntranet sunucusunda görüntü ek açıklamaları "Image blocked" olarak dışa aktarılır
Görüntüleyici ve dışa aktarma, bir ImageAnnotation'ın resmini farklı yerlerden alır:
| Yüzey | Resmi kim indirir | İntranet veya geliştirme sunucusunda |
|---|---|---|
| Tarayıcıdaki görüntüleyici | Kullanıcının tarayıcısı | Resim görünür |
ExportAnnotationsToPdfAsync / …PngZipAsync | Sunucu | Kırmızı "Image blocked" yer tutucu |
Sunucu bir resmi yanına eklemek için alırken, özel ağlara geri dönen adresleri reddeder: döngüsel (localhost, 127.0.0.1), 0.0.0.0, link‑local (169.254.x.x), özel aralıklar 10.x, 172.16–31.x ve 192.168.x, taşıyıcı‑grade NAT (100.64.0.0/10), ve IPv6 link‑local ve unique‑local adresler. Bu, sunucunun, hazırlanmış bir resim URL'si aracılığıyla iç sistemlere ulaşmak için kullanılmasını önler ve bunu kapatacak bir anahtar yoktur.
Bağıl bir resim URL'si, mevcut isteğin ana bilgisayarına göre çözülür, bu yüzden localhost'da, bir intranet sunucusunda veya özel bir adrese sahip herhangi bir sitede, resim görüntüleyicide gösterilir ve dışa aktarma bunun yerine yer tutucuyu içerir. Bu, korumanın çalıştığı anlamına gelir, bir render hatası değildir. Dışa aktarmaların resmi içermesi gerekiyorsa, resmi genel bir adrese sahip bir sunucudan sunun ve mutlak bir URL kullanın. Hiç çözülemeyen bir resim URL'si, o ek açıklamanın hatasız bir şekilde kaybolmasına neden olur — durum kodu yerine işlenen pikselleri veya ağ günlüğünü kontrol edin.
Kalıcılık İş Akışı
- Belgeyi açın ve token'ını alın.
- Daha önce depolanmış XML'i veya kodlanmış veriyi o token'a yükleyin.
- Widget'ın oturum ek açıklamalarını okumasına ve düzenlemesine izin verin.
GetAnnotationXML(token)ile XML'i alın, uygulamanız kalıcı hale getirmeye karar verdiğinde.- Düzleştirilmiş bir teslimat gerektiğinde PDF veya PNG dışa aktarın.
- Belge oturumunu kapatın.
Görüntüleyici token'ını kalıcı bir ek açıklama tanımlayıcısı olarak kullanmayın — oturumla birlikte sona erer ve uygulama havuzunun yeniden başlatılması tek bir sunucudaki tüm oturumları sonlandırır. Ek açıklama verilerini kendi belge ve sürüm tanımlayıcılarınıza karşı depolayın.
Güvenlik ve Görüntüleme Notları
- Ek açıklama istekleri, sayfa istekleriyle aynı oturum ve token güvenliğini kullanır.
- Kullanıcı tarafından sağlanan tüm resim URL'lerini doğrulayın ve kontrol edin.
- Büyük serbest el yükleri ve yüksek çözünürlüklü dışa aktarmalar bellek kullanımını artırır; gerçekçi belgeleri ve yakınlaştırma değerlerini test edin.
Sorun Giderme
| Belirti | Kontrol |
|---|---|
| Ek Açıklama Şeridi eksik | Annotation yeteneği ve dört ek açıklama CSS/skript bayrağı |
| Kaydetme bir hata rapor ediyor | Token veya oturum süresi dolması, ve widget'ın BasePath |
ctlDoc_Created (veya başka bir olay işlevi) hiç çalışmaz | Fonksiyon adı: görüntüleyici kimliği + _ + olay, global bir fonksiyon olarak |
| C# ek açıklamaları görünmüyor | Sayfa numaraları bir‑tabanlıdır ve veri aktif token'a yüklendi |
| Bir resim ek açıklaması ekranda görünüyor ancak dışa aktarımda yok | Resmin ana bilgisayarı özel veya döngüsel bir adrese sahip — yukarıya bakın |
| Yeniden açılan bir belgede ek açıklama yok | XML'i veya veriyi görüntüleyici oturumunun dışına kalıcı hale getirin, ardından yeni token'a yükleyin |
Bu sayfa yardımcı oldu mu?