Guide
Export & Import
Export PDFs and save annotation drafts
KViewer supports exporting PDFs with annotations baked in, and saving/restoring annotation state as JSON for draft workflows.
Export a PDF
Use the template ref to export the current document with annotations:
<template>
<div class="h-screen">
<KViewer ref="viewer" :source="pdfUrl" />
<button @click="exportPdf">Download PDF</button>
</div>
</template>
<script setup lang="ts">
const viewer = ref()
const pdfUrl = '/sample.pdf'
async function exportPdf() {
const bytes = await viewer.value?.exportPdf({
flatten: true,
download: true,
fileName: 'annotated-document.pdf',
})
}
</script>
Export Options
| Option | Type | Default | Description |
|---|---|---|---|
flatten | boolean | false | Burn annotations into page content (non-editable) |
download | boolean | false | Trigger a browser file download |
fileName | string | auto-generated | Custom filename for download |
preserveOriginalAnnotations | boolean | false | Keep unmodified native PDF annotations |
Get Bytes for Upload
Export without downloading to get raw bytes for server upload:
const bytes = await viewer.value?.exportPdf({ flatten: true })
// Upload to your server
await fetch('/api/documents/save', {
method: 'POST',
body: bytes,
headers: { 'Content-Type': 'application/pdf' },
})
Flatten Annotations
When flatten: true, annotations are burned into the PDF page content and become part of the rendered page. They can no longer be edited or removed.
When flatten: false (default), annotations are added as standard PDF annotation objects that can be edited in other PDF viewers.
Handle Native PDF Annotations
When a PDF has existing annotations that were auto-imported by KViewer:
// Recommended: don't preserve originals to avoid duplicates
const bytes = await viewer.value?.exportPdf({
flatten: false,
preserveOriginalAnnotations: false,
})
Setting
preserveOriginalAnnotations: true when native annotations were auto-imported may create duplicate annotations in the exported PDF. Use false in this workflow.Save Annotation Drafts
Save the current annotation state as JSON for later restoration:
// Save draft
const annotations = viewer.value?.getAnnotations() ?? []
const draft = JSON.stringify(annotations)
localStorage.setItem('document-draft', draft)
// Or save to your API
await fetch('/api/drafts', {
method: 'POST',
body: draft,
headers: { 'Content-Type': 'application/json' },
})
Restore Annotation Drafts
Import previously saved annotations:
// Load draft
const draft = localStorage.getItem('document-draft')
if (draft) {
const annotations = JSON.parse(draft)
const result = await viewer.value?.importAnnotations(annotations, {
mode: 'replace',
})
console.log(`Loaded ${result.loaded}, skipped ${result.skipped}`)
}
Import Modes
| Mode | Description |
|---|---|
replace | Clear all existing annotations, then add the imported ones |
merge | Add imported annotations alongside existing ones, skipping collisions |
Full Round-Trip Example
<template>
<div class="h-screen">
<KViewer ref="viewer" :source="pdfUrl" text-layer />
<div class="flex gap-2 p-4">
<button @click="saveDraft">Save Draft</button>
<button @click="loadDraft">Load Draft</button>
<button @click="exportFlattened">Export PDF</button>
</div>
</div>
</template>
<script setup lang="ts">
const viewer = ref()
const pdfUrl = '/sample.pdf'
function saveDraft() {
const annotations = viewer.value?.getAnnotations() ?? []
localStorage.setItem('draft', JSON.stringify(annotations))
}
async function loadDraft() {
const saved = localStorage.getItem('draft')
if (saved) {
await viewer.value?.importAnnotations(JSON.parse(saved), { mode: 'replace' })
}
}
async function exportFlattened() {
await viewer.value?.exportPdf({
flatten: true,
download: true,
fileName: 'final-document.pdf',
})
}
</script>