sign-extract
v0.1.0
Published
Zero-dependency, in-browser library that extracts clean signatures from photos and scans as transparent PNGs.
Maintainers
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-extractUsage
import { extractSignature, toObjectURL } from 'sign-extract';
const result = await extractSignature(file);
img.src = toObjectURL(result);
// result.blob, result.imageData, result.width, result.heightWith 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, default800) - 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 returnedblob/imageDataare this width. Processing cost is roughly linear in pixel count, so a lower value runs faster.thresholdAdjust(number, default0) - an offset added to the brightness threshold (0-255 scale) the library picks automatically (Otsu's method) to split ink from background.0uses 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-40to40.cleanup(number, default0) - 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.0disables it;2-8removes 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).truealways flips,falsenever does.useWorker(boolean, defaulttrue) - 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.falseforces same-thread processing.onProgress((pct: number) => void) - called repeatedly during processing with a value from0to100(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
