Compressing a PDF to a target size, and where it falls short
Compress PDF can aim at 1, 2 or 5 MB or a size you type. How it picks image quality, and why text-only files stay out of reach.
One of our test files is a short report with two 3000×2000 photos stored as PNG. It weighs 10.7 MB. When we replaced only those two images with smaller JPEG copies, the file lost 99.7% of its size. Another test file is a text-only PDF of 2,999 bytes. Nothing we tried made it smaller, and one method made it 63 times larger.
Those two files decided how the target-size mode of Compress PDF works. In our tests every large saving came from pictures, so pictures are what the mode works on. A file made of text and vector drawings gives it nothing to remove.
Why a target size
Some upload forms set a maximum file size. On 9 November we decided to add a way to say “make this fit 2 MB”, so that nobody has to choose a compression level and try again. The same release added a link that presets the target, such as ?target=2mb.
The rules came from Compress PDF as it already was. It runs in the browser. It must not touch text, fonts, forms, page boxes or rotation. It must never hand back a file larger than the original.
Five methods on generated files
Before Compress PDF existed, we compared five ways to make a PDF smaller, in two rounds. On 6 September 2026 we ran npm run trial:pdf-compression on generated PDFs with pdf-lib and PDF.js in Node, and compared extracted text, page geometry, form values and rendered pixels before and after. On 28 September a second harness ran on generated files plus one PDF exported from LibreOffice, and compared QPDF, image replacement and both together.
| Method | Round | Result on the test files |
|---|---|---|
| Re-save with pdf-lib object streams | 6 Sep | A text PDF without object streams: 36.9% smaller. The same file already optimized, two scans and a form: no saving |
| Render every page to JPEG at 108 ppi, quality 80 | 6 Sep | PNG scan 96.1% smaller and JPEG scan 33.6% smaller, both visibly softer. Text PDFs grew 40 to 63 times and lost their text; the form lost its field |
| QPDF stream recompression (A) | 28 Sep | Photo reports: 0% and 0.03%. LibreOffice export: 27.2%. Form: 13.8%. Text-only file and full-page scan: no saving |
| Replace embedded images only (B) | 28 Sep | JPEG photo report (1.47 MB): 97.6%. PNG photo report (10.7 MB): 99.7%. Full-page scan (362 KB): 80.9%. LibreOffice export: 25.3%. Text-only file and form: no saving |
| B, then A | 28 Sep | As B; LibreOffice export 27.3%, form 13.8% |
We ruled out rendering whole pages early. It removes selectable text and form fields, and on text documents it grows the file. Replacing embedded images, method B, kept the extracted text, form fields, page boxes and rotation in every test, and it changed pixels only inside the replaced images. Most of the photo savings came from reducing resolution.
What Compress PDF does now
Compress PDF is method B followed by a pdf-lib save with object streams. We left QPDF out of the first version.
Each embedded JPEG or Flate image in RGB or grayscale is scaled down to at most 150 ppi of the largest size it is drawn at on a page. When that size cannot be read from the page content, the long edge is capped at 2000 pixels. The image is re-encoded as JPEG at quality 0.75 for Standard or 0.6 for Strong. The new copy replaces the old one only when it is smaller than 90% of it.
The target-size mode sits on top of those two levels. The Target size menu offers No target, 1 MB, 2 MB, 5 MB and Custom, from 0.1 to 60 MB. One MB here is 1,048,576 bytes. A run tries Standard first, then Strong, and keeps the first copy that fits. If the original is already under the target, the page says so. If neither level fits, it reports the smallest copy and the level that made it. If no copy was smaller than the original, it says that instead. Strong is skipped when the PDF has no embedded images, because there is nothing for it to change.
After the run we open the result again in the browser and check it. Its size must match the size shown and be smaller than the original. When the target was reached, the result must be at or under it. A failed check shows a warning.
The link preset accepts only target on Compress PDF, with values such as 2mb, 1.5mb or 500kb. Other parameters and other pages ignore it. Nothing in the address can name a file or put text into a document. On 9 November we tested this in browsers on a local build of the pdfresult site. A ?target=1mb link preset the 1 MB target, the run reached it with Standard, and unknown parameters in the same link were ignored. A custom target of 102 KB on a file that could not reach it reported the smallest copy.
Where it falls short
The main limit is that there are only two levels. There is no third, harsher setting, so a target can be missed by more than a custom quality would miss it. We did not add new compressor settings for this release.
A file of text and vector drawings has nothing to recompress. The result then says “This PDF is already compact — no smaller copy was made.” Some images are left as they are: images with masks or soft masks, CMYK, Indexed or Separation colour, images that are not 8-bit, very small images (under 150×150 pixels or under 50 KB) and images over 40 megapixels. The result lists each skipped image with a reason.
Encrypted, digitally signed or certified files and files with incremental updates are not changed, because any rewrite would break a signature. Our incremental check is conservative, and it also refuses some unsigned files that were saved more than once. Compress PDF accepts one PDF up to 60 MB and 200 pages.
Our test set has limits of its own. All test files are generated, plus the one LibreOffice export. We have not verified phone memory and time on large image-heavy files, real CMYK and 16-bit images, or real signed PDFs. The skip and refusal rules are covered by unit tests only.
A scanned or photo-heavy PDF shows the largest change. A text-only PDF shows the “already compact” message.
Compress PDF is in the Laboratory’s PDF workspace on laboratoru.com.