DEV Community

Cover image for I Built a Free Browser-Based Signature Extractor — Zero Server, Zero Uploads, Zero Signup
shawala ashiq
shawala ashiq

Posted on

I Built a Free Browser-Based Signature Extractor — Zero Server, Zero Uploads, Zero Signup

The problem was simple but annoying.

Someone sends you a PDF contract. You signed it last month. Now you need your signature as a transparent PNG to paste into a new document — but you don't want to print, sign, scan, and repeat the whole process again.

So you Google "signature extractor online free."

**

What do you find?

**

Tools that upload your private legal documents to unknown servers
Tools that require account creation just to download
Tools that slap a watermark on your free download
Tools that only accept images — not PDFs
Tools that completely break on mobile

I decided to build something better. Here's how I did it and what I learned.

What the Tool Does

Free Signature Extractor — a browser-based tool that:

✅ Accepts PDF files directly (no conversion needed)
✅ Renders PDFs page by page using PDF.js
✅ Lets you manually draw a selection box around the signature
✅ Removes the paper background to give a clean transparent PNG
✅ Has an adjustable threshold slider for non-white paper backgrounds
✅ Works fully on mobile with touch events
✅ Never uploads your file anywhere — 100% local processing

🔗 Live tool: https://aitextextractors.com/free-signature-extractor-from-pdf-image-online/

The Tech Stack

No frameworks. No backend. No dependencies except one:

javascript
// PDF.js for rendering PDF pages to canvas
pdfjsLib.GlobalWorkerOptions.workerSrc =
'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.worker.min.js';

Everything else is vanilla JavaScript + HTML5 Canvas API.

How the Background Removal Works

This was the most interesting part to figure out.

The core idea: iterate over every pixel in the selected area, calculate its brightness, and make light pixels transparent while darkening dark pixels (the ink).

javascript
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];

// Weighted brightness calculation (human eye perception)
const brightness = r * 0.299 + g * 0.587 + b * 0.114;

if (brightness > threshold) {
// Light pixel = paper background → make transparent
data[i + 3] = 0;
} else {
// Dark pixel = ink → slightly darken for cleaner output
data[i] = Math.max(0, r - 25);
data[i + 1] = Math.max(0, g - 35);
data[i + 2] = Math.max(0, b - 35);
data[i + 3] = 255;
}
}

Why weighted RGB instead of simple average?

The human eye is most sensitive to green, then red, then blue. Using 0.299R + 0.587G + 0.114B gives a perceptually accurate brightness value — which means the threshold works more naturally across different ink colors and paper tones.

The Threshold Slider Problem

A fixed threshold of 175 works fine for pure white paper under good lighting.

But real documents have:

Cream or yellowish aged paper
Grey shadows from camera angle
Coffee stains (yes, really)
Coloured paper backgrounds
Inconsistent mobile phone lighting

Solution: Let the user adjust it.

javascript
// User drags slider → threshold updates live
thresh.addEventListener('input', () => {
threshVal.textContent = thresh.value;
});

// On extract, read current slider value
const threshold = parseInt(thresh.value); // 120–240 range

This single addition made the tool work on documents that a fixed algorithm completely failed on.

Mobile Touch Support — The Bug I Almost Missed

The original implementation used only mouse events:

javascript
// ❌ This breaks completely on mobile
canvas.addEventListener('mousedown', onStart);
canvas.addEventListener('mousemove', onMove);
canvas.addEventListener('mouseup', onEnd);

Adding touch support required unified pointer handling:

javascript
// ✅ Unified mouse + touch handler
function getPos(e) {
const rect = canvasWrap.getBoundingClientRect();
const src = e.touches ? e.touches[0] : e;
return {
x: src.clientX - rect.left + canvasWrap.scrollLeft,
y: src.clientY - rect.top + canvasWrap.scrollTop
};
}

// Same handler works for both mouse and touch
canvasWrap.addEventListener('mousedown', onStart);
canvasWrap.addEventListener('touchstart', onStart, { passive: false });
canvasWrap.addEventListener('mousemove', onMove);
canvasWrap.addEventListener('touchmove', onMove, { passive: false });

passive: false is required here — otherwise preventDefault() cannot stop the page from scrolling while the user is trying to draw a selection box.

The Scale Factor Bug

This one was subtle and caused wrong crop coordinates on high-DPI displays and zoomed-in PDF pages.

javascript
// ❌ Wrong — calculated once at load time
let scaleFactor = canvas.width / canvas.clientWidth;

// ✅ Correct — calculated fresh at extraction time
extractBtn.addEventListener('click', () => {
const scaleFactor = mc.width / mc.clientWidth;

const actualX = parseInt(cropBox.style.left) * scaleFactor;
const actualY = parseInt(cropBox.style.top) * scaleFactor;
const actualW = parseInt(cropBox.style.width) * scaleFactor;
const actualH = parseInt(cropBox.style.height) * scaleFactor;

const imgData = ctx.getImageData(actualX, actualY, actualW, actualH);
// ...
});

The canvas internal resolution and its displayed CSS size are different — especially on Retina displays or when PDF pages are rendered at 2x scale for sharpness. Always recalculate at the moment of use.

What I Would Improve Next

  1. Colored ink support
    Currently the algorithm assumes dark ink on light paper. Blue or red pen signatures lose saturation. A better approach would be HSL-based isolation instead of pure brightness.

  2. Edge smoothing
    The extracted PNG sometimes has jagged edges around the signature. A Gaussian blur pass on the alpha channel before output would smooth this considerably.

  3. Auto-detection
    Using contrast analysis to automatically suggest the tightest possible crop box around the signature area — so users don't have to draw manually.

Try It

🔗 https://aitextextractors.com/free-signature-extractor-from-pdf-images/

No account. No watermark. No file uploads. Just open and use.

Would love to hear thoughts on the background removal algorithm — especially from anyone who has worked with OpenCV or similar for document processing. Is there a better browser-based approach for colored ink signatures?

Top comments (1)

Collapse
 
amitfeldman profile image
Amit Feldman

Zero-server with no upload is the right architecture for this — nice build. I ran a quick passive check on the page (response headers + public HTML only, nothing intrusive) and found one thing worth fixing before this post picks up traffic:

  1. The first link in your article 404s. It points to /free-signature-extractor-from-pdf-image-online/ (singular "image"), which returns 404 — the working URL is /free-signature-extractor-from-pdf-images/ (plural). Anyone clicking through from here hits your "Page Not Found" instead of the tool. (dev.to lets you edit the post URL list — 30-second fix.)

  2. The live page has two

    tags. Browsers use the first one ("NO.1 Free signature extractor from PDF and images online"), so your better-branded second title ("Free Signature Extractor from PDF & Image Online — No Signup | AI Text Extractors") is silently ignored — and that's also the one search engines would rather see. There are also two <h1>s; keeping exactly one helps the page rank for the query you built it for.</p></li> <li><p>Quick header wins: HSTS, X-Frame-Options, X-Content-Type-Options and Referrer-Policy are all unset (CSP upgrade-insecure-requests and Permissions-Policy are already there, so you clearly know the territory). All four are one line each at whatever serves the static site.</p></li> </ol> <p>Everything else I checked came back clean — valid TLS, robots.txt live, all images with alt text. Happy to re-run the check free any time if you ship a fix.</p>