<?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: shawala ashiq</title>
    <description>The latest articles on DEV Community by shawala ashiq (@shawala_ashiq).</description>
    <link>https://dev.to/shawala_ashiq</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%2F3857086%2F6467f9e6-44dc-4771-8fdb-cb6b6213ba1d.jpg</url>
      <title>DEV Community: shawala ashiq</title>
      <link>https://dev.to/shawala_ashiq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shawala_ashiq"/>
    <language>en</language>
    <item>
      <title>I Built a Free Browser-Based Signature Extractor — Zero Server, Zero Uploads, Zero Signup</title>
      <dc:creator>shawala ashiq</dc:creator>
      <pubDate>Thu, 20 Aug 2026 06:52:37 +0000</pubDate>
      <link>https://dev.to/shawala_ashiq/i-built-a-free-browser-based-signature-extractor-zero-server-zero-uploads-zero-signup-1gie</link>
      <guid>https://dev.to/shawala_ashiq/i-built-a-free-browser-based-signature-extractor-zero-server-zero-uploads-zero-signup-1gie</guid>
      <description>&lt;p&gt;The problem was simple but annoying.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So you Google "signature extractor online free."&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you find?
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

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

&lt;p&gt;I decided to build something better. Here's how I did it and what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Tool Does
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Free Signature Extractor — a browser-based tool that:&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;🔗 Live tool: &lt;a href="https://aitextextractors.com/free-signature-extractor-from-pdf-image-online/" rel="noopener noreferrer"&gt;https://aitextextractors.com/free-signature-extractor-from-pdf-image-online/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Tech Stack&lt;/p&gt;

&lt;p&gt;No frameworks. No backend. No dependencies except one:&lt;/p&gt;

&lt;p&gt;javascript&lt;br&gt;
// PDF.js for rendering PDF pages to canvas&lt;br&gt;
pdfjsLib.GlobalWorkerOptions.workerSrc = &lt;br&gt;
'&lt;a href="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.worker.min.js" rel="noopener noreferrer"&gt;https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.worker.min.js&lt;/a&gt;';&lt;/p&gt;

&lt;p&gt;Everything else is vanilla JavaScript + HTML5 Canvas API.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How the Background Removal Works&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This was the most interesting part to figure out.&lt;/p&gt;

&lt;p&gt;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).&lt;/p&gt;

&lt;p&gt;javascript&lt;br&gt;
for (let i = 0; i &amp;lt; data.length; i += 4) {&lt;br&gt;
  const r = data[i];&lt;br&gt;
  const g = data[i + 1];&lt;br&gt;
  const b = data[i + 2];&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  Why weighted RGB instead of simple average?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The Threshold Slider Problem&lt;/p&gt;

&lt;p&gt;A fixed threshold of 175 works fine for pure white paper under good lighting.&lt;/p&gt;

&lt;p&gt;But real documents have:&lt;/p&gt;

&lt;p&gt;Cream or yellowish aged paper&lt;br&gt;
Grey shadows from camera angle&lt;br&gt;
Coffee stains (yes, really)&lt;br&gt;
Coloured paper backgrounds&lt;br&gt;
Inconsistent mobile phone lighting&lt;/p&gt;

&lt;p&gt;Solution: Let the user adjust it.&lt;/p&gt;

&lt;p&gt;javascript&lt;br&gt;
// User drags slider → threshold updates live&lt;br&gt;
thresh.addEventListener('input', () =&amp;gt; {&lt;br&gt;
  threshVal.textContent = thresh.value;&lt;br&gt;
});&lt;/p&gt;

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

&lt;p&gt;This single addition made the tool work on documents that a fixed algorithm completely failed on.&lt;/p&gt;

&lt;p&gt;Mobile Touch Support — The Bug I Almost Missed&lt;/p&gt;

&lt;p&gt;The original implementation used only mouse events:&lt;/p&gt;

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

&lt;p&gt;Adding touch support required unified pointer handling:&lt;/p&gt;

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

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

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

&lt;p&gt;The Scale Factor Bug&lt;/p&gt;

&lt;p&gt;This one was subtle and caused wrong crop coordinates on high-DPI displays and zoomed-in PDF pages.&lt;/p&gt;

&lt;p&gt;javascript&lt;br&gt;
// ❌ Wrong — calculated once at load time&lt;br&gt;
let scaleFactor = canvas.width / canvas.clientWidth;&lt;/p&gt;

&lt;p&gt;// ✅ Correct — calculated fresh at extraction time&lt;br&gt;
extractBtn.addEventListener('click', () =&amp;gt; {&lt;br&gt;
  const scaleFactor = mc.width / mc.clientWidth;&lt;/p&gt;

&lt;p&gt;const actualX = parseInt(cropBox.style.left)  * scaleFactor;&lt;br&gt;
  const actualY = parseInt(cropBox.style.top)   * scaleFactor;&lt;br&gt;
  const actualW = parseInt(cropBox.style.width)  * scaleFactor;&lt;br&gt;
  const actualH = parseInt(cropBox.style.height) * scaleFactor;&lt;/p&gt;

&lt;p&gt;const imgData = ctx.getImageData(actualX, actualY, actualW, actualH);&lt;br&gt;
  // ...&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Improve Next
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Colored ink support&lt;br&gt;
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.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Edge smoothing&lt;br&gt;
The extracted PNG sometimes has jagged edges around the signature. A Gaussian blur pass on the alpha channel before output would smooth this considerably.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Auto-detection&lt;br&gt;
Using contrast analysis to automatically suggest the tightest possible crop box around the signature area — so users don't have to draw manually.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Try It&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://aitextextractors.com/free-signature-extractor-from-pdf-images/" rel="noopener noreferrer"&gt;https://aitextextractors.com/free-signature-extractor-from-pdf-images/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No account. No watermark. No file uploads. Just open and use.&lt;/p&gt;

&lt;p&gt;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?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Ditching Tesseract: Why I Switched to AI-Powered OCR for Better Accuracy and formatting</title>
      <dc:creator>shawala ashiq</dc:creator>
      <pubDate>Thu, 02 Apr 2026 07:44:56 +0000</pubDate>
      <link>https://dev.to/shawala_ashiq/ditching-tesseract-why-i-switched-to-ai-powered-ocr-for-better-accuracy-and-formatting-1i60</link>
      <guid>https://dev.to/shawala_ashiq/ditching-tesseract-why-i-switched-to-ai-powered-ocr-for-better-accuracy-and-formatting-1i60</guid>
      <description>&lt;p&gt;If you have ever tried building a project that involves extracting text from images, you probably started with Tesseract. It's the classic choice, but let’s be real—it struggles with anything that isn't a perfectly scanned, high-contrast document.&lt;br&gt;
Recently, I decided to move away from traditional OCR engines and experiment with LLM-based vision models (like Gemini) to see if they could handle real-world "messy" data better. The results were night and day.&lt;br&gt;
I eventually turned this experiment into a free tool called &lt;a href="https://aitextextractors.com/" rel="noopener noreferrer"&gt;AITextExtractors&lt;/a&gt;.&lt;br&gt;
Why the AI approach wins:&lt;br&gt;
Context Awareness: Instead of just looking at pixels, the AI understands words. If a character is blurry, it uses the surrounding con&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7joa62viv5edlzk96yh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7joa62viv5edlzk96yh.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;text to "guess" correctly.&lt;br&gt;
Complex Layouts: It doesn't get confused by multi-column PDFs or skewed images.&lt;br&gt;
Handwriting: It can actually read human handwriting, which is a huge pain point for older OCR tools.&lt;br&gt;
The Privacy Factor&lt;br&gt;
One thing I focused on while building this was data security. Most online converters keep your files on their servers. I implemented a strict zero-log policy so that images are processed and then immediately purged.&lt;br&gt;
If you're a developer or just someone tired of fixing OCR typos, give it a shot. I’d love to hear your thoughts on how we can make AI-driven text extraction even more seamless!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
