New
Apps 1,162Makers 1,160This week 1,162
Promote your app−30%
DartPDF screenshot 1
2views in
the last 30 days

DartPDF

Free local PDF editor for Android, iOS, desktop and web.

Built with Claude Code

by ben-milanko · from AUAustralia · added Oct 29, 2026
no ratings0 comments

dart-pdf, an open-source Flutter PDF editor and pure-Dart renderer

dart-pdf: Flutter PDF editor and renderer

Tip

Want the app, not the SDK? DartPDF is the official PDF editor built on this library. Edit, annotate, sign, and fill PDFs entirely on your device, with no account and no uploads. Get it at dart-pdf.com or open it in your browser.

Need to complete a form? Fill and sign a PDF with DartPDF explains existing fields, flat forms, drawn signatures, and saving a checked copy.

DartPDF, the official PDF editor app, built on this SDK. Get the app at dart-pdf.com

An open-source Flutter PDF editor, viewer, and renderer written entirely in Dart. No PDFium, no platform channels.

The goal is a PSPDFKit-class SDK built natively for Flutter: a fast viewer, a full annotation suite with appearance-stream generation, AcroForm filling, page manipulation, and editing that preserves digital signatures.

Feature parity is only the foundation. The UX vision defines the product north star, the journeys that matter, how their quality is measured, and the definition of done for user-facing work.

Status: the roadmap below is complete. COS parsing with xref recovery, signature-preserving incremental updates with encrypt-on-write, a content-stream interpreter with TrueType/CFF/Type3 font rendering, mesh shadings, ICC color, pure-Dart CCITT/JBIG2/JPEG 2000 decoders, a zoomable Flutter viewer with text selection and search, inferred text reflow, annotation authoring and flattening, AcroForm filling, page manipulation, digital signatures with trust-store chain validation, content editing, and the full editing UI: tools, panels, forms, touch/stylus input, theming, and a sync surface for collaborative annotation stores.

The example app: PdfEditorView showing the feature showcase document

Live demo: https://dart-pdf-demo.web.app (the example app built for the web; it opens onto a six-page feature showcase, and the open button loads your own PDF).

Developer overview: Flutter PDF editor

Step-by-step integration: How to add PDF editing to a Flutter app with installation, architecture, supported editing features, and benchmarks.

Visual render results, browsable directly in GitHub: the checked-in PDF.js corpus comparison gallery shows PDF.js baselines, Dart renders, and diffs side by side, and the Ghent Output Suite render gallery shows every print-conformance page we rasterize (our own renders, which are the baselines - so no diff column).

Merge PDFs

import 'package:pdf_document/pdf_document.dart';

final mergedBytes = PdfMerger.merge([firstPdfBytes, secondPdfBytes]);

The bytes-only API runs on desktop, mobile, and web. It preserves the first PDF's encryption and viewing settings, imports form fields and bookmarks, and remaps named links. See merge options and collision rules.

In DartPDF, choose Insert document… from the app menu to insert a PDF after the current page. Dropping PDFs on the thumbnail strip inserts at the marked position; dropping on the document offers Insert pages to append them. Each inserted file is one undo step and uses the existing save/recovery session.

Reduce file size

In DartPDF, choose Reduce file size… from the app menu. Start with Lossless, or choose Screen, eBook, or Print to trade image resolution for a smaller file. Advanced settings control individual passes, target DPI, and JPEG quality. Review the before/after sizes and category breakdown, then Save copy using the platform's save/download/share flow.

The library exposes the same optimiser through PdfCompressor.optimize and PdfEditor.compress. See compression options and supported content.

Performance

The default viewer has not reached PDFium interaction parity yet. The most recent real-document checkpoint (2 October 2026, commit fadf7760) used five interleaved DartPDF/PDFium runs in Chrome 154 on an M1 Pro, a 1400×1000 viewport, and the default JS/CanvasKit web build. The input was a locally supplied 62-page, 24.1 MB illustrated PDF; the journey opened it, jumped to pages 3 and 47, zoomed to 1.72×, and drove matched wheel gestures. Lower ratios are better.

user-visible metric DartPDF p50 / p95 PDFium p50 / p95 ratio p50 / p95
open to stable visual 711 / 757 ms 1264 / 1411 ms 0.56× / 0.54×
page first visual change 24 / 31 ms 19 / 22 ms 1.26× / 1.39×
page stable visual 271 / 357 ms 118 / 121 ms 2.30× / 2.95×
zoom stable visual 44 / 47 ms 19 / 25 ms 2.32× / 1.92×
wheel journey 413 / 919 ms 972 / 1022 ms 0.42× / 0.90×
wheel rAF interval p95 83 ms 17 ms 4.96×
peak browser RSS p50 2167 MiB 1887 MiB 1.15×

The wheel journey completes sooner, but its worse rAF tail means it is not yet as smooth; total duration alone would be a misleading win. Headless Chrome 154 appears to pace frames at 60 Hz on this host (PDFium's rAF p95 is 17 ms, where it was 10 ms in August), so the cadence ratio is not directly comparable with earlier checkpoints. Open and memory are inside the current provisional budgets (memory with less headroom than in August), while stable navigation, zoom, and scroll cadence are not. These numbers describe desktop web only and are not a native-desktop or mobile parity claim. See the full methodology and historical experimental results in the PDFium parity notes.

The offline corpus benchmark remains useful as a subsystem diagnostic, not as evidence of viewer latency: over the 52-file / 268-page common subset at scale 2, pure-Dart interpretation takes 10.3 ms/page, PDFium rasterization takes 31.1 ms/page, and the complete Flutter raster plus readback takes 54.0 ms/page. Reproducible offline harnesses and file-by-file diffs live in benchmark/.

Architecture

Strictly layered packages; Flutter and dart:ui stay in the editor and its optional Flutter companions, so the core runs on servers and in plain Dart tests. Published packages use their directory name on pub.dev.

Package pub.dev Role
pdf_cos pub package The PDF file format itself: tokenizer, parser, filters (incl. CCITT/JBIG2/JPX), encryption, cross-reference machinery, serializer, crypto primitives.
pdf_document pub package Document semantics: page tree, annotations, AcroForm, digital signatures, and the incremental-save PdfEditor.
pdf_graphics pub package Content-stream interpreter, device interface, font engine, ICC color, text extraction.
dart_pdf_cli — Pure-Dart dartpdf command line and stdio MCP server for bounded document inspection, text extraction, form listing, and annotation listing.
dart_pdf_editor pub package Flutter viewer and editing UI: canvas device, PdfViewer, tools, panels, forms.
dart_pdf_printing Initial release pending Optional print preview, sheet layout and native system printing on all six Flutter platforms.
dart_pdf_editor_flutter_gpu pub package Experimental opt-in Impeller/flutter_gpu tile renderer for supported native targets, with exact Canvas fallback for unsupported pages.
dart_pdf_editor_assets pub package Optional bundled editor fonts + web render worker (~4.2 MB package download); depend on it and call registerBundledEditorAssets() for the full editor, omit for a size-minimal viewer.
pdf_ocr_ondevice pub package Optional on-device OCR engine for native Flutter apps; downloads a small PP-OCR model once and adds searchable text layers offline.
pdf_ocr_vlm pub package Optional HTTP OCR engine for web, mobile, and desktop; talks to dots.ocr/vLLM or any service returning text boxes.
pdf_test_fixtures pub package Programmatic, structurally-correct PDF builders for tests.

Quick start

For shell, CI, and local agent workflows, run the pure-Dart CLI directly from the workspace:

dart run packages/dart_pdf_cli/bin/dartpdf.dart inspect document.pdf --json
dart run packages/dart_pdf_cli/bin/dartpdf.dart text document.pdf --pages 1-5 --json

The same handlers are exposed as bounded, read-only MCP tools through dartpdf mcp. See the dart_pdf_cli guide for installation (including the copy bundled in desktop app builds), filesystem roots, password handling, and host registration.

For a Flutter app, add the editor package:

flutter pub add dart_pdf_editor

Then give the drop-in shell PDF bytes and bounded space:

import 'package:dart_pdf_editor/dart_pdf_editor.dart';

PdfEditorView(
  bytes: pdfBytes,
  onSave: (bytes) => saveBytesSomewhere(bytes),
)

PdfReader(bytes: pdfBytes)

To open a large PDF hosted remotely without downloading the whole file first, use the asynchronous byte-source API. PdfHttpByteSource fetches over HTTP Range requests (forwarding auth headers, with cancellation and progress), and falls back to a plain download when the server does not support ranges:

final source = PdfHttpByteSource(
  Uri.parse('https://host/big.pdf'),
  headers: {'Authorization': 'Bearer $token'},
  cancelToken: cancelToken,
  onProgress: (received, total) => report(received, total),
);
final document = await PdfDocument.openSource(source);

For an even faster first paint on a big, image-heavy document (a scan, a CAD sheet), pass firstPaintPages so the loader fetches only the first page's bytes, paints it, and lets you stream the rest in behind it:

final preview = await PdfDocument.openSource(
  source,
  options: PdfSourceLoadOptions(
    firstPaintPages: 1,
    onProgress: (received, total) => report(received, total),
  ),
);
// `preview` renders the first page immediately, but its buffer is deliberately
// incomplete - render-only, never edit or sign from it. Read the whole source
// in the background and reopen for the full document when you need every page.

PdfByteSource is network-agnostic (length + readRange), so any random- access transport works - including a local file. PdfDocument.open(Uint8List) and the byte-based widgets are unchanged. See doc/progressive-loading.md for the full guide (local files, the fast-first-paint pattern, Flutter viewer wiring) and doc/dev-log for the loader design.

For OCR, add one engine package and call PdfEditor.applyOcr before opening or replacing the document in your viewer:

flutter pub add pdf_ocr_ondevice   # native offline OCR
# or
flutter pub add pdf_ocr_vlm        # HTTP OCR, including Flutter web

pdf_ocr_ondevice is the simplest native path: it downloads the default model once, caches it in app support storage, then runs offline. pdf_ocr_vlm is the simplest web/server path: point it at a CORS-enabled OCR service. Both write the same invisible text layer, so scanned pages become selectable, searchable, and copyable without changing how the PDF looks.

Splitting PDFs

pdf_document can generate multiple standalone PDFs directly from bytes:

final parts = PdfSplitter.splitExpression(bytes, '1-3, 7, 10-12');
// Three outputs: pages 1–3, page 7, and pages 10–12.
final firstThree = PdfSplitter.splitRange(bytes, 0, 2); // zero-based, inclusive

PdfEditorView(onSplitPages: ...) adds a validated Split PDF… dialog to the thumbnail page-actions menu. The example opens each result in a new editable tab. Existing single-range and thumbnail-selection exports remain available.

Page annotations/resources and document information are retained; bookmarks, the document-level AcroForm field list, and named destinations are omitted. Links between pages retained in one output are remapped. Copied widgets are not registered in an AcroForm. Resources remain shared within an output where possible; each output owns its copies. Encrypted sources yield unencrypted outputs. See the splitting guide for indexing, password handling, validation, and extraction semantics.

Roadmap

  1. ✅ COS reader: lexer, parser, FlateDecode + predictors, xref tables, xref streams, object streams
  2. ✅ Incremental-update writer (signature-preserving); first edits: metadata, page rotation
  3. ✅ Encryption: opening RC4/AES-128/AES-256 documents (user and owner passwords) and encrypt-on-write, so encrypted documents are editable and signable (the signature's /Contents stays plain per ISO 32000 §7.6.1; every other string in the signed revision is encrypted).
  4. ✅ Content-stream interpreter with an abstract device interface
  5. ✅ Font engine: TrueType/CFF glyph outlines, CID fonts, CMaps, ToUnicode
  6. ✅ Flutter rendering device + viewer widget
  7. ✅ Text extraction with positions, feeding selection and search plus paragraph/reading-order inference for text reflow
  8. ✅ Annotations: model, appearance-stream rendering, authoring with generated appearances (highlight/underline/strike-out/squiggly, ink, shapes, free text, callouts, notes, stamps, measurements, count, and redaction), and flattening
  9. ✅ AcroForm: field model (text, check box, radio, choice), filling with regenerated appearances (auto-size, multiline wrap, quadding, /MK decorations), and template editing: field metadata, creating fields on any document, renaming, deleting, retyping, image-filled push buttons, and fault-tolerant whole-form flattening
  10. ✅ Page manipulation: reorder/move, remove, merge with cross-document object copying (appendPagesFrom), and split (extractPages writes a standalone file; extracting from an encrypted document decrypts)
  11. ✅ Digital signatures: validation (CMS/PKCS#7 with RSA and ECDSA P-256/384/521 and RSASSA-PSS, byte-range and revision-coverage checks) and signing (saveSigned, adbe.pkcs7.detached, RSA-SHA256, verified interoperable with OpenSSL and poppler)
  12. ✅ Content editing: stamping (stampPage, text, shapes, JPEG and PNG images over existing content), element deletion (PdfPageElements + deleteElements), and text editing (replaceText, across a line's shown strings with width-compensated re-measurement; reflowText rewraps supported single-column paragraphs, including compatible embedded Type0 fonts)

Deliberately deferred: JBIG2 Huffman/refinement variants and JPX subsampling/PCRL-CPRL progressions.

Features

Viewer

  • Zooming/panning viewer with fit-page and fit-width modes, and deep-zoom detail rendering past the raster caps.
  • Text selection with mouse or touch (long-press, then drag handles), full-text search, link navigation, outlines.
  • Reader reflow mode infers visual lines, columns, reading order, and paragraphs from positioned text, then presents a continuous selectable text view for narrow screens.
  • Custom always-visible scrollbars that stay usable while zoomed; a horizontal bar appears for panning the zoom window. Scroll metrics are computed from real page heights, so the thumb doesn't jump around on long documents with mixed page sizes.
  • Trackpad pinch and scroll don't fight each other (each gesture commits to one or the other), touch pinch zoom works with a tool armed, and flings keep their momentum, including finger scrolls while an editing tool owns the gestures.
  • Navigation (search results, links, thumbnails) accounts for the zoom window, so jumps land where the user is looking.
  • During fast flings, pages show low-resolution cached previews rather than blank paper; full rendering resumes when scrolling settles, keeping heavy CAD documents smooth.
  • Rendering is progressive: the default worker records pages off the UI thread, streams partial page records as they are produced, and reveals complex pages top-down instead of waiting for the whole page.
  • The renderer supports print-oriented overprint and spot-color behavior, including image colorants, rather than approximating every overprint draw with a blend mode.
  • Dark mode, arbitrary page background colors (PdfViewer.pageColor), chrome theming via PdfViewerTheme, and a hide-all-annotations toggle.

Annotation editing

  • PdfEditingController saves incrementally on every edit, so revisions are byte prefixes of one buffer and undo/redo is essentially free.
  • Tools: text markup (highlight/underline/strikeout/squiggly), ink, freehand highlighting, shapes (including polylines, polygons, and revision clouds), free text, Bluebeam-style callouts, notes, stamps (including saved custom stamps), hyperlinks (URI and in-document), placed images with interactive cropping, and a saved ink signature.
  • Callouts pair an editable text box with a leader line and arrowhead. The terminus and its attachment to the box can be repositioned independently, while moving the body keeps the whole callout together.
  • A stamp on the page goes back into the stamp collection from its

Description taken from the repository README.

Ratings

–
0 ratings
5 0
4 0
3 0
2 0
1 0

Rate this app

Sign in to rate

Comments 0

Sign in to comment

No comments yet.

Related apps

#pdf · #editor · #flutter