Skip to content
Projects

alam00000/bentopdf-hyper-compress

View on GitHub

alam00000/bentopdf-hyper-compress has 46 GitHub stars and 5 forks. GitHot measured +3 stars in 24 hours. Last checked 2026-11-15 04:08 UTC. Last push 2026-11-13.

How these counts are measured

46 stars5 Forks +3 in 24h

Measured star growth

in 24h
+3
in 7 days
Collecting history
in 15 days
Collecting history
in 1 month
Collecting history

Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.

About

The Best Open Source PDF Compression Engine

Self-hosted

README.md

Original

Hyper Compress

💖 Thank You to Our Sponsors

Vercel OSS Program      DigitalOcean Referral Badge      NVIDIA Inception Program      Vultr

The best open source PDF compression engine.

Hyper Compress is a high fidelity, content preserving PDF compression engine built to make PDFs smaller without unnecessarily changing the document.

Hyper Compress is built by the BentoPDF team. The same engine is available as a CLI, a Node.js SDK and a Rust crate (both on one Rust core), a C library, a self-hosted HTTP service, and a WebAssembly build that runs entirely in the browser.

Try it at hyper.bentopdf.com. Full documentation lives at hyper.bentopdf.com/docs.

License: AGPL v3 GitHub Stars


📜 Licensing

Hyper Compress is dual-licensed to fit your needs:

License Best For Price
AGPL-3.0 Open-source projects with public source code Free
Commercial Proprietary / closed-source products from $99/year
OEM Redistribution, reselling as an SDK, or offering Hyper Compress as a service from $1,999/year

Get Commercial License

Solo $99 · Indie $199 · Business $499 per year · One closed-source product per license · Unlimited developers from Indie up · No AGPL obligations

Using BentoPDF? Its commercial license already includes Hyper Compress as a bundled component for eligible products (companies under US$1 million in revenue and funding, through BentoPDF's own tools on the end user's device). Using the engine on its own, on a server, through an API or in other software needs a Hyper Compress license.

For OEM terms, contact [email protected]. See the full license terms and the pricing page.

📖 For more details, see the Licensing Page.


Table of Contents


Why Hyper Compress

PDF compression has three major problems: files ending up being larger after compression, sacrificing document content for size, and producing PDFs that are broken and non conforming.

Hyper Compress is built around solving these three problems.

  • Monotonic compression. Hyper never returns a larger file. If compression does not save space, the original PDF is returned unchanged.

  • Content preserving compression. Hyper includes a true lossless mode for compression without image re encoding or quality loss. For more aggressive compression, it preserves searchable text and document structure while making only the changes required by the selected compression level all while producing a conforming PDF.

  • Signed documents handled safely. A digitally signed PDF is returned byte for byte by default, so its signature stays valid. Set removeSignatures to compress it anyway: Hyper removes the digital signature, keeps the visible signature on the page, compresses the document and reports signaturesRemoved, so the file can be signed again.

  • Built for reliability. Hyper validates its output and verifies transformations that can affect visual fidelity. When a change cannot reproduce a page faithfully, it is rolled back. Across the benchmark, Hyper had a 0.39% corruption rate, the lowest of any engine measured.

  • One engine, everywhere. The same compression engine powers the CLI, the Node.js SDK, the Rust crate, the C API, the self-hosted service and the WebAssembly build, on macOS, Linux (x64 and ARM64) and Windows.


Benchmarks

Against commercial SDKs: PDF Tools, Apryse and Nutrient

Hyper Compress was benchmarked against the PDF Tools, Apryse and Nutrient SDKs on 1,000 real PDFs (3.13 GB) from five public sources, at four levels, for a total of 13,000 engine runs. We make Hyper, so everything needed to check or repeat these numbers is in bench/sdk-comparison/: the exact list of PDFs with download links and checksums, every per-file result, and the code.

Each engine's settings were taken from its own documentation to match each level as closely as its options allow. If you know a setting that would serve an engine better at the same level, open an issue and we will rerun it.

Size saved overall, @ average page quality (SSIMULACRA2, where 100 is identical):

Engine Lossless 200 dpi 150 dpi 72 dpi
Hyper 18.0% @ 99.5 61.0% @ 89.8 70.2% @ 86.4 79.9% @ 67.9
PDF Tools N/A 55.1% @ 86.7 64.7% @ 82.9 75.6% @ 72.2
Apryse N/A 41.8% @ 88.4 55.6% @ 85.8 74.6% @ 73.4
Nutrient N/A 55.2% @ 87.8 61.5% @ 82.8 72.0% @ 70.8

Robustness across the same benchmark:

Engine Runs Failed Grew the file
Hyper 4,000 0 0
Nutrient 3,000 6 (0.20%) 5 (0.2%)
PDF Tools 3,000 0 64 (2.1%)
Apryse 3,000 8 (0.27%) 120 (4.0%)

[!NOTE] PDF Tools, Apryse and Nutrient have no lossless mode: none of their documentation describes a lossless optimization setting, so their lossless results are N/A.

Engines, machine and corpus
Engine Version How it was run
Hyper Compress hyper-compress 1.1.4 (npm) hyper in.pdf out.pdf --preset <level>
PDF Tools SDK pdftools_sdk 1.21.0 (Python) engines/pdftools.py
Apryse SDK apryse-sdk 12.2.1 (Python), PDFNet 12.2.0 engines/apryse.py
Nutrient .NET SDK GdPicture.API 14.4.11.1 (.NET 10) engines/nutrient/Program.cs, GdPicturePDFReducer

Machine: MacBook Pro (Apple M4, 16 GB), macOS 26.2. Tools: Node 22.23.2, Python 3.14, .NET 10.0.105, Poppler 26.02.0, qpdf 12.4.2, SSIMULACRA2 from libjxl 0.11.1.

The 1,000 PDFs were drawn with a fixed seed and stratified by size: 200 files each under 100 KB, 100–500 KB, 0.5–2 MB and 2–10 MB, 93 over 10 MB, and 107 more picked at random. The exact list, with the download link, size, page count and SHA-256 of every file, is MANIFEST.csv.

Source Files What it is
Common Crawl PDFs (Digital Corpora) 489 PDFs found on the web
GovDocs1 (Digital Corpora) 199 US government documents
PubMed Central open access 136 Medical and science papers
arXiv 134 Preprints
EUR-Lex 42 EU law in several languages
Settings for each engine
Level Hyper PDF Tools Apryse Nutrient
Lossless preset lossless N/A N/A N/A
200 dpi preset low (200 dpi, JPEG 80) Web profile, 200 dpi, threshold 300, quality 0.8, BALANCED JPEG quality 8/10, above 300 dpi → 200 downscale to 200 dpi, ImageQualityHigh
150 dpi preset medium (150 dpi, JPEG 50) Web, 150 dpi, threshold 225, quality 0.5 JPEG quality 5/10, above 225 → 150 downscale to 150 dpi, ImageQualityMedium
72 dpi preset high (72 dpi, JPEG 20, black and white scans 150 dpi) Web, 72 dpi, threshold 108, quality 0.2 JPEG quality 2/10, above 108 → 72 downscale to 72 dpi, ImageQualityLow

All engines: fonts subset and merged, metadata kept.

Black and white scans: no engine was set to reuse similar-looking shapes across a page (lossy JBIG2 pattern matching), which can swap one letter or number for another:

  • Hyper stores them with lossless JBIG2.
  • Apryse uses JBIG2 with threshold 10, which its documentation describes as lossless where possible.
  • Nutrient uses JBIG2 with JBIG2PMSThreshold 1.0. Its documentation says values below 1 can be lossy.
  • PDF Tools: its SDK documents that "the JBIG2 compression quality is fixed at 1 (lossless)" (ImageRecompressionOptions.compression_quality).

Resolution of black and white scans still differs by engine: Hyper keeps full resolution, except at 72 dpi where it uses 150 dpi; PDF Tools and Nutrient shrink them to the level's resolution; Apryse leaves their resolution alone.

How it was measured
  • Size: output bytes. If an engine returned a bigger file, the bigger file counts. A failed file counts as its original size.
  • Failed: no output, an error, more than 10 minutes on one file, or a different page count from the original.
  • Time: wall time per file, 4 files at a time for every engine. For Hyper, PDF Tools and Apryse this includes starting the process (Node or Python and SDK initialisation). Nutrient's .NET runtime takes about 9 seconds to start, so it ran as 4 long-running processes and its times exclude start-up.
  • Quality: pages 1 and 2 of every output are drawn at 100 dpi with Poppler's pdftoppm and compared with the original pages using SSIMULACRA2. 100 means identical, 90 and up no visible difference, under 70 visible on close look, under 50 clearly damaged.

Known limitations:

  • Quality is scored on the first two pages of each file, drawn by one renderer (Poppler).
  • Times depend on the machine. Compare engines with each other, not with numbers from other hardware.
Full results by level and by file size

Lossless

Engine Output Saved overall Median saving per file Failed Files made bigger Total time Median time per file Avg page quality (SSIMULACRA2) Pages < 50 Pages < 70
Hyper 2.56 GB 18.0% 20.6% 0 0 8.0 min 0.15 s 99.5 0.1% 0.5%
PDF Tools N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
Apryse N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
Nutrient N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A

Low (200 dpi)

Engine Output Saved overall Median saving per file Failed Files made bigger Total time Median time per file Avg page quality (SSIMULACRA2) Pages < 50 Pages < 70
Hyper 1.22 GB 61.0% 44.5% 0 0 14.5 min 0.21 s 89.8 2.1% 10.5%
PDF Tools 1.40 GB 55.1% 41.4% 0 26 20.5 min 0.81 s 86.7 5.6% 16.6%
Apryse 1.82 GB 41.8% 29.4% 1 46 43.6 min 2.45 s 88.4 2.7% 9.3%
Nutrient 1.40 GB 55.2% 42.0% 2 2 34.2 min 0.18 s 87.8 4.4% 12.3%
  • Hyper vs PDF Tools: Hyper smaller on 704 files, PDF Tools smaller on 250, within 1% on 46 (of 1000 both handled).
  • Hyper vs Apryse: Hyper smaller on 814 files, Apryse smaller on 157, within 1% on 28 (of 999 both handled).
  • Hyper vs Nutrient: Hyper smaller on 543 files, Nutrient smaller on 382, within 1% on 73 (of 998 both handled).

Medium (150 dpi)

Engine Output Saved overall Median saving per file Failed Files made bigger Total time Median time per file Avg page quality (SSIMULACRA2) Pages < 50 Pages < 70
Hyper 0.93 GB 70.2% 54.5% 0 0 17.0 min 0.25 s 86.4 4.4% 18.1%
PDF Tools 1.10 GB 64.7% 50.1% 0 20 19.7 min 0.81 s 82.9 8.6% 21.4%
Apryse 1.39 GB 55.6% 37.6% 4 42 44.1 min 2.47 s 85.8 4.2% 14.0%
Nutrient 1.20 GB 61.5% 47.5% 2 2 36.7 min 0.21 s 82.8 8.1% 19.1%
  • Hyper vs PDF Tools: Hyper smaller on 701 files, PDF Tools smaller on 253, within 1% on 46 (of 1000 both handled).
  • Hyper vs Apryse: Hyper smaller on 808 files, Apryse smaller on 164, within 1% on 24 (of 996 both handled).
  • Hyper vs Nutrient: Hyper smaller on 585 files, Nutrient smaller on 357, within 1% on 56 (of 998 both handled).

Highest (72 dpi)

Engine Output Saved overall Median saving per file Failed Files made bigger Total time Median time per file Avg page quality (SSIMULACRA2) Pages < 50 Pages < 70
Hyper 0.63 GB 79.9% 67.5% 0 0 20.7 min 0.33 s 67.9 29.2% 45.0%
PDF Tools 0.76 GB 75.6% 64.8% 0 18 18.9 min 0.81 s 72.2 23.1% 38.0%
Apryse 0.79 GB 74.6% 58.9% 3 32 44.0 min 2.45 s 73.4 20.2% 35.3%
Nutrient 0.87 GB 72.0% 60.1% 2 1 35.6 min 0.17 s 70.8 24.6% 38.3%
  • Hyper vs PDF Tools: Hyper smaller on 729 files, PDF Tools smaller on 233, within 1% on 38 (of 1000 both handled).
  • Hyper vs Apryse: Hyper smaller on 790 files, Apryse smaller on 175, within 1% on 32 (of 997 both handled).
  • Hyper vs Nutrient: Hyper smaller on 634 files, Nutrient smaller on 309, within 1% on 55 (of 998 both handled).

Saved overall by input size

Level Engine < 100 KB 100–500 KB 0.5–2 MB 2–10 MB > 10 MB
Lossless Hyper 27.5% 33.5% 28.7% 19.9% 15.3%
Lossless PDF Tools N/A N/A N/A N/A N/A
Lossless Apryse N/A N/A N/A N/A N/A
Lossless Nutrient N/A N/A N/A N/A N/A
Low Hyper 33.7% 44.6% 49.3% 58.2% 64.3%
Low PDF Tools 28.7% 43.1% 47.9% 49.0% 59.3%
Low Apryse 22.8% 34.8% 33.3% 39.5% 44.3%
Low Nutrient 33.1% 43.1% 44.3% 54.1% 57.5%
Medium Hyper 35.3% 48.8% 57.2% 67.6% 73.8%
Medium PDF Tools 32.1% 48.2% 56.4% 59.1% 68.9%
Medium Apryse 23.1% 37.6% 42.7% 54.3% 58.4%
Medium Nutrient 35.5% 47.3% 50.4% 61.3% 63.6%
Highest Hyper 44.1% 58.8% 68.3% 77.5% 83.1%
Highest PDF Tools 36.6% 56.6% 67.4% 69.4% 80.1%
Highest Apryse 30.9% 50.9% 61.3% 72.7% 78.0%
Highest Nutrient 40.0% 54.6% 61.0% 71.4% 74.4%
Reproduce

Requirements: macOS or Linux, Node 22, Python 3.11 or later, .NET 10, Poppler (pdftoppm), qpdf, ssimulacra2 (from libjxl), bc and perl. From bench/sdk-comparison/:

python3 fetch_corpus.py                        # downloads the 1,000 PDFs and checks every SHA-256
npm install                                    # hyper-compress 1.1.4
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt --extra-index-url https://pypi.apryse.com
dotnet build engines/nutrient -c Release -o engines/nutrient/bin
export APRYSE_KEY=... PDFTOOLS_KEY=... NUTRIENT_KEY=...   # your licence keys
./run.sh                                       # writes results.csv (takes several hours)
python3 report.py results.csv                  # prints the tables above

./run.sh hyper runs one engine. python3 report.py with no argument prints the tables from our own RESULTS.csv. Expect sizes to match ours to within a few bytes; PDF Tools and Apryse write the current date and a new document ID into each file.

File What it is
MANIFEST.csv The 1,000 PDFs: file name, source, bytes, pages, SHA-256, download link
RESULTS.csv Every result: engine, level, file, input and output bytes, pass or fail, exit code, seconds, quality of pages 1 and 2
fetch_corpus.py Downloads the corpus and checks it against MANIFEST.csv
run.sh, job.sh Run the engines and score each output
engines/ The exact settings used for PDF Tools, Apryse and Nutrient
report.py Builds the tables from a results file

Against open-source tools: Ghostscript, MuPDF and qpdf

Hyper Compress was benchmarked against Ghostscript, MuPDF, and qpdf using 2,104 real world PDFs from four public corpora, for a total of 27,352 engine runs.

Visual fidelity was measured with Poppler, which was deliberately chosen as an independent renderer rather than one shared by the engines being tested.

The full methodology, per-file results, and complete document list are available in comparison.md.

Median size reduction at the median worst page SSIM:

Engine Lossless 300 dpi 150 dpi 72 dpi
Hyper 22.4% @ 1.000 52.3% @ 1.000 58.2% @ 0.999 64.8% @ 0.996
Ghostscript 21.1% @ 0.997 19.1% @ 0.996 42.4% @ 0.994 53.9% @ 0.990
MuPDF 4.7% @ 1.000 14.0% @ 1.000 19.4% @ 1.000 28.0% @ 0.999
qpdf 6.3% @ 1.000 n/a n/a n/a

Robustness across the same benchmark:

Engine Runs Corrupt Grew the file
Hyper 8,416 33 (0.39%) 0
qpdf 2,104 1 (0.05%) 53 (2.5%)
Ghostscript 8,416 256 (3.04%) 2,089 (24.8%)
MuPDF 8,416 333 (3.96%) 70 (0.8%)

[!NOTE] The corpus selection was pre registered using a fixed seed before any files were fetched. Every document's SHA-256 hash and origin URL are recorded, so the benchmark can be independently reproduced.

You can also run the harness against your own documents:

make bench CORPUS=path/to/corpus


Install

Prebuilt binaries for macOS, Linux, and Windows are attached to each release.

Download the archive for your platform, verify it against SHA256SUMS, and unpack it into cli/prebuilt/.

For the self-hosted service:

docker run -d -p 8080:8080 ghcr.io/alam00000/bentopdf-hyper-compress:latest

To build the engine yourself, see BUILDING.md.


Usage

CLI

hyper input.pdf                                     # writes input-compressed.pdf

hyper input.pdf output.pdf                          # medium preset (default)

hyper input.pdf output.pdf --preset high            # smallest output

hyper scan.pdf out.pdf --target-size 2MB            # specify a target size

hyper locked.pdf out.pdf --password hunter2         # encrypted input

hyper in.pdf out.pdf --set grayscale=true           # override an option

hyper --help                                        # every flag, with examples

--target-size searches for the highest image quality that fits under your target, pushing down to quality 5 and 36 dpi if it has to. If the target is reachable you get the best looking file that fits; if it is not, you get the smallest file the engine could produce along with a warning saying how small that was.

Node.js SDK

import { compress } from 'hyper-compress';

const r = await compress({
  sourcePath: 'input.pdf',
  savePath: 'output.pdf',
  preset: 'medium',
});

console.log(r.originalSize, '->', r.compressedSize);

The result includes the original and compressed sizes, whether the document was signed, its declared PDF/A level, and whether a requested target size was reached.

Errors are typed:

decrypt_failed, engine_error, timeout, cancelled.

Parsing runs in a worker subprocess with a timeout. If hostile or malformed input causes the worker to fail, it is isolated from your main process.

Self-hosted service

The Docker image includes a web interface at http://localhost:8080 and an HTTP API.

Your files are processed on your own server.

curl -o out.pdf --data-binary @in.pdf \
  'http://localhost:8080/api/compress?preset=high'

See SELF-HOSTING.md for the complete API, configuration options, and deployment notes.

Browser (WebAssembly)

The web/ directory contains a complete browser build.

The engine is compiled to WebAssembly and runs locally in the browser. Files are not uploaded, and the build makes is air gapped by default.

The same WebAssembly build is on npm as hyper-compress-wasm, a buffer-based SDK for platforms the native package does not cover:

import { compress } from 'hyper-compress-wasm';

const result = await compress(pdfBytes, { preset: 'medium' });
node wasm/verify.mjs some.pdf

This verifies that the WebAssembly output is byte-identical to the native build.

C API

sdk/native exposes a small C ABI:

  • hpdf_compress_file
  • hpdf_compress_buffer
  • hpdf_last_error

The shared library exports only these symbols, and the ABI is additive only within a major version.


Compression Levels

Preset Image quality Max DPI Use for
low 80 200 Archival copies and minimal visible change
medium 50 150 The default; good for sharing and email
high 20 72 Smallest output and screen reading
lossless n/a none No image re-encoding; pixel-identical

Every option behind these presets is also available individually.

You can create custom profiles using image quality and resolution, grayscale conversion, colour reduction, font subsetting and unembedding, metadata and annotation stripping, PDF 2.0 Brotli streams, and page rasterisation for image-only documents.


What the Engine Does

Depending on the document and selected options, the engine can:

  • re encode images with jpegli
  • downsample images above a configured resolution ceiling
  • choose between JPEG, JPEG 2000, Flate, CCITT, and JBIG2 on a per image basis
  • convert Type 1 fonts to CFF
  • subset embedded fonts to the glyphs actually used
  • merge duplicate font programs
  • unembed fonts that are metric-compatible clones of the standard 14 fonts
  • regenerate content streams with correct handling for CMYK, CalRGB, Lab, ICCBased, Separation, DeviceN, Indexed, and pattern fills
  • deduplicate identical objects and prune unused resources
  • flatten ICC profiles
  • remove selected metadata
  • optionally apply PDF 2.0 Brotli stream compression
  • optionally rasterise pages when the document is genuinely image-only

The engine applies multiple techniques mentioned above to achieve best possible compression.


Building from Source

The JavaScript parts require Node 22:

npm ci

make check

The native engine builds against a pinned PDFium checkout. The initial bootstrap is several gigabytes.

See BUILDING.md for complete instructions, the patch inventory, and platform-specific notes.


Testing

make check                      # typecheck, lint, unit and integration tests

make regress                    # regression failset, every preset

make bench CORPUS=path/to/dir   # benchmark harness from comparison.md

make fuzz                       # libFuzzer harness

make regress is the gate for bug fixes.

Every PDF in tests/regression/failset/ represents a file that previously exposed a bug. The suite checks validity, pixel fidelity, and text-layer survival across every relevant preset.

A clean run reports zero failing pairs.

Fuzzing runs through ClusterFuzzLite on every pull request that touches the engine, and again nightly for a longer session. Discovered crashes are pinned as regression seeds.


Licensing

Hyper Compress is licensed under the GNU AGPL v3.

If you need to use Hyper Compress in a proprietary or closed-source product, commercial licenses are available as annual subscriptions from $99/year, under the Hyper Compress Commercial License. For OEM terms, contact us at [email protected].

Bundled third-party components retain their own licenses. See NOTICE.md for the full list.


Contributing

Contributions are welcome.

Before opening your first pull request, there are two things to know:

  1. Contributors need to sign the Contributor License Agreement. The bot will prompt you automatically.
  2. Bug fixes should include the PDF that reproduces the issue so it can be added to the regression suite.

See CONTRIBUTING.md for the full contribution guide.

For security vulnerabilities, please see SECURITY.md.