Use when reaching past the high-level pdfium-render API into the raw FPDF_* C functions: porting existing C or C++ PDFium code, or calling a PDFium function that pdfium-render does not yet wrap. Prevents the unsafe-contract mistakes that crash a process, a double free of a raw handle a high-level object already owns, a use-after-free of a raw handle whose bindings dropped, and the 0.8.x assumption that FPDF_* calls are safe. Covers the PdfiumLibraryBindings trait, the bindings() accessor, the unsafe marking added in 0.9.0, the PdfiumLibraryBindingsAccessor visibility change in 0.9.2, and how to mix raw calls with RAII handles across pdfium-render 0.8.x and 0.9.x. Keywords: pdfium-render raw FFI, PdfiumLibraryBindings, FPDF_ functions, bindings(), get_bindings, unsafe fn, FPDF_LoadDocument, FPDF_GetPageCount, FPDF_DOCUMENT, FPDF_PAGE, PdfiumLibraryBindingsAccessor, porting C++ PDFium code, calling an unwrapped function, segfault calling FPDF, double free, use after free, how do I call a raw pdfium function, un
Use when reaching past the high-level pdfium-render API into the raw FPDF_* C functions: porting existing C or C++ PDFium code, or calling a PDFium function that pdfium-render does not yet wrap. Prevents the unsafe-contract mistakes that crash a process, a double free of a raw handle a high-level object already owns, a use-after-free of a raw handle whose bindings dropped, and the 0.8.x assumption that FPDF_* calls are safe. Covers the PdfiumLibraryBindings trait, the bindings() accessor, the unsafe marking added in 0.9.0, the PdfiumLibraryBindingsAccessor visibility change in 0.9.2, and how to mix raw calls with RAII handles across pdfium-render 0.8.x and 0.9.x. Keywords: pdfium-render raw FFI, PdfiumLibraryBindings, FPDF_ functions, bindings(), get_bindings, unsafe fn, FPDF_LoadDocument, FPDF_GetPageCount, FPDF_DOCUMENT, FPDF_PAGE, PdfiumLibraryBindingsAccessor, porting C++ PDFium code, calling an unwrapped function, segfault calling FPDF, double free, use after free, how do I call a raw pdfium function, unsafe contract.
license
MIT
compatibility
Designed for Claude Code. Requires pdfium-render 0.8,0.9.
metadata
{"author":"OpenAEC-Foundation","version":"1.0"}
pdfium-core-raw-ffi
What this skill covers
The high-level idiomatic interface of pdfium-render is built on top of raw
FFI bindings to the PDFium C API, defined in the trait.
That trait is the escape hatch: it exposes the flat function surface
directly, so a Rust program can port existing C or C++ PDFium code, or call a
PDFium function that does not yet wrap, while still keeping
late binding and WASM compatibility.
PdfiumLibraryBindings
FPDF_*
pdfium-render
This skill covers obtaining the bindings, the unsafe contract a caller takes
on, mixing raw calls with the RAII handles, and the 0.8.x to 0.9.x traps. For
the binding setup itself (bind_to_*, feature flags, library files) see
pdfium-core-bindings-setup. For the ownership tree see
pdfium-core-architecture.
Quick reference
Item
Detail
Trait
PdfiumLibraryBindings (in the prelude)
Accessor
pdfium.bindings() returns a reference to the active PdfiumLibraryBindings
Raw functions
every FPDF_* method; unsafe fn since 0.9.0
Raw handle types
FPDF_DOCUMENT, FPDF_PAGE, FPDF_TEXTPAGE, and the rest
Import
use pdfium_render::prelude::*;
Raw calls return raw handles and integer codes. They do NOT return
Result<_, PdfiumError> and do NOT run any RAII cleanup. The caller owns every
handle a raw call produces.
When to use raw FFI, and when NOT to
ALWAYS prefer the high-level API. Reach for raw FFI ONLY when one of these is
true:
Porting existing C or C++ PDFium code with minimal changes.
Calling a specific FPDF_* function that pdfium-render does not expose
through a high-level type.
NEVER drop to raw FFI for work the high-level API already covers (loading
documents, rendering, text extraction). The high-level API gives you
PdfiumError handling and RAII cleanup; raw FFI gives you neither and makes
crashes easy.
Does a high-level pdfium-render type already do this?
YES -> use the high-level API. Stop.
NO -> Is it a one-off unwrapped FPDF_* call?
YES -> get pdfium.bindings(), call it in an `unsafe` block,
close every handle you create yourself.
NO (porting a whole C/C++ module) -> work through the
PdfiumLibraryBindings trait directly.
Getting the bindings
A constructed Pdfium instance hands out its bindings with bindings():
use pdfium_render::prelude::*;
letpdfium = Pdfium::default();
letbindings = pdfium.bindings();
bindings() is the 0.9.x accessor. The 0.8.x and earlier name
Pdfium::get_bindings() was deprecated since 0.7.18 and removed in 0.9.0.
The bind_to_* functions return a Box<dyn PdfiumLibraryBindings> directly, so
raw calls are also possible without ever constructing a Pdfium:
letbindings = Pdfium::bind_to_system_library()?;
// `bindings` is a Box<dyn PdfiumLibraryBindings>; raw FPDF_* calls work on it.
The canonical raw-call pattern
This is the raw-FFI example from the pdfium-render README, quoted verbatim:
Every FPDF_* call sits inside an unsafe block because, since 0.9.0, every
FPDF_* method on PdfiumLibraryBindings is an unsafe fn.
The unsafe contract: caller responsibilities
When you call an unsafeFPDF_* function you take on PDFium's C-level
contract. ALWAYS hold to these rules:
Close every handle you open. A raw FPDF_LoadDocument returns an
FPDF_DOCUMENT that YOU own. Pair it with FPDF_CloseDocument. A raw
FPDF_LoadPage is paired with FPDF_ClosePage. pdfium-render does not
track raw handles and will not free them.
Close in reverse order of opening. Close pages before their document.
Closing a document while a page from it is still open is undefined behavior.
Null-check every handle. Raw loaders return a null handle on failure,
NOT a PdfiumError. Test the handle before use; on failure read
FPDF_GetLastError() for the reason.
Never use a handle after its source is gone. A raw handle is only valid
while the PdfiumLibraryBindings (and the loaded library) are alive.
Never pass a handle from one document into a raw call on another.
Breaking any of these is a memory-safety bug: a crash, a segfault, or silent
corruption, with no Rust error to catch.
Mixing raw calls with high-level handles
The high-level types (PdfDocument, PdfPage, and so on) are RAII wrappers:
each owns an underlying raw handle and frees it on Drop. Mixing is safe ONLY
under one rule:
NEVER call a FPDF_Close* or FPDF_Destroy* function on a handle that a
high-level type owns. The high-level type will free it again on Drop, which
double-frees and crashes.
A handle YOU obtained with a raw FPDF_Load* call is yours alone. Close it
yourself. pdfium-render does not see it.
The safe shape: use the high-level API to load and manage documents and pages,
and use pdfium.bindings() only to call extra FPDF_* functions that take
PDFium handles, without taking over ownership of handles the high-level API
created.
Version traps: 0.8.x to 0.9.x
Item
0.8.x
0.9.x
FPDF_* on PdfiumLibraryBindings
safe fn
unsafe fn (since 0.9.0)
Bindings accessor
Pdfium::get_bindings() (deprecated since 0.7.18)
bindings() (get_bindings removed in 0.9.0)
PdfiumLibraryBindingsAccessor trait
pub(crate)
pub since 0.9.2
The 0.9.2 change makes PdfiumLibraryBindingsAccessor public specifically to
ease raw FPDF_* use by crate consumers. Code targeting 0.9.0 or 0.9.1 can
still call bindings(); 0.9.2 makes the accessor trait nameable.
NEVER carry 0.8.x raw-FFI code into a 0.9.x build unchanged: the calls now
require unsafe blocks, and get_bindings() no longer exists.
Common failures (quick triage)
Symptom
Likely cause
Fix
compile error: call to unsafe function
FPDF_* call outside an unsafe block on 0.9.x
wrap the call in unsafe { }
compile error: get_bindings not found
0.8.x accessor name on 0.9.x
use bindings()
segfault on a raw call
handle is null, freed, or from another document
null-check, respect lifetime, never reuse a freed handle
double free / crash on drop
raw FPDF_Close* called on a handle a high-level type owns
let the high-level type free its own handle
memory leak
raw handle opened, never FPDF_Close*d
close every handle you open
Reference files
references/methods.md: the PdfiumLibraryBindings trait shape, the
bindings() accessor, verified FPDF_* signatures, raw handle types, and
the version matrix.
references/examples.md: verified raw-FFI code for getting bindings, calling
an unwrapped function, and the 0.8.x to 0.9.x unsafe difference.
references/anti-patterns.md: real raw-FFI failures, why each breaks memory
safety, and the fix.
Companion skills
pdfium-core-bindings-setup: binding to the library, feature flags, library
files.
pdfium-core-architecture: the ownership tree and the late-binding model.
pdfium-core-memory: drop order and lifetime-bound handles for the
high-level API.
pdfium-errors-binding: diagnosing a binding that fails at run time.