CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-zxing--library

TypeScript port of ZXing multi-format 1D/2D barcode image processing library

Overview
Eval results
Files

real-world-scenarios.mddocs/examples/

Real-World Scenarios

Production-ready patterns and complete implementations for common barcode use cases.

Product Inventory Scanner

Mobile-responsive barcode scanner for inventory management:

import {
  BrowserMultiFormatReader,
  BarcodeFormat,
  DecodeHintType,
  Result
} from '@zxing/library';

interface InventoryItem {
  code: string;
  format: BarcodeFormat;
  timestamp: Date;
}

class InventoryScanner {
  private reader: BrowserMultiFormatReader;
  private scanning = false;
  private items: InventoryItem[] = [];
  private seenCodes = new Set<string>();

  constructor() {
    const hints = new Map();
    hints.set(DecodeHintType.POSSIBLE_FORMATS, [
      BarcodeFormat.EAN_13,
      BarcodeFormat.UPC_A,
      BarcodeFormat.CODE_128,
      BarcodeFormat.QR_CODE
    ]);
    
    this.reader = new BrowserMultiFormatReader(hints, 300);
  }

  async start(videoElement: HTMLVideoElement): Promise<void> {
    this.scanning = true;
    
    await this.reader.decodeFromVideoDevice(
      null,
      videoElement,
      (result, error) => {
        if (!this.scanning || !result) return;
        
        const code = result.getText();
        
        // Only process new codes
        if (!this.seenCodes.has(code)) {
          this.seenCodes.add(code);
          
          this.items.push({
            code,
            format: result.getBarcodeFormat(),
            timestamp: new Date()
          });
          
          this.onItemScanned(code, result.getBarcodeFormat());
          this.playBeep();
        }
      }
    );
  }

  stop(): void {
    this.scanning = false;
    this.reader.stopContinuousDecode();
    this.reader.reset();
  }

  getItems(): InventoryItem[] {
    return [...this.items];
  }

  clearItems(): void {
    this.items = [];
    this.seenCodes.clear();
  }

  private onItemScanned(code: string, format: BarcodeFormat): void {
    console.log(`Scanned ${format}: ${code}`);
    this.updateUI();
  }

  private updateUI(): void {
    const list = document.getElementById('item-list')!;
    list.innerHTML = this.items
      .map(item => `
        <div class="item">
          <strong>${item.code}</strong>
          <span>${item.format}</span>
          <span>${item.timestamp.toLocaleTimeString()}</span>
        </div>
      `)
      .join('');
    
    document.getElementById('count')!.textContent = `${this.items.length}`;
  }

  private playBeep(): void {
    const audio = document.getElementById('beep') as HTMLAudioElement;
    audio?.play().catch(() => {});
  }
}

// HTML setup
/*
<video id="video" width="100%" autoplay></video>
<div id="count">0</div>
<div id="item-list"></div>
<audio id="beep" src="beep.mp3"></audio>
<button id="start">Start</button>
<button id="stop">Stop</button>
<button id="clear">Clear</button>
*/

const scanner = new InventoryScanner();
const video = document.getElementById('video') as HTMLVideoElement;

document.getElementById('start')!.onclick = () => scanner.start(video);
document.getElementById('stop')!.onclick = () => scanner.stop();
document.getElementById('clear')!.onclick = () => {
  scanner.clearItems();
  document.getElementById('item-list')!.innerHTML = '';
  document.getElementById('count')!.textContent = '0';
};

QR Code Business Card Generator

Generate vCard QR codes for business cards:

import {
  QRCodeWriter,
  BarcodeFormat,
  EncodeHintType,
  QRCodeDecoderErrorCorrectionLevel
} from '@zxing/library';

interface ContactInfo {
  name: string;
  email?: string;
  phone?: string;
  company?: string;
  title?: string;
  url?: string;
}

function generateVCardQR(contact: ContactInfo, size: number = 400): HTMLCanvasElement {
  // Build vCard format
  let vcard = 'BEGIN:VCARD\n';
  vcard += 'VERSION:3.0\n';
  vcard += `FN:${contact.name}\n`;
  
  if (contact.email) vcard += `EMAIL:${contact.email}\n`;
  if (contact.phone) vcard += `TEL:${contact.phone}\n`;
  if (contact.company) vcard += `ORG:${contact.company}\n`;
  if (contact.title) vcard += `TITLE:${contact.title}\n`;
  if (contact.url) vcard += `URL:${contact.url}\n`;
  
  vcard += 'END:VCARD';
  
  // Generate QR Code
  const writer = new QRCodeWriter();
  const hints = new Map();
  hints.set(EncodeHintType.ERROR_CORRECTION, QRCodeDecoderErrorCorrectionLevel.M);
  hints.set(EncodeHintType.CHARACTER_SET, 'UTF-8');
  
  const matrix = writer.encode(vcard, BarcodeFormat.QR_CODE, size, size, hints);
  
  // Render to canvas
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d')!;
  const moduleSize = Math.floor(size / matrix.getWidth());
  
  canvas.width = matrix.getWidth() * moduleSize;
  canvas.height = matrix.getHeight() * moduleSize;
  
  // White background
  ctx.fillStyle = '#FFFFFF';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  
  // Black modules
  ctx.fillStyle = '#000000';
  for (let y = 0; y < matrix.getHeight(); y++) {
    for (let x = 0; x < matrix.getWidth(); x++) {
      if (matrix.get(x, y)) {
        ctx.fillRect(x * moduleSize, y * moduleSize, moduleSize, moduleSize);
      }
    }
  }
  
  return canvas;
}

// Usage
const contact: ContactInfo = {
  name: 'John Doe',
  email: 'john@example.com',
  phone: '+1-555-0100',
  company: 'Example Corp',
  title: 'Software Engineer',
  url: 'https://example.com'
};

const qrCanvas = generateVCardQR(contact);
document.getElementById('container')!.appendChild(qrCanvas);

Ticket Validation System

Validate QR code tickets with signature verification:

import {
  QRCodeReader,
  QRCodeWriter,
  BarcodeFormat,
  BinaryBitmap,
  HybridBinarizer,
  RGBLuminanceSource
} from '@zxing/library';
import crypto from 'crypto';

interface Ticket {
  id: string;
  eventId: string;
  userId: string;
  timestamp: number;
  signature: string;
}

class TicketSystem {
  private secret: string;

  constructor(secret: string) {
    this.secret = secret;
  }

  generateTicket(ticketData: Omit<Ticket, 'signature'>): string {
    const data = JSON.stringify(ticketData);
    const signature = this.sign(data);
    
    const ticket: Ticket = {
      ...ticketData,
      signature
    };
    
    return JSON.stringify(ticket);
  }

  generateTicketQR(ticketData: Omit<Ticket, 'signature'>, size: number = 300): BitMatrix {
    const ticketJson = this.generateTicket(ticketData);
    
    const writer = new QRCodeWriter();
    const hints = new Map();
    hints.set(EncodeHintType.ERROR_CORRECTION, 'H');
    
    return writer.encode(ticketJson, BarcodeFormat.QR_CODE, size, size, hints);
  }

  validateTicket(qrData: string): { valid: boolean; ticket?: Ticket; error?: string } {
    try {
      const ticket: Ticket = JSON.parse(qrData);
      
      // Verify signature
      const { signature, ...data } = ticket;
      const expectedSignature = this.sign(JSON.stringify(data));
      
      if (signature !== expectedSignature) {
        return { valid: false, error: 'Invalid signature' };
      }
      
      // Check expiration (if needed)
      const age = Date.now() - ticket.timestamp;
      if (age > 24 * 60 * 60 * 1000) { // 24 hours
        return { valid: false, error: 'Ticket expired' };
      }
      
      return { valid: true, ticket };
    } catch (error) {
      return { valid: false, error: 'Invalid ticket data' };
    }
  }

  private sign(data: string): string {
    return crypto
      .createHmac('sha256', this.secret)
      .update(data)
      .digest('hex')
      .substring(0, 16);
  }
}

// Usage
const ticketSystem = new TicketSystem('my-secret-key');

// Generate ticket
const ticketData = {
  id: 'T12345',
  eventId: 'EVT001',
  userId: 'USR789',
  timestamp: Date.now()
};

const qrMatrix = ticketSystem.generateTicketQR(ticketData);
// Render qrMatrix to display...

// Validate scanned ticket
const scannedData = "..."; // From QR code scan
const validation = ticketSystem.validateTicket(scannedData);

if (validation.valid) {
  console.log('Valid ticket:', validation.ticket);
  // Grant access
} else {
  console.error('Invalid ticket:', validation.error);
  // Deny access
}

Shipping Label Reader

Decode shipping labels with multiple barcodes:

import {
  PDF417Reader,
  MultiFormatReader,
  BarcodeFormat,
  DecodeHintType,
  Result
} from '@zxing/library';

interface ShippingLabel {
  trackingNumber?: string;
  destination?: string;
  weight?: string;
  orderNumber?: string;
}

async function readShippingLabel(imagePath: string): Promise<ShippingLabel> {
  const { data, info } = await sharp(imagePath).raw().toBuffer({ resolveWithObject: true });
  
  const luminanceSource = new RGBLuminanceSource(
    new Uint8ClampedArray(data),
    info.width,
    info.height
  );
  
  const bitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));
  
  // Try PDF417 first (common for shipping labels)
  const pdf417Reader = new PDF417Reader();
  try {
    const results = pdf417Reader.decodeMultiple(bitmap);
    return parseShippingData(results);
  } catch (e) {}
  
  // Fall back to 1D barcodes
  const hints = new Map();
  hints.set(DecodeHintType.POSSIBLE_FORMATS, [
    BarcodeFormat.CODE_128,
    BarcodeFormat.ITF
  ]);
  
  const reader = new MultiFormatReader();
  const result = reader.decode(bitmap, hints);
  
  return {
    trackingNumber: result.getText()
  };
}

function parseShippingData(results: Result[]): ShippingLabel {
  const label: ShippingLabel = {};
  
  results.forEach(result => {
    const text = result.getText();
    
    // Parse based on format or content
    if (text.match(/^1Z\w{16}$/)) {
      label.trackingNumber = text; // UPS format
    } else if (text.match(/^\d{20,22}$/)) {
      label.trackingNumber = text; // FedEx format
    }
    // Add more parsing logic as needed
  });
  
  return label;
}

Multi-Format Barcode Printer

Generate multiple barcode formats for product labels:

import {
  MultiFormatWriter,
  QRCodeWriter,
  DataMatrixWriter,
  BarcodeFormat,
  EncodeHintType,
  SymbolShapeHint
} from '@zxing/library';

interface ProductLabel {
  sku: string;
  name: string;
  price: number;
  qrData: string;
}

function generateProductLabel(product: ProductLabel): {
  ean13: BitMatrix | null;
  qrCode: BitMatrix;
  dataMatrix: BitMatrix;
} {
  const writer = new MultiFormatWriter();
  
  // EAN-13 barcode (if SKU is 12-13 digits)
  let ean13: BitMatrix | null = null;
  if (product.sku.match(/^\d{12,13}$/)) {
    try {
      ean13 = writer.encode(
        product.sku,
        BarcodeFormat.EAN_13,
        200,
        100,
        new Map()
      );
    } catch (e) {}
  }
  
  // QR Code with product info
  const qrWriter = new QRCodeWriter();
  const qrHints = new Map();
  qrHints.set(EncodeHintType.ERROR_CORRECTION, 'M');
  
  const qrCode = qrWriter.encode(
    product.qrData,
    BarcodeFormat.QR_CODE,
    200,
    200,
    qrHints
  );
  
  // Data Matrix with SKU
  const dmWriter = new DataMatrixWriter();
  const dmHints = new Map();
  dmHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
  
  const dataMatrix = dmWriter.encode(
    product.sku,
    BarcodeFormat.DATA_MATRIX,
    100,
    100,
    dmHints
  );
  
  return { ean13, qrCode, dataMatrix };
}

// Usage
const product: ProductLabel = {
  sku: '5901234123457',
  name: 'Example Product',
  price: 29.99,
  qrData: 'https://example.com/product/5901234123457'
};

const barcodes = generateProductLabel(product);

// Render all barcodes to label
if (barcodes.ean13) {
  renderToCanvas(barcodes.ean13, document.getElementById('ean13') as HTMLCanvasElement);
}
renderToCanvas(barcodes.qrCode, document.getElementById('qr') as HTMLCanvasElement);
renderToCanvas(barcodes.dataMatrix, document.getElementById('dm') as HTMLCanvasElement);

Retail Checkout Scanner

Point-of-sale barcode scanner with product lookup:

import {
  BrowserBarcodeReader,
  BarcodeFormat,
  DecodeHintType
} from '@zxing/library';

interface Product {
  code: string;
  name: string;
  price: number;
}

class CheckoutScanner {
  private reader: BrowserBarcodeReader;
  private database: Map<string, Product>;

  constructor(productDatabase: Product[]) {
    const hints = new Map();
    hints.set(DecodeHintType.POSSIBLE_FORMATS, [
      BarcodeFormat.EAN_13,
      BarcodeFormat.UPC_A,
      BarcodeFormat.EAN_8,
      BarcodeFormat.UPC_E
    ]);
    
    this.reader = new BrowserBarcodeReader(500, hints);
    this.database = new Map(productDatabase.map(p => [p.code, p]));
  }

  async startScanning(videoElement: HTMLVideoElement): Promise<void> {
    await this.reader.decodeFromVideoDevice(
      null,
      videoElement,
      (result, error) => {
        if (!result) return;
        
        const code = result.getText();
        const product = this.database.get(code);
        
        if (product) {
          this.addToCart(product);
        } else {
          this.showError(`Product not found: ${code}`);
        }
      }
    );
  }

  stop(): void {
    this.reader.stopContinuousDecode();
    this.reader.reset();
  }

  private addToCart(product: Product): void {
    console.log('Added to cart:', product);
    // Update cart UI
  }

  private showError(message: string): void {
    console.error(message);
    // Show error in UI
  }
}

Document Scanner with Data Matrix

Medical/pharmaceutical document scanning:

import {
  DataMatrixReader,
  BinaryBitmap,
  HybridBinarizer,
  RGBLuminanceSource,
  DecodeHintType
} from '@zxing/library';

interface MedicalDocument {
  ndc: string;        // National Drug Code
  lot: string;        // Lot number
  expiration: string; // Expiration date
  serial: string;     // Serial number
}

async function scanMedicalLabel(imagePath: string): Promise<MedicalDocument | null> {
  const { data, info } = await sharp(imagePath).raw().toBuffer({ resolveWithObject: true });
  
  const luminanceSource = new RGBLuminanceSource(
    new Uint8ClampedArray(data),
    info.width,
    info.height
  );
  
  const bitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));
  const reader = new DataMatrixReader();
  
  const hints = new Map();
  hints.set(DecodeHintType.PURE_BARCODE, true);
  
  try {
    const result = reader.decode(bitmap, hints);
    const text = result.getText();
    
    // Parse GS1 format: (01)NDC(17)YYMMDD(10)LOT(21)SERIAL
    return parseGS1DataMatrix(text);
  } catch (error) {
    console.error('Failed to read Data Matrix:', error);
    return null;
  }
}

function parseGS1DataMatrix(data: string): MedicalDocument | null {
  const aiPattern = /\((\d{2})\)([^\(]+)/g;
  const ais = new Map<string, string>();
  
  let match;
  while ((match = aiPattern.exec(data)) !== null) {
    ais.set(match[1], match[2]);
  }
  
  return {
    ndc: ais.get('01') || '',
    expiration: ais.get('17') || '',
    lot: ais.get('10') || '',
    serial: ais.get('21') || ''
  };
}

WiFi QR Code Generator

Generate WiFi credential QR codes:

import {
  QRCodeWriter,
  BarcodeFormat,
  EncodeHintType,
  QRCodeDecoderErrorCorrectionLevel
} from '@zxing/library';

interface WiFiCredentials {
  ssid: string;
  password: string;
  security: 'WPA' | 'WEP' | 'nopass';
  hidden?: boolean;
}

function generateWiFiQR(wifi: WiFiCredentials, size: number = 300): BitMatrix {
  // WiFi QR format: WIFI:T:WPA;S:ssid;P:password;H:true;;
  let wifiString = `WIFI:T:${wifi.security};S:${escapeWiFi(wifi.ssid)};`;
  
  if (wifi.security !== 'nopass') {
    wifiString += `P:${escapeWiFi(wifi.password)};`;
  }
  
  if (wifi.hidden) {
    wifiString += 'H:true;';
  }
  
  wifiString += ';';
  
  const writer = new QRCodeWriter();
  const hints = new Map();
  hints.set(EncodeHintType.ERROR_CORRECTION, QRCodeDecoderErrorCorrectionLevel.M);
  
  return writer.encode(wifiString, BarcodeFormat.QR_CODE, size, size, hints);
}

function escapeWiFi(str: string): string {
  return str.replace(/([\\";,:])/g, '\\$1');
}

// Usage
const wifi: WiFiCredentials = {
  ssid: 'MyNetwork',
  password: 'SecurePassword123',
  security: 'WPA'
};

const qrMatrix = generateWiFiQR(wifi);
// Render qrMatrix...

Batch Image Processing

Process multiple barcode images in parallel:

import {
  MultiFormatReader,
  BinaryBitmap,
  HybridBinarizer,
  RGBLuminanceSource,
  DecodeHintType
} from '@zxing/library';
import sharp from 'sharp';
import { promises as fs } from 'fs';
import path from 'path';

interface DecodeResult {
  filename: string;
  success: boolean;
  text?: string;
  format?: BarcodeFormat;
  error?: string;
}

async function processBarcodeImages(dirPath: string): Promise<DecodeResult[]> {
  const files = await fs.readdir(dirPath);
  const imageFiles = files.filter(f => f.match(/\.(png|jpg|jpeg)$/i));
  
  // Process in parallel
  const promises = imageFiles.map(file => 
    decodeImageFile(path.join(dirPath, file))
      .then(result => ({
        filename: file,
        success: true,
        text: result.text,
        format: result.format
      }))
      .catch(error => ({
        filename: file,
        success: false,
        error: error.message
      }))
  );
  
  return Promise.all(promises);
}

async function decodeImageFile(filePath: string): Promise<{ text: string; format: BarcodeFormat }> {
  const { data, info } = await sharp(filePath)
    .raw()
    .toBuffer({ resolveWithObject: true });
  
  const luminanceSource = new RGBLuminanceSource(
    new Uint8ClampedArray(data),
    info.width,
    info.height
  );
  
  const bitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));
  
  const reader = new MultiFormatReader();
  const hints = new Map();
  hints.set(DecodeHintType.TRY_HARDER, true);
  
  const result = reader.decode(bitmap, hints);
  
  return {
    text: result.getText(),
    format: result.getBarcodeFormat()
  };
}

// Usage
const results = await processBarcodeImages('./images');

console.log(`Processed ${results.length} images`);
console.log(`Successful: ${results.filter(r => r.success).length}`);
console.log(`Failed: ${results.filter(r => !r.success).length}`);

results.forEach(result => {
  if (result.success) {
    console.log(`${result.filename}: ${result.format} = ${result.text}`);
  } else {
    console.log(`${result.filename}: ${result.error}`);
  }
});

Related

  • Quick Start Guide
  • Edge Cases
  • API Reference

Install with Tessl CLI

npx tessl i tessl/npm-zxing--library@0.21.14

docs

examples

edge-cases.md

real-world-scenarios.md

index.md

tile.json