QPDF
QPDF is an open-source PDF transformation and inspection tool (Apache 2.0). Its --check mode validates the structural integrity of a PDF file: cross-reference tables, page tree, stream lengths, linearization parameters, and encryption dictionaries.
What it catches
Section titled “What it catches”- Malformed or inconsistent cross-reference tables
- Invalid page tree structure (missing
/Type, broken/Parentlinks) - Stream
/Lengthmismatches - Linearization parameter errors
- Encryption dictionary inconsistencies
- Object numbering and generation number issues
- Missing or malformed
%%EOFmarkers
Installation
Section titled “Installation”# Docker (recommended — no local install needed)cd docker && docker compose build
# Or install locally as a fallback:brew install qpdf # macOSsudo apt-get install qpdf # Ubuntu/DebianHow it works
Section titled “How it works”The QpdfValidationTrait provides two assertion methods:
// Validate a PDF file on disk$this->assertQpdfValid('/path/to/file.pdf');
// Validate in-memory PDF bytes (writes to temp file, validates, cleans up)$this->assertQpdfValidBytes($pdfBytes);Both methods:
- Try Docker first via
DockerToolRunner(image:phpdftk/qpdf) - Fall back to local binary via
ExternalToolLocator::find('qpdf') - If neither is available, silently return (the test passes on its existing assertions)
- Run
qpdf --check <file>and assert exit code 0 - On failure, include the full QPDF error output in the assertion message
Trait source
Section titled “Trait source”tests/Support/QpdfValidationTrait.php (Phpdftk\Tests\Support\QpdfValidationTrait)
Coverage
Section titled “Coverage”QPDF validation is applied to every integration test that generates a PDF across all three PDF packages:
| Package | Test files | Assertion calls |
|---|---|---|
pdf/core | 21 | ~25 |
pdf/writer | 6 | ~35 |
pdf/toolkit | 11 | ~80 |
| Total | 39 | ~140 |
Core integration tests
Section titled “Core integration tests”| Test file | Assertions |
|---|---|
SimpleTextTest | assertQpdfValid(OUTPUT_FILE) |
MultiPageComplexTest | assertQpdfValid(OUTPUT_FILE) |
GraphicsTest | assertQpdfValid(OUTPUT_FILE) |
AnnotationsTest | assertQpdfValid(OUTPUT_FILE) |
FormFieldsTest | assertQpdfValid(OUTPUT_FILE) |
BookmarksTest | assertQpdfValid(OUTPUT_FILE) |
PageLabelsTest | assertQpdfValid(OUTPUT_FILE) |
DocumentFeaturesTest | assertQpdfValid(OUTPUT_FILE) + assertQpdfValid($outPath) |
ExtGStateIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
SignedPdfIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
SignatureFieldIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
FormAppearancesIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
MarkupAnnotationsIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
AnnotationSubtypesTest | assertQpdfValid(OUTPUT_FILE) |
MultimediaAndThreeDIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
OpenTypeFontIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
Type3FontIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
GraphicsPipelineIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
XRefStreamIntegrationTest | assertQpdfValid(OUTPUT_FILE) |
EmbeddedFontsTest | assertQpdfValid($outPath) |
EmbeddedType1FontTest | assertQpdfValid($outPath) |
Writer tests
Section titled “Writer tests”WriterTest, PdfTest, PdfIntegrationTest, KerningIntegrationTest, XmpMetadataTest, UnicodeFontTest — assertions on generate(), toBytes(), and save() outputs.
Toolkit tests
Section titled “Toolkit tests”AnnotationFlattenerTest, PdfStamperTest, PageTransformerTest, TextRedactorTest, PageSlicerTest, PdfMergerTest, PdfEncryptTest, BookmarkEditorTest, PageLabelerTest, FormFillerTest, MetadataEditorTest — assertions on toBytes() and save() outputs.
CI configuration
Section titled “CI configuration”The QPDF Docker image is built in the test job and runs on every push and pull request:
- name: Build validation tool images run: cd docker && docker compose buildManual usage
Section titled “Manual usage”Validate any PDF from the command line:
# Check a single fileqpdf --check docs/sample-pdfs/simple_text.pdf
# Check all sample PDFsfor f in docs/sample-pdfs/*.pdf; do echo "Checking $f..." qpdf --check "$f"done
# JSON output for programmatic inspectionqpdf --json docs/sample-pdfs/simple_text.pdf | jq .