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

prescription-scanner

v1.1.5

Published

Lightweight WASM barcode scanner (495KB) - DataMatrix, QR Code, configurable preloading, PDF support, headless API

Readme

Prescription Scanner

npm version npm downloads bundle size license TypeScript WebAssembly Zero Dependencies Buy Me A Coffee

Lightweight WASM barcode scanner for web applications. Supports DataMatrix and QR Code.

v1.1.5 - scanBounds API for custom scan areas!

Features

  • Single WASM file with DataMatrix and QR Code support
  • Zero dependencies - pure vanilla JavaScript
  • Headless mode (default) - use without UI for custom integrations
  • Configurable WASM preloading - lazy, idle, eager, or manual
  • PDF support - scan barcodes from PDF files
  • Multi-code detection - find all codes in one scan
  • Image enhancement - auto upscaling & contrast for better detection
  • Works with any framework (React, Vue, Angular, vanilla JS)
  • Mobile-optimized camera handling

Installation

npm install prescription-scanner

Usage

Headless Mode (Default)

The scanner runs in headless mode by default - no UI, just the scanning API:

import { PrescriptionScanner } from 'prescription-scanner';

const scanner = new PrescriptionScanner({
  preload: 'idle',  // Load WASM when browser is idle
  onReady: () => {
    console.log('WASM loaded, scanner ready!');
    startButton.disabled = false;
  },
  onScan: (result) => {
    console.log('Found:', result.data, result.format);
  }
});

// === Camera Scanning ===

// Start camera in your container
const video = await scanner.startCamera(myContainer);

// Stop scanning and cleanup
scanner.stop();

// === Static Scanning ===

const results = await scanner.scanImage(imgElement);
const results = await scanner.scanImageData(imageData);
const results = await scanner.scanCanvas(canvasElement);
const results = await scanner.scanPDF(pdfFile);

WASM Preloading

The WASM module (~450KB) can be loaded with different strategies:

// Load when browser is idle (recommended for best UX)
const scanner = new PrescriptionScanner({
  preload: 'idle',
  onReady: () => button.disabled = false
});

// Load immediately on instantiation
const scanner = new PrescriptionScanner({
  preload: 'eager'
});

// Load on first use (default)
const scanner = new PrescriptionScanner({
  preload: 'lazy'  // or omit - this is the default
});

// Manual loading
const scanner = new PrescriptionScanner({
  preload: false
});
await scanner.preload();  // or scanner.init()

| Strategy | When | Use Case | |----------|------|----------| | 'idle' | Browser idle | Best UX - preload without blocking | | 'eager' | Immediately | When scanner is primary feature | | 'lazy' | First use | Minimal initial load | | false | Manual | Full control over timing |

React Example with Loading State

const [isReady, setIsReady] = useState(false);
const scannerRef = useRef<PrescriptionScanner | null>(null);

useEffect(() => {
  const scanner = new PrescriptionScanner({
    preload: 'idle',  // Loads WASM when browser is idle
    onReady: () => setIsReady(true),
    onScan: (result) => console.log(result)
  });
  scannerRef.current = scanner;
  return () => scanner.stop();
}, []);

// Button shows loading state until WASM is ready
<button disabled={!isReady} onClick={startCamera}>
  {isReady ? 'Start Camera' : 'Loading...'}
</button>

Note: The WASM module is cached globally. Once loaded by any scanner instance, subsequent instances can use it immediately without reloading.

Browser (IIFE)

<script src="prescription-scanner.global.js"></script>
<script>
  const scanner = new PrescriptionScanner.PrescriptionScanner({
    preload: 'eager',
    onReady: () => console.log('Ready!'),
    onScan: (result) => alert('Scanned: ' + result.data)
  });

  document.getElementById('startBtn').onclick = async () => {
    await scanner.startCamera(document.getElementById('camera'));
  };
</script>

Options

interface ScannerOptions {
  // WASM Loading
  preload?: 'idle' | 'eager' | 'lazy' | false;  // Preload strategy (default: 'lazy')

  // Formats to detect
  formats?: ('DataMatrix' | 'QRCode')[];

  // Scan area (optional - default: full frame)
  scanBounds?: ScanBounds;

  // Callbacks
  onReady?: () => void;                   // Called when WASM is loaded
  onScan?: (result: ScanResult) => void;  // Called for each detected code
  onError?: (error: Error) => void;       // Called on errors
}

interface ScanBounds {
  x: number;      // X offset (0-1 relative or pixels)
  y: number;      // Y offset (0-1 relative or pixels)
  width: number;  // Width (0-1 relative or pixels)
  height: number; // Height (0-1 relative or pixels)
}

interface ScanResult {
  data: string;
  format: 'DataMatrix' | 'QRCode';
  timestamp: number;
  points: { x: number; y: number }[];  // Code position in full frame
}

API

new PrescriptionScanner(options)

Creates a new scanner instance.

Preload Methods

scanner.preload()

Preload WASM module in background. Returns Promise<void>. Triggers onReady when complete.

scanner.init()

Initialize scanner and load WASM. Returns Promise<void>. Triggers onReady when complete.

scanner.isReady()

Returns true if WASM is loaded and scanner is ready.

Camera Methods

scanner.startCamera(container)

Creates a video element in the container, requests camera access, and starts scanning. Returns the video element for custom styling.

scanner.start(videoElement)

Start scanning on an existing video element (must have camera stream attached).

scanner.stop()

Stop scanning and clean up camera stream and video element.

scanner.isScanning()

Returns true if currently scanning.

Static Methods

scanner.scanImage(image)

Scan an HTMLImageElement. Returns Promise<ScanResult[]>.

scanner.scanImageData(imageData)

Scan ImageData directly. Returns Promise<ScanResult[]>.

scanner.scanCanvas(canvas)

Scan an HTMLCanvasElement. Returns Promise<ScanResult[]>.

scanner.scanPDF(file)

Scan all pages of a PDF file. Returns Promise<ScanResult[]>.

Common Methods

scanner.getResults()

Returns all scanned results so far.

scanner.clearResults()

Clears all stored results, allowing the same codes to be scanned again.

scanner.setScanBounds(bounds)

Set the scan area. Values 0-1 are relative to frame size, >1 are absolute pixels.

// Scan center 50% of frame
scanner.setScanBounds({ x: 0.25, y: 0.25, width: 0.5, height: 0.5 });

// Scan full frame (default)
scanner.setScanBounds(null);

scanner.getScanBounds()

Returns current scan bounds or null if scanning full frame.

scanner.getComputedBounds()

Returns scan bounds in pixels based on current video dimensions.

scanner.destroy()

Cleanup - stops camera and removes event listeners.

PDF Support

PDF.js is loaded dynamically from CDN when needed (~200 KB). No additional setup required.

import { processPDF, isPDF } from 'prescription-scanner';

// Check if file is PDF
if (isPDF(file)) {
  const pages = await processPDF(file, {
    scale: 2,        // Render at 2x for better recognition
    maxPages: 10,    // Process max 10 pages
    onProgress: (current, total) => {
      console.log(`Processing page ${current}/${total}`);
    }
  });
}

Supported Formats

| Format | Use Case | |--------|----------| | DataMatrix | German prescriptions (eRezept), medical packaging | | QR Code | General purpose, URLs, vCards |

Building from Source

Prerequisites

  • Node.js 18+
  • Emscripten SDK (for WASM build)

Build JavaScript

npm run build

Build WASM (optional)

npm run build:wasm

Bundle Size

| File | Size | |------|------| | scanner.wasm | 442 KB | | scanner.js | 53 KB | | index.js (ESM) | 18 KB | | PDF.js (CDN, lazy) | ~200 KB | | Core Total | ~495 KB |

WASM loading is configurable via preload option: 'lazy' (default), 'idle', 'eager', or false. PDF.js is lazy-loaded only when processing PDFs.

Browser Support

  • Chrome 66+
  • Firefox 62+
  • Safari 12+
  • Edge 79+

Requires WebAssembly and getUserMedia (camera) support.

Changelog

v1.1.5

  • Added scanBounds option to limit scan area within video frame
  • Added setScanBounds(), getScanBounds(), getComputedBounds() methods
  • Bounds support relative (0-1) and absolute pixel values
  • Code positions in results are adjusted to full frame coordinates
  • Added ScanBounds demo page

v1.1.4

  • Added clearResults() method to allow rescanning same codes
  • Fixed camera restart bug (camera couldn't restart after stopping)
  • Renamed "Built-in Modal Demo" to "Lazyload Demo"
  • Added unit tests

v1.1.3

  • Configurable WASM preloading: 'idle', 'eager', 'lazy', or false
  • onReady callback: Get notified when WASM is loaded
  • Headless mode is now the default (headless: true)
  • Added camera API: startCamera(container), start(video), stop(), isScanning()
  • Added preload methods: preload(), init(), isReady()
  • Added static scan methods: scanImage(), scanImageData(), scanCanvas(), scanPDF()
  • Fixed modal scrolling when many codes are scanned
  • Added proper Apache 2.0 attribution for zxing-cpp

v1.1.2

  • Fixed README: clarified API classes

v1.1.1

  • Updated README and package.json documentation

v1.1.0

  • Added PDF support with PDF.js
  • Added multi-code detection
  • Added file upload UI (drag & drop)
  • Added image enhancement (upscaling, contrast adjustment)
  • Added onMultiScan callback
  • Added getResults() method
  • Added enhanceForScanning() utility

v1.0.0

  • Initial release

Third-Party Licenses

This package includes zxing-cpp for barcode decoding, licensed under Apache 2.0. See THIRD-PARTY-NOTICES for details.

License

MIT (this package) AND Apache-2.0 (zxing-cpp)