# jscanify: JavaScript document detection and paper extraction

> jscanify is an MIT-licensed JavaScript library that uses OpenCV.js to detect, highlight, and extract paper from images. It fits browser and React applications, while its Node.js entry point requires separate setup that the README delegates to the project wiki.

**puffinsoft/jscanify** — The Javascript document scanning library.

- Repository: https://github.com/puffinsoft/jscanify
- Website: https://colonelparrot.github.io/jscanify/
- Stars: 1,789 · Forks: 81
- Language: JavaScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/puffinsoft-jscanify

## Why jscanify targets browser document capture

jscanify addresses the gap between showing a camera image and turning it into a scan-like document image. Its documented features include detecting paper, drawing a highlight around the detected region, and extracting paper with distortion correction. Newer versions also add glare suppression and support for paper in multiple colors. This puts jscanify below the level of a complete scanning application: it processes images and returns canvases, but the application still owns camera capture, interface design, storage, and any PDF conversion.

The intended users are JavaScript developers building document-capture features in web pages or React applications. The README says it supports the web, Node.js, React, and other environments. Its package metadata describes it as an open-source JavaScript mobile document scanner, and the examples use `HTMLImageElement` and `HTMLCanvasElement` objects. A mobile web application that already captures frames as canvases is therefore the clearest use case.

Detection quality depends on the photographed scene. The README specifically recommends placing paper on a flat surface with a solid background color. That condition matters because the library receives an image rather than depth, document metadata, or a physical sensor reading. Wrinkled paper, shadows, reflective glare, clutter, or a busy background can all make the visual problem less defined, although the repository does not publish numerical detection limits or supported failure rates.

## OpenCV.js processing behind the jscanify API

jscanify is built around OpenCV.js, as the README states with its `opencv.js` attribution. Its browser-facing source entry is `src/jscanify.js`, while the default package entry is `src/jscanify-node.js`. This split is visible in `package.json`: importing `jscanify` resolves to the Node.js file, and the explicit `jscanify/client` export resolves to the browser file. That packaging detail matters for projects that distinguish server and browser bundles.

The main processing operations are `highlightPaper(image)` and `extractPaper(image, paperWidth, paperHeight)`. Both accept an image object and return a canvas according to the README examples. `highlightPaper` produces a canvas suitable for visually checking where the library found the sheet. `extractPaper` also needs an output width and height, which tells the caller what dimensions the extracted document should have.

The repository advertises distortion correction for paper scanning, but the README does not describe its internal computer-vision pipeline. It does not identify the contour detector, corner model, interpolation method, or confidence threshold. It is therefore reasonable to identify the public canvas-in, canvas-out behavior, but not to claim a particular algorithm beneath it. The documented debugging page at `https://colonelparrot.github.io/jscanify/tester.html` is intended for observing highlighting and extraction on test images, which gives evaluators a practical way to inspect output without inferring internals.

## Installing jscanify and extracting a browser image

For an npm-based browser project, the README gives this installation command and default import. The command installs the package under the published name `jscanify`.

```bash
$ npm i jscanify
import jscanify from 'jscanify'
```

The import line is JavaScript rather than shell syntax, although the README places it in the same block. Package metadata indicates that the default export is the Node.js entry point, so browser consumers should verify whether their bundler resolves that default correctly or whether they need the `jscanify/client` subpath. The repository provides that subpath, but the README's quickstart does not show the import form.

For a browser-only page, the documented CDN setup loads OpenCV.js and jscanify separately. OpenCV is asynchronous, so the README warns that it can take time to load. The page should also delay jscanify execution until OpenCV and the input image are available.

```html
<script src="https://docs.opencv.org/4.7.0/opencv.js" async></script>
<script src="https://cdn.jsdelivr.net/gh/ColonelParrot/jscanify@master/src/jscanify.min.js"></script>
```

After adding an image to the document, construct the scanner and append the returned canvas. The README recommends wrapping this code in a `window` `load` event listener to help ensure OpenCV has loaded.

```js
const scanner = new jscanify();
image.onload = function () {
  const highlightedCanvas = scanner.highlightPaper(image);
  document.body.appendChild(highlightedCanvas);
};
```

The visible result should be a canvas containing the image with paper highlighting. The browser example does not itself define the `image` element, so a complete application must supply an image element and wait for its `onload` event.

## Replacing highlighting with rectangular extraction

Paper extraction uses the same scanner object but passes an explicit target width and height. The README uses 500 by 1000 pixels for a portrait-like document.

```js
const scanner = new jscanify();
const paperWidth = 500;
const paperHeight = 1000;
image.onload = function () {
  const resultCanvas = scanner.extractPaper(image, paperWidth, paperHeight);
  document.body.appendChild(resultCanvas);
};
```

The returned object is a canvas, not a PDF. The README points readers to an external Stack Overflow discussion for converting a canvas to a PDF. That distinction affects adoption. Teams looking for a complete scanner workflow may need to implement capture controls, page sequencing, image encoding, file storage, and document export themselves.

For live camera input, the README demonstrates copying video frames into a canvas and running `highlightPaper` on each captured canvas. A timer then copies the returned result into another canvas.

```js
const scanner = new jscanify();
const canvasCtx = canvas.getContext("2d");
const resultCtx = result.getContext("2d");
navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => {
  video.srcObject = stream;
  video.onloadedmetadata = () => {
    video.play();

    setInterval(() => {
      canvasCtx.drawImage(video, 0, 0);
      const resultCanvas = scanner.highlightPaper(canvas);
      resultCtx.drawImage(resultCanvas, 0, 0);
    }, 10);
  };
});
```

The example schedules processing every 10 milliseconds, but it includes no cancellation, frame dropping, permission error handling, or camera teardown. It is a minimal demonstration rather than a complete camera controller.

## OpenCV.js loading and scene constraints in practice

The clearest operational limitation is the dependency between application readiness and OpenCV.js. The CDN script has the `async` attribute, which means it may finish after other page code executes. The README explicitly advises using a `window` `load` event listener and warns that loading OpenCV can take time. A page that constructs jscanify before the runtime is ready can encounter a loading-order failure even when the image itself has loaded.

The second limitation is image quality control. jscanify cannot compensate for a source scene that lacks a clear paper boundary. The README's flat-surface and solid-background recommendation is therefore part of the expected operating procedure, not optional polish. Applications need to give users guidance about lighting, placement, and camera angle if their capture environment permits those controls.

The API also does not expose documented detection confidence, rejected-frame reasons, or a callback for uncertain results. The available interface indicates success by returning a canvas. To assess reliability, developers can use the project's `tester.html` page with representative images, including difficult lighting and colored paper. That page is documented for observing highlighting and extraction, but the README provides no sample dataset or acceptance thresholds.

Node.js is another boundary. The README says Node.js usage is "slightly different" and links to its wiki rather than showing a complete Node.js tutorial in the quickstart. `package.json` lists `canvas` and `jsdom` as runtime dependencies, and its test command is `mocha --trace-uncaught`. Those details confirm a distinct Node.js implementation, but they do not establish that a browser import example can be copied directly into server-side code.

## OpenCV.js scripts compared with manual canvas processing

The closest documented alternative is a manual OpenCV.js pipeline built directly in the application. Both approaches use OpenCV.js and can operate on canvases, but jscanify packages paper highlighting and extraction into `highlightPaper` and `extractPaper`. A manual implementation would leave the developer responsible for image preprocessing, finding the document region, handling output dimensions, and correcting distortion.

That approach offers more control over detection rules, but it also transfers implementation responsibility to the application. The README does not expose tuning parameters, so a project that needs to adjust thresholds or replace a detection stage may find the public API too narrow. Conversely, a project that only needs conventional paper detection and extraction can avoid reimplementing the document-oriented operations.

jscanify is also not equivalent to a document-generation service. It returns canvas output and does not, in the documented quickstart, generate a PDF, save a file, manage multiple pages, or perform optical character recognition. A manual OpenCV.js pipeline has the same output boundary unless the developer adds those stages.

The MIT license makes the library suitable for review as an embeddable component, subject to the actual permissions and conditions in the repository's `LICENSE` file. Teams should inspect that file themselves before deciding how to distribute modified code or integrate the package.

## Release history, Node.js packaging, and upgrade work

The repository is not archived. Its last push was on 2026-07-20, and the release list includes v1.4.0 dated 2025-02-18 after v1.3.0 dated 2025-01-28 and v1.2.0 dated 2023-05-10. The README says v1.3.0 and later retain the same API while adding improved results, glare suppression, and multi-colored paper support. This suggests that adopters should not expect those additions to require new documented method names, although changes outside the quickstart are not described in the README.

The checked-in `package.json` reports version `1.4.3`, while the release list stops at v1.4.0. The repository file is therefore more current than the abbreviated release list, but the README does not document what changed in 1.4.3. An upgrade review should compare that package version with the application's pinned version and examine the repository's release information before assuming a documented change set.

Upgrade costs include more than package installation. OpenCV.js loading can affect initial page behavior, and Node.js consumers have a different source entry and setup path. The package dependencies also bring `canvas`, `jsdom`, and their transitive installations into Node.js environments. The `test` script runs Mocha with uncaught-exception tracing, but the README does not document the tests, their fixtures, or whether they cover browser camera behavior.

## Conclusion

Browser developers who need client-side paper detection or extraction should evaluate jscanify, especially when they already depend on OpenCV.js. Projects that require a documented production PDF workflow, deterministic edge detection, or a turnkey Node.js integration should first verify those areas against the project wiki. For an initial adoption decision, confirm that the `jscanify/client` entry works with the intended bundler, load OpenCV.js successfully, and produce acceptable results on representative camera images.

## FAQ

### What is jscanify used for?

jscanify is a JavaScript document-scanning library for detecting and highlighting paper, then extracting it with distortion correction. It returns canvases and supports browser, Node.js, and React contexts.

### How do I install jscanify in a JavaScript project?

The README documents `npm i jscanify`. It also provides browser CDN scripts for OpenCV.js and the minified jscanify source, but warns that OpenCV can take time to load.

### Does jscanify directly create PDF files?

No. The documented extraction method returns a canvas. The README separately links to an external explanation for converting a canvas to a PDF.

## Sources

- [License: MIT](https://github.com/puffinsoft/jscanify/blob/master/LICENSE)
- [Project website](https://colonelparrot.github.io/jscanify/)
- [puffinsoft/jscanify on GitHub](https://github.com/puffinsoft/jscanify)
- [README](https://github.com/puffinsoft/jscanify/blob/master/README.md)
- [Releases](https://github.com/puffinsoft/jscanify/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/puffinsoft-jscanify
