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

ppu-ocv

v3.1.5

Published

A type-safe, modular, chainable image processing library built on top of OpenCV.js with a fluent API leveraging pipeline processing.

Readme

ppu-ocv

NPM JSR

A type-safe, modular, chainable image processing library built on top of OpenCV.js with a fluent API leveraging pipeline processing. Decoupled canvas utilities run anywhere — Node, Bun, browsers, browser extensions, and service workers — with or without OpenCV.

ppu-ocv pipeline demo

const processor = new ImageProcessor(canvas);

const result = processor
  .grayscale()
  .blur({ size: [5, 5] })
  .threshold()
  .invert()
  .dilate({ size: [20, 20], iter: 5 })
  .toCanvas();

processor.destroy();

Based on TechStark/opencv-js.

Table of Contents

Why ppu-ocv?

  • Simplified API — chainable methods that hide OpenCV's verbose Mat allocation
  • No memory management — automatic Mat lifecycle within the pipeline
  • Type-safe — full TypeScript inference for operations and options
  • Extensible — register custom operations with registry.register(...) without forking
  • Cross-platform — same API in Node, Bun, browsers, and constrained runtimes
  • Loosely coupled — canvas utilities work standalone; OpenCV is only loaded when actually needed

Installation

Install using your preferred package manager:

npm install ppu-ocv
yarn add ppu-ocv
bun add ppu-ocv

Usage (Node.js / Bun)

Note that operation order matters — you should have at least basic familiarity with OpenCV. See the operations table below.

import { CanvasProcessor, ImageProcessor } from "ppu-ocv";

const file = Bun.file("./assets/receipt.jpg");
const image = await file.arrayBuffer();

await ImageProcessor.initRuntime(); // init opencv
const canvas = await CanvasProcessor.prepareCanvas(image);

const processor = new ImageProcessor(canvas);
processor
  .grayscale()
  .blur({ size: [5, 5] })
  .threshold();

const resultCanvas = processor.toCanvas();
processor.destroy();

Or use the execute API directly:

import { CanvasProcessor, CanvasToolkit, ImageProcessor, cv } from "ppu-ocv";

const file = Bun.file("./assets/receipt.jpg");
const image = await file.arrayBuffer();

const canvasToolkit = CanvasToolkit.getInstance();
await ImageProcessor.initRuntime();
const canvas = await CanvasProcessor.prepareCanvas(image);

const processor = new ImageProcessor(canvas);
const grayscaleImg = processor.execute("grayscale").toCanvas();

// The pipeline continues from the grayscaled image
const thresholdImg = processor
  .execute("blur")
  .execute("threshold", {
    type: cv.THRESH_BINARY_INV + cv.THRESH_OTSU,
  })
  .toCanvas();

await canvasToolkit.saveImage({
  canvas: thresholdImg,
  filename: "threshold",
  path: "out",
});

For more advanced usage, see: Example usage of ppu-ocv

Canvas-only usage (no OpenCV)

Starting from v3.0.0, canvas utilities are fully decoupled from OpenCV. If you only need canvas I/O (e.g. loading/saving images, cropping, drawing) without any image processing, import from ppu-ocv/canvas (Node) or ppu-ocv/canvas-web (browser). OpenCV is never imported or initialised by these entry points, making them safe for use in Browser Extensions, Service Workers, and edge runtimes.

// Node.js — zero OpenCV dependency
import { CanvasProcessor, CanvasToolkit } from "ppu-ocv/canvas";

const file = Bun.file("./assets/image.jpg");
const canvas = await CanvasProcessor.prepareCanvas(await file.arrayBuffer());

const toolkit = CanvasToolkit.getInstance();
const cropped = toolkit.crop({
  canvas,
  bbox: { x0: 0, y0: 0, x1: 100, y1: 100 },
});

const buffer = await CanvasProcessor.prepareBuffer(cropped);
// Browser Extension background script — zero OpenCV dependency
import { CanvasProcessor, CanvasToolkit } from "ppu-ocv/canvas-web";

const response = await fetch("/image.jpg");
const canvas = await CanvasProcessor.prepareCanvas(await response.arrayBuffer());

Web / Browser Support

Import from ppu-ocv/web to use the browser-native canvas APIs (HTMLCanvasElement / OffscreenCanvas) instead of @napi-rs/canvas.

With a bundler (Vite, webpack, etc.)

import { CanvasProcessor, ImageProcessor, cv } from "ppu-ocv/web";

await ImageProcessor.initRuntime();

const response = await fetch("/my-image.jpg");
const buffer = await response.arrayBuffer();

const canvas = await CanvasProcessor.prepareCanvas(buffer);
const processor = new ImageProcessor(canvas);

processor
  .grayscale()
  .blur({ size: [5, 5] })
  .threshold();

const result = processor.toCanvas(); // returns HTMLCanvasElement
document.body.appendChild(result);

processor.destroy();

Vanilla HTML (no bundler)

initRuntime() automatically loads @techstark/opencv-js from the npm CDN if it's not already available. No extra script tags or import maps needed:

<script type="module">
  import {
    CanvasProcessor,
    ImageProcessor,
  } from "https://cdn.jsdelivr.net/npm/ppu-ocv@3/index.web.js";
  await ImageProcessor.initRuntime();

  const response = await fetch("/my-image.jpg");
  const canvas = await CanvasProcessor.prepareCanvas(await response.arrayBuffer());

  const processor = new ImageProcessor(canvas);
  processor
    .grayscale()
    .blur({ size: [5, 5] })
    .threshold();

  const result = processor.toCanvas();
  processor.destroy();
</script>

Note: ES modules require HTTP/HTTPS — use a local server (npx serve .) for dev, or deploy to GitHub Pages.

See the interactive demo for a full working example.

Entry point reference

| Import path | OpenCV | Canvas backend | CanvasToolkit | Use case | | -------------------- | ------ | ------------------------------------- | -------------------- | ------------------------------------------ | | ppu-ocv | ✅ | @napi-rs/canvas | Full (with file I/O) | Full pipeline, Node.js / Bun | | ppu-ocv/web | ✅ | HTMLCanvasElement/OffscreenCanvas | Base only | Full pipeline, browser | | ppu-ocv/canvas | ❌ | @napi-rs/canvas | Full (with file I/O) | Canvas-only, Node (extensions, edge, etc.) | | ppu-ocv/canvas-web | ❌ | HTMLCanvasElement/OffscreenCanvas | Base only | Canvas-only, browser extensions / SW |

Platform abstraction

Under the hood, ppu-ocv uses a platform abstraction layer. Each entry point auto-registers its platform. You can also register a custom platform:

import { setPlatform, type CanvasPlatform } from "ppu-ocv/web";

const myPlatform: CanvasPlatform = {
  createCanvas(width, height) {
    /* ... */
  },
  loadImage(source) {
    /* ... */
  },
  isCanvas(value) {
    /* ... */
  },
};

setPlatform(myPlatform);

Built-in pipeline operations

To avoid bloat, we only ship essential operations for chaining. Currently shipped operations are:

| Operation | Depends on… | Why | | ------------------------- | ------------------------------------------- | --------------------------------------------------------------- | | grayscale | – | Converts to single‐channel; many ops expect a gray image first. | | blur | (ideally after) grayscale | Noise reduction works best on 1-channel data. | | threshold | (after) grayscale | Produces a binary image; needs gray levels. | | adaptiveThreshold | (after) grayscale (and optionally blur) | Local thresholding on gray values (smoother if blurred first). | | invert | (after) threshold or adaptiveThreshold | Inverting a binary mask flips foreground/background. | | canny | (after) grayscale + blur | Edge detection expects a smoothed gray image. | | dilate | (after) threshold or edge detection | Expands foreground regions—usually on a binary mask. | | erode | (after) threshold or edge detection | Shrinks or cleans up binary regions. | | morphologicalGradient | (after) dilation + erosion (or threshold) | Highlights boundaries by subtracting eroded from dilated image. | | warp | – | Geometric transform; can be applied at any point. | | resize | – | Also independent; purely geometry. | | border | – | Independent; purely geometry. | | rotate | – | Independent. |

Extending operations

You can easily add your own by creating a prototype method or extending the ImageProcessor class.

See: How to extend ppu-ocv operations

Class documentation

CanvasProcessor

Canvas-native image processing with no OpenCV dependency. Available from all entry points including ppu-ocv/canvas and ppu-ocv/canvas-web. Provides a chainable instance API alongside static I/O helpers.

const result = new CanvasProcessor(canvas)
  .resize({ width: 360, height: 640 })
  .grayscale()
  .threshold({ thresh: 127 })
  .invert()
  .border({ size: 10, color: "white" })
  .toCanvas();

// Detect connected white regions on a binary image
const regions = new CanvasProcessor(binaryCanvas).findRegions({
  foreground: "light",
  minArea: 20,
  // thresh: 0  ← use on resized binary images to match OpenCV (any non-zero pixel = foreground)
  // padding: { vertical: 0.4, horizontal: 0.6 }  ← expand bbox by fraction of height
  // scale: 1 / resizeRatio                        ← map coords back to original image space
});
regions.sort((a, b) => b.area - a.area); // largest first
// regions[0] → { bbox: { x0, y0, x1, y1 }, area }

Static I/O

| Method | Args | Description | | ---------------------- | ----------- | ----------------------------------------------------- | | static prepareCanvas | ArrayBuffer | Load image bytes into a CanvasLike | | static prepareBuffer | CanvasLike | Export a CanvasLike to an ArrayBuffer (PNG bytes) |

Instance operations (chainable, return this)

| Method | Options | OpenCV equivalent | Fidelity | | ----------- | ---------------------------------- | ------------------------- | -------------- | | resize | width, height | cv.resize INTER_LINEAR | 1:1 (↓), ≈ (↑) | | grayscale | — | COLOR_RGBA2GRAY | 1:1 | | convert | alpha?, beta? | Mat.convertTo (α·x + β) | 1:1 | | invert | — | cv.bitwise_not | 1:1 ¹ | | threshold | thresh? (127), maxValue? (255) | THRESH_BINARY | 1:1 | | border | size? (10), color? (CSS) | BORDER_CONSTANT | 1:1 | | rotate | angle, cx?, cy? | warpAffine | ≈ (±6 px) ² | | toCanvas | — | — | — |

Region detection (returns data, does not mutate)

| Method | Options | Description | | ------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------- | | findRegions | foreground? ("light"), thresh? (127), minArea?, maxArea?, padding?, scale? | 8-connected flood-fill on a binary canvas → DetectedRegion[] |

DetectedRegion shape: { bbox: BoundingBox, area: number } where bbox is { x0, y0, x1, y1 } (x1/y1 exclusive). Equivalent to OpenCV's findContours(RETR_EXTERNAL) + boundingRect — all matched bboxes agree within ±1 px on solid binary images. ³

thresh option — pixel value threshold for foreground detection (default 127). For resized binary images, use thresh: 0 so anti-aliased border pixels (values 1–127) are included as foreground, matching OpenCV's non-zero threshold. With thresh: 0 + padding + scale, full-pipeline IoU vs OpenCV is 98.4% (all 21/21 boxes matched).

¹ Canvas invert preserves the alpha channel; OpenCV bitwise_not also inverts alpha. Results are identical when the source is opaque (alpha=255).

² Canvas uses anti-aliased bilinear interpolation; OpenCV uses plain bilinear. Difference is visually imperceptible and has no impact on OCR quality.

³ RETR_LIST may return additional inner-hole contours for white regions that contain dark sub-regions; findRegions counts each connected white component once regardless of interior holes.

ImageProcessor

Requires OpenCV. Available from ppu-ocv and ppu-ocv/web.

| Method | Args | Description | | -------------------- | ---------------- | ------------------------------------------------------------------ | | constructor | cv.Mat or Canvas | Instantiate processor with initial image | | static initRuntime | | OpenCV runtime initialization — required once per runtime | | operations | depends | Chainable operations like blur, grayscale, resize, and so on | | execute | name, options | Chainable operations via the execute API | | toMat | | Return the current image as a cv.Mat | | toCanvas | | Return the current image as a CanvasLike | | destroy | | Clean up cv.Mat memory |

CanvasToolkit

| Method | Args | Description | | ------------- | ---------------------- | ----------------------------------------------------------------------------------------- | | crop | BoundingBox, Canvas | Crop a part of source canvas and return a new canvas of the cropped part | | isDirty | Canvas, threshold | Check whether a binary canvas is dirty (full of major color either black or white) or not | | saveImage | Canvas, filename, path | Save a canvas to an image file (Node only) | | clearOutput | path | Clear the output folder (Node only) | | drawLine | ctx, coordinate, style | Draw a non-filled rectangle outline on the canvas | | drawContour | ctx, contour, style | Draw a contour on the canvas — accepts any ContourLike ({ data32S }) |

DeskewService

Detects and corrects text skew in document images using a multi-method consensus approach (minAreaRect, baseline analysis, Hough transform). Requires OpenCV. Available from ppu-ocv and ppu-ocv/web.

| Method | Args | Description | | -------------------- | ------------- | ------------------------------------ | | constructor | DeskewOptions | verbose, minimumAreaThreshold | | calculateSkewAngle | CanvasLike | Detect skew angle in degrees | | deskewImage | CanvasLike | Return a deskewed copy of the canvas |

Contours

| Method | Args | Description | | -------------------------------- | --------------- | ---------------------------------------------------------------- | | constructor | cv.Mat, options | Instantiate Contours and automatically find & store contour list | | getAll | | Return the full cv.MatVector of contours | | getFromIndex | index | Get contour at a specific index | | getRect | contour | Get the bounding rectangle of a contour | | iterate | callback | Iterate over all contours | | getLargestContourArea | | Return the contour with the largest area | | getCornerPoints | options | Get four corner points for perspective transformation (warp) | | getApproximateRectangleContour | options | Simplify a contour to an approximate rectangle | | destroy | | Destroy and clean up contour memory |

ImageAnalysis

A collection of utility functions for analyzing image properties (requires OpenCV).

  • calculateMeanNormalizedLabLightness: Calculates the mean normalized lightness of an image using the L channel of the Lab color space.
  • calculateMeanGrayscaleValue: Calculates the mean pixel value after converting to grayscale.

Contributing

See CONTRIBUTING.md for the full guide — setup, commit conventions, quality checks, and PR flow. Also:

Quick local commands:

bun install
bun test           # run unit tests
bun run fmt        # check formatting
bun run lint       # check lint
bun run type-check # tsgo --noEmit
bun task build     # emit ./lib
bun task bench     # micro-bench the operations registry

Migrating from v2

See MIGRATION.md for a full guide. The short version:

- import { ImageProcessor } from "ppu-ocv";
- const canvas = await ImageProcessor.prepareCanvas(buffer);
- const buf    = await ImageProcessor.prepareBuffer(canvas);

+ import { CanvasProcessor } from "ppu-ocv";
+ const canvas = await CanvasProcessor.prepareCanvas(buffer);
+ const buf    = await CanvasProcessor.prepareBuffer(canvas);

License

This project is licensed under the MIT License. See the LICENSE file for details.

Support

If you encounter any issues or have suggestions, please open an issue in the repository.

Happy coding!