npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sign-extract

v0.1.0

Published

Zero-dependency, in-browser library that extracts clean signatures from photos and scans as transparent PNGs.

Readme

sign-extract

Extract clean, transparent-background signature PNGs from photos and scans - entirely in the browser. Zero dependencies.

sign-extract removes the paper, shadows and background from a photographed or scanned signature and returns black ink on a transparent PNG. It runs 100% client-side and offloads the heavy pixel work to a Web Worker.

Install

npm install sign-extract

Usage

import { extractSignature, toObjectURL } from 'sign-extract';

const result = await extractSignature(file);
img.src = toObjectURL(result);
// result.blob, result.imageData, result.width, result.height

With options:

const result = await extractSignature(file, {
  thresholdAdjust: 10, // keep fainter ink
  cleanup: 2, // drop tiny noise blobs
});

input accepts a File, Blob, ImageData, ImageBitmap, HTMLImageElement, HTMLCanvasElement, ArrayBuffer, a data URL, an http(s) URL, or a base64 string.

API reference

extractSignature(input, options?) resolves to { blob, imageData, width, height }. All options are optional:

| Option | Type | Default | What it does | | ----------------- | --------------------- | -------- | ----------------------------------------------------- | | maxWidth | number | 800 | Downscale target width (aspect ratio kept). | | thresholdAdjust | number | 0 | Nudge the auto threshold (0-255). + keeps more ink. | | cleanup | number | 0 | Despeckle: drop ink blobs smaller than this many px. | | blurRadius | number \| 'auto' | 'auto' | Background-estimation blur radius. | | invert | 'auto' \| boolean | 'auto' | Polarity; auto-flips an inverted mask. | | useWorker | boolean | true | Run in a Web Worker (auto-fallback to sync). | | onProgress | (pct: number)=>void | - | Progress callback, 0-100. |

  • maxWidth (number, default 800) - the image is resized so its width is at most this many pixels before processing (height scales to keep the aspect ratio); narrower inputs are left as-is. The returned blob/imageData are this width. Processing cost is roughly linear in pixel count, so a lower value runs faster.
  • thresholdAdjust (number, default 0) - an offset added to the brightness threshold (0-255 scale) the library picks automatically (Otsu's method) to split ink from background. 0 uses the computed value; positive numbers count more pixels as ink (keeps faint strokes, lets in more noise), negative numbers keep only the darkest pixels. Useful range is roughly -40 to 40.
  • cleanup (number, default 0) - the minimum number of connected pixels an ink region must contain to be kept. After the mask is computed, any group of touching ink pixels smaller than this is deleted. 0 disables it; 2-8 removes isolated specks (dust, JPEG artifacts); large values can delete real marks like the dot on an "i".
  • blurRadius (number | 'auto', default 'auto') - radius in pixels of the blur used to estimate the page background, which is subtracted to isolate the ink. Must be larger than your stroke width: too small and strokes blur into the background and fade; too large and broad stains/shadows survive. 'auto' derives a radius from the image size.
  • invert ('auto' | boolean, default 'auto') - whether the ink/background mask is flipped. 'auto' flips it when the detected ink covers more than ~50% of the image (a sign foreground and background were swapped). true always flips, false never does.
  • useWorker (boolean, default true) - runs the CPU-heavy pixel pipeline in a Web Worker so the main thread / UI stays responsive. If a Worker cannot be created (SSR, strict CSP, very old browser) it falls back to the calling thread. false forces same-thread processing.
  • onProgress ((pct: number) => void) - called repeatedly during processing with a value from 0 to 100 (for a progress bar). Runs on the calling thread, not inside the worker.

Returns ExtractResult = { blob, imageData, width, height }. blob is a transparent image/png (black ink only); imageData is the same pixels as raw RGBA. Use toObjectURL(result) (a thin URL.createObjectURL wrapper) to preview or download it.

How it works

grayscale → heavy background blur → high-pass subtraction → Otsu threshold → auto-invert → cleanup → render. See the full write-up and benchmarks.

License

MIT © Siddhi Kotak