PoDoFo
| Language | C++17 |
|---|---|
| License | LGPL-2.0-or-later or MPL-2.0 (the command-line tools are GPL) |
| Repository | github.com/podofo/podofo |
| Documentation | API reference, examples in the repository |
| Depends on | FreeType, OpenSSL, libxml2, zlib, fontconfig (Unix); optional libjpeg, libtiff, libpng |
| Read / write | yes / yes: create, edit, merge, text extraction, forms, annotations, encryption, digital signatures |
PoDoFo is a C++ library for working with the PDF object model and for drawing new content: pages, text with embedded and subset fonts, images, vector graphics, annotations, form fields and digital signatures (including PAdES). Version 1.0 modernized the API (C++17, PdfMemDocument, PdfPainter with TextState) and added Unicode text extraction. It doesn’t render pages.
Choose PoDoFo when you need to both generate and modify PDFs from C++ under a library-friendly license. For structural tasks only (merge, split, encrypt), QPDF is simpler; for rendering use PDFium or MuPDF.
Installation#
# Debian / Ubuntu (check that the packaged version is 1.x)
sudo apt install libpodofo-dev
# macOS
brew install podofo
# Windows (vcpkg)
vcpkg install podofo
find_package(PoDoFo 1.0.0 REQUIRED)
target_link_libraries(myapp PRIVATE podofo::podofo)
Basic usage: create a PDF with text#
#include <podofo/podofo.h>
#include <iostream>
using namespace PoDoFo;
int main() {
try {
PdfMemDocument doc;
PdfPage &page = doc.GetPages().CreatePage(PdfPageSize::A4);
PdfFont *font = doc.GetFonts().SearchFont("Arial");
if (font == nullptr) throw std::runtime_error("font not found");
PdfPainter painter;
painter.SetCanvas(page);
painter.TextState.SetFont(*font, 18);
// origin is bottom-left; 56.69 points = 2 cm
painter.DrawText("Hello, PDF!", 56.69, page.GetRect().Height - 56.69);
painter.FinishDrawing();
doc.GetMetadata().SetTitle(PdfString("Hello"));
doc.Save("hello.pdf");
} catch (const PdfError &e) {
std::cerr << "error: " << e.what() << "\n";
return 1;
}
return 0;
}
SearchFont finds a system font and embeds a subset. Use doc.GetFonts().GetStandard14Font(PdfStandard14FontType::Helvetica) for a non-embedded standard font.
How to extract text from a PDF#
PdfMemDocument doc;
doc.Load("in.pdf");
auto &pages = doc.GetPages();
for (unsigned i = 0; i < pages.GetCount(); i++) {
std::vector<PdfTextEntry> entries;
pages.GetPageAt(i).ExtractTextTo(entries);
for (const auto &e : entries)
std::cout << e.Text << " (x=" << e.X << ", y=" << e.Y << ")\n";
}
Each entry is a run of text with its position.
How to merge PDFs#
PdfMemDocument out;
out.Load("a.pdf");
PdfMemDocument other;
other.Load("b.pdf");
out.GetPages().AppendDocumentPages(other);
out.Save("merged.pdf");
AppendDocumentPages(doc, pageIndex, pageCount) copies a range; RemovePageAt(index) deletes a page.
How to rotate pages#
PdfMemDocument doc;
doc.Load("in.pdf");
auto &pages = doc.GetPages();
for (unsigned i = 0; i < pages.GetCount(); i++)
pages.GetPageAt(i).SetRotation(90);
doc.Save("rotated.pdf");
How to fill a form field#
PdfMemDocument doc;
doc.Load("form.pdf");
PdfAcroForm *form = doc.GetAcroForm();
if (form != nullptr) {
for (unsigned i = 0; i < form->GetFieldCount(); i++) {
PdfField &field = form->GetFieldAt(i);
std::cout << field.GetFullName() << "\n";
if (field.GetType() == PdfFieldType::TextBox && field.GetFullName() == "name")
static_cast<PdfTextBox &>(field).SetText(PdfString("Jane Doe"));
}
}
doc.Save("filled.pdf");
How to read metadata and encrypt a PDF#
PdfMemDocument doc;
doc.Load("in.pdf", PdfLoadOptions::None, "password-if-any");
auto title = doc.GetMetadata().GetTitle();
if (title.has_value())
std::cout << "Title: " << title->GetString() << "\n";
doc.SetEncrypted("user", "owner",
PdfPermissions::Print | PdfPermissions::Copy,
PdfEncryptionAlgorithm::AESV3R6);
doc.Save("encrypted.pdf");
Tips#
doc.SaveUpdate(path)writes an incremental update instead of rewriting the file, which keeps existing signatures valid.PdfSaveOptions::NoMetadataUpdatekeeps the original/Producerand modification date.- PoDoFo throws
PdfErroron parse errors; catch it aroundLoadfor untrusted input.