How to Build a Browser-Based PDF Blur Tool Using JavaScript — Opportunihub
Course Remote

How to Build a Browser-Based PDF Blur Tool Using JavaScript

Bhavin Sheth · Remote

At a glance

Type
Course
Organisation
Bhavin Sheth
Location
Remote
Work mode
Remote
Deadline
Rolling / not stated
Posted
24 Jul 2026

About this course

<p>Many PDF documents contain information that shouldn't be shared publicly. Personal details, financial figures, signatures, addresses, account numbers, employee information, or confidential business data often need to be hidden before a file is sent to someone else.</p> <p>A PDF Blur Tool makes this process simple. Instead of permanently removing content, it places a blur effect over selected areas of a PDF so sensitive information becomes difficult to read while the rest of the document remains unchanged.</p> <p>In this tutorial, you'll build a browser-based PDF Blur Tool using JavaScript. Users will be able to upload a PDF, preview every page, draw blur boxes over sensitive content, adjust the blur intensity, apply the blur to selected pages, preview the final result, and download the processed PDF, all without uploading files to a server.</p> <p>We'll use PDF.js to render PDF pages inside the browser, HTML Canvas to create and manage blur regions, and PDF-lib to generate the final blurred PDF.</p> <p>By the end of this tutorial, you'll have a fully functional client-side PDF editing tool similar to the one available on my site, AllInOneTools.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/76925a1f-2b94-4b5b-923c-0252d1703b22.png" alt="allinonetools - pdf tools- blur pdf documents" style="display:block;margin:0 auto" width="905" height="282" loading="lazy"> <h2 id="heading-table-of-contents">Table of Contents</h2> <ul> <li><p><a href="#heading-what-this-pdf-blur-tool-does-and-how-it-works">What This PDF Blur Tool Does and How It Works</a></p> </li> <li><p><a href="#heading-project-setup">Project Setup</a></p> </li> <li><p><a href="#heading-creating-the-html-layout">Creating the HTML Layout</a></p> </li> <li><p><a href="#heading-uploading-and-previewing-pdfs">Uploading and Previewing PDFs</a></p> </li> <li><p><a href="#heading-creating-blur-regions">Creating Blur Regions</a></p> </li> <li><p><a href="#heading-applying-blur-to-pages">Applying Blur to Pages</a></p> </li> <li><p><a href="#heading-generating-the-final-pdf">Generating the Final PDF</a></p> </li> <li><p><a href="#heading-previewing-the-result">Previewing the Result</a></p> </li> <li><p><a href="#heading-renaming-and-downloading">Renaming and Downloading</a></p> </li> <li><p><a href="#heading-demo-how-the-pdf-blur-tool-works">Demo: How the PDF Blur Tool Works</a></p> </li> <li><p><a href="#heading-performance-tips">Performance Tips</a></p> </li> <li><p><a href="#heading-common-mistakes">Common Mistakes</a></p> </li> <li><p><a href="#heading-conclusion">Conclusion</a></p> </li> </ul> <h2 id="heading-what-this-pdf-blur-tool-does-and-how-it-works">What This PDF Blur Tool Does and How It Works</h2> <p>A PDF Blur Tool helps protect sensitive information before a document is shared. Instead of editing or deleting the original content, it applies a visual blur effect over selected areas so confidential information becomes unreadable while the rest of the document remains unchanged.</p> <p>This approach is useful for hiding personal details, financial information, account numbers, signatures, addresses, faces, or any other private content that shouldn't be visible in the final document.</p> <p>In this project, users can upload a PDF directly from their browser, preview every page, and draw one or more blur regions over the areas they want to hide. The tool also allows users to adjust the blur intensity, blur either selected areas or entire pages, apply the effect to the current page, all pages, or specific page ranges, preview the completed document, rename the output file, and download the final PDF.</p> <p>Because everything runs inside the browser, no files are uploaded to a server, helping maintain document privacy.</p> <p>Behind the scenes, the application first renders each PDF page onto an HTML canvas using PDF.js. Rather than modifying the original PDF immediately, it records the position, size, page number, and blur intensity for every blur region that the user creates.</p> <p>When the user clicks Apply &amp; Finalize, those stored regions are converted from browser coordinates into actual PDF page coordinates. The selected blur effect is then applied to the rendered page, and PDF-lib generates a new PDF containing the blurred content while preserving the rest of the document.</p> <p>This workflow provides an interactive editing experience while keeping the original PDF unchanged until the final document is generated.</p> <p>For example, each blur region can be represented as an object like this:</p> <pre><code class="language-javascript">const blurRegion = { page: 2, x: 180, y: 240, width: 260, height: 90, intensity: 6 }; </code></pre> <p>Each object stores all the information required to recreate the blur effect during the final PDF generation process.</p> <h2 id="heading-project-setup">Project Setup</h2> <p>Before writing any code, let's create a simple project structure for our PDF Blur Tool.</p> <p>We'll use plain HTML, CSS, and JavaScript, along with two libraries:</p> <ul> <li><p><strong>PDF.js</strong> for rendering PDF pages inside the browser.</p> </li> <li><p><strong>PDF-lib</strong> for generating the final blurred PDF.</p> </li> </ul> <p>Our project structure looks like this:</p> <pre><code class="language-text">pdf-blur-tool/ │── index.html │── style.css │── script.js │── pdf.worker.min.js │── assets/ </code></pre> <p>Keeping the project simple makes it easier to understand how each part works.</p> <p>Add PDF.js and PDF-lib before loading your own JavaScript.</p> <pre><code class="language-html">&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.4.168/pdf.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"&gt;&lt;/script&gt; &lt;script src="script.js"&gt;&lt;/script&gt; </code></pre> <p>Configure the PDF worker.</p> <pre><code class="language-javascript">pdfjsLib.GlobalWorkerOptions.workerSrc = "pdf.worker.min.js"; </code></pre> <p>The worker processes PDF rendering in a background thread, helping keep the interface responsive while pages are rendered.</p> <h2 id="heading-creating-the-html-layout">Creating the HTML Layout</h2> <p>The application consists of four main sections:</p> <ul> <li><p>Upload area</p> </li> <li><p>PDF preview</p> </li> <li><p>Blur settings panel</p> </li> <li><p>Final download section</p> </li> </ul> <p>Create the basic layout:</p> <pre><code class="language-html">&lt;div id="uploadSection"&gt;&lt;/div&gt; &lt;div id="editorSection" hidden&gt; &lt;div id="pdfPreview"&gt;&lt;/div&gt; &lt;aside id="blurSettings"&gt;&lt;/aside&gt; &lt;/div&gt; &lt;div id="resultSection" hidden&gt;&lt;/div&gt; </code></pre> <p>Initially, only the upload section is visible.</p> <p>After a PDF is selected, the editor becomes visible.</p> <h3 id="heading-selecting-dom-elements">Selecting DOM Elements</h3> <p>Create references to the elements used throughout the application.</p> <pre><code class="language-javascript">const uploadSection = document.getElementById( "uploadSection" ); const editorSection = document.getElementById( "editorSection" ); const resultSection = document.getElementById( "resultSection" ); const fileInput = document.getElementById( "pdfInput" ); const pdfCanvas = document.getElementById( "pdfCanvas" ); const canvasContext = pdfCanvas.getContext("2d"); </code></pre> <p>These references allow the application to switch between the upload, editing, and download stages.</p> <h2 id="heading-uploading-and-previewing-pdfs">Uploading and Previewing PDFs</h2> <p>The upload section accepts both drag-and-drop and traditional file selection.</p> <p>When a PDF is chosen, verify that it's actually a PDF before continuing.</p> <pre><code class="language-javascript">async function handlePdfUpload( file ) { if ( !file || file.type !== "application/pdf" ) { alert( "Please select a PDF file." ); return; } await loadPdf(file); } </code></pre> <p>If validation succeeds, the document is loaded into memory.</p> <h3 id="heading-reading-the-pdf">Reading the PDF</h3> <p>Use the File API to convert the uploaded file into an ArrayBuffer.</p> <pre><code class="language-javascript">async function loadPdf( file ) { const bytes = await file.arrayBuffer(); pdfDocument = await pdfjsLib .getDocument({ data: bytes }) .promise; currentPage = 1; await renderPage( currentPage ); } </code></pre> <p>The uploaded bytes will also be reused later when generating the blurred PDF.</p> <h3 id="heading-rendering-the-first-page">Rendering the First Page</h3> <p>PDF.js renders each page onto an HTML canvas.</p> <p>Start by retrieving the requested page.</p> <pre><code class="language-javascript">async function renderPage( pageNumber ) { const page = await pdfDocument .getPage( pageNumber ); const viewport = page.getViewport({ scale: 1.5 }); </code></pre> <p>Resize the canvas to match the page dimensions.</p> <pre><code class="language-javascript">pdfCanvas.width = viewport.width; pdfCanvas.height = viewport.height; </code></pre> <p>Render the page.</p> <pre><code class="language-javascript">await page.render({ canvasContext, viewport }).promise; </code></pre> <p>After rendering finishes, the PDF page becomes visible inside the editor.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/0dbda32b-6bfa-4403-97bd-288dfe808239.png" alt=" Uploaded PDF displayed in the preview area with page navigation controls." style="display:block;margin:0 auto" width="1256" height="515" loading="lazy"> <h3 id="heading-creating-page-navigation">Creating Page Navigation</h3> <p>Most PDF documents contain multiple pages.</p> <p>Allow users to move between pages using Previous and Next buttons.</p> <pre><code class="language-javascript">let currentPage = 1; let pdfDocument = null; </code></pre> <p>Move to the previous page.</p> <pre><code class="language-javascript">previousButton .addEventListener( "click", async () =&gt; { if ( currentPage === 1 ) { return; } currentPage--; await renderPage( currentPage ); } ); </code></pre> <p>Move to the next page.</p> <pre><code class="language-javascript">nextButton .addEventListener( "click", async () =&gt; { if ( currentPage === pdfDocument.numPages ) { return; } currentPage++; await renderPage( currentPage ); } ); </code></pre> <p>Update the page counter whenever the current page changes.</p> <pre><code class="language-javascript">pageIndicator.textContent = `Page ${currentPage} of ${pdfDocument.numPages}`; </code></pre> <p>This provides users with clear feedback while navigating large PDF documents.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/c99410bc-7d7c-411f-a8f1-8fd9b1aaf3b8.png" alt=" PDF preview with Previous and Next buttons for navigating between pages." style="display:block;margin:0 auto" width="546" height="818" loading="lazy"> <h3 id="heading-preparing-for-blur-editing">Preparing for Blur Editing</h3> <p>Once the current page is rendered, the application prepares a transparent layer above the PDF canvas.</p> <p>This overlay captures mouse interactions without modifying the original page preview.</p> <p>Create the overlay.</p> <pre><code class="language-html">&lt;canvas id="overlayCanvas"&gt; &lt;/canvas&gt; </code></pre> <p>Match its size to the PDF preview.</p> <pre><code class="language-javascript">overlayCanvas.width = pdfCanvas.width; overlayCanvas.height = pdfCanvas.height; </code></pre> <p>Later in the tutorial, this overlay will allow users to draw blur regions while keeping the underlying PDF page untouched.</p> <h3 id="heading-showing-the-editor">Showing the Editor</h3> <p>After the first page finishes rendering, switch from the upload screen to the editor interface.</p> <pre><code class="language-javascript">uploadSection.hidden = true; editorSection.hidden = false; </code></pre> <p>Users can now preview the document, navigate between pages, and begin selecting areas that should be blurred.</p> <h2 id="heading-creating-blur-regions">Creating Blur Regions</h2> <p>Now that the PDF preview is working, we can build the most important feature of the application: allowing users to blur sensitive information.</p> <p>Instead of editing the PDF immediately, users first draw one or more blur regions over the page preview.</p> <p>Each region stores its own position, size, and blur intensity. These regions are later converted into actual PDF coordinates during final processing.</p> <h3 id="heading-creating-the-blur-area-object">Creating the Blur Area Object</h3> <p>Every blur region is represented as a JavaScript object.</p> <p>For example:</p> <pre><code class="language-javascript">const blurArea = { page: currentPage, x: 0, y: 0, width: 0, height: 0, intensity: 6 }; </code></pre> <p>Rather than modifying the PDF immediately, the application simply keeps track of these objects until the user clicks <strong>Apply &amp; Finalize</strong>.</p> <h3 id="heading-storing-multiple-blur-regions">Storing Multiple Blur Regions</h3> <p>Users often need to hide more than one piece of information.</p> <p>Store all blur areas inside an array.</p> <pre><code class="language-javascript">const blurAreas = []; </code></pre> <p>Whenever a new blur box is created, push it into the array.</p> <pre><code class="language-javascript">blurAreas.push({ page: currentPage, x, y, width, height, intensity: blurIntensity }); </code></pre> <p>This makes it easy to redraw, edit, or remove individual blur regions later.</p> <h3 id="heading-starting-a-blur-selection">Starting a Blur Selection</h3> <p>The transparent overlay canvas captures mouse interactions.</p> <p>When the user presses the mouse button, record the starting position.</p> <pre><code class="language-javascript">let isDrawing = false; let startX = 0; let startY = 0; overlayCanvas .addEventListener( "mousedown", event =&gt; { isDrawing = true; startX = event.offsetX; startY = event.offsetY; } ); </code></pre> <p>The blur rectangle begins at this point.</p> <h3 id="heading-drawing-the-blur-rectangle">Drawing the Blur Rectangle</h3> <p>As the mouse moves, update the rectangle dimensions.</p> <pre><code class="language-javascript">overlayCanvas .addEventListener( "mousemove", event =&gt; { if ( !isDrawing ) { return; } drawPreviewBox( startX, startY, event.offsetX, event.offsetY ); } ); </code></pre> <p>The preview updates continuously while the user drags the mouse.</p> <h3 id="heading-finishing-the-selection">Finishing the Selection</h3> <p>When the mouse button is released, save the completed blur region.</p> <pre><code class="language-javascript">overlayCanvas .addEventListener( "mouseup", event =&gt; { isDrawing = false; blurAreas.push({ page: currentPage, x: startX, y: startY, width: event.offsetX - startX, height: event.offsetY - startY, intensity: blurIntensity }); redrawBlurAreas(); updateBlurList(); } ); </code></pre> <p>Each blur region becomes part of the current editing session.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/31655d91-dcb6-412c-8762-c6aedc732b81.png" alt="User dragging a blur rectangle over sensitive information in the PDF preview." style="display:block;margin:0 auto" width="565" height="863" loading="lazy"> <h3 id="heading-drawing-existing-blur-areas">Drawing Existing Blur Areas</h3> <p>Whenever the page changes or a blur region is added, redraw every blur box.</p> <pre><code class="language-javascript">function redrawBlurAreas() { overlayContext.clearRect( 0, 0, overlayCanvas.width, overlayCanvas.height ); blurAreas .filter( area =&gt; area.page === currentPage ) .forEach( drawBlurArea ); } </code></pre> <p>This ensures that previously created blur regions remain visible while editing.</p> <h3 id="heading-displaying-blur-boxes">Displaying Blur Boxes</h3> <p>Render every stored region with a dashed outline.</p> <pre><code class="language-javascript">function drawBlurArea( area ) { overlayContext .setLineDash([6, 4]); overlayContext .strokeStyle = "#4f6cff"; overlayContext .strokeRect( area.x, area.y, area.width, area.height ); } </code></pre> <p>The outline acts as a guide and doesn't become part of the final PDF.</p> <h3 id="heading-blur-options">Blur Options</h3> <p>Users can choose how the blur should be applied.</p> <p>The tool supports two modes:</p> <ul> <li><p>Blur selected areas</p> </li> <li><p>Blur entire page(s)</p> </li> </ul> <p>The selected option controls the editing behavior.</p> <pre><code class="language-javascript">const blurMode = document.querySelector( 'input[name="blurMode"]:checked' ).value; </code></pre> <p>If <strong>Blur selected areas</strong> is chosen, users draw blur rectangles manually.</p> <p>If <strong>Blur entire page(s)</strong> is selected, the application skips manual selection and prepares to blur the entire page during final processing.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/54004f00-c974-4d77-b385-fe3136acaf04.png" alt="Blur options showing choices for blurring selected regions or entire PDF pages." style="display:block;margin:0 auto" width="642" height="231" loading="lazy"> <h3 id="heading-adjusting-blur-intensity">Adjusting Blur Intensity</h3> <p>Different documents require different levels of blur.</p> <p>A slider lets users control the blur strength before applying the effect.</p> <pre><code class="language-javascript">const blurSlider = document.getElementById( "blurIntensity" ); let blurIntensity = 6; blurSlider .addEventListener( "input", event =&gt; { blurIntensity = Number( event.target.value ); } ); </code></pre> <p>The selected value is stored with every newly created blur region.</p> <pre><code class="language-javascript">blurArea.intensity = blurIntensity; </code></pre> <p>Higher values produce a stronger blur effect.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/097cba2c-a441-401c-9f1c-f8ce0b5a26a1.png" alt="Blur intensity slider allowing users to adjust the strength of the blur effect." style="display:block;margin:0 auto" width="861" height="131" loading="lazy"> <h2 id="heading-managing-multiple-blur-areas">Managing Multiple Blur Areas</h2> <p>Many documents contain several pieces of confidential information.</p> <p>Instead of limiting users to a single blur rectangle, the application displays every saved region.</p> <p>For example:</p> <pre><code class="language-text">Blur Area #1 Blur Area #2 Blur Area #3 </code></pre> <p>Each entry includes a remove button.</p> <pre><code class="language-javascript">function removeBlurArea( index ) { blurAreas.splice( index, 1 ); redrawBlurAreas(); updateBlurList(); } </code></pre> <p>This allows users to delete only the blur region they no longer need.</p> <p>To remove all blur regions from the current page:</p> <pre><code class="language-javascript">function clearCurrentPage() { const remaining = blurAreas.filter( area =&gt; area.page !== currentPage ); blurAreas.length = 0; blurAreas.push( ...remaining ); redrawBlurAreas(); } </code></pre> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/ef44e87e-7c39-4e2b-8e67-7e354853501d.png" alt="Blur area manager displaying multiple blur regions with delete controls and a Clear All on This Page button." style="display:block;margin:0 auto" width="876" height="273" loading="lazy"> <h2 id="heading-applying-blur-to-pages">Applying Blur to Pages</h2> <p>Users may want to blur only one page or several pages within a document.</p> <p>The editor provides three options:</p> <ul> <li><p>Current page only</p> </li> <li><p>All pages</p> </li> <li><p>Specific pages</p> </li> </ul> <pre><code class="language-javascript">const pageOption = document.querySelector( 'input[name="pageOption"]:checked' ).value; </code></pre> <p>If the user selects <strong>Specific pages</strong>, they can enter values such as:</p> <pre><code class="language-text">1, 3-5, 8 </code></pre> <p>These values will later be converted into an array of page numbers before the final PDF is generated.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/f3e1a72c-690d-4454-8b7a-50920817cd13.png" alt="Apply to Pages section with Current Page, All Pages, and Specific Pages options." style="display:block;margin:0 auto" width="566" height="292" loading="lazy"> <h3 id="heading-applying-the-blur-effect">Applying the Blur Effect</h3> <p>So far, users have uploaded a PDF, selected one or more blur regions, adjusted the blur intensity, and chosen which pages should be processed.</p> <p>The final step is converting those blur regions into actual blurred content inside the generated PDF.</p> <p>Rather than modifying the original document directly, the application creates a new PDF while preserving the original file.</p> <h3 id="heading-loading-the-original-pdf">Loading the Original PDF</h3> <p>Start by loading the uploaded PDF into PDF-lib.</p> <pre><code class="language-javascript">async function applyBlur() { const pdfDoc = await PDFLib.PDFDocument.load( originalPdfBytes.slice() ); const pages = pdfDoc.getPages(); } </code></pre> <p>Using a copy of the original bytes ensures that the uploaded document remains unchanged.</p> <h3 id="heading-processing-the-selected-pages">Processing the Selected Pages</h3> <p>Determine which pages should receive the blur effect.</p> <pre><code class="language-javascript">const selectedPages = parsePageSelection( pageSelection, pdfDoc.getPageCount() ); </code></pre> <p>For example:</p> <pre><code class="language-text">Current Page ↓ [2] All Pages ↓ [1,2,3,4] Specific Pages ↓ [1,3,5] </code></pre> <p>Only these pages will be modified during processing.</p> <h3 id="heading-rendering-each-page-as-an-image">Rendering Each Page as an Image</h3> <p>Since blur is a pixel-based effect, each selected PDF page is rendered into an off-screen canvas.</p> <pre><code class="language-javascript">const page = await pdfDocument.getPage( pageNumber ); const viewport = page.getViewport({ scale: 2 }); const canvas = document.createElement( "canvas" ); canvas.width = viewport.width; canvas.height = viewport.height; </code></pre> <p>Render the page.</p> <pre><code class="language-javascript">await page.render({ canvasContext: canvas.getContext("2d"), viewport }).promise; </code></pre> <p>The canvas now contains a bitmap version of the PDF page that can be edited.</p> <h3 id="heading-applying-blur-to-selected-regions">Applying Blur to Selected Regions</h3> <p>Retrieve all blur regions that belong to the current page.</p> <pre><code class="language-javascript">const pageRegions = blurAreas.filter( area =&gt; area.page === pageNumber ); </code></pre> <p>Loop through every blur region.</p> <pre><code class="language-javascript">pageRegions.forEach( area =&gt; { blurCanvasRegion( canvas, area ); } ); </code></pre> <p>Each region is blurred independently.</p> <h3 id="heading-blurring-the-canvas-region">Blurring the Canvas Region</h3> <p>The browser's Canvas API allows filters to be applied while drawing.</p> <p>Set the blur filter based on the selected intensity.</p> <pre><code class="language-javascript">context.filter = `blur(${area.intensity}px)`; </code></pre> <p>Redraw only the selected region.</p> <pre><code class="language-javascript">context.drawImage( canvas, area.x, area.y, area.width, area.height, area.x, area.y, area.width, area.height ); </code></pre> <p>After drawing, reset the filter.</p> <pre><code class="language-javascript">context.filter = "none"; </code></pre> <p>Only the selected rectangle becomes blurred while the rest of the page remains unchanged.</p> <h3 id="heading-blurring-an-entire-page">Blurring an Entire Page</h3> <p>If the user chooses <strong>Blur entire page(s)</strong>, the process is much simpler.</p> <p>Apply the filter to the full canvas.</p> <pre><code class="language-javascript">context.filter = `blur(${blurIntensity}px)`; context.drawImage( canvas, 0, 0 ); context.filter = "none"; </code></pre> <p>The entire rendered page receives the selected blur effect.</p> <h3 id="heading-converting-the-canvas-back-into-a-pdf-image">Converting the Canvas Back into a PDF Image</h3> <p>After editing the canvas, convert it into an image.</p> <pre><code class="language-javascript">const imageData = canvas.toDataURL( "image/png" ); </code></pre> <p>Convert the image into bytes.</p> <pre><code class="language-javascript">const bytes = await fetch(imageData) .then( response =&gt; response.arrayBuffer() ); </code></pre> <p>Embed the image inside PDF-lib.</p> <pre><code class="language-javascript">const image = await pdfDoc.embedPng( bytes ); </code></pre> <p>Replace the page contents.</p> <pre><code class="language-javascript">const pdfPage = pages[ pageNumber - 1 ]; const size = pdfPage.getSize(); pdfPage.drawImage( image, { x: 0, y: 0, width: size.width, height: size.height } ); </code></pre> <p>Repeat the same process for every selected page.</p> <h3 id="heading-showing-the-processing-state">Showing the Processing State</h3> <p>Generating large PDF files may take a few seconds.</p> <p>Display a loading state while processing.</p> <pre><code class="language-javascript">applyButton.disabled = true; applyButton.textContent = "Applying..."; </code></pre> <p>After processing finishes:</p> <pre><code class="language-javascript">applyButton.disabled = false; applyButton.textContent = "Apply &amp; Finalize"; </code></pre> <p>This gives users clear feedback that the application is working.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/75e1e622-9769-4c17-8f39-49376de81041.png" alt="Apply &amp; Finalize button used to generate the blurred PDF." style="display:block;margin:0 auto" width="582" height="92" loading="lazy"> <p>During processing:</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/68ae927f-aa3f-4e8c-8b37-2ef89ba0ad40.png" alt="Applying state displayed while the PDF blur operation is being completed." style="display:block;margin:0 auto" width="285" height="113" loading="lazy"> <h2 id="heading-generating-the-final-pdf">Generating the Final PDF</h2> <p>After every page has been processed, save the completed document.</p> <pre><code class="language-javascript">const pdfBytes = await pdfDoc.save(); const outputBlob = new Blob( [pdfBytes], { type: "application/pdf" } ); </code></pre> <p>Store the result so it can be previewed and downloaded later.</p> <pre><code class="language-javascript">generatedPdfBlob = outputBlob; </code></pre> <p>At this point, the blurred PDF has been successfully generated.</p> <h2 id="heading-previewing-the-result">Previewing the Result</h2> <p>Hide the editing interface and display the completed document.</p> <pre><code class="language-javascript">editorSection.hidden = true; resultSection.hidden = false; </code></pre> <p>The result screen displays:</p> <ul> <li><p>Final PDF preview</p> </li> <li><p>Editable filename</p> </li> <li><p>Total pages</p> </li> <li><p>File size</p> </li> <li><p>Download button</p> </li> </ul> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/1e96e1ec-b114-4ebb-955e-1e277d7f98da.png" alt="Final PDF preview showing multiple blurred regions with download options displayed beside the document." style="display:block;margin:0 auto" width="857" height="816" loading="lazy"> <p>The user can review the processed document before downloading it.</p> <h2 id="heading-renaming-and-downloading">Renaming and Downloading</h2> <p>Before downloading, users may want to rename the generated file.</p> <p>Create a filename field.</p> <pre><code class="language-html">&lt;input type="text" id="outputFilename" value="blurred-document.pdf"&gt; </code></pre> <p>Validate the filename.</p> <pre><code class="language-javascript">function getFilename() { let filename = outputFilename.value.trim(); if (!filename) { filename = "blurred-document.pdf"; } if ( !filename .toLowerCase() .endsWith(".pdf") ) { filename += ".pdf"; } return filename; } </code></pre> <p>Display additional file information.</p> <pre><code class="language-javascript">pageCount.textContent = `Pages: ${finalPdfDocument.numPages}`; fileSize.textContent = formatFileSize( generatedPdfBlob.size ); </code></pre> <p>Download the processed document.</p> <pre><code class="language-javascript">downloadButton .addEventListener( "click", () =&gt; { const url = URL.createObjectURL( generatedPdfBlob ); const link = document.createElement( "a" ); link.href = url; link.download = getFilename(); link.click(); URL.revokeObjectURL( url ); }); </code></pre> <p>The browser downloads the completed PDF without sending any files to a remote server.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/1cd1538e-7a90-4994-bbd0-da84365e1d34.png" alt="Download section showing editable filename, page count, file size, and Download button." style="display:block;margin:0 auto" width="272" height="166" loading="lazy"> <p><img src="align=%22center%22" alt="align=%22center%22" width="600" height="400" loading="lazy"></p> <h2 id="heading-demo-how-the-pdf-blur-tool-works">Demo: How the PDF Blur Tool Works</h2> <p>Let's walk through the complete workflow.</p> <h3 id="heading-step-1-upload-the-pdf">Step 1: Upload the PDF</h3> <p>Users upload a PDF using drag-and-drop or the <strong>Select PDF</strong> button.</p> <p>The browser validates the file and prepares it for rendering.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/9a08c61c-814a-4c44-9a74-6f4eef7ddefc.png" alt="Upload screen for selecting a PDF file." style="display:block;margin:0 auto" width="1256" height="515" loading="lazy"> <h3 id="heading-step-2-preview-the-document">Step 2: Preview the Document</h3> <p>The uploaded PDF appears inside the preview window.</p> <p>Users can move through the document using the page navigation controls.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/27024335-d786-476c-9c34-e050ca4162e7.png" alt="PDF preview with Previous and Next page navigation." style="display:block;margin:0 auto" width="546" height="818" loading="lazy"> <h3 id="heading-step-3-configure-blur-settings">Step 3: Configure Blur Settings</h3> <p>Users choose whether to blur selected areas or entire pages.</p> <p>They can also configure the blur intensity before creating any blur regions.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/6fdcce22-b42d-48ca-94cd-c99bc679b7f5.png" alt="Blur settings panel showing available blur options." style="display:block;margin:0 auto" width="400" height="758" loading="lazy"> <h3 id="heading-step-4-draw-blur-areas">Step 4: Draw Blur Areas</h3> <p>Users click and drag directly on the PDF preview to create blur rectangles over sensitive content.</p> <p>Multiple blur regions can be created on the same page.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/c5404708-118c-4f7f-a768-c20ea66626a7.png" alt="User creating blur rectangles over confidential information." style="display:block;margin:0 auto" width="565" height="863" loading="lazy"> <h3 id="heading-step-5-adjust-blur-intensity">Step 5: Adjust Blur Intensity</h3> <p>The blur intensity slider controls how strong the blur effect should appear.</p> <p>Higher values produce a stronger blur.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/b485fa69-8952-4e4a-b91c-945c9879838a.png" alt="blur seleted option" style="display:block;margin:0 auto" width="642" height="231" loading="lazy"> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/d0ece3b0-2c75-45a2-9286-8a38a0ef706a.png" alt="Blur intensity slider controlling the strength of the blur effect." style="display:block;margin:0 auto" width="861" height="131" loading="lazy"> <h3 id="heading-step-6-manage-blur-regions">Step 6: Manage Blur Regions</h3> <p>Individual blur areas can be removed, or all blur regions on the current page can be cleared.</p> <p>This makes editing much easier before generating the final PDF.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/c90a4b21-9cfe-4c99-9b11-29b862621ca1.png" alt="Blur area management panel with multiple blur regions." style="display:block;margin:0 auto" width="876" height="273" loading="lazy"> <h3 id="heading-step-7-choose-the-pages">Step 7: Choose the Pages</h3> <p>Users decide whether the blur should be applied to:</p> <ul> <li><p>Current page</p> </li> <li><p>All pages</p> </li> <li><p>Specific pages</p> </li> </ul> <p>For example:</p> <pre><code class="language-text">1,3-5,8 </code></pre> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/663facb2-f312-43a0-b4c8-4a029da0ed81.png" alt="Apply to Pages section with Current Page, All Pages, and Specific Pages options." style="display:block;margin:0 auto" width="566" height="292" loading="lazy"> <h3 id="heading-step-8-apply-the-blur">Step 8: Apply the Blur</h3> <p>After reviewing the settings, users click <strong>Apply &amp; Finalize</strong>.</p> <p>The application generates a new PDF containing the selected blur effects.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/53eb6910-25ec-4b66-aaf1-a0c11363a3f8.png" alt="Apply &amp; Finalize button generating the blurred PDF." style="display:block;margin:0 auto" width="582" height="92" loading="lazy"> <h3 id="heading-step-9-review-the-final-document">Step 9: Review the Final Document</h3> <p>The completed PDF appears in the preview window.</p> <p>Users can verify every blurred region before downloading.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/834a4f6d-e12a-45ae-b977-e761f624bb34.png" alt=" Final blurred PDF preview before downloading." style="display:block;margin:0 auto" width="857" height="816" loading="lazy"> <h3 id="heading-step-10-rename-and-download">Step 10: Rename and Download</h3> <p>Finally, users rename the output file if needed and click <strong>Download</strong>.</p> <p>The browser saves the completed PDF locally.</p> <img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/573a6966-d0af-47af-a4d3-2c99b9a79622.png" alt=" Download section showing filename editing and Download button." style="display:block;margin:0 auto" width="272" height="166" loading="lazy"> <h2 id="heading-performance-tips">Performance Tips</h2> <p>Large PDF files can take longer to render and process, but a few simple optimizations can keep the editor responsive.</p> <p>Render only the page the user is currently viewing instead of loading the entire document.</p> <pre><code class="language-javascript">await renderPage( currentPage ); </code></pre> <p>Reuse the same canvas and redraw only the blur regions when changes are made.</p> <pre><code class="language-javascript">overlayContext.clearRect( 0, 0, overlayCanvas.width, overlayCanvas.height ); redrawBlurAreas(); </code></pre> <p>During final processing, generate only the pages selected by the user.</p> <pre><code class="language-javascript">for (const page of selectedPages) { await processPage(page); } </code></pre> <p>Finally, release temporary resources after the download completes.</p> <pre><code class="language-javascript">URL.revokeObjectURL( downloadUrl ); </code></pre> <p>These optimizations reduce memory usage and help the PDF Blur Tool perform smoothly, even with large multi-page documents.</p> <h2 id="heading-common-mistakes">Common Mistakes</h2> <p>One common issue is storing blur coordinates before accounting for the current zoom level.</p> <p>Always convert preview coordinates into the PDF's coordinate system before generating the final document.</p> <pre><code class="language-javascript">const scaleX = pdfWidth / canvas.width; const scaleY = pdfHeight / canvas.height; </code></pre> <p>Another mistake is allowing blur regions to extend beyond the page boundaries.</p> <p>Clamp the values before processing.</p> <pre><code class="language-javascript">blurArea.x = Math.max( 0, blurArea.x ); blurArea.y = Math.max( 0, blurArea.y ); </code></pre> <p>Users should also verify the final preview before downloading, especially when multiple blur regions exist across different pages.</p> <p>Finally, remember that this project applies a <strong>visual blur effect</strong> to the rendered PDF pages. If your application requires permanent removal of sensitive content rather than visual obscuring, additional document-redaction techniques are needed.</p> <h2 id="heading-conclusion">Conclusion</h2> <p>In this tutorial, you built a browser-based PDF Blur Tool using JavaScript.</p> <p>You learned how to upload and preview PDF documents, navigate between pages, create and manage multiple blur regions, adjust blur intensity, apply blur to selected pages, generate a new PDF with PDF-lib, preview the processed document, and download the final file –&nbsp;all without uploading data to a server.</p> <p>By combining PDF.js, the HTML Canvas API, and PDF-lib, you created a privacy-focused PDF editing tool that runs entirely inside the browser.</p> <p>You can explore the complete workflow using the <a href="https://allinonetools.net/blur-pdf/">PDF Blur Tool</a>.</p> <p>From here, you could extend the project with features such as movable and resizable blur regions, undo and redo support, reusable blur presets, keyboard shortcuts, touch-device editing, or additional annotation tools for even more advanced browser-based PDF editing.</p>

How to apply

  1. 1 Read the full details above and confirm you meet the eligibility criteria.
  2. 2 Prepare your documents — an updated CV, and any cover letter, proposal or certificates required.
  3. 3 Click Apply on official site to complete your application on Bhavin Sheth’s official page.
  4. 4 Submit as early as possible — many close once filled.
Apply on official site

Sourced from freecodecamp. Always verify details on the official website. Opportunihub never charges you to apply.

Frequently asked questions

How do I apply for How to Build a Browser-Based PDF Blur Tool Using JavaScript?

Review the full details and eligibility on this page, prepare your documents, then use the “Apply on official site” button to complete your application on Bhavin Sheth’s official page.

Is this opportunity remote or location-based?

This opportunity is remote-friendly and open to applicants who can work from anywhere.

Is How to Build a Browser-Based PDF Blur Tool Using JavaScript free to apply for?

Opportunihub lists this Course for free. Legitimate Courses do not ask for payment to apply — never pay a fee to submit an application.