betto_pdfium
A pure Dart package wrapping the PDFium library for PDF rendering, text extraction, and annotation support.
0.1.0
bettongia/pdfium
What this package is like to depend on
Last release today
24 Aug 2026
Too new to tell
only 2 release windows
Nearly every release is documented
notes for 1 of 1 stable releases
1 version withdrawn
withdrawn after publishing
1 months old
5 releases · first in 2026
5 releases in the last 12 months
see the full history below
Release timeline
5 releases · Jun 2026 to Aug 2026Releases
latest 5-
0.1.024 Aug 2026Release notes
Open source →The first stable release of
betto_pdfiumand its iOS companion plugin
betto_pdfium_ios.betto_pdfiumis a pure Dart wrapper around
PDFium viadart:ffi. There is no
dependency ondart:uior Flutter, so it works in CLI tools, server-side Dart,
and Flutter apps alike. Pre-built PDFium binaries
(bblanchon/pdfium-binaries
chromium/7906) are downloaded automatically by the native-assets build hook on
first use — no C++ toolchain required.There are no functional changes since
0.1.0-dev.4; this release promotes the
dev channel to a stable version. The notes below summarise everything that
landed across0.1.0-dev.1→0.1.0.Installation
dependencies: betto_pdfium: ^0.1.0
Flutter iOS apps also need the companion plugin, which delivers the PDFium
xcframework via Swift Package Manager:dependencies: betto_pdfium: ^0.1.0 betto_pdfium_ios: ^0.1.0
Platform support
All eight targets are supported:
Platform Status macOS arm64 Supported Linux x86_64 Supported Linux arm64 Supported Windows x86_64 Supported iOS arm64 Supported (xcframework) Android arm64 Supported Android x86_64 Supported Web (WASM) Supported On desktop the binary is fetched automatically on the first
dart testor
dart run. On iOS the xcframework arrives through SPM duringflutter pub get.
Web requiresmake fetch_wasm_assetsto stage the WASM/JS artifacts — see the
package README.API surface
Everything hangs off
PdfDocument:- Document loading —
PdfDocument.fromBytes()loads into a background
isolate so the calling isolate is never blocked.PdfExtractionException
distinguishesPdfError.passwordRequiredfromPdfError.invalidDocument.
close()releases the native handle and is safe to call more than once. - Metadata —
getMetadata()(title, author, subject, keywords, creator,
producer, creation/modification dates),getDocumentInfo()(file version,
permanent/changing IDs), andpageCount. - Text extraction —
extractPlainText()streamsPdfPageTextper page with
hasTextLayerandhasUnicodeErrorsflags;isPlainTextExtractable()gives
a quick scanned-document check. - Rendering —
renderPageToBytes()produces a raw BGRA pixel buffer, with
optional annotation rendering, LCD text, and background colour.
getPageSize()returns dimensions in points plussizeForDpi(). - Annotations —
extractAnnotations()streams typed annotations: text,
markup (highlight/underline/squiggly/strikeout, withquadPoints), free text,
ink, shape, popup, and stamp. - Images —
extractImages()streams image objects with bounding boxes and
metadata, optionally with bitmaps;renderImage()fetches a single image's
BGRA bitmap on demand. - Search —
search()streams matches with page index, character index, and
rects in PDF user space; supports case, whole-word, and consecutive flags. - Table of contents —
tableOfContentsreturns the full nested bookmark
tree. - Thumbnails —
getThumbnail()returns the embedded/Thumbstream when
present, or a rendered fallback at a requested maximum dimension. pdfinfoCLI —dart run bin/pdfinfo.dartinspects metadata, document
info, page count, table of contents, and text extractability.
Streams are fully cancellable — cancelling or calling
close()stops processing
immediately with no native handle leaks.Architecture notes
- PDFium is not thread-safe, so all calls run on a single process-wide isolate
(PdfiumIsolate), lazily spawned and shared by everyPdfDocument. - On web,
dart:isolateis unavailable, so the same concurrency model is
implemented with a dedicated Web Worker and apostMessageprotocol. Large
document operations do not block the browser main thread. - Rendering returns raw BGRA bytes rather than a
dart:uiImage, keeping the
rendering surface usable outside Flutter.
Notable fixes in the dev channel
- Native library resolution in a Pub workspace (
dev.4) — when running from
a workspace member package, the native-assets pipeline stages the library to
the workspace root.dart_tool/lib/. The loader now walks up from the
working directory probing each ancestor, covering both single-package and
workspace layouts on Linux, macOS, and Windows. - Dart 3.13 support (
dev.4) — SDK constraint raised to^3.13.0, verified
end-to-end against the 3.13 native-assets pipeline on macOS, Linux (x64 and
arm64), and Windows.
Quality
608 tests passing at 96.2% line coverage.
Documentation
- Package README:
packages/betto_pdfium/README.md - Full specification and API docs: https://bettongia.github.io/pdfium
- Changelog:
packages/betto_pdfium/CHANGELOG.md
Packages on pub.dev
- Document loading —
-
0.1.0-dev.422 Aug 2026 pre-releaseRelease notes
Open source →When
dart testruns from a workspace member package, the native-assets
pipeline stages the bundled PDFium library to the workspace root
.dart_tool/lib/, not the package's own.dart_tool/lib/. The runtime loader
(_openLibrary) previously probed only the current directory's
.dart_tool/lib/, so a PDFium call issued from a spawned isolate — which cannot
see the test runner'sLD_LIBRARY_PATHand so cannot use the bare-name
fallback — failed withcannot open shared object file: No such file or directory.This surfaced under Dart 3.13 in the kmdb workspace's PDF vault indexing:
dart test(run frompackages/kmdb_cli) stageslibpdfium.soto the
workspace root.dart_tool/lib/, but_openLibrarylooked in the package dir
and missed it. betto_pdfium's own CI never exercised this because its test
suite injects an explicit dylib path vianativeDylibPath().- Add
dartToolLibCandidates(startDir, libName): walks up from the working
directory, yielding each ancestor's.dart_tool/lib/<libName>nearest-first.
Covers both the single-package layout (staged in cwd) and the workspace
layout (staged in an ancestor root). - Use it in the Linux, macOS, and Windows branches of
_openLibraryin place
of the single$cwd/.dart_tool/lib/probe. - Add unit tests for the walk-up (ordering, ancestor inclusion, root
termination, library-name embedding). The helper is pure and testable, so it
is not under the platformcoverage:ignoreregion.
Version stays at 0.1.0-dev.4; bump to 0.1.0 (WI-9) once CI is green.
Co-authored-by: Claude Opus 4.8 [email protected]
Release notes
Open source →Fixed
- Native library resolution in a Pub workspace. When
dart testruns from a workspace member package, the native-assets pipeline stages the bundled PDFium library to the workspace root.dart_tool/lib/, not the package's own. The runtime loader previously probed only the current directory, so a PDFium call issued from a spawned isolate (which cannot see the test runner'sLD_LIBRARY_PATH) failed to load the library withcannot open shared object file. The loader now walks up from the working directory, probing each ancestor's.dart_tool/lib/, covering both the single-package and workspace layouts on Linux, macOS, and Windows. This surfaced under Dart 3.13 in thekmdbworkspace's PDF vault indexing.
Toolchain
- Dart 3.13 support. SDK constraint raised to
^3.13.0. Verified end-to-end against the Dart 3.13 native-assets pipeline: the prebuilt-binary build hook, library loading, and the full native API surface (text/annotation/image extraction, rendering, and search) pass on macOS, Linux (x64 and arm64), and Windows. - lcov 2.x build compatibility. Coverage
lcov/genhtmlinvocations now pass--ignore-errors empty, so the line-only tracefiles Dart emits no longer fail the build under lcov 2.0 (shipped on current Ubuntu runners). - Regenerated the web
pdfium_worker.jswith the Dart 3.13 toolchain.
- Add
-
0.1.0-dev.302 Jul 2026 pre-releaseRelease notes
Open source →Platform support
- Windows x86_64 — pre-built
pdfium.dll(bblanchon/pdfium-binaries) is now downloaded automatically by the native-assets hook, matching the existing macOS/Linux workflow. No native toolchain required. - Web (WASM) —
PdfDocumentis now fully implemented on Flutter web anddart2wasmviadart:js_interop, covering the complete API surface (metadata, text/annotation/image extraction, rendering, search, table of contents, thumbnails). Runmake fetch_wasm_assetsto place the PDFium WASM + JS + Worker artifacts in your app'sweb/assets/pdfium/directory; see the package README for setup. - Web (WASM) — Web Worker offload — PDFium calls on web now run inside a
dedicated Web Worker instead of the browser main thread, so large document
operations no longer block the UI.
dart:isolateis not supported on web, so this uses a hand-rolledWorker+postMessageprotocol mirroring the nativePdfiumIsolatearchitecture's shape.make fetch_wasm_assetsnow also copies the checked-inpdfium_worker.jsartifact alongsidepdfium.wasm/pdfium.js— no other consumer-facing change. See the README's "Web (WASM)" section, including the "Adopting the Web Worker backend" migration guide, andspec/02_pdfium_isolate.md's "Web Worker concurrency model" section.
- Windows x86_64 — pre-built
-
0.1.0-dev.229 Jun 2026 pre-release -
0.1.0-dev.128 Jun 2026 pre-release withdrawnRelease notes
Open source →First developer preview. All core PDF operations are implemented and tested (96.1 % line coverage). API is subject to change before 1.0.
Platform support
Pre-built PDFium binaries (bblanchon/pdfium-binaries chromium/7906) are shipped for:
- macOS arm64
- Linux x86_64 and arm64
- iOS arm64 (xcframework via SPM)
- Android arm64 and x86_64
The binary is downloaded automatically by the native-assets hook on the first
dart testordart run— no manual setup needed on desktop. Windows and WASM are not yet supported.Document loading
PdfDocument.fromBytes(Uint8List)— loads a PDF from raw bytes into a background isolate so the calling isolate is never blocked.PdfExtractionException— thrown when loading fails;exception.errordistinguishesPdfError.passwordRequiredfromPdfError.invalidDocument.PdfDocument.close()— releases the native PDFium handle; safe to call more than once. AFinalizeris registered as a fallback but explicit disposal is preferred. Afterclose(), all methods throwStateError.
Metadata and document info
getMetadata()— returnsPdfMetadatawithtitle,author,subject,keywords,creator,producer,creationDate, andmodificationDate. All fields are nullable; dates arePdfDatevalues with a parsedDateTime?.getDocumentInfo()— returnsPdfDocumentInfowithfileVersionand the 16-bytepermanentId/changingIdfile identifiers.pageCount— total page count.
Text extraction
extractPlainText({int? pageIndex})— streamsPdfPageTextper page. Each result carriestext,hasTextLayer, andhasUnicodeErrors.isPlainTextExtractable()— quick check that returnsfalsewhen too many pages lack a text layer (configurable viaPdfTextExtractorConfig.scannedPageRatio).- Cancelling the stream or calling
close()stops further processing immediately with no handle leaks.
Page size and rendering
getPageSize(int pageIndex)— returnsPdfPageSizewithwidthPt,heightPt,aspectRatio, andsizeForDpi(dpi)for pixel conversion.renderPageToBytes(pageIndex, pixelWidth, pixelHeight)— renders a page to a raw BGRA pixel buffer; returns({Uint8List pixels, int pixelWidth, int pixelHeight}). Optional flags:renderAnnotations,lcdText,backgroundColor(ARGB packed int).
Annotation extraction
extractAnnotations({int? pageIndex})— streamsPdfPageAnnotationsper page; pages with no annotations yield an entry with an empty list so callers can track page coverage without gaps.- Concrete annotation types:
PdfTextAnnotation,PdfMarkupAnnotation(highlight, underline, squiggly, strikeout),PdfFreeTextAnnotation,PdfInkAnnotation,PdfShapeAnnotation,PdfPopupAnnotation,PdfStampAnnotation,PdfUnknownAnnotation. PdfMarkupAnnotationincludesquadPointsfor precise text-span geometry.- Annotations with a linked popup carry a non-null
popupfield.
Image extraction
extractImages({int? pageIndex, bool includeBitmap})— streamsPdfPageImagesper page, each containing a list ofPdfImageobjects with bounding box andPdfImageMetadata(dimensions, colour space, bits per pixel, filter chain).includeBitmap: false(default) — metadata-only; no bitmap allocation.includeBitmap: true— populatesPdfImage.bgrafor every image on the page.renderImage(pageIndex, objectIndex)— fetches the BGRA bitmap for a single image object on demand; returnsnullfor mask-only images.
Search
search(String query, {Set<PdfSearchFlag> flags, int? pageIndex})— streamsPdfSearchMatchvalues withpageIndex,charIndex, andrectsin PDF user-space (origin bottom-left).- Search flags:
PdfSearchFlag.matchCase,PdfSearchFlag.matchWholeWord,PdfSearchFlag.consecutive.
Table of contents
tableOfContents— returns the complete bookmark tree asList<PdfTocEntry>. Each entry hastitle,pageIndex, andchildrenfor nested entries. Returns an empty list when the document has no bookmarks.
Thumbnails
getThumbnail(int pageIndex, {bool generateIfAbsent, int maxDimension})— returns aPdfThumbnailwithbgra,width,height, andsource(embeddedorrendered). When no embedded/Thumbstream is present, a fallback render is produced at the requestedmaxDimension(longest edge) unlessgenerateIfAbsent: false.
pdfinfoCLI tooldart run bin/pdfinfo.dart— a command-line tool for inspecting PDF metadata, document info, page count, table of contents, and plain-text extractability.