From C++ PDF to Rust

A guide for C++ developers moving from libpoppler, MuPDF, or custom PDF code to PDFluent. Same performance, no manual memory management, and memory-safe by construction.

Migrating from C++ PDF to PDFluent. Install with cargo add pdfluent

Migration steps

1

Replace manual memory management with ownership

C++ PDF code allocates and frees objects manually. Poppler hands you raw pointers; you decide when to delete them. In Rust, the compiler tracks ownership at compile time. Values are freed when they go out of scope. There are no delete calls and no use-after-free bugs.

C++ PDF (before)
// libpoppler-cpp
#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-page.h>

poppler::document* doc =
    poppler::document::load_from_file("report.pdf");
if (!doc) {
    std::cerr << "Failed to open PDF" << std::endl;
    return 1;
}

poppler::page* p = doc->create_page(0);
// must manually delete both
delete p;
delete doc;
PDFluent (after)
use pdfluent::Document;

fn process() -> pdfluent::Result<()> {
    let doc = Document::open("report.pdf")?;
    // doc and page freed automatically when they go out of scope
    Ok(())
}
2

Replace raw pointer APIs with safe method calls

C++ PDF libraries pass raw pointers for page objects, text content, and annotations. You must check for null pointers at every step. PDFluent methods return Option or Result — the compiler forces you to handle the failure case, eliminating null pointer crashes.

C++ PDF (before)
poppler::page* page = doc->create_page(0);
if (!page) return 1;

std::vector<poppler::text_box> boxes = page->text_list();
for (const auto& box : boxes) {
    std::string text = box.text().to_latin1();
    std::cout << text << std::endl;
}
delete page;
PDFluent (after)
let page = doc.page(0)?;
let text = page.extract_text()?;
println!("{}", text);
3

Migrate build configuration from CMake to Cargo

C++ projects link against poppler or MuPDF through CMake or pkg-config. Cargo handles all dependency resolution automatically. Remove the C++ library linkage from your build scripts and add PDFluent to Cargo.toml.

C++ PDF (before)
# CMakeLists.txt
find_package(PkgConfig REQUIRED)
pkg_check_modules(POPPLER REQUIRED poppler-cpp)

target_include_directories(myapp PRIVATE
    ${POPPLER_INCLUDE_DIRS})
target_link_libraries(myapp PRIVATE
    ${POPPLER_LIBRARIES})
PDFluent (after)
# Cargo.toml
[dependencies]
pdfluent = "0.9"

# cargo build --release
# No pkg-config, no system library required

Things to watch out for

  • !Poppler is GPL-licensed. If your C++ code links against it, your application must also be GPL-licensed. PDFluent is MIT/commercial — check your licensing obligations before and after migration.
  • !MuPDF has a custom Affero GPL license for open-source use and a commercial license for proprietary use. PDFluent offers transparent published pricing with no per-seat fees.
  • !C++ page indexing varies by library. PDFluent uses 0-based page indexing consistently.
  • !If you have C++ code that calls Poppler through a wrapper, you can introduce PDFluent incrementally via its C API before fully migrating.

Frequently asked questions