Media editor: build vs buy in the age of AI
Polotno

PDF EDITING

PDF editor SDK and API – open a PDF and edit it as layers

Embed a JavaScript PDF editor in your app. Import a PDF and get editable text, images, and vector paths on a canvas, then export a vector PDF back out.

Most PDF tooling treats a document as something to view or annotate on top of. Polotno takes a different route: it parses the PDF into a design schema, so text stays text, images stay images, and vector artwork stays paths. The result is a document your users can genuinely edit on a canvas: then export back out as a vector PDF.

The round trip

Three steps, all available in the browser or on a server.

js
import { pdfToJson } from '@polotno/pdf-import';
import { jsonToPDFBlob } from '@polotno/pdf-export/browser';
import { createStore } from 'polotno/model/store';

// 1. Parse
const json = await pdfToJson({ pdf: await file.arrayBuffer() });

// 2. Edit – programmatically, or hand the store to the editor UI
const store = createStore({ key: 'YOUR_KEY' });
store.loadJSON(json);
await store.waitLoading();

// 3. Export as vector PDF, with text still selectable
const blob = await jsonToPDFBlob(store.toJSON());

Between step two and step three you can do anything the SDK allows: change copy, swap a logo, recolour a background, delete pages, add elements, or apply a template. The editor UI is the same canvas used for images, text, and video, so a user who can edit a social post can edit a PDF.

Try the parse step without writing code in the PDF to JSON tool, which runs the same pdfToJson() function in your browser.

Mounting a JavaScript PDF editor

The store from step two is the same store the editor UI renders, so putting a JavaScript PDF editor in front of users is a matter of mounting the components around it:

js
import { PolotnoContainer, SidePanelWrap, WorkspaceWrap } from 'polotno';
import { Toolbar } from 'polotno/toolbar/toolbar';
import { SidePanel } from 'polotno/side-panel';
import { Workspace } from 'polotno/canvas/workspace';

export const PdfEditor = () => (
  <PolotnoContainer style={{ height: '90vh' }}>
    <SidePanelWrap><SidePanel store={store} /></SidePanelWrap>
    <WorkspaceWrap>
      <Toolbar store={store} />
      <Workspace store={store} />
    </WorkspaceWrap>
  </PolotnoContainer>
);

The store itself is plain JavaScript and the UI layer is React, so React and Next.js are the shortest path while Vue, Svelte, Angular, and vanilla JS work by mounting the store yourself. @polotno/pdf-import and @polotno/pdf-export carry no UI dependency at all and run the same in the browser or under Node.

For a walkthrough that compares this approach against the pdf-lib style of PDF editing, see how to build a JavaScript PDF editor.

What you get back from a PDF

The parser emits typed elements, not a flattened bitmap:

  • text: content, font family, size, weight, fill, position, rotation, alignment. Rich-text styling survives: mixed weights inside a paragraph, justified text, multi-column bodies, footnotes, and dotted tables of contents. Headings filled with an image or gradient through a glyph clip come back as editable text rather than a picture of text, and a text outline as Word or Canva writes it comes back as the text's own stroke.
  • table: ruled grids are reconstructed as real table elements with editable cells, borders, and alignment, not as loose lines and text.
  • image: base64 source, crop region, position, opacity.
  • svg: vector artwork re-emitted as inline SVG with position and size, dashed strokes included.
  • group: a PDF transparency group whose opacity or blend mode changes the result stays an editable group, and PDF blend modes carry over as each element's own blend mode.

Bullet columns import as a single text element with real <ul> markup rather than glyphs faked with spaces. Damaged embedded fonts are repaired before use, and each page is sized from its own viewport, so a document that mixes page sizes or rotations does not get forced into one box. A shadow baked into a bitmap, or painted as a semi-transparent offset copy under each line, is folded into the text element's own shadow, so it follows the wording when you edit it.

Pages are sized at the PDF's TrimBox, with any bleed carried outside the page, so a print-ready file round-trips without losing its geometry. Password-protected files import by passing the password option to pdfToJson.

Because every element carries explicit coordinates, edits are precise and repeatable. The full shape is documented in the PDF import reference and the design schema.

Editing programmatically – the edit PDF API

The same API that powers the UI is available headlessly, which makes scripted PDF manipulation straightforward.

js
// Replace a placeholder across every page, inside groups too
store.find((el) => {
  if (el.type === 'text' && el.text.includes('{{name}}')) {
    el.set({ text: el.text.replace('{{name}}', customer) });
  }
  return false; // keep walking
});

Typical uses: correcting a price across a catalogue, localizing a template, injecting a customer name into a contract draft, or normalizing brand colours across a set of supplied documents.

Export fidelity

There are two export paths, and the difference matters. store.saveAsPDF() is built in and raster: each page is flattened to an image, which is right when you need pixel parity with the canvas. @polotno/pdf-export is vector: text is embedded as subsetted fonts and stays selectable, files are smaller, and output scales for print. Use vector unless you specifically want the flattened version.

Vector export runs in the browser (jsonToPDFBlob) or under Node (jsonToPDF), and supports CMYK, spot colours, bleed, crop marks, and PDF/X-4 or PDF/X-1a: see PDF export.

The browser build carries all 14 standard PDF fonts — Arial/Helvetica, Times New Roman, and Courier New in regular, bold, italic, and bold-italic, plus Symbol and Zapf Dingbats — so text set in them exports without downloading a font.

You are not limited to PDF on the way out. The same edited design exports to PNG, JPG, SVG, HTML, or PPTX.

Honest limits

Worth knowing before you scope a build:

  • Scanned PDFs contain no text layer. The parser returns image elements and nothing to edit as text. Run OCR first with a dedicated tool, then import the text-augmented file.
  • Form fields come in as text, not as fields. The text a form carries is imported and stays editable, but AcroForm widgets are not parsed as interactive fields, so a filled form loses its form-ness on the way through.
  • Annotations arrive flattened into the page. There is no editable comment or markup layer.
  • Redaction in the security sense is not provided. Deleting an element removes it from the design, which is an editing operation, not a certified redaction.
  • Exotic layouts – heavily ligatured scripts, unusual embedded font subsets, and complex transparency groups can shift on re-export. Test with your own documents.

If those limits rule Polotno out, they are genuine reasons to pick a document-processing SDK instead.

Related reading

Embed creative infrastructure into your product

TRUSTED BY

100,000+

CREATORS

300+

BUSINESSES

ExpediaUnbounceLovePopPostGridPredis.ai