Overview
Vanilla.PDF is a modern, high-performance, open-source C++17 SDK for creating, editing, signing, and analyzing PDF documents. With no external runtime dependencies and full cross-platform support, it’s ideal for embedding into desktop, server, or automation workflows.
Create & modify PDF documents — pages, text, images, vector graphics
Sign & verify digital signatures (CMS/PKCS#7) with certificate chain validation
Encrypt & decrypt with AES or RC4 using passwords or certificates
ABI-stable C API — opaque handles callable from any language with a C FFI
Thread-safe — no global state, process documents in parallel without locking
Where to go next
Getting started – install the library and create your first PDF:
Quickstart – Create a PDF document in a few lines of C code
Installation – All package manager options with copy-paste commands
Developer guide – build from source and understand the internals:
Building from Source – Clone, configure, build, and test
C API Guide – Handle system, memory management, error handling
Architecture – Three-layer design, object model, memory model
Signature Verification Guide – Trust stores, chain validation, weak-algorithm detection
CLI Tools – sign, verify, merge, extract, encrypt, decrypt
Learning – understand the PDF format and see examples:
PDF Format Guide – PDF syntax, objects, and document structure
Examples – Code samples from the test suite and CLI tools
Scope and non-goals
Vanilla.PDF is a document structure library. It operates on the PDF object graph – creating pages, embedding images, attaching digital signatures, encrypting content, and parsing the binary format down to individual XRef entries. It is not a rendering engine.
What it does:
Create, open, modify, and save PDF documents
Validate PDF file structure (xref, trailers, streams) and report issues
Add and verify CMS digital signatures with RSA, ECDSA (P-256/P-384/P-521), Ed25519, and Ed448
Encrypt and decrypt with AES/RC4 (password and certificate-based); compatible with FIPS-enabled OpenSSL
Fill and read interactive form fields
Extract embedded images (JPEG, JPEG2000)
Parse and encode content streams (PostScript-style page instructions)
Low-level access to XRef tables, indirect objects, and file trailers
What it does not do:
Rasterize or render PDF pages to images or screen
Lay out text with font shaping or line breaking
Validate PAdES compliance levels (BES, T, LTV)
Perform CRL or OCSP revocation checking (planned: #157)
Validate RFC 3161 timestamps
Functionality
Operation |
Interface |
Description |
|---|---|---|
Create documents |
C API |
Generate PDFs with pages, text, images, and vector paths |
Digital signatures |
C API, CLI |
OpenSSL CMS signatures with RSA, ECDSA (P-256/P-384/P-521), Ed25519, and Ed448 using PKCS#12 keys or custom callbacks |
Signature verification |
C API, CLI |
Validate signatures with chain validation, weak-algorithm detection, and signing-time checks |
File structure validation |
C API, CLI |
Walk xref tables, trailers, and streams to detect malformed or corrupt files |
Interactive forms |
C API |
Read and write AcroForm field values (text, choice, checkbox, radio button) |
Merge documents |
CLI |
Combine multiple PDFs into a single file |
Encryption / decryption |
CLI |
AES and RC4 with owner/user passwords; certificate-based decryption; compatible with FIPS-enabled OpenSSL |
Image extraction |
CLI |
Export embedded JPEG and JPEG2000 images from PDF streams |
Content stream processing |
C API, CLI |
Parse and encode PostScript-style page content; apply compression filters |
Low-level parsing |
C API |
Inspect XRef tables, indirect objects, cross-reference streams, and file trailers |
Design philosophy
Why a C API over C++? The C++ ABI is not stable across compilers or even
across major versions of the same compiler. A native C++ interface would force
every consumer to use the exact same toolchain. By exposing only ANSI C
functions with cdecl calling conventions, Vanilla.PDF can be linked by any
C or C++ compiler and called from any language with a C FFI – Python, C#,
Rust, Go, Java (via JNI), and others.
Handle-based design. All objects are represented as opaque pointers
(DocumentHandle*, FileHandle*, PageObjectHandle*). The internal C++
class layout is never visible to callers, which means the library can change its
implementation without breaking binary compatibility.
Reference-counted ownership. Handles use intrusive reference counting.
When you receive a handle through an output parameter, you own one reference and
must release it when done. There are no hidden shared-ownership surprises:
every _Release call is explicit.
No global state. Error codes and messages are stored in thread-local buffers, one per thread. The library does not allocate process-wide singletons or require initialization/shutdown calls.
Architecture overview
The library is organized into three layers:
Layer |
Responsibility |
|---|---|
Syntax |
PDF object types (boolean, integer, string, name, array, dictionary, stream), tokenizer, parser, XRef tables, compression filters (Flate, DCT, JPX, ASCII85, ASCIIHex, LZW) |
Semantics |
High-level document model: documents, catalogs, page trees, pages, annotations, interactive forms, digital signatures, outlines, named destinations, fonts, and resource dictionaries |
Contents |
Content stream parsing and instruction processing for PostScript-style page content (text operations, graphics state, inline images) |
A thin C interface layer wraps the C++ implementation, mapping each internal object to an opaque handle. See Architecture for the full design description including the object model, memory model, and extension points.
Thread safety
Vanilla.PDF is thread-safe. Key internal objects are protected by
std::recursive_mutex, reference counting is atomic, and error context is
stored in thread_local buffers so concurrent threads never interfere with
each other. See Architecture for implementation details.
Versioning and compatibility
Vanilla.PDF follows Semantic Versioning:
Component |
Meaning |
|---|---|
Major |
Backward-incompatible changes to the C API |
Minor |
New functionality, backward-compatible with existing callers |
Patch |
Bug fixes only, no interface changes |
Build |
No functional impact (CI metadata) |
The C API is stable within a major version. Code compiled against 2.0 will continue to link and run correctly against 2.1, 2.2, and so on. Query the version at runtime:
integer_type major, minor, patch;
LibraryInfo_GetVersionMajor(&major);
LibraryInfo_GetVersionMinor(&minor);
LibraryInfo_GetVersionPatch(&patch);
Nightly builds use a patch override (999) and a build suffix
(e.g. -nightly.main) to distinguish them from release builds.
Optional dependencies
All dependencies are managed automatically via vcpkg. Each can be disabled or replaced with a system package:
Library |
Purpose |
CMake flag |
|---|---|---|
OpenSSL |
Encryption, decryption, digital signatures |
|
libjpeg-turbo |
JPEG image decoding |
|
OpenJPEG |
JPEG2000 image support |
|
zlib |
Flate compression of PDF objects |
|
spdlog |
Diagnostic logging |
|
nlohmann-json |
Configuration file parsing |
|
Supported platforms
Platform |
Compilers |
Architectures |
|---|---|---|
Windows |
Visual Studio 2022 (MSVC 17.x), Visual Studio 2026 (MSVC 18.x) |
x86, x64, ARM64 |
Linux |
GCC 8.1+, Clang 10+ |
x64, ARM64, ARM |
macOS |
AppleClang 15+ (Xcode 15) |
x64, ARM64 |
Android |
NDK toolchain |
arm64-v8a, armeabi-v7a, x86, x86_64 |
Package availability
Format |
Install command |
Notes |
|---|---|---|
vcpkg |
|
Recommended; pre-built binaries |
FetchContent |
|
No external tools; caller manages dependencies |
Conan |
|
Coming soon; not yet on Conan Center |
Homebrew |
|
Coming soon; macOS formula not yet live |
NuGet |
|
.NET interop with native runtime |
Debian |
|
Built via Packaging |
Source |
|
External resources
Adobe PDF specification: official site | local copy