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

@qrstuff/qured

v0.1.0

Published

Decode QR codes from images in browser and Node.js — file, blob, buffer, or base64

Readme

Qured

Qured is a JavaScript library that decodes QR codes from images entirely in the client — in the browser and in Node.js. No server, no camera, no external services. You pass an image (file, blob, buffer, or base64 string) and get back the decoded text.


Purpose

  • Decode QR codes from static images (PNG, JPEG, etc.) in browser and Node.js.
  • Support stylized QRs: custom colors, gradients, center logos, transparent or inverted backgrounds, as long as finder patterns and contrast are preserved.
  • Work offline and keep decoding logic client-side for privacy and simplicity.
  • Accept multiple input types: File, Blob, ArrayBuffer, Uint8Array, or base64/data URL string.

Features

  • Multi-input: File, Blob, ArrayBuffer, Uint8Array, or base64/data URL string.
  • Dual engine: Uses native BarcodeDetector when available (e.g. Chrome), otherwise ZXing with multi-pass preprocessing.
  • Preprocessing: Luminance grayscale, adaptive thresholding (small/medium/large), inversion, transparent-background flatten (white/black), light denoise — tried in sequence until decode succeeds.
  • Transparent backgrounds: Flattens transparent pixels onto white or black so normal and inverted transparent QRs decode.
  • Web Worker: Decoding runs in a worker by default in the browser to avoid blocking the main thread; worker: false for Node or debugging.
  • Extensible: Engine interface is generic so additional barcode formats can be added later without breaking the public API.
  • TypeScript: Typed API and shipped .d.ts.

Requirements

  • Browser: Modern Chrome, Firefox, Safari (ES2020). Worker support for off-thread decoding.
  • Node.js: >= 18. For decoding from image buffers (e.g. file path → buffer), the optional canvas package is required; without it, only decodeFromImageData() with your own ImageData is supported.

Install

yarn add @qrstuff/qured

For Node.js image loading (decoding from file paths or raw buffers), add the optional dependency:

yarn add canvas

Usage

Browser

import { decode } from "@qrstuff/qured";

// From <input type="file">
const file = document.querySelector('input[type="file"]').files[0];
const result = await decode(file);
console.log(result?.text ?? "No QR found");

// From Blob, ArrayBuffer, or base64 / data URL
const fromBlob = await decode(blob);
const fromBuffer = await decode(arrayBuffer);
const fromBase64 = await decode("data:image/png;base64,...");

Serve the built dist/ (including qured.js, decodeWorker.js, and any chunk files) so the worker can load. To run decoding on the main thread (e.g. for debugging), pass { worker: false }.

Node.js

import { decode } from "@qrstuff/qured";
import { readFileSync } from "fs";

const buffer = readFileSync("./qrcode.png");
const result = await decode(buffer, { worker: false });
console.log(result?.text);

In Node, use { worker: false }; worker URL resolution is intended for the browser. Install the optional canvas package so Qured can decode image buffers; without it, only decodeFromImageData() with your own ImageData is supported.

Decode from raw ImageData

If you already have ImageData (e.g. from a canvas), you can skip image loading and worker:

import { decodeFromImageData } from "@qrstuff/qured";

const imageData = ctx.getImageData(0, 0, width, height);
const result = await decodeFromImageData(imageData);

Decode all variants

To get every result found across preprocessing passes (e.g. for multi-QR or debugging):

import { decodeAll } from "@qrstuff/qured";

const results = await decodeAll(fileInput.files[0]);
results.forEach(r => console.log(r.text, r.meta?.preprocessingPass));

API

| Function | Description | | --- | --- | | decode(input, options?) | Decode one QR from an image. Returns Promise<DecodeResult \| null>. | | decodeFromImageData(imageData, options?) | Decode from raw ImageData. Returns Promise<DecodeResult \| null>. | | decodeAll(input, options?) | Same inputs as decode; returns Promise<DecodeResult[]> with all results from preprocessing passes. |

Input types: File | Blob | ArrayBuffer | Uint8Array | string (base64 or data URL).

DecodeResult

interface DecodeResult {
  text: string;
  format: "QR_CODE";
  points?: { x: number; y: number }[]; // finder/corner points if available
  meta?: {
    engine: "native" | "zxing";
    inverted?: boolean;
    preprocessingPass?: string; // e.g. 'luma', 'flatten-white', 'luma+invert'
  };
}

On failure, decode and decodeFromImageData return null (no throw).

DecodeOptions

interface DecodeOptions {
  aggressive?: boolean; // default false — more preprocessing passes
  maxPasses?: number; // default 6 (12 if aggressive)
  downscaleMaxDim?: number; // default 1400 — max width/height before downscale
  tryInvert?: boolean; // default true — try inverted luminance
  colorHint?: {
    foreground?: [number, number, number]; // RGB
    background?: [number, number, number]; // RGB
  };
  worker?: boolean; // default true in browser; use false in Node
}

Behaviour and limitations

  • Stylized QRs: Optimized for codes that keep finder patterns (mostly square) and a quiet zone, with sufficient luminance contrast. Custom colors, gradients, and center logos are supported when contrast is adequate. Transparent and inverted transparent backgrounds are handled via flatten passes.
  • Not supported: QRs without a quiet zone, merged modules, or finder patterns replaced by decorative shapes. No guarantee for “irresponsibly designed” codes.
  • Engines: Uses native BarcodeDetector when available and when it supports QR; otherwise falls back to ZXing with multi-pass preprocessing (grayscale, adaptive threshold, inversion, flatten transparent, light denoise).
  • Worker: In the browser, decoding runs in a Web Worker by default. Serve the full dist/ so the worker script and chunks can load. Set worker: false to run on the main thread (e.g. Node or debugging).

Build

yarn build

Produces dist/qured.js, dist/decodeWorker.js, and chunk files, plus TypeScript declarations under dist/. No minification by default.


Testing

Tests live under test/node/ (Mocha) and test/browser/ (Playwright + Mocha harness).

Node (Mocha)

Tests in test/node/decode-test.js use Mocha and Chai.

yarn test
  • Must decode: Asserts that each of a set of sample images (basic, colored, gradient, inverted, transparent, shaped-1, shaped-2) decodes successfully and returns a result with text and format: 'QR_CODE'.
  • Must fail: Asserts that certain “bad” samples (e.g. shaped-3-bad.png) return null, documenting out-of-scope or irresponsibly designed QRs.

Requires the optional canvas dependency so Node can load image files from data/. Run from the project root.

Browser (Playwright)

Browser tests run the same decode logic in real browsers (Chromium, Firefox) via Playwright.

yarn build
npx playwright install chromium firefox   # first run only
yarn test:browser

The harness (test/browser/browser-test.html) loads Mocha, Chai, and Qured; test/browser/decode-test.js runs the decode tests. Playwright starts a static server, loads the harness, and asserts all Mocha tests passed.


Releasing

Push a version tag (e.g. v1.0.0) to trigger the release workflow:

git tag v1.0.0
git push origin v1.0.0

The workflow will run tests, publish to npm, and create a GitHub release with a changelog of commit messages since the previous tag. Configure the NPM_TOKEN repository secret (npm → Access Tokens) with publish permission.


License

MIT