Anmärkningar
Lägg till stöd för anmärkningar i visaren
Anmärkningar i Doconut fungerar i två riktningar: användare ritar dem i webbläsarwidgeten och servern sparar dem per sida, eller så bygger din kod dem och laddar dem i en öppen session. I båda fallen renderas de på sidorna och kan brännas in i PDF- eller PNG-exporter.
Stöd för anmärkningar styrs av licensfunktionen Annotation (tilldelas automatiskt under en aktiv temporär licens).
Aktivera anmärknings‑UI
Anmärkning är en Viewer-modul, inte ett fristående verktygsfält. Sidan måste inkludera Viewer-resurserna, Viewer-verktygsfältet, Viewer-mounten och en initierad objViewer; Annotations‑Ribbonen monteras sedan och fästs på samma instans.
Skicka med anmärkningsfilerna tillsammans med visarfilerna. De är licensstyrda, så deras taggar visas endast när funktionen är beviljad. I MVC 5 byggs taggarna i kontrollern (vyer har ingen @inject):
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;Behåll hela Viewer-sammansättningen i markupen:
<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>Annotations‑filerna genererar Ribbonen i annBarMount; du kopierar inte dess knappar eller dialoger. Initiera docViewer först, skapa sedan Ribbonen endast när servern bekräftar att Anmärkning är licensierad:
@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>Utan funktionen utelämnar ReferenceScripts Ribbon‑skriptet, så server‑side if‑satsen skyddar ett oövervakat doconutAnnotationBar(...)‑anrop från att bryta sidan. I Web Forms skriver du samma skydd som <% if (IsAnnotationEnabled) { %> … <% } %>.
Sparande från Ribbonen postar data till DocImage.axd (AnnSave), som lagrar den i dokumentsessionen per sida. Laddning (AnnLoad) sker automatiskt när en sida med anmärkningar renderas.
Öppna och stäng Ribbonen från ditt eget verktygsfält med annBar.open() och annBar.close(). Dess publika API:
| Metod | Syfte |
|---|---|
attach(objViewer) | Koppla Ribbonen till den initierade visaren; krävs en gång |
open() / close() | Starta eller avsluta anmärkningsredigering |
reset() | Återställ Ribbonen till dess stängda, icke‑redigerande tillstånd |
isOpen() / annotating() | Läs Ribbonens tillstånd / visarens anmärkningsredigeringstillstånd |
reopenEditable() | Läs om den aktuella sidans anmärkningar som redigerbara objekt |
updateActionState() | Uppdatera spara‑ och raderingskontrollerna efter värdförändringar |
headerSlot() | Den valfria rubrikplatsen för värdeägda kontroller |
onStatus, onToast, onLayout, onEditStart och onEditEnd är valfria värd‑callback‑funktioner. endpoints‑objektet kan också tillhandahålla exportPdf, exportPng, imageUpload och imageList; kontroller utan en konfigurerad endpoint förblir dolda.
Två typer av återuppringning, kopplade på två sätt
Annotationskoden använder två återuppringningsstilar, och varje stil misslyckas tyst när den kopplas på det andra sättet:
onAnnLoaded,onAnnSaved,onAnnSaveError,onAnnClosedär alternativ tilldocViewer({...}), precis som varje visningsåteruppringning.Created,Changed,DeletedochPropertiesär globala funktioner som hittas efter namn: visnings‑ID:t prefixas till händelsen. För visaren i#div_ctlDocär ID:tctlDoc, så funktionerna ärctlDoc_Created,ctlDoc_Changed,ctlDoc_DeletedochctlDoc_Properties. En felstavad eller omdöpt funktion anropas helt enkelt aldrig.
SaveAnnotations() returnerar inte om den sparade: resultatet kommer via onAnnSaved eller onAnnSaveError. Kod som läser dess returvärde rensar aldrig flaggan för "osparade ändringar".
Bygg annotationer i C#
Hämta en manager bunden till den öppna sessionen, lägg till annotationer och ladda dem (med using Doconut.Annotations; för typerna och using System.Drawing; för Rectangle och Color):
// 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);
}Annotationstyper
Alla typer finns i Doconut.Annotations och ärver från BaseAnnotation (sidnummer plus avgränsande Rectangle):
| Typ | Anteckningar |
|---|---|
StampAnnotation | Textstämpel med teckenstorlek, kant, färg; stöder Opacity, Rotate |
NoteAnnotation | Klistrig lapp med text, bakgrundsfärg, teckenstorlek, TitleColor |
RectangleAnnotation | Kant- och fyllnadsfärger, Title/ShowTitle |
CircleAnnotation | Kant och fyllning, ShowBorder |
EllipseAnnotation | Kant och fyllning, ShowBorder |
TriangleAnnotation | Kantfärg, BackColor, ShowBorder |
LineAnnotation | Raka linjen med bredd och färg |
ArrowAnnotation | Linje med pilspets; inställningsbar Direction (ArrowDirection, kompassriktningar, standard E) |
FreehandAnnotation | Fri penseldrag från kodade FreehandData-punkter |
ImageAnnotation | Bild från en URL. En relativ URL löses upp mot den aktuella begärans värd när annotationen läggs till — se exportnoteringen nedan |
AnnotationManager‑API
| Medlem | Syfte |
|---|---|
Add(BaseAnnotation) | Köa en annotation |
GetAnnotations() / GetAnnotations(int page) | Inspektera vad manageren innehåller |
ClearAnnotations() / ClearAnnotations(int page) | Ta bort alla / per sida |
GetAnnotationData() / GetAnnotationData(int page) | Kodat annoteringsdata — omslaget som widgeten konsumerar |
GetAnnotationXml() | XML‑form |
Viewer speglar laddnings‑ och läsoperationerna mot en session: LoadAnnotationData(token, manager) eller LoadAnnotationData(token, encodedData), LoadAnnotationXML(token, xml), och GetAnnotationXML(token).
Export med inbrända annotationer
// 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");
}Export använder samma brännare som skärmrendering, och samma licens‑ och anpassade vattenstämpel‑beslut.
Bildanteckningar på en intranätvärd exporteras som "Bild blockerad"
Visaren och exporten hämtar en ImageAnnotations bild från olika platser:
| Yta | Vem laddar ner bilden | På en intranät- eller utvecklingsvärd |
|---|---|---|
| Visaren i webbläsaren | Användarens webbläsare | Bilden visas |
ExportAnnotationsToPdfAsync / …PngZipAsync | Servern | En röd "Bild blockerad" platshållare |
När servern hämtar en bild för att bränna in den, avvisar den adresser som pekar tillbaka till privata nätverk: loopback (localhost, 127.0.0.1), 0.0.0.0, link‑local (169.254.x.x), de privata intervallen 10.x, 172.16–31.x och 192.168.x, carrier‑grade NAT (100.64.0.0/10) samt IPv6 link‑local och unique‑local adresser. Detta skyddar servern från att användas för att nå interna system via en konstruerad bild‑URL, och det finns ingen omkopplare för att stänga av detta.
En relativ bild‑URL löses mot värden för den aktuella begäran, så på localhost, på en intranät‑server eller på någon webbplats som nås via en privat adress, visas bilden i visaren och exporten innehåller platshållaren istället. Det är skyddet som fungerar, inte ett renderingsfel. Om exporten måste innehålla bilden, servera den från en värd med en publik adress och använd en absolut URL. En bild‑URL som inte kan lösas alls får den anteckningen att försvinna utan fel — kontrollera de renderade pixlarna eller nätverksloggen, inte en statuskod.
Arbetsflöde för beständighet
- Öppna dokumentet och hämta dess token.
- Ladda tidigare lagrad XML eller kodad data i den token.
- Låt widgeten läsa och redigera sessions‑anteckningarna.
- Hämta XML med
GetAnnotationXML(token)när din applikation beslutar att bestå. - Exportera PDF eller PNG när en platt leverans krävs.
- Stäng dokumentsessionen.
Använd inte visartoken som en permanent identifierare för anteckningar — den dör med sessionen, och en återställning av applikationspoolen avslutar varje session på en enskild server. Spara anteckningsdata mot dina egna dokument‑ och versionsidentifierare.
Säkerhet och renderingsanteckningar
- Anteckningsförfrågningar använder samma sessions‑ och token‑säkerhet som sidförfrågningar.
- Validera och kontrollera alla användargenererade bild‑URL:er.
- Stora handritade payloads och högupplösta export ökar minnesanvändning; testa realistiska dokument och zoomvärden.
Felsökning
| Symtom | Kontroll |
|---|---|
| Annoteringsverktygsfältet saknas | Annotation‑kapaciteten och de fyra annoterings‑CSS/script‑flaggorna |
| Sparande rapporterar ett fel | Token‑ eller sessionsutgång, och widgetens BasePath |
ctlDoc_Created (eller en annan händelsefunktion) körs aldrig | Funktionsnamnet: visare‑id + _ + händelse, som en global funktion |
| C#‑anteckningar visas inte | Sidnumren är en‑baserade, och data laddades in i den aktiva token |
| En bildanteckning visas på skärmen men inte i exporten | Bildens värd har en privat eller loopback‑adress — se ovan |
| Ett återöppnat dokument har inga anteckningar | Spara XML eller data utanför visarsessionen, ladda sedan in dem i den nya token |
Var den här sidan hjälpsam?