Skip to content

Export & Print ​

The Svelte viewer can turn slides into a range of formats and save the document back to .pptx. Everything is available both from the built-in toolbar's export menu (with a progress modal and cancellation) and programmatically on the component instance.

Supported formats ​

FormatPipeline
PNGhtml2canvas-pro rasterisation (dynamically imported on first use)
PDFjspdf (dynamically imported) + rasterisation, multi-page, one slide per page
GIFAnimated GIF frame encoder over rasterised frames
WebMMediaRecorder over a canvas capture stream (codec picked from the shared WebM candidates)
SVGVector export straight from the parsed data model (no rasterisation), via standalone functions
PrintShared print document (slides / handouts / notes / outline) in a hidden same-origin iframe
JSONexportToJson (core model serializer): a portable JSON document that re-imports with full fidelity
PPTXCore serializer via save(format), downloadAs, downloadPptx ('pptx' | 'ppsx' | 'pptm')

Lazy dependencies

html2canvas-pro and jspdf are dynamic imports: the first raster/PDF export pays a one-time load cost, and apps that never export never ship them to the client.

Raster and video export ​

All methods live on the component instance (bind:this):

svelte
<script lang="ts">
	import { PowerPointViewer, type PowerPointViewerApi } from 'pptx-svelte-viewer';

	let { bytes }: { bytes: Uint8Array } = $props();
	let viewer = $state<PowerPointViewerApi>();
	let progress = $state('');

	async function exportPdf() {
		await viewer?.exportPdf({
			onProgress: (current, total) => (progress = `${current}/${total}`),
		});
	}
</script>

<PowerPointViewer source={bytes} bind:this={viewer} />
<button onclick={() => viewer?.exportSlidePng()}>PNG (current slide)</button>
<button onclick={() => viewer?.copySlideAsImage()}>Copy as image</button>
<button onclick={exportPdf}>PDF {progress}</button>

ExportPdfOptions ​

OptionTypeDefaultDescription
onProgress(current: number, total: number) => void-Capture-phase progress callback.
signalAbortSignal-Abort the export early (checked between slides).

ExportGifOptions ​

OptionTypeDefaultDescription
slideDurationMsnumber2000Duration each slide is shown.
slideTimingsMsnumber[]-Per-slide duration overrides (index maps to slide index).
maxDimensionnumber960Longest allowed output side in pixels; frames scale down proportionally.
onProgress(current: number, total: number) => void-Capture-phase progress callback.
signalAbortSignal-Abort the export early.

ExportVideoOptions ​

OptionTypeDefaultDescription
slideDurationMsnumber3000Duration each slide is shown.
slideTimingsMsnumber[]-Per-slide duration overrides.
fpsnumber30Recording frame rate.
videoBitsPerSecondnumber5_000_000Recorder bitrate.
onProgress(current: number, total: number) => void-Capture-phase progress callback.
onRecordProgress(current: number, total: number) => void-Recording-phase progress callback.
signalAbortSignal-Abort between slides and between frames.

renderToCanvas ​

A standalone utility exported from the package root (no component instance needed) that rasterises any DOM element to a Canvas:

ts
import { renderToCanvas } from 'pptx-svelte-viewer';

const canvas: HTMLCanvasElement = await renderToCanvas(element, { scale: 2 });
const dataUrl = canvas.toDataURL('image/png');
ts
function renderToCanvas(
	element: HTMLElement,
	options?: Partial<Html2CanvasOptions>, // the html2canvas-pro Options type
): Promise<HTMLCanvasElement>;

This is the same html2canvas-pro wrapper React, Vue, Angular and Vanilla export. Reach for it rather than calling html2canvas yourself: during the onclone phase it runs the shared CSS-preprocessing passes, which convert modern colour functions (oklch / oklab / lch / lab / color()) to sRGB and flatten backdrop-filter, mix-blend-mode and CSS 3D transforms. The viewer's theme tokens are authored in oklch, which html2canvas cannot parse on its own.

Print ​

print(options) assembles the shared print document and opens the browser print dialog. The default print surface is a hidden same-origin iframe, so no popup window is involved. It resolves true once the print surface opened.

ts
await viewer?.print({ printWhat: 'handouts', slidesPerPage: 6, colorMode: 'grayscale' });
await viewer?.print({
	printWhat: 'slides',
	slideRange: 'custom',
	customRangeFrom: 2,
	customRangeTo: 5,
});

PrintOptions is any subset of the shared print settings:

OptionTypeDefaultDescription
printWhat'slides' | 'handouts' | 'notes' | 'outline''slides'What to print.
orientation'landscape' | 'portrait''landscape'Page orientation.
colorMode'color' | 'grayscale' | 'blackAndWhite''color'Colour treatment.
frameSlidesbooleanfalseDraw a border around each slide.
slidesPerPagehandout slides-per-page count6Handout layout density.
slideRange'all' | 'current' | 'custom''all'Which slides to include.
customRangeFromnumber1Custom range start (1-based).
customRangeTonumber1Custom range end (1-based).

Popup blockers

The default iframe surface is immune to popup blockers. A custom window.open-based opener (injectable at the controller level) is not; when blocked, the promise resolves false.

Saving the document ​

MethodSignatureDescription
save(format?: PptxSaveFormat) => Promise<Uint8Array>Serialise the (edited) slides via the core handler.
getContent() => Promise<Uint8Array>Alias of save() from the shared viewer contract.
downloadAs(format: PptxSaveFormat, fileName?: string) => Promise<void>Save + browser download in pptx, ppsx, or pptm.
downloadPptx(fileName?: string) => Promise<void>Save + download as .pptx with a default name.
packageForSharing(fileName?: string) => Promise<void>Assemble and download the sharing package.

SVG: standalone functions ​

SVG export is vector output straight from the parsed data model, exported as plain functions from the package root (no component instance needed):

ts
import { exportSlideToSvg, exportSlideToSvgBlob, exportSlideAsSvg } from 'pptx-svelte-viewer';
FunctionSignatureReturns
exportSlideToSvg(slide, width, height, options?)SVG markup string
exportSlideToSvgBlob(slide, width, height, options?)Blob (image/svg+xml)
exportSlideAsSvg(slide, slideIndex, width, height, options?)triggers a download
exportAllSlidesToSvg(data, options?)string[]
exportAllSlidesToSvgBlobs(data, options?)Blob[]

slide is a PptxSlide (get one from the instance's getSlides() / getActiveSlide()); width/height are the canvas size in pixels from the onload payload. The exportAll* variants take the full parsed PptxData from a pptx-viewer-core handler.

Options (SvgExportSingleSlideOptions / SvgExportAllOptions):

OptionTypeDefaultDescription
includeHiddenbooleanfalseInclude hidden slides when exporting all.
slideIndicesnumber[]allSlide indices to export (0-based).
defaultFontFamilystring-Fallback font family for elements without one.
defaultFontSizenumber-Fallback font size in points.
ts
const slide = viewer?.getActiveSlide();
if (slide) {
	const svg = exportSlideToSvg(slide, canvasSize.width, canvasSize.height);
	// e.g. inline it, upload it, or hand it to a design tool
}

Pipeline limitations ​

Raster export inherits the html2canvas-pro constraints (see Limitations): some CSS features (backdrop-filter, CSS 3D transforms) lose fidelity in capture, mix-blend-mode is approximated, and canvas size is capped by the browser's maximum, bounding the export resolution. The SVG path avoids rasterisation entirely but covers the data model, not arbitrary DOM styling.

Released under the Apache-2.0 License.