DEV Community

hao jia
hao jia

Posted on

Our PDF upload limit says 2 MB. I tested auto-compression before adding it

Our upload form rejects PDFs over "2 MB". Every month a few support tickets land with the same complaint: "My file says it's under the limit." A product manager on my team suggested the obvious fix: when a PDF is too big, compress it in the browser and retry automatically. Before estimating that, I ran a small test. The auto-retry idea didn't survive it, but two smaller changes did.

First, decide which "2 MB" you mean

"2 MB" is either 2,000,000 bytes or 2,097,152 bytes. Our frontend formatted sizes in base 1024. macOS Finder shows base 1000. The backend compared raw bytes. Three parties, three numbers, no bug anywhere, and still tickets.

One of my test files makes the gap obvious: 19,458,294 bytes. The compression tool I used shows it as "18.56 MB" (base 1024). In base 1000 it's 19.46 MB. Near the limit, that difference decides pass or fail.

We now store the limit as a byte constant, pick the stricter 2,000,000, and show both readings in the error message:

const LIMIT_BYTES = 2_000_000;
const fmt = (b) => `${(b / 1048576).toFixed(2)} MiB / ${(b / 1e6).toFixed(2)} MB`;

function checkUpload(file) {
  if (file.size <= LIMIT_BYTES) return { ok: true };
  return { ok: false, message: `This file is ${fmt(file.size)}. The limit is ${fmt(LIMIT_BYTES)}.` };
}
Enter fullscreen mode Exit fullscreen mode

A 2,905,274-byte file gets "This file is 2.77 MiB / 2.91 MB. The limit is 1.91 MiB / 2.00 MB." Nobody has to guess which unit we meant.

Then, check whether compression would even help

I didn't want to test with customer files (we went through a compliance review once and I'm not repeating it), so I built three fake samples:

  • an 8-page product brochure, 19,458,294 bytes, photos from a CC0 Wikimedia Commons image, cropped and upscaled
  • a 10-page text-only document, 137,782 bytes
  • a 4-page 300 dpi "scan": a made-up form rendered to full-page images, no text layer, 8,948,995 bytes

I compressed them with the PDF tool on ImgIng (https://imging.ai/), mainly because it runs in the browser. I kept DevTools' Network tab open during every run and saw no non-GET requests, which is the first thing our compliance people would ask about. I don't know how it works internally; everything below is inferred from the output files.

English UI of the PDF compressor with the self-made scanned sample (Chinese placeholder text) on the E-book preset. Red boxes: the preset, and the result card showing 8.53 MB to 1.84 MB

On the default E-book preset (150 dpi):

Sample Before (bytes) After (bytes) Saved
Brochure 19,458,294 864,614 95.6%
Scan 8,948,995 1,927,707 78.5%
Text-only 137,782 131,156 4.8%

The scan ends at 1.84 MiB, or 1.93 MB. Under 2 MB in both readings.

The text-only file is the problem. All four presets produced the identical 131,156-byte file. Splitting the PDF by stream type explains it: 85.22% of its bytes are embedded fonts, and the tool's docs say it doesn't subset fonts. The brochure is 99.23% images. That's one sample with fonts that were already subset, so I'm not claiming every text PDF behaves like this. Still, it was enough to kill "compress and retry" as a silent fallback. For a file like that, the user waits through a compression pass and then gets rejected anyway.

Verify what comes back

A smaller file only helps if it's still the same document. I compared page count and extracted text before and after. The brochure (3,357 characters) and the text-only file (11,174 characters) matched exactly, and so did every page count. The scan has no text layer, so only the page count means anything there. For image quality I rendered the pages and looked. The lowest preset (Screen, 72 dpi) got the brochure down to 352,318 bytes, but the small table text in its screenshots became unreadable. That's why our message suggests "around 150 dpi" instead of "smallest".

What we shipped

No automatic compression. When a PDF is over the limit, we check it before showing the error. If it looks like a scan, we suggest compressing to about 150 dpi. If it mixes images and text, we suggest compressing the images. If there are no images at all, we suggest splitting the file. Encrypted PDFs get their own message, because the compressor I tested refuses them until protection is removed.

I only tested three self-made files, in Chromium on a Mac. Mobile browsers and Windows are untested, and scans that already have an OCR text layer will probably confuse our "looks like a scan" check. That's next on the list.

Top comments (0)