<?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>Forem: kabir daki</title>
    <description>The latest articles on Forem by kabir daki (@kabir_daki).</description>
    <link>https://forem.com/kabir_daki</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3864599%2Fcedfb1f5-147e-4e25-b7d9-01da035bd883.png</url>
      <title>Forem: kabir daki</title>
      <link>https://forem.com/kabir_daki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kabir_daki"/>
    <language>en</language>
    <item>
      <title>How I Reduced PDF File Size by 80% in the Browser — No Server Needed</title>
      <dc:creator>kabir daki</dc:creator>
      <pubDate>Tue, 21 Apr 2026 23:24:36 +0000</pubDate>
      <link>https://forem.com/kabir_daki/how-i-reduced-pdf-file-size-by-80-in-the-browser-no-server-needed-2dd</link>
      <guid>https://forem.com/kabir_daki/how-i-reduced-pdf-file-size-by-80-in-the-browser-no-server-needed-2dd</guid>
      <description>&lt;p&gt;When I started building &lt;a href="https://pdfonlinelovepdf.com" rel="noopener noreferrer"&gt;PDFOnlineLovePDF&lt;/a&gt;, I faced one big challenge: &lt;strong&gt;how do you compress a PDF file entirely in the browser, without sending it to a server?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most PDF tools upload your file to a remote server, process it, then send it back. That's slow, raises privacy concerns, and costs money to run at scale.&lt;/p&gt;

&lt;p&gt;I wanted something different: &lt;strong&gt;100% client-side PDF compression.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's exactly how I did it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem With Server-Side PDF Compression
&lt;/h2&gt;

&lt;p&gt;Most online PDF tools work like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User uploads file → goes to your server&lt;/li&gt;
&lt;li&gt;Server runs ghostscript or similar tool&lt;/li&gt;
&lt;li&gt;Compressed file is sent back to the user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This works, but has real problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy:&lt;/strong&gt; Your files touch someone else's server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; Upload + processing + download = slow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; Server bandwidth and CPU are expensive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; 1000 users uploading 10MB files = infrastructure nightmare&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted to eliminate all of these problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: PDF.js + PDF-lib in the Browser
&lt;/h2&gt;

&lt;p&gt;The key insight is that modern browsers are incredibly powerful. With the right libraries, you can parse, manipulate, and re-render PDF files entirely in JavaScript — no server required.&lt;/p&gt;

&lt;p&gt;Here are the two libraries that made this possible:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. PDF.js (by Mozilla)
&lt;/h3&gt;

&lt;p&gt;PDF.js lets you &lt;strong&gt;read and render&lt;/strong&gt; PDF files in the browser. It parses the PDF structure and gives you access to every page, image, font, and element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pdfjsLib&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdfjs-dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loadPDF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pdfjsLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. PDF-lib
&lt;/h3&gt;

&lt;p&gt;PDF-lib lets you &lt;strong&gt;create and modify&lt;/strong&gt; PDF files entirely in JavaScript. You can add pages, embed images, compress content, and save the result as a new PDF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PDFDocument&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdf-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compressPDF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdfDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;PDFDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compressedBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pdfDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;useObjectStreams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// This is key for compression&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;compressedBytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Compression Strategy
&lt;/h2&gt;

&lt;p&gt;Simply re-saving a PDF with &lt;code&gt;useObjectStreams: true&lt;/code&gt; gives you some compression, but not enough. The real gains come from &lt;strong&gt;re-rendering each page as a compressed image&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's the full strategy I used:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Render Each Page to Canvas
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderPageToCanvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;viewport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getViewport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;scale&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;canvasContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Convert Canvas to Compressed JPEG
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvasToJpeg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image/jpeg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;quality&lt;/span&gt; &lt;span class="c1"&gt;// 0.7 = 70% quality, good balance&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Rebuild the PDF With Compressed Images
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rebuildPDF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdfjsLib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdfjs-dist/build/pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loadingTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pdfjsLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;originalArrayBuffer&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdfDoc_original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;loadingTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newPdfDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;PDFDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;pdfDoc_original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;numPages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pdfDoc_original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderPageToCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jpegBlob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;canvasToJpeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jpegArrayBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;jpegBlob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jpegImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;newPdfDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;embedJpg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jpegArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jpegImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newPdfDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addPage&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nx"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jpegImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;newPdfDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Results
&lt;/h2&gt;

&lt;p&gt;Using this approach, here's what I observed across different PDF types:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PDF Type&lt;/th&gt;
&lt;th&gt;Original Size&lt;/th&gt;
&lt;th&gt;Compressed Size&lt;/th&gt;
&lt;th&gt;Reduction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scanned document (10 pages)&lt;/td&gt;
&lt;td&gt;8.2 MB&lt;/td&gt;
&lt;td&gt;1.4 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;83%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Report with images (5 pages)&lt;/td&gt;
&lt;td&gt;3.1 MB&lt;/td&gt;
&lt;td&gt;0.7 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;77%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text-heavy document (20 pages)&lt;/td&gt;
&lt;td&gt;1.8 MB&lt;/td&gt;
&lt;td&gt;0.4 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;78%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Presentation slides (15 pages)&lt;/td&gt;
&lt;td&gt;12.4 MB&lt;/td&gt;
&lt;td&gt;2.1 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;83%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Average reduction: &lt;strong&gt;~80%&lt;/strong&gt; — entirely in the browser.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quality vs Compression Tradeoff
&lt;/h2&gt;

&lt;p&gt;The JPEG quality setting is the main lever you can pull:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Higher quality = larger file, better text readability&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HIGH_QUALITY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// ~60% reduction&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MEDIUM_QUALITY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// ~75% reduction  &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LOW_QUALITY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// ~85% reduction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For my tool, I offer three preset levels so users can choose based on their needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High Quality&lt;/strong&gt; — best for documents you'll print&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medium Quality&lt;/strong&gt; — best for email attachments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low Quality&lt;/strong&gt; — best for web upload or WhatsApp sharing&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Handling Large Files Without Freezing the UI
&lt;/h2&gt;

&lt;p&gt;Processing large PDFs page by page can freeze the browser if you're not careful. The solution is to use &lt;strong&gt;Web Workers&lt;/strong&gt; and update a progress bar as each page is processed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In your main thread&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/pdf-compress-worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;updateProgressBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// e.g. "Processing page 3 of 10"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;downloadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In pdf-compress-worker.js&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/* get from pdf */&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// process page i&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; / &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;compressedBytes&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Privacy as a Feature
&lt;/h2&gt;

&lt;p&gt;One unexpected benefit of this approach: &lt;strong&gt;you can genuinely tell users their files never leave their device.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This turned out to be a real differentiator. Many users explicitly mentioned in feedback that they chose PDFOnlineLovePDF because they didn't want to upload sensitive documents (contracts, medical records, financial statements) to an unknown server.&lt;/p&gt;

&lt;p&gt;The privacy benefit is not just marketing — it's a direct result of the technical architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This approach isn't perfect. Here are the tradeoffs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Text becomes non-selectable&lt;/strong&gt;&lt;br&gt;
When you re-render pages as images, the text layer is lost. The output is a purely image-based PDF — you can't select or copy text from it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. File size depends on content complexity&lt;/strong&gt;&lt;br&gt;
Text-heavy PDFs compress more than image-heavy ones. A PDF that's already full of JPEG photos may not compress much.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Processing is CPU-intensive&lt;/strong&gt;&lt;br&gt;
On older or low-end devices, processing a 50-page PDF can take 10-20 seconds. The progress bar is essential for UX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Very large files (100+ pages) are slow&lt;/strong&gt;&lt;br&gt;
For very large documents, a hybrid approach (client-side for preview, server-side for heavy processing) might be better.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building this feature taught me several things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The browser is more powerful than most developers assume.&lt;/strong&gt; PDF manipulation, image compression, file download — all doable without a backend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy-first architecture is a real competitive advantage&lt;/strong&gt;, especially for document tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Workers are underused.&lt;/strong&gt; They make CPU-intensive tasks smooth and non-blocking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UX matters more than perfect compression.&lt;/strong&gt; Users care more about a fast, responsive experience than squeezing out the last few kilobytes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The PDF compression tool is live at &lt;a href="https://pdfonlinelovepdf.com/compress-pdf" rel="noopener noreferrer"&gt;PDFOnlineLovePDF.com&lt;/a&gt;. It's completely free, no signup required.&lt;/p&gt;

&lt;p&gt;If you're building something similar or have questions about the implementation, drop a comment below — happy to help!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If this was useful, consider following me here on DEV.to for more posts about building browser-based tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I built a free alternative to iLovePDF — here's what I learned</title>
      <dc:creator>kabir daki</dc:creator>
      <pubDate>Thu, 16 Apr 2026 22:08:18 +0000</pubDate>
      <link>https://forem.com/kabir_daki/i-built-a-free-alternative-to-ilovepdf-heres-what-i-learned-40o8</link>
      <guid>https://forem.com/kabir_daki/i-built-a-free-alternative-to-ilovepdf-heres-what-i-learned-40o8</guid>
      <description>&lt;p&gt;Everyone uses iLovePDF. I did too.&lt;/p&gt;

&lt;p&gt;Until I realized: every file I uploaded was sitting on their servers.&lt;br&gt;
Contracts. Invoices. ID scans.&lt;/p&gt;

&lt;p&gt;That bothered me. So I built something different.&lt;/p&gt;




&lt;h2&gt;
  
  
  PDFOnlineLovePDF — 31 tools, zero uploads
&lt;/h2&gt;

&lt;p&gt;Here's the core difference:&lt;/p&gt;

&lt;p&gt;❌ iLovePDF → uploads your file to their server&lt;br&gt;
✅ PDFOnlineLovePDF → processes everything in your browser&lt;/p&gt;

&lt;p&gt;Your files never leave your device. Ever.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it can do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Convert PDF to Word, Excel, PowerPoint&lt;/li&gt;
&lt;li&gt;Compress PDF (up to 90% smaller)&lt;/li&gt;
&lt;li&gt;Merge, split, rotate, crop&lt;/li&gt;
&lt;li&gt;OCR — extract text from scanned PDFs&lt;/li&gt;
&lt;li&gt;Translate PDF into 50+ languages&lt;/li&gt;
&lt;li&gt;Sign, protect, watermark&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All free. No signup. No limits.&lt;/p&gt;




&lt;h2&gt;
  
  
  The tech stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15&lt;/strong&gt; — fast, SEO-friendly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF.js + pdf-lib&lt;/strong&gt; — browser-side processing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; — clean UI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;More tools&lt;/li&gt;
&lt;li&gt;Better OCR accuracy&lt;/li&gt;
&lt;li&gt;Mobile app (maybe)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Would love your feedback! 🙏&lt;br&gt;
Search "PDFOnlineLovePDF" on Google or drop a comment below.&lt;/p&gt;

&lt;h1&gt;
  
  
  showdev #webdev #javascript #productivity #opensource
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Show DEV: I built a free browser-based PDF toolkit with 31 tools tags: showdev, webdev, javascript, productivity ---</title>
      <dc:creator>kabir daki</dc:creator>
      <pubDate>Wed, 15 Apr 2026 21:39:04 +0000</pubDate>
      <link>https://forem.com/kabir_daki/show-dev-i-built-a-free-browser-based-pdf-toolkit-with-31-tools-tags-showdev-webdev-javascript-2dmn</link>
      <guid>https://forem.com/kabir_daki/show-dev-i-built-a-free-browser-based-pdf-toolkit-with-31-tools-tags-showdev-webdev-javascript-2dmn</guid>
      <description>

&lt;h2&gt;
  
  
  Hey DEV community! 👋
&lt;/h2&gt;

&lt;p&gt;I just launched &lt;strong&gt;PDFOnlineLovePDF&lt;/strong&gt; — a 100% free, browser-based PDF toolkit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Every PDF tool I tried had at least one of these issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expensive subscriptions&lt;/li&gt;
&lt;li&gt;Full of ads&lt;/li&gt;
&lt;li&gt;Uploads your files to remote servers (privacy risk)&lt;/li&gt;
&lt;li&gt;Requires signup just to compress a file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;31 tools, all running 100% in your browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Convert PDF to Word, Excel, PowerPoint&lt;/li&gt;
&lt;li&gt;Compress up to 90%&lt;/li&gt;
&lt;li&gt;Merge, split, rotate&lt;/li&gt;
&lt;li&gt;OCR (extract text from scanned PDFs)&lt;/li&gt;
&lt;li&gt;Sign PDFs&lt;/li&gt;
&lt;li&gt;Translate into 50+ languages (AI-powered)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Everything runs client-side using WebAssembly and modern browser APIs. &lt;strong&gt;Your files never leave your device.&lt;/strong&gt; No server, no storage, no privacy risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;100% client-side processing&lt;/li&gt;
&lt;li&gt;WebAssembly for performance&lt;/li&gt;
&lt;li&gt;AI-powered translation&lt;/li&gt;
&lt;li&gt;Zero dependencies on external servers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;👉 &lt;a href="https://pdfonlinelovepdf.com" rel="noopener noreferrer"&gt;pdfonlinelovepdf.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also live on Product Hunt if you want to show some support:&lt;br&gt;
👉 &lt;a href="https://www.producthunt.com/products/pdfonlinelovepdf" rel="noopener noreferrer"&gt;Product Hunt page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would love your feedback — what features would you add? 🙏&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Best PDF Tools in 2026: I Tested 7 — Here's the Honest Truth</title>
      <dc:creator>kabir daki</dc:creator>
      <pubDate>Mon, 13 Apr 2026 22:28:04 +0000</pubDate>
      <link>https://forem.com/kabir_daki/best-pdf-tools-in-2026-i-tested-7-heres-the-honest-truth-476p</link>
      <guid>https://forem.com/kabir_daki/best-pdf-tools-in-2026-i-tested-7-heres-the-honest-truth-476p</guid>
      <description>&lt;p&gt;I spent a week testing the most popular PDF tools. Here's what I found — and why I ended up building my own.&lt;br&gt;
Adobe Acrobat — Powerful, but $19.99/month for basic tasks is hard to justify.&lt;br&gt;
iLovePDF — Clean UI, but hits limits fast and forces signup.&lt;br&gt;
Smallpdf — Same story. 2 free tasks/day, then paywall.&lt;br&gt;
PDF24 — Generous free tier, but no AI features.&lt;br&gt;
Sejda — Good, but 3 tasks/hour limit.&lt;br&gt;
PDFescape — Outdated UI, limited tools.&lt;br&gt;
PDFOnlineLovePDF — 31 tools, no signup, no watermark, AI-powered. Built this one myself after getting blocked one too many times.&lt;br&gt;
The gap nobody fills: unlimited + no signup + AI features together.&lt;br&gt;
Try it free → pdfonlinelovepdf.com&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Tested Adobe, iLovePDF, and 5 Other PDF Tools — Then Built My Own (Free, No Limits)</title>
      <dc:creator>kabir daki</dc:creator>
      <pubDate>Sat, 11 Apr 2026 15:54:29 +0000</pubDate>
      <link>https://forem.com/kabir_daki/i-tested-adobe-ilovepdf-and-5-other-pdf-tools-then-built-my-own-free-no-limits-15cm</link>
      <guid>https://forem.com/kabir_daki/i-tested-adobe-ilovepdf-and-5-other-pdf-tools-then-built-my-own-free-no-limits-15cm</guid>
      <description>&lt;p&gt;Everyone has that moment.&lt;br&gt;
You need to compress a PDF. You Google it. You click the first result. You upload your file. Then — "Sign up to download your file."&lt;br&gt;
Or worse: "You've reached your free limit. Upgrade to Pro."&lt;br&gt;
I got tired of it. So I tested the most popular PDF tools out there, and then I built my own. Here's what I found.&lt;/p&gt;

&lt;p&gt;The Contenders&lt;br&gt;
ToolFree LimitSignup RequiredAI FeaturesAdobe Acrobat2 tasks/dayYesYes (paid)iLovePDFLimited tasksYesNoSmallpdf2 tasks/dayYesNoPDF24UnlimitedNoNoSejda3 tasks/hourNoNoMy ToolUnlimitedNoYes&lt;/p&gt;

&lt;p&gt;Adobe Acrobat — Powerful but Expensive&lt;br&gt;
Adobe is the gold standard. The UI is polished, the features are deep, and the AI Assistant is genuinely useful. But the free tier is aggressively limited — 2 tasks per day — and the paid plan starts at $19.99/month.&lt;br&gt;
For occasional users, it's overkill. For daily use without paying? Forget it.&lt;/p&gt;

&lt;p&gt;iLovePDF — Great UI, Frustrating Limits&lt;br&gt;
iLovePDF has a clean interface and covers most common tasks: merge, split, compress, convert. It's probably the most popular free option out there.&lt;br&gt;
The problem? You hit the limit faster than you expect. And the "free" experience is designed to push you toward the paid plan. No AI features either.&lt;/p&gt;

&lt;p&gt;Smallpdf — Same Story&lt;br&gt;
Smallpdf is smooth and well-designed. But 2 tasks per day is basically nothing if you work with PDFs regularly. It also requires an account to do anything useful.&lt;/p&gt;

&lt;p&gt;PDF24 — The Hidden Gem&lt;br&gt;
PDF24 is genuinely generous. No signup, no hard limits, and it covers a wide range of tools. The UI feels a bit dated, but it works.&lt;br&gt;
No AI features though.&lt;/p&gt;

&lt;p&gt;So I Built My Own&lt;br&gt;
After testing all of these, I noticed a gap: unlimited + no signup + AI features didn't exist in one place.&lt;br&gt;
So I built [pdfonlinelovepdf] — a free PDF toolkit with 31 tools and AI features baked in. No account needed. No daily limits. No paywalls.&lt;br&gt;
What it does that others don't:&lt;/p&gt;

&lt;p&gt;✅ AI-powered PDF summarization&lt;br&gt;
✅ Ask questions about your PDF (chat with PDF)&lt;br&gt;
✅ All 31 tools completely free&lt;br&gt;
✅ No signup, ever&lt;br&gt;
✅ No file limits&lt;/p&gt;

&lt;p&gt;The Honest Comparison&lt;br&gt;
If you need deep editing and professional features → Adobe is worth paying for.&lt;br&gt;
If you want a clean UI for occasional use → iLovePDF or Smallpdf work fine.&lt;br&gt;
If you want unlimited, free, with AI → try what I built.&lt;/p&gt;

&lt;p&gt;Final Thought&lt;br&gt;
The PDF tool space is dominated by freemium products designed to frustrate you into paying. I wanted to see if it was possible to just... not do that.&lt;br&gt;
So far, so good.&lt;br&gt;
👉 [Try it free — no signup needed] &lt;a href="https://pdfonlinelovepdf.com/" rel="noopener noreferrer"&gt;https://pdfonlinelovepdf.com/&lt;/a&gt;&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>tools</category>
      <category>productivity</category>
      <category>pdf</category>
    </item>
    <item>
      <title>I built a free PDF toolkit with 31 AI tools — no signup, no limits</title>
      <dc:creator>kabir daki</dc:creator>
      <pubDate>Mon, 06 Apr 2026 21:39:03 +0000</pubDate>
      <link>https://forem.com/kabir_daki/i-built-a-free-pdf-toolkit-with-31-ai-tools-no-signup-no-limits-3k5d</link>
      <guid>https://forem.com/kabir_daki/i-built-a-free-pdf-toolkit-with-31-ai-tools-no-signup-no-limits-3k5d</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Every PDF tool online either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Costs money 💸&lt;/li&gt;
&lt;li&gt;Requires registration 📧&lt;/li&gt;
&lt;li&gt;Uploads your files to their servers 🔓&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Solution
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;PDFOnlineLovePDF&lt;/strong&gt; — a 100% free, browser-based PDF toolkit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;31 tools including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Convert: PDF to Word, Excel, PowerPoint, JPG&lt;/li&gt;
&lt;li&gt;Edit: merge, split, compress up to 90%&lt;/li&gt;
&lt;li&gt;AI-powered: translate into 50+ languages, summarize, OCR&lt;/li&gt;
&lt;li&gt;Security: protect, unlock, redact&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why it's different
&lt;/h2&gt;

&lt;p&gt;✅ No signup required&lt;br&gt;&lt;br&gt;
✅ Files never leave your browser&lt;br&gt;&lt;br&gt;
✅ 100% free, no limits&lt;br&gt;&lt;br&gt;
✅ Powered by AI  &lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;👉 &lt;a href="https://pdfonlinelovepdf.com" rel="noopener noreferrer"&gt;https://pdfonlinelovepdf.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would love your feedback!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>buildinpublic</category>
    </item>
  </channel>
</rss>
