<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: PaperPDF</title>
    <description>The latest articles on DEV Community by PaperPDF (@paperpdf).</description>
    <link>https://dev.to/paperpdf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4196483%2Fadd3f1fc-45be-49b2-b211-84d4fd6e1587.png</url>
      <title>DEV Community: PaperPDF</title>
      <link>https://dev.to/paperpdf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/paperpdf"/>
    <language>en</language>
    <item>
      <title>How we built 60+ PDF, image and video tools that never upload your files</title>
      <dc:creator>PaperPDF</dc:creator>
      <pubDate>Tue, 20 Oct 2026 15:44:23 +0000</pubDate>
      <link>https://dev.to/paperpdf/how-we-built-60-pdf-image-and-video-tools-that-never-upload-your-files-425d</link>
      <guid>https://dev.to/paperpdf/how-we-built-60-pdf-image-and-video-tools-that-never-upload-your-files-425d</guid>
      <description>&lt;p&gt;Most "free online PDF tools" work the same way: you upload your file to their server, they process it, and you download the result. That's fine for a cat photo. It's not fine for a passport scan, a bank statement or a salary certificate.&lt;/p&gt;

&lt;p&gt;So we built &lt;strong&gt;&lt;a href="https://getpaperpdf.com" rel="noopener noreferrer"&gt;PaperPDF&lt;/a&gt;&lt;/strong&gt; around one rule: &lt;strong&gt;your file never leaves your device.&lt;/strong&gt; Every tool runs inside the browser. There is no upload step at all, not even a temporary one.&lt;/p&gt;

&lt;p&gt;Here's how that works, and what we learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that shaped everything
&lt;/h2&gt;

&lt;p&gt;If nothing is uploaded, the browser has to do all the work, on all kinds of devices, including cheap Android phones on slow mobile data. That one rule decided almost every technical choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static site, no backend for tools.&lt;/strong&gt; Pages are plain HTML/CSS with small, lazy-loaded scripts. A tool's code is only downloaded when you open that tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heavy work in Web Workers&lt;/strong&gt;, so the page never freezes while a 200-page PDF or a 1-minute video is processed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process in pieces, not all at once.&lt;/strong&gt; Files are read in slices and video frames are handled one at a time, so phones don't run out of memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works offline after the first visit&lt;/strong&gt;, thanks to a service worker that caches each tool once you've used it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  PDF tools
&lt;/h2&gt;

&lt;p&gt;For merging, splitting, rotating, page numbers, watermarks, forms and signing, we use &lt;strong&gt;pdf-lib&lt;/strong&gt; to edit the PDF structure directly. Text stays as text, so files stay small and searchable.&lt;/p&gt;

&lt;p&gt;For anything that needs to &lt;em&gt;see&lt;/em&gt; a page (previews, PDF to JPG/PNG, grayscale), we render with &lt;strong&gt;PDF.js&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Compression was the hardest part. Online forms in many countries ask for a PDF "under 100 KB" or even "under 50 KB". Our Compress PDF tool tries progressively stronger settings until it fits the target, and it tells you honestly when a file can't get that small without becoming unreadable.&lt;/p&gt;

&lt;p&gt;Password protection and unlocking use &lt;strong&gt;qpdf compiled to WebAssembly&lt;/strong&gt;, with AES-256.&lt;/p&gt;

&lt;h2&gt;
  
  
  Images and OCR
&lt;/h2&gt;

&lt;p&gt;Image tools use the browser's own canvas and image encoders: compress to a target KB, resize, crop, convert, change DPI. The DPI tool can change only the DPI value in the file header, without touching a single pixel, which is exactly what many photo upload forms need.&lt;/p&gt;

&lt;p&gt;Text recognition (image to text) uses &lt;strong&gt;Tesseract.js&lt;/strong&gt;. Language data is downloaded only when you pick a language, and the size is shown first.&lt;/p&gt;

&lt;p&gt;Background removal runs a small segmentation model with &lt;strong&gt;ONNX Runtime Web&lt;/strong&gt;, entirely on the device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video and audio, without uploading
&lt;/h2&gt;

&lt;p&gt;This was the part people told us wouldn't work in a browser. It does, thanks to &lt;strong&gt;WebCodecs&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;decode and encode with the browser's own codecs&lt;/li&gt;
&lt;li&gt;read MP4/MOV with &lt;strong&gt;mp4box.js&lt;/strong&gt;, write with &lt;strong&gt;mp4-muxer&lt;/strong&gt; / &lt;strong&gt;webm-muxer&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;do some jobs &lt;strong&gt;without re-encoding at all&lt;/strong&gt;: muting a video, fast trims, instant rotation and joining matching clips just copy the data, so they finish in about a second with zero quality loss&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a typical computer, compressing a 1-minute 1080p clip to WhatsApp size takes around 30 seconds. Phones are slower, and the page says so instead of pretending.&lt;/p&gt;

&lt;p&gt;Where a browser can't do something (for example, no WebCodecs, or a codec the device can't decode), the tool shows a clear message rather than failing silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy beyond "no upload"
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No accounts, no watermark, no limits.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookieless analytics&lt;/strong&gt; that count visits, not people.&lt;/li&gt;
&lt;li&gt;A strict Content Security Policy, so the pages can only load their own code.&lt;/li&gt;
&lt;li&gt;The microphone is allowed on exactly one page (the voice recorder), and blocked everywhere else by a Permissions-Policy header.&lt;/li&gt;
&lt;li&gt;Drafts (for example an invoice you're filling in) are saved only in your own browser, with a "Delete my saved details" button.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Because each page only loads what it needs, the pages score 98–100 on mobile Lighthouse, even the video tools. Lazy-loading per tool made the biggest difference. Shared code that quietly pulls in "just one more" module is the usual culprit when every page gets slower.&lt;/p&gt;

&lt;h2&gt;
  
  
  Licences
&lt;/h2&gt;

&lt;p&gt;We only use permissively licensed libraries (MIT, Apache-2.0, BSD). Where an LGPL component was the only good option (an MP3 encoder and a HEIC decoder), it's shipped unmodified as a separate file, and everything is listed on our licences page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's there today
&lt;/h2&gt;

&lt;p&gt;More than 60 tools in five groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PDF:&lt;/strong&gt; merge, split, compress, edit, sign, fill forms, redact, protect, unlock, crop, page numbers and more&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image:&lt;/strong&gt; compress, resize, convert, HEIC to JPG, passport photo maker, signature maker, background remover, OCR&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video:&lt;/strong&gt; compress, trim, split for Status, crop to 9:16, speed, merge, add music, video to MP3/GIF&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio:&lt;/strong&gt; MP3 cutter/ringtone maker, converter (including WhatsApp voice notes), voice recorder, join audio&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document makers:&lt;/strong&gt; invoices, letters and certificates, downloadable as PDF or Word&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's free to use: &lt;strong&gt;&lt;a href="https://getpaperpdf.com" rel="noopener noreferrer"&gt;getpaperpdf.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you try it, we'd really like to hear what breaks, especially on older phones. There's a feedback box on every page.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>privacy</category>
      <category>pdf</category>
    </item>
  </channel>
</rss>
