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):

csharp
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:

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 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
@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öntemAmaç
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, onAnnClosed docViewer({...})'nin seçenekleridir, tıpkı her görüntüleyici geri çağırması gibi.
  • Created, Changed, Deleted ve Properties isimle bulunan küresel fonksiyonlardır: olayın önüne görüntüleyici kimliği eklenir. #div_ctlDoc içindeki görüntüleyicinin kimliği ctlDoc olduğundan fonksiyonlar ctlDoc_Created, ctlDoc_Changed, ctlDoc_Deleted ve ctlDoc_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):

csharp
// 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ürNotlar
StampAnnotationYazı damgası, yazı tipi boyutu, kenarlık, renk; Opacity, Rotate destekler
NoteAnnotationYapışkan not, metin, arka plan rengi, yazı tipi boyutu, TitleColor
RectangleAnnotationKenarlık ve dolgu renkleri, Title/ShowTitle
CircleAnnotationKenarlık ve dolgu, ShowBorder
EllipseAnnotationKenarlık ve dolgu, ShowBorder
TriangleAnnotationKenarlık rengi, BackColor, ShowBorder
LineAnnotationGenişlik ve renk ile düz çizgi
ArrowAnnotationOk başlığı olan çizgi; ayarlanabilir Direction (ArrowDirection, pusula yönleri, varsayılan E)
FreehandAnnotationKodlanmış FreehandData noktalarından serbest çizgi
ImageAnnotationBir 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

ÜyeAmaç
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ı

csharp
// 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üzeyResmi kim indirirİntranet veya geliştirme sunucusunda
Tarayıcıdaki görüntüleyiciKullanıcının tarayıcısıResim görünür
ExportAnnotationsToPdfAsync / …PngZipAsyncSunucuKı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ışı

  1. Belgeyi açın ve token'ını alın.
  2. Daha önce depolanmış XML'i veya kodlanmış veriyi o token'a yükleyin.
  3. Widget'ın oturum ek açıklamalarını okumasına ve düzenlemesine izin verin.
  4. GetAnnotationXML(token) ile XML'i alın, uygulamanız kalıcı hale getirmeye karar verdiğinde.
  5. Düzleştirilmiş bir teslimat gerektiğinde PDF veya PNG dışa aktarın.
  6. 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

BelirtiKontrol
Ek Açıklama Şeridi eksikAnnotation yeteneği ve dört ek açıklama CSS/skript bayrağı
Kaydetme bir hata rapor ediyorToken veya oturum süresi dolması, ve widget'ın BasePath
ctlDoc_Created (veya başka bir olay işlevi) hiç çalışmazFonksiyon adı: görüntüleyici kimliği + _ + olay, global bir fonksiyon olarak
C# ek açıklamaları görünmüyorSayfa 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 yokResmin ana bilgisayarı özel veya döngüsel bir adrese sahip — yukarıya bakın
Yeniden açılan bir belgede ek açıklama yokXML'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?