Library / SDK
galkahana/PDF-Writer avatar
galkahana/PDF-Writer

PDF-Writer: a C++ library for reading, writing and encrypting PDF files

High performance library for creating, modiyfing and parsing PDF files in C++

1,027 stars231 forksCApache-2.0

At a glance

What is it?
PDF-Writer, also known as PDFHummus, is an Apache-2.0 licensed C++ library for creating, parsing and manipulating PDF files and streams, with bundled FreeType, LibJpeg, LibPng, LibTiff and Zlib so a build does not depend on the system's imaging libraries. Its dependency trimming flags are the interesting part of the build.
Who is it for?
PDF-Writer is the right pick for a C++ project that has to write or read PDF files without binding to a scripting language, especially one that needs encryption or image embedding, since the library ships its own image codecs and a full build with CMake FetchContent is a short sequence of commands; it is the wrong pick if you only need to stamp a header on an existing document, since the whole library is a large build for that, and before you commit you should check whether the OpenSSL encryption support is required in your deployment, because PDFHUMMUS_NO_OPENSSL=TRUE strips it and that option is the one most likely to change your build plan.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 17 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the library actually covers

PDF-Writer is described as a fast and free C++ library for creating, parsing and manipulating PDF files and streams. The project site is pdfhummus.com, the documentation is a wiki, and the name PDFHummus is the one you will meet in the build options and in the CMake package name.

The three verbs matter. Creating a PDF means building a document structure and writing it out. Parsing means reading an existing file and navigating its object graph. Manipulating covers the space in between, where you take a document apart, change it and put it back, which is the least common capability and the one most libraries of this kind do not offer at all.

The streaming part is a separate capability rather than a synonym for file handling. Working with streams means you can consume and produce PDF data without materialising a whole document in memory, which is what you need when the source is a network response or the destination is a pipe.

The declared purpose is high performance, and the project description says creating, modifying and parsing PDF files in C++. The primary language is listed as C rather than C++, which reflects the codebase rather than the API style, and the licence is Apache-2.0 with the LICENSE file and a LicenseTemplate.txt at the repository root.

The repository is not archived, the last push was on 2026-10-06, and the release history shows v4.9.1 from 2026-09-21 after v4.9.0 from 2026-05-29 and v4.8.1 from 2025-12-01.

Building from source with CMake

The prerequisites are short: a compiler, which is Visual Studio on Windows and GCC or Clang on Linux and macOS, CMake, and OpenSSL if you need PDF 2.0 encryption.

The build itself is three commands:

bash
mkdir build && cd build
cmake ..
cmake --build . --config Release

Then the tests run through ctest, and the install step uses a local prefix, which is a good habit for a library you do not want to install system wide:

bash
ctest --test-dir . -C Release
cmake --install . --prefix ./install --config Release

The project structure explains where the size comes from. The PDFWriter directory is the main library implementation and PDFWriterTesting holds the test code used by ctest. The remaining directories, FreeType, LibAesgm, LibJpeg, LibPng, LibTiff and Zlib, are bundled dependencies rather than separate submodules you have to source yourself.

That last point is the design decision with the most practical consequences. A build does not need the system to have libjpeg, libpng, libtiff, zlib or freetype installed, which removes a whole class of version mismatch problems, at the cost of a larger source tree and a longer compile. There is an xmake.lua at the root as well as the CMakeLists.txt, so the xmake build system is supported as an alternative.

The dependency trimming flags are the build's real interface

The CMake options table is where most of the practical decisions live, and every option follows the same pattern: switch a capability off and the corresponding bundled dependency drops out of the build.

PDFHUMMUS_NO_DCT excludes DCT decoding support and detaches the LibJpeg dependency. DCT is the JPEG compression scheme, so this is the switch for a project that never handles JPEG images. PDFHUMMUS_NO_TIFF does the same for TIFF images and LibTiff. PDFHUMMUS_NO_PNG excludes PNG image support and detaches LibPng. PDFHUMMUS_NO_OPENSSL excludes PDF 2.0 encryption and detaches OpenSSL.

The defaults are all FALSE, so a default build has every capability. Turning the flags on is a per-target decision, and it is the difference between shipping an image decoder your application never uses and not shipping it.

Two more options control dependency resolution. USE_BUNDLED defaults to TRUE and selects the bundled copies. USE_UNBUNDLED_FALLBACK_BUNDLED defaults to FALSE and means fall back to the bundled versions if the system libraries are not found. The example given is `cmake .. -DUSE_BUNDLED=FALSE`, which asks the build to prefer what the system provides.

There is also BUILD_FUZZING_HARNESS, defaulting to FALSE, which enables fuzz testing. That is a small signal about the project's posture towards untrusted input, and it matters for a library that parses files it did not create.

Three ways to pull it into a project

The integration options cover the usual range, and the documentation marks one of them as recommended.

The recommended path is CMake FetchContent, which downloads and builds the library as part of your own configure step:

cmake
include(FetchContent)
FetchContent_Declare(
  PDFHummus
  GIT_REPOSITORY https://github.com/galkahana/PDF-Writer.git
  GIT_TAG        v4.6.2
  FIND_PACKAGE_ARGS
)
FetchContent_MakeAvailable(PDFHummus)
target_link_libraries(YourTarget PDFHummus::PDFWriter)

The exported target is PDFHummus::PDFWriter in all three cases, which is the detail that makes switching between them cheap.

The second option is find_package, for a system-wide or manually installed copy, and it uses the same target name:

cmake
find_package(PDFHummus REQUIRED)
target_link_libraries(YourTarget PDFHummus::PDFWriter)

The third is the old-fashioned one, copying the source folders into your project and including them directly. The documentation says simply to copy the source folders and include them, and for a manual build it points at the PDFWriter folder and the list of libraries to link against, which is Zlib, LibTiff, LibJpeg, LibPng, FreeType and OpenSSL.

Two things in the FetchContent block are worth noticing. The GIT_TAG is pinned to v4.6.2, which is behind the current v4.9.1, so the example in the documentation is not tracking the latest release. And the FIND_PACKAGE_ARGS line makes FetchContent fall back to find_package when the library is already installed, which is a genuinely useful pattern for a library that is often present system wide in distribution packages.

Testing, the fuzzing harness, and the development documentation

The test workflow is ctest based, and the documentation gives both a general invocation and a build-and-test target.

bash
ctest --test-dir build -C Release -j8
cmake --build build --target pdfWriterCheck --config Release

The parallel flag of 8 on the test run is a hint that the test suite is slow enough to want parallel execution, which is what you would expect from a library with image decoders in the loop. Test output files land in ./build/Testing/Output.

The build also defines a pdfWriterCheck target that builds and runs the tests in one step, which is the target to wire into CI.

For developers, the recommended editor setup is given explicitly: the C/C++ Extension Pack, CMake Tools, and CMake Test Explorer in Visual Studio Code. The third one is the useful detail, since it puts the ctest results into the editor's test explorer rather than making you read console output.

Packaging has its own command, `cd build && cpack .`, which produces a binary package of the built library.

Development guidance lives in CLAUDE.md at the repository root, which the readme says contains coding standards and conventions, build commands and configuration options, error handling patterns and best practices, and testing guidelines and organisational structure. The readme is explicit that this document is also optimised for AI-assisted development with Claude Code, which tells you the file is written for machine readers as much as human ones.

Encryption support and the platform notes

PDF 2.0 encryption is the feature that has the clearest dependency consequence, and it is the one to decide on early.

OpenSSL is required for it, and the option PDFHUMMUS_NO_OPENSSL=TRUE disables it and detaches the OpenSSL dependency. A build without OpenSSL cannot produce or read encrypted documents. The readme lists OpenSSL in the prerequisites as required for PDF 2.0 encryption, and a plain image library would normally want to be built without it.

The decision depends on the threat model of the documents you handle. A report generator producing unencrypted PDFs for a customer portal does not need it. A document pipeline that has to open an encrypted file from a partner does, and discovering that at integration time rather than at design time is an expensive way to learn it.

For iOS there is a separate build guide on the project site for building iPhone apps that use PDFHummus, which is a reasonable accommodation of the fact that the CMake and Visual Studio paths do not cover Apple's toolchain directly.

The manual build path is also documented for the case where you are porting to something the build system does not know about. All PDFWriter sources are in the PDFWriter folder, and you link against Zlib, LibTiff, LibJpeg, LibPng, FreeType and OpenSSL. That list is the real dependency surface of the library, and the bundled copies are there so you do not have to match versions on six separate libraries by hand.

What PDF-Writer is not the right choice for

The scope is a full PDF engine, so it is overkill for a specific set of tasks, and knowing which ones saves a lot of build time.

If you need to add a footer, stamp a page number, or fill a form field in an existing document, this library is a large amount of machinery for the job. The parsing and manipulation capability is the reason to choose it, and if you do not need to take a document apart, you are paying for a decoder, a renderer and a full object model you will not call.

It is also a C++ library, and the repository notes a NodeJS wrapper built on it as a separate project. If your pipeline is Python or JavaScript, the honest comparison is between embedding a native library through a binding and using a library written in your language, and the decision usually turns on whether the team can support a native dependency at all.

The version example is a caution too. The FetchContent snippet pins v4.6.2 while the current release is v4.9.1, so a project that copies the documentation example literally starts three minor versions behind. That is a fixable thing, and it is also a reminder to read the release notes, which the readme does not summarise and which are not part of the repository listing.

The last thing to check is the CMake option set against your own build policy. A project that requires reproducible, minimal dependency graphs, or that runs builds in a sandbox with no network access, will need to think about USE_BUNDLED and about whether the bundled codecs are acceptable in the artefact you ship.

Editorial conclusion

PDF-Writer is the right pick for a C++ project that has to write or read PDF files without binding to a scripting language, especially one that needs encryption or image embedding, since the library ships its own image codecs and a full build with CMake FetchContent is a short sequence of commands; it is the wrong pick if you only need to stamp a header on an existing document, since the whole library is a large build for that, and before you commit you should check whether the OpenSSL encryption support is required in your deployment, because PDFHUMMUS_NO_OPENSSL=TRUE strips it and that option is the one most likely to change your build plan.

Frequently asked questions

How do I build PDF-Writer from source?

With CMake: mkdir build && cd build, then cmake .. and cmake --build . --config Release. The tests run with ctest --test-dir . -C Release and the install step uses cmake --install . --prefix ./install --config Release. The compiler is Visual Studio on Windows and GCC or Clang on Linux and macOS.

How do I use PDF-Writer in a CMake project?

The recommended route is FetchContent, declaring the repository with a GIT_TAG, calling FetchContent_MakeAvailable and then linking the exported target PDFHummus::PDFWriter. A find_package route is also supported with the same target name, or you can copy the source folders into your project.

Can I build PDF-Writer without OpenSSL?

Yes. Setting PDFHUMMUS_NO_OPENSSL=TRUE excludes PDF 2.0 encryption support and detaches the OpenSSL dependency. The same pattern applies to PDFHUMMUS_NO_DCT, PDFHUMMUS_NO_TIFF and PDFHUMMUS_NO_PNG for the corresponding image codecs.

What dependencies does PDF-Writer bundle?

FreeType, LibAesgm, LibJpeg, LibPng, LibTiff and Zlib are bundled in the repository, so a default build does not need those libraries installed on the system. The USE_BUNDLED option defaults to TRUE, and USE_UNBUNDLED_FALLBACK_BUNDLED can be enabled to fall back to the bundled copies when system libraries are missing.

How do I run the PDF-Writer tests?

With ctest, for example ctest --test-dir build -C Release -j8, or through the pdfWriterCheck build target that builds and runs them together. Test output files are written to ./build/Testing/Output.

Official sources

  1. galkahana/PDF-Writer on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/galkahana-pdf-writer.svg)](https://hysenlabs.com/projects/galkahana-pdf-writer)

Was this useful?