“Compress my PDF” has 100 answers in search results, and each one is only half right. The truth: PDF compressibility is strongly tied to its “content type”. A 5 MB scanned PDF might compress to 800 KB; the same 5 MB pure-text PDF might only compress to 4.7 MB.

This article uses real compression data from 4 typical PDF types to explain: what a PDF file is made of, how much of each part is compressible, and why a browser-based local compressor can never match desktop GhostScript.

PDF File Anatomy

A PDF file has 4 components:

  • Text streams — text inside the PDF, stored as vectors (not images)
  • Image streams — images inside the PDF, usually JPEG/PNG-compressed, possibly uncompressed
  • Fonts — embedded font files (sometimes re-embedded, sometimes subset-embedded)
  • Metadata — author, creator software, modification history

Compression basically does 4 things: re-compress images (shrink image streams), rewrite font dictionaries (drop unused glyphs), Deflate text streams (zip-like), strip redundant metadata.

The browser-side pdf-lib tool mainly does #4 (metadata cleanup) and the simple case of #1 (cleanup of metadata of already-compressed JPEGs). What it cannot do: re-encode unoptimized scanned images, force-subset fonts, deeply restructure the PDF object graph.

Real Compression Ratios for 4 PDF Types

Type 1: Scanned PDFs

Characteristics: Every page is a high-resolution image (usually 200-300 DPI, JPEG-compressed). 90% of the file volume is the image stream.

Expected compression: 30-70%

Example: 5 MB scanned contract → 1.5-3.5 MB

Why the browser cannot: Compressing scanned PDFs requires re-encoding JPEGs (drop quality from 85 to 70, or convert to WebP), which needs decoding of the original image. Browser tools have limited capability here, so our v1 does not support this kind of compression. Desktop tools (GhostScript, Adobe Acrobat, Foxit) do it, at the cost of installing software.

Manual workaround: Export every page to JPEG (using a PDF reader or pdf-lib), then [image-compress](URL to image-compressor) to quality 70, then assemble the JPEGs into a new PDF using an empty PDF as a frame. Manual, slow, but it works.

Type 2: Pure-text PDFs

Characteristics: Text streams dominate. Fonts are subset-embedded. Almost no images.

Expected compression: 2-10%

Example: 1 MB research report (no images) → 0.9-0.98 MB

Why the browser can do it: Metadata cleanup + Deflate text streams. That’s what pdf-lib’s useObjectStreams: true does.

Type 3: Mixed PDFs (text + images)

Characteristics: Think product manuals, reports, exported slide decks — there are charts, text, cover images.

Expected compression: 10-30%

Example: 8 MB product manual → 5.6-7.2 MB

Why the browser can do part of it: Metadata cleanup + Deflate of text streams both work fully. The image part — if the images were already compressed (JPEG quality 80+) — the browser cannot compress further. If the images inside are PNG or high-quality JPEG, in theory there’s headroom.

Type 4: Encrypted PDFs

Expected compression: 0% (encrypted content cannot be compressed)

Why: After encryption, content is a random byte stream. Any meaningful compression algorithm becomes useless on it. You must decrypt → compress → re-encrypt (if you still need encryption).

Why Local Tools Will Never Beat Desktop GhostScript

GhostScript (gs) is the Swiss Army knife of PDF compression. Its core capabilities:

  1. Complete PDF object-graph restructure — re-interleaves page content, fonts, images for better incremental update (we can’t do this)
  2. Image re-encoding — re-encodes JPEG/PNG to more aggressive quality (we can’t do this)
  3. Font subsetting — embeds only the characters actually used in the document (we can’t — needs a rendering engine)
  4. Stream filtering — switches to more efficient zlib level (we do baseline deflate)

GhostScript is a 200 MB install with tons of command-line flags (-dPDFSETTINGS=/screen for max compression, /prepress for highest quality). Browsers cannot do any of this — TypeScript runs in a sandbox without a low-level PDF rendering pipeline.

How Our v1 Compresses

Our PDF Tools — Compress mode “Compress” button does 3 things:

  1. useObjectStreams: true — merges multiple PDF objects into a single compressed stream. Empirically saves 5-15% of volume.
  2. Drop default page — pdf-lib adds a default blank page; we don’t.
  3. Strip redundant metadata — like Producer, Creator, ModDate — if downstream tooling doesn’t need them, drop them.

If you compress a PDF and see no significant change (e.g. 5 MB → 4.95 MB), the tool politely tells you “this PDF is already well compressed.” That’s honest feedback — not “I compressed it, so it shrank by 30%”, but “your PDF has nothing left to shrink.”

v2 Plans

We are evaluating:

  • @pdf-lib/original’s experimental image re-encoding API (community has a PR, may merge to main in 2026 Q3)
  • pdfjs-dist worker render + canvas → WebP — render each page via PDF.js, export to WebP, repackage. This is the toolified version of manual workaround #1; significant bundle cost (+30 MB)

Before v2, if you need aggressive compression, there is no shortcut — install a desktop tool (GhostScript, PDFsam, NAPS2) or use a paid online service (smallpdf, ilovepdf).

  1. Check the type first — open the file in your PDF reader, quickly judge (all text? all images? mixed?)
  2. Don’t expect miracles — pure-text PDFs don’t compress. Don’t compress in a loop (each cycle saves a tiny amount while taking longer)
  3. Small batches — compress 10 or fewer at a time, wait for the result, then the next batch
  4. Open and check after compress — re-open the compressed PDF and flip through it. There is no “looks-right” visual test; there is only “actually flipping through every page” visual test.

Try our PDF Tools — Compress mode. It honestly tells you how much it saved.