CLI tool
qpdf/qpdf avatar
qpdf/qpdf

qpdf rewrites PDF structure without rendering a single page

qpdf: A content-preserving PDF document transformer

5,588 stars419 forksC++Apache-2.0

At a glance

What is it?
A C++ command-line tool and library for content-preserving PDF work: linearization, encryption, splitting, merging, and object-level inspection, with no rendering and no text extraction. Release verification, the macOS quarantine problem, the QPDF_ZOPFLI switch, and how the library is linked are covered from the project's own documentation.
Who is it for?
qpdf earns a place in a pipeline that treats a PDF as an object graph rather than a set of pages: it preserves content, handles linearization and encryption, and leaves rendering, text extraction, and layout to other tools.
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 49 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 November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • qpdf/qpdf5,588 ★ · +151
Star history
Repository2026-09-232026-11-14
qpdf/qpdf5.4k5.6k

151 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Content-preserving transformations leave page content alone

qpdf is a command-line tool and C++ library that performs content-preserving transformations on PDF files. The scope is narrow on purpose. It works on the structure of a PDF file, so what a page draws stays as its author left it. The features it names are linearization, encryption, and numerous others, and the same opening paragraph says it can be used for splitting and merging files, for creating PDF files where you supply all the content yourself, and for inspecting files for study or analysis.

The project keeps three addresses separate: the manual sits at qpdf.readthedocs.io, the project website is qpdf.sourceforge.io, and the source repository is hosted on GitHub at github.com/qpdf/qpdf. Releases are frequent and carry patch numbers. Recent tags include v12.4.0 from 2026-08-09, v12.4.1 from 2026-08-27, and v12.4.2 from 2026-09-27.

Licensing changed once in the project's history. qpdf is copyright (c) 2005-2021 Jay Berkenbilt and 2022-2026 Jay Berkenbilt and Manfred Holger, released under the Apache License, Version 2.0, with the license text in the LICENSE.txt file of the source distribution. Versions of qpdf prior to version 7 were released under version 2.0 of the Artistic License, and at your option you can continue to consider qpdf licensed under those terms. That text is in the Artistic-2.0 file.

Splitting and merging work, creating a PDF means supplying every object

Splitting and merging files appear in the list of jobs qpdf takes on, and both are pure structure operations. Page objects move, and the file around them is rewritten to match. Nothing about the appearance of a page is recomputed.

Creating files is the qualified one, and the wording is exact: you have to supply all the content yourself. There is no layout engine, no font handling, no line breaking, no text placement. So qpdf is the wrong tool if the goal is turning a data set into a good looking document, and the right tool if the goal is writing an object graph out in a form that is valid and streamable.

The example programs in the repository show how narrow that band is. examples/pdf-attach-file.cc attaches a file, examples/pdf-bookmarks.cc builds bookmarks, examples/pdf-create.cc creates a PDF, examples/pdf-overlay-page.cc overlays one page on another, examples/pdf-split-pages.cc splits pages, examples/pdf-mod-info.cc changes document information, examples/pdf-set-form-values.cc sets form values, and examples/pdf-invert-images.cc inverts image data. Each is a short program against the library, not a framework with a plugin system.

No rendering, no text extraction, no page-content interfaces

Three things qpdf states it does not do: it does not render PDFs, it does not perform text extraction, and it does not contain higher-level interfaces for working with page contents. That is the low-level position the project takes for itself, and it shapes everything downstream.

If a task ends in a picture of page 4, qpdf will not produce one. If a task ends in the words written on a page, qpdf will not hand them over either. Content streams are objects that a caller parses itself, which is why examples/pdf-parse-content.cc exists in the tree. Page geometry changes work by rewriting page objects, which is what examples/pdf-double-page-size.cc shows. Counting pages, or inspecting a name or number tree, means walking the object structure, which examples/pdf-npages.cc and examples/pdf-name-number-tree.cc do directly.

The practical consequence is a pipeline, not a replacement. Pair qpdf with something that rasterizes pages and something that extracts text, or accept object-level output and do the interpretation in your own code. The split also shows up in the example set: examples/pdf-count-strings.cc and examples/pdf-filter-tokens.cc inspect rather than convert, because inspecting a file for study or analysis is one of the stated jobs.

macOS downloads carry a quarantine attribute you have to strip

Starting with version 12.4.2, macOS binaries are available for download in the releases area of the repository. They come with a caveat that matters on first run: they are not signed with an Apple Developer ID and they are not notarized, so the quarantine attribute that macOS adds to downloaded files gets in the way of executing them.

The remedy is one command, run in the directory where you unzipped the Mac binaries:

code
xattr -r -d com.apple.quarantine bin lib

The `-r` flag recurses, and the two trailing arguments cover both the bin directory and the lib directory in one pass, which matters because the binaries need their shared libraries from lib. Without this step macOS treats the files as coming from an unidentified developer.

The project does not point to a signed and notarized macOS build in this README. It says instead that detailed information appears in the manual, at the installation page, and that pre-built binary versions of zlib and jpeg can be downloaded for some compilers on Windows, with the specifics in README-windows.md.

cosign signatures and a sha256 file guard every release download

Official qpdf releases are signed using cosign. Each release includes a sha256 file containing sha256 checksums of all the release files. The check on your side is short: generate the checksum of the file you downloaded with `sha256sum file`, or a similar tool, and confirm it matches the value in the sha256 file.

The sha256 file itself can be verified with gpg or with `cosign verify-blob`:

code
cosign verify-blob qpdf-x.y.z.sha256 --bundle qpdf-x.y.z.sha256.sigstore \
   [email protected] \
   --certificate-oidc-issuer=https://github.com/login/oauth

Replace `[email protected]` with the name of the person who signed the release, which the release notes indicate. The two valid signers are Jay Berkenbilt <[email protected]> and Manfred Holger <[email protected]>. The gpg route uses Jay Berkenbilt's GPG key, whose fingerprint is `C2C9 6B10 011F E009 E6D1 DF82 8A75 D109 9801 2C7E`, published at https://q.ql.org/pubkey.asc and also obtainable from a public key server.

So there are two separate checks in front of you, and neither substitutes for the other. One covers the individual archive you downloaded. The other covers the list of checksums.

Linking needs a C++17 compiler, building qpdf needs C++20

Two different compiler requirements, and the difference is worth tracking. To build and test qpdf itself, a C++ compiler that supports C++20 is required. To link with qpdf, a C++17-compatible compiler is sufficient.

To compile and link something against the library, the project offers pkg-config with the package name `libqpdf`, or cmake with the package name `qpdf`. A minimal CMakeLists.txt looks like this:

code
cmake_minimum_required(VERSION 3.16)
project(some-application LANGUAGES CXX)
find_package(qpdf)
add_executable(some-application some-application.cc)
target_link_libraries(some-application qpdf::libqpdf)

The runtime dependencies are short. qpdf depends on the external libraries zlib and jpeg. The libjpeg-turbo library is also known to work, since it is compatible with the regular jpeg library and qpdf does not use any interfaces that are absent from the straight jpeg8 API. Both are part of every Linux distribution and are readily available.

For Windows, pre-built binary versions of these libraries can be downloaded for some compilers, and README-windows.md holds the details. The repository also ships build infrastructure you will notice in the tree: CMakeLists.txt, CMakePresets.json, cmake/, build-scripts/, and copy_dlls.ps1 for assembling the runtime directory.

QPDF_ZOPFLI trades a lot of speed for a slightly smaller file

If qpdf is built with zopfli support and the QPDF_ZOPFLI environment variable is set to any value other than `disabled`, qpdf uses the zopfli compression library instead of zlib to generate flate-compressed streams. The trade is stated plainly: the zopfli algorithm is much slower, about 100x according to the zopfli website, but it produces slightly smaller output. That makes it suitable for cases such as generation of archival PDFs where size matters regardless of speed.

The variable has four distinct behaviours. `disabled`, or leaving it unset, means zopfli is not used. `force` means use zopfli and fail if zopfli is not compiled in, which turns a silent downgrade into a build or run failure you have to notice. `silent` means use zopfli if it is available and otherwise fall back to zlib with no warning. Any other value uses zopfli when it is available and warns when it is not.

Enabling the feature is a build-time task, not an environment task. To build with zopfli support you must have the zopfli library and its header file installed. Setting QPDF_ZOPFLI to `force` on a binary compiled without zopfli fails rather than quietly producing larger output.

Crypto providers get picked at build time or at run time

qpdf can use different crypto implementations, and they can be selected at compile time or at runtime. The native crypto implementations that were used in all versions prior to 9.1.0 are still present in the source, but they are not built into qpdf by default if any external providers are available at build time. That default is worth knowing before you measure anything about encryption in a given binary.

The providers include `gnutls`, an implementation that uses the GnuTLS library to provide crypto and causes libqpdf to link with the GnuTLS library, and `openssl`. Depending on which crypto providers are enabled, GnuTLS and OpenSSL may also be required on your system.

For information on licenses of embedded software, the README points to the NOTICE file, NOTICE.md. Read it before redistributing a qpdf binary.

Editorial conclusion

qpdf earns a place in a pipeline that treats a PDF as an object graph rather than a set of pages: it preserves content, handles linearization and encryption, and leaves rendering, text extraction, and layout to other tools. Before adopting it, check three things in your own setup, which is the provider your build linked against, gnutls or openssl or the native code, whether the macOS quarantine attribute has been stripped from downloaded binaries, and whether QPDF_ZOPFLI is set to a value that suits archival work rather than everyday speed.

Frequently asked questions

What is qpdf used for?

qpdf performs content-preserving transformations on PDF files. It supports linearization and encryption, and it can split and merge files, create PDF files when you supply all the content yourself, and inspect files for study or analysis. It does not render PDFs and does not perform text extraction.

Is qpdf safe?

Official releases are signed using cosign, and each release includes a sha256 file with checksums of all the release files, so a download can be checked before it is used. The macOS binaries are not signed with an Apple Developer ID and are not notarized, so the quarantine attribute has to be removed before running them.

How do I install qpdf?

Building and testing qpdf requires a C++20 compiler, while linking against it only needs a C++17-compatible compiler, using pkg-config with package name libqpdf or cmake with package name qpdf. On macOS, binaries are downloadable from the releases area starting with version 12.4.2, and the manual's installation page carries the details.

How can I compress a PDF file using qpdf?

Set the QPDF_ZOPFLI environment variable to a value other than disabled when qpdf was built with zopfli support, and flate-compressed streams are generated with zopfli instead of zlib. Use force to fail if zopfli was not compiled in, or silent to fall back to zlib without any warning. Zopfli is about 100x slower and slightly smaller.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. qpdf/qpdf on GitHub
  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/qpdf-qpdf.svg)](https://hysenlabs.com/projects/qpdf-qpdf)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/qpdf-qpdf.svg)](https://hysenlabs.com/projects/qpdf-qpdf)

Was this useful?