DEV Community

Toolsy Hub
Toolsy Hub

Posted on

Building PDF tools that never upload your file: pdf-lib, pdf.js and qpdf in WebAssembly

Most "free PDF tools" upload your file to a server, process it there and send it back. For a bank statement or a CNIC scan that is a lot of trust to hand a site you found a minute ago. I wanted merge, split, compress and unlock to work with no upload at all, so I built them to run entirely in the browser. This post is what that took, and where it falls short.

The three engines

  • pdf-lib (1.17) reads and writes the PDF structure: merging, splitting, picking pages, building a PDF from JPGs. It is plain JavaScript and works the same in every modern browser.
  • pdf.js (Mozilla's renderer) draws a page onto a canvas. I use it to turn pages into images for "PDF to JPG" and for the stronger compress mode.
  • qpdf, compiled to WebAssembly (about 1.3 MB), removes the password and restrictions from a PDF when the user types the password they already know. pdf-lib cannot decrypt, so this is the one job that needed a native tool.

None of them load with the page. Each is imported inside the click handler with await import(...), so someone who only wants the word counter never downloads a PDF engine.

Caching the engines for a year

The WASM and worker files are copied at build time into a folder named after the package version, for example /engines/qpdf-<version>/, and served with Cache-Control: public, max-age=31536000, immutable. A new version gets a new folder, so a browser never mixes an old worker with new code, and a returning visitor does not download 1-2 MB again.

Compress: two modes, and why

There is no magic "compress PDF" call. What shrinks a PDF depends on what is inside it.

  1. Light mode re-saves the file with pdf-lib using compressed object streams. Text stays selectable. The saving is small, often a few percent, because the pictures inside are untouched.
  2. Image mode renders every page with pdf.js to a JPEG (150 dpi at quality 0.8 for "high", down to 96 dpi at 0.5 for "low") and builds a new PDF from those images. For scanned documents, which are pictures anyway, this is where the big savings are. The cost: text becomes part of the picture and is no longer selectable.

The tool says which mode does what before you click, rather than after.

Hitting an exact size

Upload forms in Pakistan ask for "PDF under 200 KB" or "under 100 KB", so a slider is not enough. With a target set, the pages are rendered at the sharpest level first, and the packer lowers JPEG quality only as far as it has to until the whole PDF fits. If it cannot get there, it says so instead of quietly handing back a file that is still too big.

What does not work well

  • Very large files on phones. Rendering 60 pages at 150 dpi in a phone browser uses a lot of memory. Server tools win here.
  • Image mode on text PDFs. A text-only PDF can come out bigger as images. Light mode is the right choice there. Image mode is still the default, because most files people bring to a "PDF under 200 KB" form are scans.
  • Password cracking. The unlock tool opens a file with the password you type. It does not guess passwords, on purpose.

Try it

The tools are free with no sign-up: Compress PDF, Merge PDF, Unlock PDF. Open the network tab while you use one and you will see no request carrying your file.

If you have built something similar, I would like to hear how you dealt with memory on phones.

Top comments (0)