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

oned-barcodes.mddocs/reference/

1D Barcode Reading

Comprehensive API documentation for reading 1D (one-dimensional) barcodes in @zxing/library. These readers support common linear barcode formats including EAN-13, EAN-8, UPC-A, UPC-E, Code 128, Code 39, Code 93, ITF, Codabar, RSS-14, and RSS-Expanded.

Package Information

  • Package Name: @zxing/library
  • Package Type: npm
  • Language: TypeScript
  • Module Path: core/oned/
  • Standards: Various (GS1, ISO/IEC, ANSI)

Core Imports

import {
  // Base and multi-format
  OneDReader,
  MultiFormatOneDReader,
  
  // UPC/EAN formats
  EAN13Reader,
  EAN8Reader,
  UPCAReader,
  UPCEReader,
  UPCEANReader,
  
  // Code formats
  Code128Reader,
  Code39Reader,
  Code93Reader,
  
  // Other 1D formats
  ITFReader,
  CodaBarReader,
  RSS14Reader,
  RSSExpandedReader,
  
  // Supporting types
  BarcodeFormat,
  DecodeHintType,
  Result,
  BitArray,
  BinaryBitmap
} from "@zxing/library";

For CommonJS:

const {
  OneDReader,
  MultiFormatOneDReader,
  EAN13Reader,
  EAN8Reader,
  UPCAReader,
  UPCEReader,
  Code128Reader,
  Code39Reader,
  Code93Reader,
  ITFReader,
  CodaBarReader,
  RSS14Reader,
  RSSExpandedReader,
} = require("@zxing/library");

Basic Usage

import {
  MultiFormatOneDReader,
  BinaryBitmap,
  HybridBinarizer,
  RGBLuminanceSource,
  DecodeHintType,
  BarcodeFormat,
  Result
} from "@zxing/library";

// Prepare image data
const luminanceSource = new RGBLuminanceSource(imageData, width, height);
const binarizer = new HybridBinarizer(luminanceSource);
const bitmap = new BinaryBitmap(binarizer);

// Create reader
const reader = new MultiFormatOneDReader();

// Decode barcode
try {
  const result: Result = reader.decode(bitmap);
  console.log("Decoded text:", result.getText());
  console.log("Format:", result.getBarcodeFormat());
} catch (error) {
  console.error("Decoding failed:", error);
}

// With hints for specific formats
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.POSSIBLE_FORMATS, [
  BarcodeFormat.CODE_128,
  BarcodeFormat.EAN_13,
  BarcodeFormat.UPC_A
]);
hints.set(DecodeHintType.TRY_HARDER, true);

const reader2 = new MultiFormatOneDReader(hints);
const result2: Result = reader2.decode(bitmap, hints);

Architecture

The 1D barcode reading system is built around several key components:

  • Base Reader: OneDReader provides common functionality for all 1D barcode formats including row scanning, pattern matching, and rotation support
  • Multi-Format Reader: MultiFormatOneDReader attempts to decode using multiple format-specific readers
  • Format-Specific Readers: Specialized readers for each barcode format (EAN-13, Code 128, etc.)
  • Pattern Matching: All readers use pattern recognition to identify barcode elements (bars and spaces)
  • Row Scanning: Images are scanned horizontally from the center outward to locate barcodes

Capabilities

OneDReader - Base 1D Barcode Reader

Abstract base class providing common functionality for all 1D barcode readers including row scanning, pattern matching, and rotation support.

/**
 * Abstract base class for 1D barcode readers
 * Provides common decoding logic including row scanning and pattern matching
 */
abstract class OneDReader implements Reader {
  /**
   * Decode a barcode from a binary bitmap
   * Scans rows from center outward, tries both directions
   * @param image - BinaryBitmap: binary image containing the barcode
   * @param hints - Map<DecodeHintType, any>: optional hints (TRY_HARDER enables rotation)
   * @returns Result: decoded barcode with text and metadata
   * @throws NotFoundException if no barcode is found
   * @throws FormatException if barcode format is invalid
   * @throws ChecksumException if checksum validation fails
   */
  decode(image: BinaryBitmap, hints?: Map<DecodeHintType, any>): Result;

  /**
   * Reset reader state between decoding attempts
   */
  reset(): void;

  /**
   * Decode a barcode from a single row of pixels (implemented by subclasses)
   * @param rowNumber - number: row number from top of image (0-based)
   * @param row - BitArray: bit array representing black/white pixels
   * @param hints - Map<DecodeHintType, any>: optional decoding hints
   * @returns Result: decoded barcode data
   * @throws NotFoundException if no barcode found in this row
   * @throws FormatException if barcode is invalid
   * @throws ChecksumException if checksum fails
   */
  abstract decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;

  /**
   * Records runs of black/white pixels into counters array
   * Starts at 'start' position and fills counters with run lengths
   * @param row - BitArray: bit array to read from
   * @param start - number: starting offset in row
   * @param counters - Int32Array: array to fill with run lengths (modified in place)
   * @throws NotFoundException if pattern cannot be recorded
   */
  protected static recordPattern(
    row: BitArray,
    start: number,
    counters: Int32Array
  ): void;

  /**
   * Records pattern in reverse direction (right to left)
   * @param row - BitArray: bit array to read from
   * @param start - number: starting offset in row
   * @param counters - Int32Array: array to fill with run lengths (modified in place)
   * @throws NotFoundException if pattern cannot be recorded
   */
  protected static recordPatternInReverse(
    row: BitArray,
    start: number,
    counters: Int32Array
  ): void;

  /**
   * Calculate variance between observed and expected pattern
   * Lower variance means better match
   * @param counters - Int32Array: observed run lengths
   * @param pattern - Int32Array: expected pattern (proportional widths)
   * @param maxIndividualVariance - number: maximum allowed variance per element
   * @returns number: total variance ratio (lower is better, infinity if exceeds max)
   */
  protected static patternMatchVariance(
    counters: Int32Array,
    pattern: Int32Array,
    maxIndividualVariance: number
  ): number;
}

Key Features:

  • Scans image rows from center outward for efficient barcode location
  • Supports 90-degree rotation when TRY_HARDER hint is enabled
  • Attempts both normal (left-to-right) and reversed (right-to-left) reading directions
  • Provides pattern matching utilities for subclasses to identify barcode elements

Usage Example:

import {
  Code128Reader,
  BinaryBitmap,
  HybridBinarizer,
  RGBLuminanceSource,
  Result,
  DecodeHintType
} from "@zxing/library";

// Custom implementation extending OneDReader
class CustomOneDReader extends OneDReader {
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result {
    // Custom barcode decoding logic
    const counters = new Int32Array(6);
    const startPos = this.findStartPattern(row);
    
    // Record pattern from start position
    OneDReader.recordPattern(row, startPos, counters);
    
    // Match against expected pattern
    const expectedPattern = new Int32Array([1, 1, 1, 1, 1, 1]);
    const variance = OneDReader.patternMatchVariance(
      counters,
      expectedPattern,
      0.5 // Max individual variance
    );
    
    if (variance < 0.3) {
      // Good match - decode the pattern
      return this.constructResult(counters, rowNumber);
    }
    
    throw new NotFoundException();
  }
  
  // Helper methods would be implemented here
}

// Using a concrete 1D reader
const reader = new Code128Reader();
const luminanceSource = new RGBLuminanceSource(imageData, width, height);
const bitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));

const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.TRY_HARDER, true); // Enables rotation attempts

try {
  const result: Result = reader.decode(bitmap, hints);
  console.log("Decoded:", result.getText());
} catch (error) {
  console.error("Failed:", error);
}

Multi-Format Reader

MultiFormatOneDReader

Multi-format 1D barcode reader that attempts decoding with multiple format-specific readers. Automatically selects appropriate readers based on hints.

/**
 * Multi-format 1D barcode reader
 * Attempts to decode using multiple format-specific readers in sequence
 */
class MultiFormatOneDReader extends OneDReader {
  /**
   * Create multi-format reader with optional format hints
   * @param hints - Map<DecodeHintType, any>: optional hints specifying which formats to try
   *   - POSSIBLE_FORMATS: BarcodeFormat[] limits attempted formats
   *   - TRY_HARDER: boolean enables rotation and more thorough scanning
   *   - Other format-specific hints (ASSUME_CODE_39_CHECK_DIGIT, etc.)
   */
  constructor(hints?: Map<DecodeHintType, any>);

  /**
   * Attempt to decode row using all configured readers
   * Tries readers in order until one succeeds
   * @param rowNumber - number: row number from top of image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decoding hints
   * @returns Result: decoded data from first successful reader
   * @throws NotFoundException if no reader can decode the row
   * @throws FormatException if barcode found but invalid
   * @throws ChecksumException if checksum validation fails
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;

  /**
   * Reset all internal readers
   * Clears cached state from all format-specific readers
   */
  reset(): void;
}

Supported Formats:

By default (no POSSIBLE_FORMATS hint), attempts to decode:

  • UPC/EAN formats: UPC-A, UPC-E, EAN-8, EAN-13
  • Code 39: Alphanumeric 1D barcode
  • Code 93: High-density alphanumeric
  • Code 128: High-density ASCII barcode
  • ITF: Interleaved Two of Five
  • RSS-14: GS1 DataBar (Reduced Space Symbology)
  • Codabar: Self-checking numeric barcode

With POSSIBLE_FORMATS hint, only specified formats are attempted (improves performance).

Usage Examples:

import {
  MultiFormatOneDReader,
  BinaryBitmap,
  DecodeHintType,
  BarcodeFormat,
  Result
} from "@zxing/library";

// Basic usage - tries all formats
const reader = new MultiFormatOneDReader();
try {
  const result: Result = reader.decode(bitmap);
  console.log(`Decoded: ${result.getText()}`);
  console.log(`Format: ${result.getBarcodeFormat()}`);
} catch (error) {
  console.error("No 1D barcode found:", error);
}

// With format hints - only try specific formats (faster)
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.POSSIBLE_FORMATS, [
  BarcodeFormat.CODE_128,
  BarcodeFormat.CODE_39,
  BarcodeFormat.EAN_13,
]);

const reader2 = new MultiFormatOneDReader(hints);
const result2: Result = reader2.decode(bitmap, hints);

// With TRY_HARDER for difficult barcodes
const hardHints = new Map<DecodeHintType, any>();
hardHints.set(DecodeHintType.TRY_HARDER, true);
hardHints.set(DecodeHintType.POSSIBLE_FORMATS, [
  BarcodeFormat.CODE_128
]);

const reader3 = new MultiFormatOneDReader(hardHints);
const result3: Result = reader3.decode(bitmap, hardHints);

// With extended Code 39 mode
const code39Hints = new Map<DecodeHintType, any>();
code39Hints.set(DecodeHintType.POSSIBLE_FORMATS, [BarcodeFormat.CODE_39]);
code39Hints.set(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT, true);
code39Hints.set(DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE, true);

const reader4 = new MultiFormatOneDReader(code39Hints);
const result4: Result = reader4.decode(bitmap, code39Hints);

// GS1-128 (Code 128 with GS1 Application Identifiers)
const gs1Hints = new Map<DecodeHintType, any>();
gs1Hints.set(DecodeHintType.POSSIBLE_FORMATS, [BarcodeFormat.CODE_128]);
gs1Hints.set(DecodeHintType.ASSUME_GS1, true);

const reader5 = new MultiFormatOneDReader(gs1Hints);
const result5: Result = reader5.decode(bitmap, gs1Hints);

// Continuous scanning with reader reuse
const continuousReader = new MultiFormatOneDReader(hints);

for (const frame of videoFrames) {
  try {
    const result: Result = continuousReader.decode(frame);
    console.log("Found:", result.getText());
    break; // Stop on first success
  } catch (error) {
    // Continue to next frame
  }
}

continuousReader.reset(); // Clean up when done

EAN-13 Reader

EAN13Reader

EAN-13 barcode reader for European Article Number 13-digit product codes. Commonly used for retail product identification worldwide.

/**
 * EAN-13 barcode reader
 * Decodes 13-digit European Article Number barcodes
 * Most common barcode format for retail products globally
 */
class EAN13Reader extends UPCEANReader {
  /**
   * Create EAN-13 reader
   */
  constructor();

  /**
   * Decode EAN-13 barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data (true=black, false=white)
   * @param hints - Map<DecodeHintType, any>: optional decode hints
   *   - ALLOWED_EAN_EXTENSIONS: Int32Array([2, 5]) for extension support
   * @returns Result: decoded 13-digit EAN code with optional extension
   * @throws NotFoundException if EAN-13 pattern not found
   * @throws FormatException if pattern is invalid
   * @throws ChecksumException if check digit validation fails
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;

  /**
   * Get the barcode format
   * @returns BarcodeFormat: always BarcodeFormat.EAN_13
   */
  getBarcodeFormat(): BarcodeFormat;
}

Format Specification:

  • Structure: 13 digits total in format: C1 C2 C3 M1 M2 M3 M4 M5 P1 P2 P3 P4 P5 K
    • C1-C3: Country/GS1 prefix (3 digits)
    • M1-M5: Manufacturer code (5 digits)
    • P1-P5: Product code (5 digits)
    • K: Check digit (1 digit, calculated using modulo 10)
  • Encoding: First digit encoded in left-side pattern choice
  • Left patterns: 6 digits using L (odd parity) and G (even parity) patterns
  • Right patterns: 6 digits using R patterns
  • Guard patterns: Start, middle, and end guards

Usage Examples:

import {
  EAN13Reader,
  BinaryBitmap,
  Result,
  ResultMetadataType,
  BarcodeFormat,
  DecodeHintType
} from "@zxing/library";

// Basic EAN-13 decoding
const reader = new EAN13Reader();
try {
  const result: Result = reader.decode(bitmap);
  const code: string = result.getText();
  
  console.log(`EAN-13: ${code}`); // e.g., "5901234123457"
  
  // Parse components
  if (code.length === 13) {
    const country: string = code.substring(0, 3);
    const manufacturer: string = code.substring(3, 8);
    const product: string = code.substring(8, 13);
    
    console.log(`Country/GS1: ${country}`);
    console.log(`Manufacturer: ${manufacturer}`);
    console.log(`Product: ${product}`);
    console.log(`Check digit: ${code.charAt(12)}`);
  }
} catch (error) {
  console.error("EAN-13 decode failed:", error);
}

// With UPC/EAN extensions (2 or 5 digit supplements)
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.ALLOWED_EAN_EXTENSIONS, new Int32Array([2, 5]));

try {
  const result2: Result = reader.decode(bitmap, hints);
  const extension = result2.getResultMetadata()?.get(ResultMetadataType.UPC_EAN_EXTENSION);
  
  if (extension) {
    console.log(`Main code: ${result2.getText()}`);
    console.log(`Extension: ${extension}`);
    
    // 2-digit extension typically encodes issue number (magazines)
    // 5-digit extension typically encodes suggested retail price
  }
} catch (error) {
  console.error("EAN-13 with extension decode failed:", error);
}

// Validate EAN-13 check digit
function validateEAN13CheckDigit(code: string): boolean {
  if (code.length !== 13) return false;
  
  let sum = 0;
  for (let i = 0; i < 12; i++) {
    const digit = parseInt(code.charAt(i), 10);
    sum += (i % 2 === 0) ? digit : digit * 3;
  }
  
  const checkDigit = (10 - (sum % 10)) % 10;
  return checkDigit === parseInt(code.charAt(12), 10);
}

console.log("Valid check digit:", validateEAN13CheckDigit("5901234123457"));

// Country prefixes (examples)
function getCountryPrefix(ean13: string): string {
  const prefix = ean13.substring(0, 3);
  const countryMap: {[key: string]: string} = {
    '000-019': 'US/Canada',
    '020-029': 'Restricted (in-store)',
    '030-039': 'US Drugs',
    '040-049': 'Restricted (in-store)',
    '050-059': 'Coupons',
    '060-139': 'US/Canada',
    '200-299': 'Restricted (in-store)',
    '300-379': 'France',
    '380': 'Bulgaria',
    '400-440': 'Germany',
    '450-459': 'Japan',
    '460-469': 'Russia',
    '470': 'Kyrgyzstan',
    '471': 'Taiwan',
    '474': 'Estonia',
    '475': 'Latvia',
    '476': 'Azerbaijan',
    '477': 'Lithuania',
    '478': 'Uzbekistan',
    '479': 'Sri Lanka',
    '480': 'Philippines',
    '481': 'Belarus',
    '482': 'Ukraine',
    '484': 'Moldova',
    '485': 'Armenia',
    '486': 'Georgia',
    '487': 'Kazakhstan',
    '489': 'Hong Kong',
    '490-499': 'Japan',
    '500-509': 'UK',
    '520-521': 'Greece',
    '528': 'Lebanon',
    '529': 'Cyprus',
    '530': 'Albania',
    '531': 'Macedonia',
    '535': 'Malta',
    '539': 'Ireland',
    '540-549': 'Belgium/Luxembourg',
    '560': 'Portugal',
    '569': 'Iceland',
    '570-579': 'Denmark',
    '590': 'Poland',
    '594': 'Romania',
    '599': 'Hungary',
    '600-601': 'South Africa',
    '603': 'Ghana',
    '604': 'Senegal',
    '608': 'Bahrain',
    '609': 'Mauritius',
    '611': 'Morocco',
    '613': 'Algeria',
    '615': 'Nigeria',
    '616': 'Kenya',
    '618': 'Ivory Coast',
    '619': 'Tunisia',
    '621': 'Syria',
    '622': 'Egypt',
    '624': 'Libya',
    '625': 'Jordan',
    '626': 'Iran',
    '627': 'Kuwait',
    '628': 'Saudi Arabia',
    '629': 'UAE',
    '640-649': 'Finland',
    '690-699': 'China',
    '700-709': 'Norway',
    '729': 'Israel',
    '730-739': 'Sweden',
    '740': 'Guatemala',
    '741': 'El Salvador',
    '742': 'Honduras',
    '743': 'Nicaragua',
    '744': 'Costa Rica',
    '745': 'Panama',
    '746': 'Dominican Republic',
    '750': 'Mexico',
    '754-755': 'Canada',
    '759': 'Venezuela',
    '760-769': 'Switzerland',
    '770-771': 'Colombia',
    '773': 'Uruguay',
    '775': 'Peru',
    '777': 'Bolivia',
    '778-779': 'Argentina',
    '780': 'Chile',
    '784': 'Paraguay',
    '786': 'Ecuador',
    '789-790': 'Brazil',
    '800-839': 'Italy',
    '840-849': 'Spain',
    '850': 'Cuba',
    '858': 'Slovakia',
    '859': 'Czech Republic',
    '860': 'Serbia',
    '865': 'Mongolia',
    '867': 'North Korea',
    '868-869': 'Turkey',
    '870-879': 'Netherlands',
    '880': 'South Korea',
    '884': 'Cambodia',
    '885': 'Thailand',
    '888': 'Singapore',
    '890': 'India',
    '893': 'Vietnam',
    '896': 'Pakistan',
    '899': 'Indonesia',
    '900-919': 'Austria',
    '930-939': 'Australia',
    '940-949': 'New Zealand',
    '950': 'GS1 Global Office',
    '951': 'EAN/EPCglobal',
    '955': 'Malaysia',
    '958': 'Macau',
    '960-969': 'GS1 UK Office',
    '977': 'Serial publications (ISSN)',
    '978-979': 'Books (ISBN)',
    '980': 'Refund receipts',
    '981-984': 'Common Currency Coupons',
    '990-999': 'Coupons'
  };
  
  // Simple lookup (for common prefixes)
  const prefixNum = parseInt(prefix, 10);
  if (prefixNum >= 0 && prefixNum < 20) return 'US/Canada';
  if (prefixNum >= 300 && prefixNum < 380) return 'France';
  if (prefixNum >= 400 && prefixNum < 441) return 'Germany';
  if (prefixNum >= 450 && prefixNum < 460) return 'Japan';
  if (prefixNum >= 690 && prefixNum < 700) return 'China';
  
  return countryMap[prefix] || 'Unknown';
}

UPC-A Reader | EAN-8 Reader

UPCAReader

UPC-A (Universal Product Code) barcode reader for 12-digit product codes used primarily in North American retail. UPC-A is the most common barcode format for consumer products.

/**
 * UPC-A barcode reader
 * Decodes 12-digit Universal Product Code barcodes
 * Delegates to EAN-13 reader internally (UPC-A is EAN-13 with leading 0)
 */
class UPCAReader extends UPCEANReader {
  /**
   * Create UPC-A reader
   */
  constructor();

  /**
   * Decode UPC-A barcode from image
   * @param image - BinaryBitmap: binary image containing the barcode
   * @param hints - Map<DecodeHintType, any>: optional decoding hints
   *   - ALLOWED_EAN_EXTENSIONS: Int32Array for 2 or 5 digit extensions
   * @returns Result: decoded 12-digit UPC-A code
   * @throws NotFoundException if UPC-A not found
   * @throws FormatException if format is invalid
   * @throws ChecksumException if check digit fails
   */
  decode(image: BinaryBitmap, hints?: Map<DecodeHintType, any>): Result;

  /**
   * Decode UPC-A barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decoding hints
   * @returns Result: decoded 12-digit UPC-A code
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;

  /**
   * Get the barcode format
   * @returns BarcodeFormat: always BarcodeFormat.UPC_A
   */
  getBarcodeFormat(): BarcodeFormat;

  /**
   * Reset reader state
   */
  reset(): void;
}

Format Specification:

  • Structure: 12 digits total in format: N M1 M2 M3 M4 M5 P1 P2 P3 P4 P5 K
    • N: Number system digit (0-9)
    • M1-M5: Manufacturer code (5 digits)
    • P1-P5: Product code (5 digits)
    • K: Check digit (1 digit)
  • Equivalence: UPC-A with number system 0 is equivalent to EAN-13 with leading 0
  • Example: UPC-A "012345678905" = EAN-13 "0012345678905"

Implementation Notes:

UPCAReader delegates to an internal EAN-13 reader and converts the result:

  1. Decodes as EAN-13 (which includes leading '0' for UPC-A codes)
  2. Strips the leading '0' if present
  3. Converts the barcode format from EAN_13 to UPC_A in the result

Usage Examples:

import {
  UPCAReader,
  BinaryBitmap,
  Result,
  BarcodeFormat,
  DecodeHintType,
  ResultMetadataType
} from "@zxing/library";

// Basic UPC-A decoding
const reader = new UPCAReader();
try {
  const result: Result = reader.decode(bitmap);
  const code: string = result.getText();
  
  console.log(`UPC-A: ${code}`); // e.g., "012345678905"
  
  // Validate format
  if (result.getBarcodeFormat() === BarcodeFormat.UPC_A && code.length === 12) {
    const numberSystem: string = code.charAt(0);
    const manufacturer: string = code.substring(1, 6);
    const product: string = code.substring(6, 11);
    const checkDigit: string = code.charAt(11);
    
    console.log(`Number system: ${numberSystem}`);
    console.log(`Manufacturer: ${manufacturer}`);
    console.log(`Product: ${product}`);
    console.log(`Check digit: ${checkDigit}`);
    
    // Number system meanings:
    // 0: Regular UPC
    // 1: Reserved
    // 2: Random weight items
    // 3: Drug/pharmaceutical
    // 4: In-store use (no check digit)
    // 5: Coupons
    // 6: Regular UPC
    // 7: Regular UPC
    // 8: Reserved
    // 9: Reserved
  }
} catch (error) {
  console.error("UPC-A decode failed:", error);
}

// UPC-A with extensions
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.ALLOWED_EAN_EXTENSIONS, new Int32Array([2, 5]));

try {
  const result2: Result = reader.decode(bitmap, hints);
  const extension = result2.getResultMetadata()?.get(ResultMetadataType.UPC_EAN_EXTENSION);
  
  if (extension) {
    console.log(`Main code: ${result2.getText()}`);
    console.log(`Extension: ${extension}`);
    
    // Parse 5-digit price extension (US format: $XX.XX)
    if (extension.length === 5) {
      const firstDigit = extension.charAt(0);
      const amount = extension.substring(1);
      
      if (firstDigit === '0') {
        console.log(`Price: $${amount.substring(0, 2)}.${amount.substring(2)}`);
      } else if (firstDigit === '5') {
        console.log(`Price: $${amount.substring(0, 3)}.${amount.substring(3)}`);
      }
    }
  }
} catch (error) {
  console.error("UPC-A with extension decode failed:", error);
}

// Validate UPC-A check digit
function validateUPCACheckDigit(code: string): boolean {
  if (code.length !== 12) return false;
  
  let oddSum = 0;
  let evenSum = 0;
  
  for (let i = 0; i < 11; i++) {
    const digit = parseInt(code.charAt(i), 10);
    if (i % 2 === 0) {
      oddSum += digit;
    } else {
      evenSum += digit;
    }
  }
  
  const checkSum = (oddSum * 3 + evenSum) % 10;
  const checkDigit = (10 - checkSum) % 10;
  
  return checkDigit === parseInt(code.charAt(11), 10);
}

console.log("Valid:", validateUPCACheckDigit("012345678905"));

// Compare with EAN-13
// UPC-A:  012345678905 (12 digits)
// EAN-13: 0012345678905 (13 digits, same product with leading 0)

UPC-E Reader | EAN-8 Reader

UPCEReader

UPC-E barcode reader for compressed 8-digit product codes. UPC-E is a zero-suppressed version of UPC-A designed for small packages.

/**
 * UPC-E barcode reader
 * Decodes compressed 8-digit UPC codes (zero-suppressed UPC-A)
 * Used when full UPC-A would be too large for small packages
 */
class UPCEReader extends UPCEANReader {
  /**
   * Create UPC-E reader
   */
  constructor();

  /**
   * Decode UPC-E barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decoding hints
   * @returns Result: decoded 8-digit UPC-E code
   * @throws NotFoundException if UPC-E pattern not found
   * @throws FormatException if pattern is invalid
   * @throws ChecksumException if check digit validation fails
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;

  /**
   * Get the barcode format
   * @returns BarcodeFormat: always BarcodeFormat.UPC_E
   */
  getBarcodeFormat(): BarcodeFormat;

  /**
   * Expands a UPC-E code to its equivalent full UPC-A format
   * Decompresses zero-suppressed representation
   * @param upce - string: UPC-E code (7-8 digits including check digit)
   * @returns string: equivalent 12-digit UPC-A code
   * @throws FormatException if input format is invalid
   */
  static convertUPCEtoUPCA(upce: string): string;
}

Format Specification:

  • Structure: 8 digits total: N D1 D2 D3 D4 D5 D6 K
    • N: Number system digit (0 or 1)
    • D1-D6: Compressed data digits (6 digits)
    • K: Check digit (1 digit)
  • Suppression: Only specific manufacturer/product patterns can be compressed
  • Expansion: Last digit (D6) indicates suppression pattern

Compression Rules:

The last data digit determines how zeros are suppressed:

Last DigitUPC-E FormatUPC-A Expansion
0, 1, 2XXXYY0-2XXX00-00YY0-2
3XXXXY3XXXX00000Y
4XXXXZ4XXXXX0000Z
5-9XXXXXV5-9XXXXX0000V

Usage Examples:

import {
  UPCEReader,
  BinaryBitmap,
  Result,
  BarcodeFormat
} from "@zxing/library";

// Basic UPC-E decoding
const reader = new UPCEReader();
try {
  const result: Result = reader.decode(bitmap);
  const code: string = result.getText();
  
  console.log(`UPC-E: ${code}`); // e.g., "04210000"
  
  // Parse UPC-E components
  if (result.getBarcodeFormat() === BarcodeFormat.UPC_E && code.length >= 7) {
    const numberSystem: string = code.charAt(0); // 0 or 1
    const compressedData: string = code.substring(1, 7);
    const checkDigit: string = code.charAt(7);
    
    console.log(`Number system: ${numberSystem}`);
    console.log(`Compressed data: ${compressedData}`);
    console.log(`Check digit: ${checkDigit}`);
  }
} catch (error) {
  console.error("UPC-E decode failed:", error);
}

// Expand to UPC-A
const upce: string = "04210000";
const upca: string = UPCEReader.convertUPCEtoUPCA(upce);
console.log(`UPC-E: ${upce}`);
console.log(`UPC-A: ${upca}`); // e.g., "042100005264"

// Expansion examples
console.log(UPCEReader.convertUPCEtoUPCA("04252614")); // Expands based on last digit (4)
console.log(UPCEReader.convertUPCEtoUPCA("04252617")); // Different expansion based on last digit (7)

// Understanding compression pattern
function explainCompression(upce: string): string {
  if (upce.length < 7) return "Invalid UPC-E";
  
  const lastDigit = parseInt(upce.charAt(6), 10);
  
  if (lastDigit <= 2) {
    return `Pattern 0-2: Manufacturer code ${upce.substring(1, 4)} expands with 00-${lastDigit}00`;
  } else if (lastDigit === 3) {
    return `Pattern 3: Manufacturer code ${upce.substring(1, 5)} expands with 00000`;
  } else if (lastDigit === 4) {
    return `Pattern 4: Manufacturer code ${upce.substring(1, 6)} expands with 0000`;
  } else {
    return `Pattern 5-9: Product ends in ${lastDigit}, manufacturer ${upce.substring(1, 6)}`;
  }
}

console.log(explainCompression("04252614"));

EAN-8 Reader | Code 128 Reader

EAN8Reader

EAN-8 barcode reader for 8-digit European Article Numbers. EAN-8 is a compact version of EAN-13 designed for small packages where full EAN-13 wouldn't fit.

/**
 * EAN-8 barcode reader
 * Decodes 8-digit European Article Number barcodes
 * Compact format for small packages
 */
class EAN8Reader extends UPCEANReader {
  /**
   * Create EAN-8 reader
   */
  constructor();

  /**
   * Decode EAN-8 barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decoding hints
   * @returns Result: decoded 8-digit EAN-8 code
   * @throws NotFoundException if EAN-8 pattern not found
   * @throws FormatException if pattern is invalid
   * @throws ChecksumException if check digit validation fails
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;

  /**
   * Get the barcode format
   * @returns BarcodeFormat: always BarcodeFormat.EAN_8
   */
  getBarcodeFormat(): BarcodeFormat;
}

Format Specification:

  • Structure: 8 digits total: C1 C2 C3 P1 P2 P3 P4 K
    • C1-C3: Country code (2-3 digits)
    • P1-P4: Product identifier (4-5 digits)
    • K: Check digit (1 digit)
  • Symmetry: 4 digits left + middle guard + 4 digits right
  • Use case: Small packages where space is limited

Usage Examples:

import {
  EAN8Reader,
  BinaryBitmap,
  Result,
  BarcodeFormat,
  DecodeHintType,
  ResultMetadataType
} from "@zxing/library";

// Basic EAN-8 decoding
const reader = new EAN8Reader();
try {
  const result: Result = reader.decode(bitmap);
  const code: string = result.getText();
  
  console.log(`EAN-8: ${code}`); // e.g., "12345670"
  
  // Validate EAN-8 format
  if (result.getBarcodeFormat() === BarcodeFormat.EAN_8 && code.length === 8) {
    const country: string = code.substring(0, 3);
    const product: string = code.substring(3, 7);
    const checkDigit: string = code.charAt(7);
    
    console.log(`Country: ${country}`);
    console.log(`Product: ${product}`);
    console.log(`Check digit: ${checkDigit}`);
  }
} catch (error) {
  console.error("EAN-8 decode failed:", error);
}

// With extensions (rare but supported)
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.ALLOWED_EAN_EXTENSIONS, new Int32Array([2, 5]));

try {
  const result2: Result = reader.decode(bitmap, hints);
  const extension = result2.getResultMetadata()?.get(ResultMetadataType.UPC_EAN_EXTENSION);
  
  if (extension) {
    console.log(`Extension: ${extension}`);
  }
} catch (error) {
  console.error("EAN-8 with extension failed:", error);
}

// Validate EAN-8 check digit
function validateEAN8CheckDigit(code: string): boolean {
  if (code.length !== 8) return false;
  
  let sum = 0;
  for (let i = 0; i < 7; i++) {
    const digit = parseInt(code.charAt(i), 10);
    sum += (i % 2 === 0) ? digit * 3 : digit;
  }
  
  const checkDigit = (10 - (sum % 10)) % 10;
  return checkDigit === parseInt(code.charAt(7), 10);
}

console.log("Valid:", validateEAN8CheckDigit("12345670"));

// Compare with EAN-13
// EAN-8:  12345670 (8 digits, for small packages)
// EAN-13: 5901234123457 (13 digits, standard size)

Code 128 Reader | Code 39 Reader

Code128Reader

Code 128 barcode reader supporting high-density alphanumeric barcodes with three code sets (A, B, C) for optimal data compression.

/**
 * Code 128 barcode reader
 * Supports high-density alphanumeric encoding with automatic code set switching
 * One of the most versatile 1D barcode formats
 */
class Code128Reader extends OneDReader {
  /**
   * Create Code 128 reader
   */
  constructor();

  /**
   * Decode Code 128 barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decode hints
   *   - ASSUME_GS1: boolean treats as GS1-128 (Application Identifiers)
   * @returns Result: decoded text with full ASCII support
   * @throws NotFoundException if Code 128 pattern not found
   * @throws FormatException if pattern is invalid
   * @throws ChecksumException if checksum validation fails
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;
}

Format Features:

  • Code Set A: ASCII 00-95 (uppercase letters, control characters, digits, punctuation)
  • Code Set B: ASCII 32-127 (uppercase, lowercase, digits, punctuation)
  • Code Set C: Numeric pairs 00-99 (compact encoding: 2 digits per codeword)
  • Function Codes: FNC1-FNC4 for special applications (GS1, industry codes)
  • Dynamic Switching: Automatic code set selection for optimal compression
  • GS1-128: When FNC1 is first character (use ASSUME_GS1 hint)

Encoding Details:

  • Each character encoded as pattern of 3 bars and 3 spaces (11 modules total)
  • Start code determines initial code set (Start A, Start B, or Start C)
  • Shift codes allow temporary code set switch for single character
  • Latch codes provide permanent code set switch
  • Check digit calculated using weighted sum (modulo 103)
  • Stop pattern: 2 bars + 3 spaces + 2-module terminator bar

Usage Examples:

import {
  Code128Reader,
  BinaryBitmap,
  Result,
  DecodeHintType,
  BarcodeFormat
} from "@zxing/library";

// Basic Code 128 decoding
const reader = new Code128Reader();
try {
  const result: Result = reader.decode(bitmap);
  console.log(`Code 128: ${result.getText()}`);
  console.log("Length:", result.getText().length);
} catch (error) {
  console.error("Code 128 decode failed:", error);
}

// GS1-128 (Application Identifiers for supply chain)
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.ASSUME_GS1, true);

try {
  const result2: Result = reader.decode(bitmap, hints);
  const text: string = result2.getText();
  
  // GS1-128 starts with ]C1 symbology identifier
  if (text.startsWith("]C1")) {
    console.log("GS1-128 barcode detected");
    
    // Parse application identifiers (separated by ASCII 29)
    const ais: string[] = text.substring(3).split(String.fromCharCode(29));
    ais.forEach((ai, index) => {
      console.log(`AI ${index}: ${ai}`);
      
      // Parse common AIs
      if (ai.startsWith("01")) {
        console.log("  GTIN:", ai.substring(2, 16));
      } else if (ai.startsWith("10")) {
        console.log("  Batch/Lot:", ai.substring(2));
      } else if (ai.startsWith("17")) {
        console.log("  Expiration Date (YYMMDD):", ai.substring(2, 8));
      } else if (ai.startsWith("21")) {
        console.log("  Serial Number:", ai.substring(2));
      }
    });
  }
} catch (error) {
  console.error("GS1-128 decode failed:", error);
}

// Code 128 handles mixed content efficiently
// Example: "ABC123" uses Code Set B for letters and Code Set C for digits
const mixedContent = reader.decode(mixedBitmap);
console.log("Mixed content:", mixedContent.getText());

// Common GS1 Application Identifiers
const GS1_AIS = {
  "00": "Serial Shipping Container Code (SSCC)",
  "01": "Global Trade Item Number (GTIN)",
  "02": "GTIN of Contained Trade Items",
  "10": "Batch or Lot Number",
  "11": "Production Date (YYMMDD)",
  "13": "Packaging Date (YYMMDD)",
  "15": "Best Before Date (YYMMDD)",
  "17": "Expiration Date (YYMMDD)",
  "20": "Internal Product Variant",
  "21": "Serial Number",
  "22": "Consumer Product Variant",
  "240": "Additional Product Identification",
  "241": "Customer Part Number",
  "242": "Made-to-Order Variation Number",
  "250": "Secondary Serial Number",
  "251": "Reference to Source Entity",
  "253": "Global Document Type Identifier (GDTI)",
  "254": "Global Location Number (GLN) Extension",
  "255": "Global Coupon Number (GCN)",
  "30": "Variable Count",
  "310": "Net Weight (kg)",
  "3100-3105": "Net Weight (kg, 0-5 decimals)",
  "320": "Net Weight (lbs)",
  "3200-3205": "Net Weight (lbs, 0-5 decimals)",
  "37": "Count of Items",
  "3900-3909": "Amount Payable",
  "400": "Customer Purchase Order Number",
  "401": "Global Identification Number for Consignment (GINC)",
  "402": "Global Shipment Identification Number (GSIN)",
  "403": "Routing Code",
  "410": "Ship to/Deliver to GLN",
  "411": "Bill to/Invoice to GLN",
  "412": "Purchase from GLN",
  "413": "Ship for/Deliver for/Forward to GLN",
  "414": "Identification of Physical Location GLN",
  "420": "Ship to/Deliver to Postal Code",
  "421": "Ship to/Deliver to Postal Code with ISO Country Code",
  "7001": "NATO Stock Number (NSN)",
  "7002": "UN/ECE Meat Carcasses Classification",
  "7003": "Expiration Date and Time",
  "7004": "Active Potency",
  "8001": "Roll Products (width, length, core diameter, direction, splices)",
  "8002": "Cellular Mobile Telephone Identifier",
  "8003": "Global Returnable Asset Identifier (GRAI)",
  "8004": "Global Individual Asset Identifier (GIAI)",
  "8005": "Price per Unit of Measure",
  "8006": "Identification of Component",
  "8007": "International Bank Account Number (IBAN)",
  "8008": "Date and Time of Production",
  "8018": "Global Service Relation Number (GSRN)",
  "8020": "Payment Slip Reference Number",
  "8110": "Coupon Code",
  "8200": "Product URL"
};

// Parse GS1 data
function parseGS1Data(text: string): Map<string, string> {
  const result = new Map<string, string>();
  
  if (!text.startsWith("]C1")) {
    return result;
  }
  
  const data = text.substring(3);
  const parts = data.split(String.fromCharCode(29));
  
  for (const part of parts) {
    if (part.length >= 2) {
      // Try 2, 3, and 4 digit AI codes
      for (const aiLength of [4, 3, 2]) {
        if (part.length >= aiLength) {
          const ai = part.substring(0, aiLength);
          if (GS1_AIS[ai]) {
            result.set(ai, part.substring(aiLength));
            break;
          }
        }
      }
    }
  }
  
  return result;
}

Code 39 Reader | Code 93 Reader

Code39Reader

Code 39 barcode reader supporting alphanumeric data with optional check digit validation and extended mode for full ASCII support.

/**
 * Code 39 barcode reader
 * Supports alphanumeric encoding with optional check digit and extended mode
 * Also known as Code 3 of 9 or USS Code 39
 */
class Code39Reader extends OneDReader {
  /**
   * Create Code 39 reader
   * @param usingCheckDigit - boolean: if true, validate and remove check digit (default: false)
   * @param extendedMode - boolean: if true, decode extended Code 39 for full ASCII (default: false)
   */
  constructor(usingCheckDigit?: boolean, extendedMode?: boolean);

  /**
   * Decode Code 39 barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decode hints
   *   - ASSUME_CODE_39_CHECK_DIGIT: boolean overrides constructor setting
   *   - ENABLE_CODE_39_EXTENDED_MODE: boolean overrides constructor setting
   * @returns Result: decoded text (check digit removed if validated)
   * @throws NotFoundException if Code 39 pattern not found
   * @throws FormatException if pattern is invalid
   * @throws ChecksumException if check digit validation fails
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;
}

Format Features:

  • Standard Character Set: 0-9, A-Z (uppercase only), space, and symbols: - . $ / + %
  • Check Digit: Optional modulo-43 checksum using all 43 characters
  • Extended Mode: Encodes full ASCII (0-127) using special character pairs
    • Example: "+A" represents lowercase 'a', "%A" represents control character
  • Start/Stop Pattern: Asterisk (*) character (not included in decoded text)
  • Self-Checking: Wide/narrow bar patterns provide built-in error detection
  • Variable Length: No fixed length requirement

Character Mappings:

Standard Code 39 supports 43 characters with these codes:

  • 0-9: Digits (codes 0-9)
  • A-Z: Uppercase letters (codes 10-35)
  • -: Hyphen (code 36)
  • .: Period (code 37)
  • Space: (code 38)
  • $: Dollar (code 39)
  • /: Slash (code 40)
  • +: Plus (code 41)
  • %: Percent (code 42)

Extended Code 39 uses combinations:

  • Lowercase letters: +A = 'a', +Z = 'z'
  • Control characters: %A = SOH, %Z = SUB
  • Special symbols: /A = '!', %F = '&'

Usage Examples:

import {
  Code39Reader,
  BinaryBitmap,
  Result,
  DecodeHintType
} from "@zxing/library";

// Basic Code 39 decoding (no check digit, standard mode)
const reader = new Code39Reader();
try {
  const result: Result = reader.decode(bitmap);
  console.log(`Code 39: ${result.getText()}`);
} catch (error) {
  console.error("Code 39 decode failed:", error);
}

// With check digit validation
const reader2 = new Code39Reader(true, false);
try {
  const result2: Result = reader2.decode(bitmap);
  console.log(`Valid Code 39 (check digit verified): ${result2.getText()}`);
  // Check digit is validated and removed from result
} catch (e) {
  if (e instanceof ChecksumException) {
    console.error("Check digit validation failed");
  } else {
    console.error("Decode failed:", e);
  }
}

// Extended Code 39 for full ASCII
const reader3 = new Code39Reader(false, true);
try {
  const result3: Result = reader3.decode(bitmap);
  console.log(`Extended Code 39: ${result3.getText()}`);
  // Can decode lowercase letters and special characters
} catch (error) {
  console.error("Extended Code 39 decode failed:", error);
}

// With both check digit and extended mode
const reader4 = new Code39Reader(true, true);
const result4: Result = reader4.decode(bitmap);

// Using hints (alternative to constructor parameters)
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT, true);
hints.set(DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE, true);

const reader5 = new Code39Reader(
  hints.get(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT),
  hints.get(DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE)
);
const result5: Result = reader5.decode(bitmap, hints);

// Validate standard Code 39 content
function isValidCode39(text: string): boolean {
  // Valid: 0-9, A-Z, space, - . $ / + %
  return /^[0-9A-Z\-\. \$\/\+\%]+$/.test(text);
}

console.log("CODE39 is valid:", isValidCode39("CODE39"));     // true
console.log("Code39 is valid:", isValidCode39("Code39"));     // false (lowercase)
console.log("CODE-39 is valid:", isValidCode39("CODE-39"));   // true
console.log("CODE_39 is valid:", isValidCode39("CODE_39"));   // false (underscore)

// Calculate Code 39 check digit
function calculateCode39CheckDigit(data: string): string {
  const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
  let sum = 0;
  
  for (let i = 0; i < data.length; i++) {
    const index = alphabet.indexOf(data.charAt(i));
    if (index === -1) {
      throw new Error(`Invalid character: ${data.charAt(i)}`);
    }
    sum += index;
  }
  
  const checkValue = sum % 43;
  return alphabet.charAt(checkValue);
}

const data = "CODE39";
const checkDigit = calculateCode39CheckDigit(data);
console.log(`Check digit for "${data}": ${checkDigit}`);
console.log(`Full code: ${data}${checkDigit}`);

Code 93 Reader | ITF Reader

Code93Reader

Code 93 barcode reader providing higher density than Code 39 with automatic check digit validation and extended character support.

/**
 * Code 93 barcode reader
 * Higher density than Code 39 with automatic check digit validation
 * Supports full ASCII through shift characters
 */
class Code93Reader extends OneDReader {
  /**
   * Create Code 93 reader
   */
  constructor();

  /**
   * Decode Code 93 barcode from row
   * Automatically validates and removes two check digits
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decode hints
   * @returns Result: decoded text with check digits automatically validated and removed
   * @throws NotFoundException if Code 93 pattern not found
   * @throws FormatException if pattern is invalid
   * @throws ChecksumException if check digit validation fails
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;
}

Format Features:

  • Character Set: 0-9, A-Z (uppercase), space, and symbols: - . $ / + %, plus 4 shift characters
  • Check Digits: Two modulo-47 check digits (C and K) automatically validated and removed
  • Extended Characters: Full ASCII support through shift character combinations
  • Compact: Higher density than Code 39 (approximately 25% more dense)
  • Start/Stop Pattern: Special asterisk-like pattern
  • Self-Checking: Two check digits provide strong error detection

Check Digit Calculation:

Code 93 uses two check digits (C and K):

  1. C check digit: Weighted modulo-47 over all data characters (weights 1-20 cycling)
  2. K check digit: Weighted modulo-47 over data + C (weights 1-15 cycling)

Both are automatically validated during decoding and removed from the result.

Usage Examples:

import {
  Code93Reader,
  BinaryBitmap,
  Result,
  ChecksumException
} from "@zxing/library";

// Basic Code 93 decoding
const reader = new Code93Reader();
try {
  const result: Result = reader.decode(bitmap);
  console.log(`Code 93: ${result.getText()}`);
  // Note: Check digits are automatically validated and removed from result
} catch (error) {
  if (error instanceof ChecksumException) {
    console.error("Code 93 checksum validation failed");
    // Barcode is damaged or not a valid Code 93
  } else {
    console.error("Code 93 decode failed:", error);
  }
}

// Code 93 automatically handles extended characters
try {
  const result2: Result = reader.decode(bitmap);
  const text: string = result2.getText();
  
  if (text.length > 0) {
    console.log(`Decoded: ${text}`);
    // Can include lowercase letters, control characters, and special symbols
    // These are decoded from shift character sequences
  }
} catch (error) {
  console.error("Extended Code 93 decode failed:", error);
}

// Standard Code 93 character set validation
function isValidCode93Standard(text: string): boolean {
  // Valid: 0-9, A-Z, space, - . $ / + %
  return /^[0-9A-Z\-\. \$\/\+\%]+$/.test(text);
}

console.log("CODE93 is valid:", isValidCode93Standard("CODE93"));     // true
console.log("Code93 is valid:", isValidCode93Standard("Code93"));     // false (lowercase decoded from shifts)

// Continuous scanning for Code 93
function scanCode93Continuous(bitmaps: BinaryBitmap[]): Result | null {
  const reader = new Code93Reader();
  
  for (const bitmap of bitmaps) {
    try {
      const result: Result = reader.decode(bitmap);
      return result; // Return first successful decode
    } catch (error) {
      // Continue to next bitmap
    }
  }
  
  return null; // No Code 93 found in any bitmap
}

// Extended ASCII mapping (examples)
// Shift 1 (+): lowercase and controls
//   +A='a', +B='b', ..., +Z='z'
// Shift 2 (!): special characters
//   !A=control, !B=control, ..., !E='&'
// Shift 3 ($): more special characters
// Shift 4 (/): more special characters

// Note: Shifts are decoded automatically by Code93Reader
// The returned text contains the decoded ASCII characters

ITF Reader | Codabar Reader

ITFReader

Interleaved Two of Five (ITF) barcode reader for numeric-only data, commonly used in logistics and warehouse applications.

/**
 * Interleaved Two of Five (ITF) barcode reader
 * Numeric-only format commonly used in logistics, shipping, and warehousing
 */
class ITFReader extends OneDReader {
  /**
   * Create ITF reader
   */
  constructor();

  /**
   * Decode ITF barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decode hints
   *   - ALLOWED_LENGTHS: Int32Array specifying valid barcode lengths
   * @returns Result: decoded numeric string
   * @throws NotFoundException if ITF pattern not found
   * @throws FormatException if pattern is invalid or length not allowed
   * @throws ChecksumException if checksum validation fails
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;
}

Format Features:

  • Character Set: Numeric only (0-9)
  • Interleaving: Pairs of digits encoded together - bars encode first digit, spaces encode second
  • Valid Lengths: Default accepted lengths are 6, 8, 10, 12, 14, or longer (even numbers only)
  • Quiet Zone: Requires 10× narrow bar width before and after barcode
  • Compact: High information density compared to other numeric formats
  • Structure: Start pattern (4 narrow) + digit pairs + stop pattern (2 wide + 1 narrow)

Interleaving Explanation:

ITF encodes two digits simultaneously:

  • First digit: Encoded in the 5 bars (widths represent digit 0-9)
  • Second digit: Encoded in the 5 spaces between bars
  • This interleaving doubles the information density

Usage Examples:

import {
  ITFReader,
  BinaryBitmap,
  Result,
  DecodeHintType
} from "@zxing/library";

// Basic ITF decoding
const reader = new ITFReader();
try {
  const result: Result = reader.decode(bitmap);
  const code: string = result.getText();
  
  console.log(`ITF: ${code}`); // e.g., "123456789012"
  console.log(`Length: ${code.length}`);
} catch (error) {
  console.error("ITF decode failed:", error);
}

// With custom allowed lengths (e.g., ITF-14 only)
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.ALLOWED_LENGTHS, new Int32Array([14]));

const reader2 = new ITFReader();
try {
  const result2: Result = reader2.decode(bitmap, hints);
  const code: string = result2.getText();
  
  if (code.length === 14) {
    console.log(`ITF-14 (GTIN-14): ${code}`);
    
    // Parse ITF-14 structure
    const packagingIndicator: string = code.charAt(0);
    const gtin13: string = code.substring(1, 14);
    
    console.log(`Packaging indicator: ${packagingIndicator}`);
    console.log(`GTIN-13: ${gtin13}`);
    
    // Packaging indicator meanings:
    // 0: Base unit
    // 1-8: Different packaging levels (case, pallet, etc.)
    // 9: Variable measure trade item
  }
} catch (error) {
  console.error("ITF-14 decode failed:", error);
}

// Multiple allowed lengths
const multiLengthHints = new Map<DecodeHintType, any>();
multiLengthHints.set(DecodeHintType.ALLOWED_LENGTHS, new Int32Array([14, 16, 20]));

const reader3 = new ITFReader();
const result3: Result = reader3.decode(bitmap, multiLengthHints);

// Validate numeric content
const text: string = result.getText();
if (/^\d+$/.test(text)) {
  console.log(`Valid ITF numeric code: ${text}`);
  console.log(`Length: ${text.length}`);
  console.log(`Is even length: ${text.length % 2 === 0}`); // ITF always has even length
} else {
  console.error("ITF should only contain digits");
}

// Default allowed lengths
// By default, ITF reader accepts these lengths:
// 6, 8, 10, 12, 14 digits (most common)
// Also accepts any length >= 6 if it's even

// Common ITF variants:
// ITF-6:  6 digits
// ITF-14: 14 digits (GTIN-14, most common for logistics)
// ITF-16: 16 digits

Codabar Reader | RSS-14 Reader

CodaBarReader

Codabar barcode reader supporting numeric data with start/stop characters, commonly used in libraries, blood banks, and logistics.

/**
 * Codabar barcode reader
 * Self-checking numeric format with start/stop characters (A, B, C, D)
 * Also known as USD-4, NW-7, or Code 2 of 7
 */
class CodaBarReader extends OneDReader {
  /**
   * Create Codabar reader
   */
  constructor();

  /**
   * Decode Codabar barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decode hints
   *   - RETURN_CODABAR_START_END: boolean to include start/stop characters in result
   * @returns Result: decoded text (start/stop removed unless hint set)
   * @throws NotFoundException if Codabar pattern not found
   * @throws FormatException if pattern is invalid
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;
}

Format Features:

  • Character Set: Digits 0-9 and symbols: - $ : / . +
  • Start/Stop Characters: A, B, C, or D (must match at both ends)
  • Self-Checking: Each character has unique bar/space pattern
  • Variable Length: No fixed length requirement
  • Use Cases:
    • Libraries: Book tracking
    • Blood banks: Blood product identification
    • FedEx: Airbill tracking
    • Photo labs: Film processing

Start/Stop Character Meanings:

By convention in some applications:

  • A: Often used for standard labels
  • B: Used for some library applications
  • C: Used for some clinical applications
  • D: Used for some library applications

The reader strips start/stop characters by default unless RETURN_CODABAR_START_END hint is set.

Usage Examples:

import {
  CodaBarReader,
  BinaryBitmap,
  Result,
  DecodeHintType
} from "@zxing/library";

// Basic Codabar decoding (start/stop removed)
const reader = new CodaBarReader();
try {
  const result: Result = reader.decode(bitmap);
  const data: string = result.getText();
  
  console.log(`Codabar: ${data}`);
  // Returns data between start/stop characters
  // e.g., "1234567" (without start 'A' and stop 'D')
} catch (error) {
  console.error("Codabar decode failed:", error);
}

// With start/stop characters included
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.RETURN_CODABAR_START_END, true);

const reader2 = new CodaBarReader();
try {
  const result2: Result = reader2.decode(bitmap, hints);
  const fullCode: string = result2.getText();
  
  console.log(`Full Codabar: ${fullCode}`);
  // e.g., "A1234567D" (with start 'A' and stop 'D')
  
  if (fullCode.length >= 3) {
    const startChar: string = fullCode.charAt(0);         // A, B, C, or D
    const stopChar: string = fullCode.charAt(fullCode.length - 1); // A, B, C, or D
    const data: string = fullCode.substring(1, fullCode.length - 1);
    
    console.log(`Start: ${startChar}`);
    console.log(`Data: ${data}`);
    console.log(`Stop: ${stopChar}`);
    
    // Validate matching start/stop (recommended but not required)
    if (startChar === stopChar) {
      console.log("Matching start/stop characters");
    }
  }
} catch (error) {
  console.error("Codabar with start/stop decode failed:", error);
}

// Validate Codabar format
function isValidCodabar(text: string): boolean {
  // Valid characters: 0-9, - $ : / . +
  return /^[0-9\-\$\:\/\.\+]+$/.test(text);
}

const data = result.getText();
if (isValidCodabar(data)) {
  console.log(`Valid Codabar data: ${data}`);
} else {
  console.error("Invalid Codabar characters");
}

// Codabar in library applications
function parseLibraryCodabar(fullCode: string): {
  startStop: string;
  libraryCode: string;
  itemNumber: string;
} | null {
  if (fullCode.length < 3) return null;
  
  const startStop = fullCode.charAt(0);
  const data = fullCode.substring(1, fullCode.length - 1);
  
  // Example library format: A123456789D
  // Could be library code + item number
  return {
    startStop,
    libraryCode: data.substring(0, 5),
    itemNumber: data.substring(5)
  };
}

RSS-14 Reader | RSS Expanded Reader

RSS14Reader

RSS-14 (Reduced Space Symbology, also known as GS1 DataBar) barcode reader for encoding GTIN-14 product identification codes in limited space.

/**
 * RSS-14 barcode reader (GS1 DataBar)
 * Encodes GTIN-14 in compact space (smaller than traditional barcodes)
 * Omnidirectional scanning capability
 */
class RSS14Reader extends AbstractRSSReader {
  /**
   * Create RSS-14 reader
   */
  constructor();

  /**
   * Decode RSS-14 barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decode hints
   * @returns Result: decoded 14-digit GTIN code
   * @throws NotFoundException if RSS-14 pattern not found
   * @throws FormatException if pattern is invalid
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;

  /**
   * Reset internal state for new decoding session
   * Clears cached finder patterns and state
   */
  reset(): void;
}

Format Features:

  • Data Capacity: 14 digits (GTIN-14)
  • Omnidirectional: Can be scanned from any angle
  • Compact: Significantly smaller than UPC/EAN for same data
  • Stacked Variants: Can span multiple rows (RSS-14 Stacked)
  • Check Digit: Automatic validation using modulo 10 algorithm
  • Applications: Fresh foods, small items, healthcare, coupons

Usage Examples:

import {
  RSS14Reader,
  BinaryBitmap,
  Result,
  BarcodeFormat
} from "@zxing/library";

// Basic RSS-14 decoding
const reader = new RSS14Reader();
try {
  const result: Result = reader.decode(bitmap);
  const gtin14: string = result.getText();
  
  console.log(`RSS-14: ${gtin14}`); // 14-digit code
  
  // Verify format
  if (result.getBarcodeFormat() === BarcodeFormat.RSS_14 && gtin14.length === 14) {
    console.log("Valid RSS-14 / GS1 DataBar barcode");
  }
} catch (error) {
  console.error("RSS-14 decode failed:", error);
}

// Parse GTIN-14 structure
function parseGTIN14(gtin14: string): {
  indicator: string;
  companyPrefix: string;
  itemReference: string;
  checkDigit: string;
} | null {
  if (gtin14.length !== 14) return null;
  
  return {
    indicator: gtin14.charAt(0),
    companyPrefix: gtin14.substring(1, 7),  // Typically 6-9 digits
    itemReference: gtin14.substring(7, 13), // Remaining digits
    checkDigit: gtin14.charAt(13)
  };
}

const gtin14: string = result.getText();
const parsed = parseGTIN14(gtin14);

if (parsed) {
  console.log(`Indicator: ${parsed.indicator}`);
  console.log(`Company Prefix: ${parsed.companyPrefix}`);
  console.log(`Item Reference: ${parsed.itemReference}`);
  console.log(`Check Digit: ${parsed.checkDigit}`);
  
  // Indicator digit meanings:
  // 0: Base unit (individual item)
  // 1-8: Different packaging levels (case, inner pack, pallet, etc.)
  // 9: Variable measure item
}

// Reset for multiple scans
reader.reset();

// Get result points (barcode location)
const points = result.getResultPoints();
if (points.length > 0) {
  console.log(`Found at: (${points[0].getX()}, ${points[0].getY()})`);
}

// Validate GTIN-14 check digit
function validateGTIN14CheckDigit(gtin: string): boolean {
  if (gtin.length !== 14) return false;
  
  let sum = 0;
  for (let i = 0; i < 13; i++) {
    const digit = parseInt(gtin.charAt(i), 10);
    sum += (i % 2 === 0) ? digit * 3 : digit;
  }
  
  const checkDigit = (10 - (sum % 10)) % 10;
  return checkDigit === parseInt(gtin.charAt(13), 10);
}

console.log("Valid GTIN-14:", validateGTIN14CheckDigit("12345678901231"));

RSS Expanded Reader

RSSExpandedReader

RSS Expanded barcode reader for encoding variable-length data including product codes, weights, prices, and expiration dates using GS1 Application Identifiers.

/**
 * RSS Expanded barcode reader (GS1 DataBar Expanded)
 * Variable-length format for product information with AI data
 * @experimental - RSS Expanded support is NOT production-ready
 * @warning This reader is experimental and may fail on many valid barcodes
 */
class RSSExpandedReader extends AbstractRSSReader {
  /**
   * Create RSS Expanded reader
   * @warning This reader is experimental - use with caution
   */
  constructor();

  /**
   * Decode RSS Expanded barcode from row
   * @param rowNumber - number: row number in image (0-based)
   * @param row - BitArray: binary row data
   * @param hints - Map<DecodeHintType, any>: optional decode hints
   * @returns Result: decoded data with Application Identifiers in parentheses
   * @throws NotFoundException if RSS Expanded not found
   * @throws FormatException if pattern is invalid
   * @experimental May fail on valid barcodes - not production ready
   */
  decodeRow(
    rowNumber: number,
    row: BitArray,
    hints?: Map<DecodeHintType, any>
  ): Result;

  /**
   * Reset internal state for new decoding session
   * Clears cached rows and decoding state
   */
  reset(): void;
}

Format Features:

  • Variable Length: Can encode up to 74 numeric or 41 alphanumeric characters
  • Application Identifiers: GS1 AI format for structured data
  • Stacked Mode: Can span multiple rows for more data
  • Composite Capability: Can be combined with 2D component (CC-A/CC-B)
  • Data Types: Product codes, weights, prices, dates, batch numbers, serial numbers

Status Warning:

⚠️ RSS Expanded reader is EXPERIMENTAL and NOT production-ready

  • Decoding may fail on many valid RSS Expanded barcodes
  • Use with extreme caution in production environments
  • Consider using alternative formats (QR Code, Data Matrix) for complex variable data
  • If RSS Expanded is required, extensive testing is necessary

Usage Examples:

import {
  RSSExpandedReader,
  BinaryBitmap,
  Result,
  BarcodeFormat
} from "@zxing/library";

// WARNING: RSS Expanded reader is experimental
console.warn("RSS Expanded reader is NOT ready for production use");

// Attempt RSS Expanded decoding (may fail)
const reader = new RSSExpandedReader();
try {
  const result: Result = reader.decode(bitmap);
  const data: string = result.getText();
  
  console.log(`RSS Expanded: ${data}`);
  
  // Data format: (AI)Value(AI)Value...
  // Example: "(01)12345678901234(3102)001234(10)BATCH123"
  
  // Parse Application Identifiers
  const aiPattern = /\((\d{2,4})\)([^\(]+)/g;
  let match;
  
  while ((match = aiPattern.exec(data)) !== null) {
    const aiCode: string = match[1];
    const value: string = match[2];
    console.log(`AI (${aiCode}): ${value}`);
    
    // Common AIs
    if (aiCode === "01") console.log("  → GTIN");
    else if (aiCode === "10") console.log("  → Batch/Lot Number");
    else if (aiCode === "17") console.log("  → Expiration Date");
    else if (aiCode.startsWith("310")) console.log("  → Net Weight (kg)");
    else if (aiCode.startsWith("320")) console.log("  → Net Weight (lbs)");
    else if (aiCode.startsWith("392")) console.log("  → Price");
  }
} catch (error) {
  console.error("RSS Expanded decoding failed (expected for experimental reader):", error);
}

// Common GS1 Application Identifiers
const GS1_AI_DESCRIPTIONS: {[key: string]: string} = {
  "01": "GTIN (Global Trade Item Number)",
  "10": "Batch or Lot Number",
  "11": "Production Date (YYMMDD)",
  "13": "Packaging Date (YYMMDD)",
  "15": "Best Before Date (YYMMDD)",
  "17": "Expiration Date (YYMMDD)",
  "20": "Internal Product Variant",
  "21": "Serial Number",
  "22": "Consumer Product Variant",
  "30": "Variable Count",
  "3100": "Net Weight (kg, 0 decimals)",
  "3101": "Net Weight (kg, 1 decimal)",
  "3102": "Net Weight (kg, 2 decimals)",
  "3103": "Net Weight (kg, 3 decimals)",
  "3200": "Net Weight (lbs, 0 decimals)",
  "3201": "Net Weight (lbs, 1 decimal)",
  "3202": "Net Weight (lbs, 2 decimals)",
  "3203": "Net Weight (lbs, 3 decimals)",
  "37": "Count of Items",
  "3920": "Price (2 decimals)",
  "3921": "Price (2 decimals)",
  "3922": "Price (2 decimals)",
  "3923": "Price (2 decimals)",
  "400": "Customer Purchase Order Number",
  "410": "Ship To / Deliver To GLN",
  "420": "Ship To / Deliver To Postal Code",
  "8005": "Price Per Unit of Measure"
};

// Parse Application Identifiers from result
function parseApplicationIdentifiers(data: string): Map<string, string> {
  const ais = new Map<string, string>();
  const aiPattern = /\((\d{2,4})\)([^\(]+)/g;
  let match;

  while ((match = aiPattern.exec(data)) !== null) {
    const [, aiCode, value] = match;
    ais.set(aiCode, value);
  }

  return ais;
}

// Display parsed information with descriptions
function displayRSSExpandedData(data: string): void {
  console.log("RSS Expanded Data:");
  const ais = parseApplicationIdentifiers(data);
  
  ais.forEach((value, code) => {
    const description = GS1_AI_DESCRIPTIONS[code] || "Unknown AI";
    console.log(`  (${code}) [${description}]: ${value}`);
  });
}

// Example usage (if decoding succeeds)
try {
  const result: Result = reader.decode(bitmap);
  displayRSSExpandedData(result.getText());
} catch (error) {
  console.error("RSS Expanded not supported or failed");
}

// Reset between attempts
reader.reset();

// Recommended alternative for complex data
console.log("For reliable variable-length data encoding, use:");
console.log("  - QR Code (more reliable, better error correction)");
console.log("  - Data Matrix (compact, widely supported)");
console.log("  - PDF417 (high capacity, structured append support)");

Common Decode Hints

All 1D barcode readers support these decode hints:

/**
 * Common decode hints for 1D barcode readers
 */
interface OneDDecodeHints {
  /**
   * POSSIBLE_FORMATS: BarcodeFormat[]
   * Limit decoding to specific barcode formats
   * Improves performance by skipping irrelevant format attempts
   */
  [DecodeHintType.POSSIBLE_FORMATS]?: BarcodeFormat[];

  /**
   * TRY_HARDER: boolean
   * Enable more thorough scanning (slower but more accurate)
   * - Scans more rows
   * - Tries image rotation (90°, 180°, 270°)
   * - More aggressive pattern matching
   */
  [DecodeHintType.TRY_HARDER]?: boolean;

  /**
   * CHARACTER_SET: string
   * Character encoding for result text
   * Examples: "UTF-8", "ISO-8859-1", "Shift_JIS", "Windows-1252"
   */
  [DecodeHintType.CHARACTER_SET]?: string;

  /**
   * ASSUME_CODE_39_CHECK_DIGIT: boolean
   * For Code 39: assume and validate check digit
   */
  [DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT]?: boolean;

  /**
   * ENABLE_CODE_39_EXTENDED_MODE: boolean
   * For Code 39: enable full ASCII character support
   */
  [DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE]?: boolean;

  /**
   * ASSUME_GS1: boolean
   * For Code 128: treat as GS1-128 with Application Identifiers
   * Affects FNC1 character handling
   */
  [DecodeHintType.ASSUME_GS1]?: boolean;

  /**
   * RETURN_CODABAR_START_END: boolean
   * For Codabar: include start/stop characters (A/B/C/D) in result
   */
  [DecodeHintType.RETURN_CODABAR_START_END]?: boolean;

  /**
   * ALLOWED_LENGTHS: Int32Array
   * For ITF: specify valid barcode lengths
   * Default: [6, 8, 10, 12, 14] or any even length >= 6
   */
  [DecodeHintType.ALLOWED_LENGTHS]?: Int32Array;

  /**
   * ALLOWED_EAN_EXTENSIONS: Int32Array
   * For UPC/EAN: specify which extension lengths to decode
   * Examples: [2], [5], or [2, 5]
   */
  [DecodeHintType.ALLOWED_EAN_EXTENSIONS]?: Int32Array;

  /**
   * NEED_RESULT_POINT_CALLBACK: ResultPointCallback
   * Receive callbacks when finder patterns or key points detected
   */
  [DecodeHintType.NEED_RESULT_POINT_CALLBACK]?: ResultPointCallback;
}

Usage Examples:

import {
  DecodeHintType,
  BarcodeFormat,
  ResultPointCallback,
  ResultPoint,
  MultiFormatOneDReader
} from "@zxing/library";

// Complete hints configuration
const hints = new Map<DecodeHintType, any>();

// Specify which barcode formats to try
hints.set(DecodeHintType.POSSIBLE_FORMATS, [
  BarcodeFormat.CODE_128,
  BarcodeFormat.CODE_39,
  BarcodeFormat.EAN_13
]);

// Try harder to find barcode (slower but more accurate)
hints.set(DecodeHintType.TRY_HARDER, true);

// Character encoding for the result text
hints.set(DecodeHintType.CHARACTER_SET, "UTF-8");

// Code 39 specific hints
// hints.set(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT, true);
// hints.set(DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE, true);

// GS1 format (for Code 128 as GS1-128)
// hints.set(DecodeHintType.ASSUME_GS1, true);

// Codabar specific
// hints.set(DecodeHintType.RETURN_CODABAR_START_END, true);

// ITF specific - only accept specific lengths
// hints.set(DecodeHintType.ALLOWED_LENGTHS, new Int32Array([14, 16]));

// UPC/EAN extensions
// hints.set(DecodeHintType.ALLOWED_EAN_EXTENSIONS, new Int32Array([2, 5]));

// Result point callback for tracking detection
const callback: ResultPointCallback = {
  foundPossibleResultPoint: (point: ResultPoint) => {
    console.log(`Detected pattern at (${point.getX()}, ${point.getY()})`);
  }
};
hints.set(DecodeHintType.NEED_RESULT_POINT_CALLBACK, callback);

// Use hints with reader
const reader = new MultiFormatOneDReader(hints);
const result = reader.decode(bitmap, hints);

Error Handling

All 1D barcode readers can throw these exceptions:

/**
 * Exception hierarchy for 1D barcode reading
 */
interface OneDReadingExceptions {
  /**
   * NotFoundException
   * Thrown when no barcode is found in the image or row
   * Most common exception - indicates barcode not present or not detectable
   */
  NotFoundException: typeof NotFoundException;

  /**
   * FormatException
   * Thrown when barcode is found but format is invalid or corrupted
   * Indicates barcode structure doesn't match expected format
   */
  FormatException: typeof FormatException;

  /**
   * ChecksumException
   * Thrown when barcode checksum/check digit validation fails
   * Indicates barcode is damaged or partially obscured
   */
  ChecksumException: typeof ChecksumException;
}

Usage Examples:

import {
  MultiFormatOneDReader,
  NotFoundException,
  FormatException,
  ChecksumException,
  BinaryBitmap,
  Result
} from "@zxing/library";

const reader = new MultiFormatOneDReader();

// Basic error handling
try {
  const result: Result = reader.decode(bitmap);
  console.log(`Success: ${result.getText()}`);
} catch (error) {
  if (error instanceof NotFoundException) {
    console.error("No barcode found in image");
    // Image may not contain a barcode
    // Try different image preprocessing or scanning position
  } else if (error instanceof FormatException) {
    console.error("Barcode format is invalid or corrupted");
    // Barcode structure is malformed
    // Check if barcode is partially obscured or damaged
  } else if (error instanceof ChecksumException) {
    console.error("Barcode checksum validation failed");
    // Barcode detected but contains errors
    // May succeed with better image quality or TRY_HARDER hint
  } else {
    console.error("Unexpected error:", error);
  }
}

// Retry with increasing hint aggressiveness
function decodeWithRetry(bitmap: BinaryBitmap, maxAttempts: number = 3): Result | null {
  const reader = new MultiFormatOneDReader();

  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const hints = new Map<DecodeHintType, any>();
    
    // Progressive hints
    if (attempt > 0) {
      hints.set(DecodeHintType.TRY_HARDER, true);
    }
    if (attempt > 1) {
      hints.set(DecodeHintType.POSSIBLE_FORMATS, [
        BarcodeFormat.CODE_128,
        BarcodeFormat.CODE_39,
        BarcodeFormat.EAN_13,
        BarcodeFormat.UPC_A
      ]);
    }

    try {
      const result: Result = reader.decode(bitmap, hints);
      console.log(`Decoded on attempt ${attempt + 1}`);
      return result;
    } catch (error) {
      if (error instanceof NotFoundException) {
        // No barcode found, no point retrying
        return null;
      }
      // Retry for FormatException or ChecksumException
      console.debug(`Attempt ${attempt + 1} failed, retrying...`);
    }
  }

  return null;
}

// Format-specific error handling
function decodeWithFormatFallback(bitmap: BinaryBitmap): Result | null {
  const formats = [
    BarcodeFormat.CODE_128,
    BarcodeFormat.CODE_39,
    BarcodeFormat.EAN_13,
    BarcodeFormat.EAN_8,
    BarcodeFormat.UPC_A
  ];

  for (const format of formats) {
    const hints = new Map<DecodeHintType, any>();
    hints.set(DecodeHintType.POSSIBLE_FORMATS, [format]);

    try {
      const reader = new MultiFormatOneDReader(hints);
      const result: Result = reader.decode(bitmap, hints);
      console.log(`Decoded as ${format}`);
      return result;
    } catch (error) {
      console.debug(`${format} failed:`, error.message);
    }
  }

  console.error("All formats failed");
  return null;
}

Performance Optimization

Reader Reuse

import { MultiFormatOneDReader, DecodeHintType, BarcodeFormat } from "@zxing/library";

// GOOD: Create reader once, reuse for multiple scans
const reader = new MultiFormatOneDReader();

// Configure hints once
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.POSSIBLE_FORMATS, [BarcodeFormat.CODE_128]);
hints.set(DecodeHintType.TRY_HARDER, false); // Faster scanning
reader.setHints(hints);

// Decode multiple images efficiently
const bitmaps = [bitmap1, bitmap2, bitmap3];
const results: (Result|null)[] = [];

for (const bitmap of bitmaps) {
  try {
    const result: Result = reader.decodeWithState(bitmap);
    results.push(result);
    console.log("Decoded:", result.getText());
  } catch (e) {
    results.push(null);
  }
}

// Reset when done
reader.reset();

console.log(`Successfully decoded ${results.filter(r => r !== null).length} of ${bitmaps.length} barcodes`);

// BAD: Creating new reader each time (wasteful)
for (const bitmap of bitmaps) {
  const reader = new MultiFormatOneDReader(); // DON'T DO THIS
  // ...
}

Hint Optimization

import { MultiFormatOneDReader, DecodeHintType, BarcodeFormat } from "@zxing/library";

// Optimize for speed: limit formats, disable TRY_HARDER
const fastHints = new Map<DecodeHintType, any>();
fastHints.set(DecodeHintType.POSSIBLE_FORMATS, [BarcodeFormat.CODE_128]);
// TRY_HARDER omitted = faster

const fastReader = new MultiFormatOneDReader(fastHints);

// Optimize for accuracy: enable TRY_HARDER, allow multiple formats
const accurateHints = new Map<DecodeHintType, any>();
accurateHints.set(DecodeHintType.TRY_HARDER, true);
accurateHints.set(DecodeHintType.POSSIBLE_FORMATS, [
  BarcodeFormat.CODE_128,
  BarcodeFormat.CODE_39,
  BarcodeFormat.EAN_13
]);

const accurateReader = new MultiFormatOneDReader(accurateHints);

// Adaptive scanning: start fast, fall back to accurate
function adaptiveScan(bitmap: BinaryBitmap): Result | null {
  try {
    return fastReader.decode(bitmap);
  } catch (error) {
    try {
      return accurateReader.decode(bitmap);
    } catch (error2) {
      return null;
    }
  }
}

Related APIs

  • Core API - MultiFormatReader, Result, BinaryBitmap
  • Image Processing - LuminanceSource, Binarizer
  • Types and Enums - BarcodeFormat, DecodeHintType
  • Common Utilities - BitArray utilities

Format Comparison

FormatTypeCharactersCheck DigitTypical LengthUse Case
EAN-13Numeric0-9Yes (mod 10)13 digitsRetail products worldwide
EAN-8Numeric0-9Yes (mod 10)8 digitsSmall packages
UPC-ANumeric0-9Yes (mod 10)12 digitsRetail products (US/Canada)
UPC-ENumeric0-9Yes (mod 10)8 digitsSmall packages (compressed)
Code 128Full ASCIIASCII 0-127Yes (mod 103)VariableShipping, logistics, general
Code 39Alphanumeric0-9, A-Z, 7 symbolsOptional (mod 43)VariableIndustrial, automotive
Code 93Full ASCIIFull ASCII via shiftsYes (2 digits)VariableLogistics, postal
ITFNumeric0-9OptionalEven lengthDistribution, warehousing
CodabarNumeric + symbols0-9, 6 symbolsNoVariableLibraries, blood banks
RSS-14Numeric14 digits (GTIN)Yes (mod 10)14 digitsSmall items, fresh food
RSS ExpandedAlphanumericVariableYesVariableVariable data (experimental)

Install with Tessl CLI

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

docs

index.md

tile.json