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

core-api.mddocs/reference/

Core Reading and Writing API

This document covers the primary entry points for barcode decoding and encoding in @zxing/library. These high-level APIs automatically detect barcode formats and delegate to format-specific implementations.

Package Information

  • Package Name: @zxing/library
  • Package Type: npm
  • Language: TypeScript
  • Module Path: Core module (root exports)

Core Imports

import {
  // Primary reader/writer classes
  MultiFormatReader,
  MultiFormatWriter,
  
  // Base interfaces
  Reader,
  Writer,
  
  // Result types
  Result,
  ResultPoint,
  ResultPointCallback,
  
  // Hint enums
  DecodeHintType,
  EncodeHintType,
  
  // Barcode format
  BarcodeFormat,
  
  // Data structures
  BitMatrix,
  BinaryBitmap
} from '@zxing/library';

Capabilities

Multi-Format Reader

Primary barcode decoder that auto-detects format. Supports configurable hints for optimization and format filtering.

/**
 * Multi-format barcode reader with auto-format detection
 * Delegates to format-specific readers based on hints
 */
class MultiFormatReader implements Reader {
  /**
   * Decode a barcode from a binary bitmap
   * Attempts to decode using all configured format readers
   * @param image - BinaryBitmap: binary representation of image containing barcode
   * @param hints - Map<DecodeHintType, any>: optional hints for decoding behavior
   *   - POSSIBLE_FORMATS: BarcodeFormat[] to limit format attempts
   *   - TRY_HARDER: boolean for accuracy over speed
   *   - CHARACTER_SET: string for text encoding
   *   - PURE_BARCODE: boolean if image contains only barcode
   * @returns Result: decoded barcode with text, format, and metadata
   * @throws NotFoundException if no barcode is found in any format
   * @throws FormatException if barcode is found but invalid
   * @throws ChecksumException if checksum validation fails
   */
  decode(image: BinaryBitmap, hints?: Map<DecodeHintType, any>): Result;

  /**
   * Decode using previously set hints
   * More efficient for continuous scanning as hints are cached
   * Call setHints() first to configure reader
   * @param image - BinaryBitmap: binary image containing barcode
   * @returns Result: decoded barcode data
   * @throws NotFoundException if no barcode is found
   * @throws FormatException if barcode is invalid
   * @throws ChecksumException if checksum fails
   */
  decodeWithState(image: BinaryBitmap): Result;

  /**
   * Set hints for subsequent decode operations
   * Hints are cached for use with decodeWithState()
   * @param hints - Map<DecodeHintType, any>|null: decode hints, or null to clear
   */
  setHints(hints: Map<DecodeHintType, any> | null): void;

  /**
   * Reset reader state
   * Clears cached hints and resets internal readers
   */
  reset(): void;
}

Usage Examples:

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

// Prepare image
const luminanceSource = new RGBLuminanceSource(pixels, width, height);
const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));

// Configure reader with hints
const reader = new MultiFormatReader();
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.POSSIBLE_FORMATS, [
  BarcodeFormat.QR_CODE,
  BarcodeFormat.EAN_13,
  BarcodeFormat.CODE_128
]);
hints.set(DecodeHintType.TRY_HARDER, true);
hints.set(DecodeHintType.CHARACTER_SET, 'UTF-8');

// Decode with hints
try {
  const result: Result = reader.decode(binaryBitmap, hints);
  console.log('Text:', result.getText());
  console.log('Format:', result.getBarcodeFormat());
  console.log('Raw bytes:', result.getRawBytes());
  console.log('Timestamp:', result.getTimestamp());
} catch (error) {
  console.error('Decode failed:', error);
}

// For continuous scanning (more efficient with setHints)
reader.setHints(hints);

// Process multiple frames
const frames: BinaryBitmap[] = [bitmap1, bitmap2, bitmap3];
for (const bitmap of frames) {
  try {
    const result: Result = reader.decodeWithState(bitmap);
    console.log('Frame decoded:', result.getText());
    break; // Stop on first success
  } catch (error) {
    // Continue to next frame
  }
}

// Reset when done
reader.reset();

Decode without hints (tries all formats):

import { MultiFormatReader, BinaryBitmap, Result } from '@zxing/library';

const reader = new MultiFormatReader();

try {
  // Attempts all formats: QR, Data Matrix, Aztec, PDF417, and all 1D formats
  const result: Result = reader.decode(binaryBitmap);
  console.log('Decoded:', result.getText());
  console.log('Format:', result.getBarcodeFormat());
} catch (error) {
  console.error('No barcode found in any format:', error);
}

Progressive hint strategy:

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

async function decodeWithProgression(bitmap: BinaryBitmap): Promise<Result | null> {
  const reader = new MultiFormatReader();

  // Strategy 1: Fast decode with common formats
  try {
    const hints1 = new Map<DecodeHintType, any>();
    hints1.set(DecodeHintType.POSSIBLE_FORMATS, [
      BarcodeFormat.QR_CODE,
      BarcodeFormat.EAN_13
    ]);
    return reader.decode(bitmap, hints1);
  } catch (e) {
    console.debug('Fast decode failed, trying harder...');
  }

  // Strategy 2: Try harder with same formats
  try {
    const hints2 = new Map<DecodeHintType, any>();
    hints2.set(DecodeHintType.POSSIBLE_FORMATS, [
      BarcodeFormat.QR_CODE,
      BarcodeFormat.EAN_13
    ]);
    hints2.set(DecodeHintType.TRY_HARDER, true);
    return reader.decode(bitmap, hints2);
  } catch (e) {
    console.debug('Hard decode failed, trying all formats...');
  }

  // Strategy 3: Try all formats with TRY_HARDER
  try {
    const hints3 = new Map<DecodeHintType, any>();
    hints3.set(DecodeHintType.TRY_HARDER, true);
    return reader.decode(bitmap, hints3);
  } catch (e) {
    console.debug('All strategies failed');
  }

  return null;
}

Multi-Format Writer

Primary barcode encoder. Creates barcode matrix from text content.

/**
 * Multi-format barcode writer
 * Delegates to format-specific writers
 */
class MultiFormatWriter implements Writer {
  /**
   * Encode content as a barcode in specified format
   * @param contents - string: text content to encode
   * @param format - BarcodeFormat: barcode format to generate (QR_CODE, DATA_MATRIX, AZTEC, PDF_417, CODE_128, CODE_39, EAN_13, EAN_8, UPC_A, ITF)
   * @param width - number: width in pixels
   * @param height - number: height in pixels
   * @param hints - Map<EncodeHintType, any>: encoding hints (pass new Map() if no hints needed)
   *   - ERROR_CORRECTION: varies by format
   *   - CHARACTER_SET: string (e.g., "UTF-8")
   *   - MARGIN: number (pixels)
   *   - QR_VERSION: number (1-40 for QR Code)
   *   - AZTEC_LAYERS: number (negative=compact, 0=auto, positive=full)
   *   - DATA_MATRIX_SHAPE: SymbolShapeHint
   *   - GS1_FORMAT: boolean
   * @returns BitMatrix: encoded barcode as binary matrix
   * @throws WriterException if encoding fails
   * @throws IllegalArgumentException if parameters are invalid
   * @throws UnsupportedOperationException if format doesn't support encoding
   */
  encode(
    contents: string,
    format: BarcodeFormat,
    width: number,
    height: number,
    hints: Map<EncodeHintType, any>
  ): BitMatrix;
}

Usage Examples:

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

const writer = new MultiFormatWriter();

// Encode QR Code with hints
const qrHints = new Map<EncodeHintType, any>();
qrHints.set(EncodeHintType.ERROR_CORRECTION, QRCodeDecoderErrorCorrectionLevel.H);
qrHints.set(EncodeHintType.MARGIN, 1);
qrHints.set(EncodeHintType.CHARACTER_SET, 'UTF-8');

const qrMatrix: BitMatrix = writer.encode(
  'https://example.com',
  BarcodeFormat.QR_CODE,
  300,
  300,
  qrHints
);

// Render to canvas/image
const width: number = qrMatrix.getWidth();
const height: number = qrMatrix.getHeight();

for (let y = 0; y < height; y++) {
  for (let x = 0; x < width; x++) {
    const isBlack: boolean = qrMatrix.get(x, y);
    // Draw black or white pixel at (x, y)
  }
}

Encode different formats:

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

const writer = new MultiFormatWriter();

// Data Matrix with square shape
const dmHints = new Map<EncodeHintType, any>();
dmHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
dmHints.set(EncodeHintType.CHARACTER_SET, 'UTF-8');

const dmMatrix: BitMatrix = writer.encode(
  'Data Matrix',
  BarcodeFormat.DATA_MATRIX,
  200,
  200,
  dmHints
);

// Aztec with compact mode
const aztecHints = new Map<EncodeHintType, any>();
aztecHints.set(EncodeHintType.AZTEC_LAYERS, -3); // Compact, 3 layers
aztecHints.set(EncodeHintType.ERROR_CORRECTION, 33); // 33% ECC

const aztecMatrix: BitMatrix = writer.encode(
  'Aztec Code',
  BarcodeFormat.AZTEC,
  0,   // 0 = auto-size
  0,
  aztecHints
);

// Code 128 with margin
const code128Hints = new Map<EncodeHintType, any>();
code128Hints.set(EncodeHintType.MARGIN, 10);

const code128Matrix: BitMatrix = writer.encode(
  'CODE128',
  BarcodeFormat.CODE_128,
  300,
  100,
  code128Hints
);

// EAN-13 (must be 12 or 13 digits, check digit auto-calculated)
const ean13Matrix: BitMatrix = writer.encode(
  '123456789012',  // 12 digits, check digit added automatically
  BarcodeFormat.EAN_13,
  200,
  100,
  new Map()
);

Error handling:

import {
  MultiFormatWriter,
  BarcodeFormat,
  WriterException,
  IllegalArgumentException,
  UnsupportedOperationException,
  BitMatrix
} from '@zxing/library';

const writer = new MultiFormatWriter();

try {
  const matrix: BitMatrix = writer.encode(
    'Data to encode',
    BarcodeFormat.QR_CODE,
    200,
    200,
    new Map()
  );
  console.log('Encoding successful');
} catch (error) {
  if (error instanceof WriterException) {
    console.error('Encoding failed:', error.message);
    // Data may be incompatible with format
  } else if (error instanceof IllegalArgumentException) {
    console.error('Invalid parameters:', error.message);
    // Check dimensions, format, or hints
  } else if (error instanceof UnsupportedOperationException) {
    console.error('Format not supported for encoding:', error.message);
    // MaxiCode and some others don't have writers
  } else {
    console.error('Unexpected error:', error);
  }
}

Reader Interface

Base interface for barcode readers.

/**
 * Interface for barcode decoders
 * All format-specific readers implement this interface
 */
interface Reader {
  /**
   * Decode a barcode from binary image
   * @param image - BinaryBitmap: binary representation of image to decode
   * @param hints - Map<DecodeHintType, any>: optional decoding hints
   * @returns Result: decoded barcode with text and metadata
   * @throws NotFoundException if no barcode found
   * @throws FormatException if barcode is invalid
   * @throws ChecksumException if checksum validation fails
   */
  decode(image: BinaryBitmap, hints?: Map<DecodeHintType, any>): Result;

  /**
   * Reset reader state
   * Clears cached data and prepares for next decode
   */
  reset(): void;
}

Implementation Examples:

import { Reader, BinaryBitmap, Result, DecodeHintType } from '@zxing/library';

// Using any Reader implementation
function decodeWithReader(reader: Reader, bitmap: BinaryBitmap): Result | null {
  try {
    const result: Result = reader.decode(bitmap);
    return result;
  } catch (error) {
    console.error('Decode failed:', error);
    return null;
  }
}

// With hints
function decodeWithReaderAndHints(
  reader: Reader,
  bitmap: BinaryBitmap,
  hints: Map<DecodeHintType, any>
): Result | null {
  try {
    const result: Result = reader.decode(bitmap, hints);
    return result;
  } catch (error) {
    console.error('Decode with hints failed:', error);
    return null;
  }
}

// Multiple decode attempts with different readers
import { QRCodeReader, DataMatrixReader, AztecCodeReader } from '@zxing/library';

function tryMultipleReaders(bitmap: BinaryBitmap): Result | null {
  const readers: Reader[] = [
    new QRCodeReader(),
    new DataMatrixReader(),
    new AztecCodeReader()
  ];

  for (const reader of readers) {
    try {
      const result: Result = reader.decode(bitmap);
      console.log(`Decoded with ${reader.constructor.name}`);
      return result;
    } catch (error) {
      // Try next reader
    }
  }

  console.error('All readers failed');
  return null;
}

Writer Interface

Base interface for barcode encoders.

/**
 * Interface for barcode encoders
 * All format-specific writers implement this interface
 */
interface Writer {
  /**
   * Encode content as barcode matrix
   * @param contents - string: text content to encode
   * @param format - BarcodeFormat: barcode format to generate
   * @param width - number: desired width in pixels
   * @param height - number: desired height in pixels
   * @param hints - Map<EncodeHintType, any>: optional encoding hints
   * @returns BitMatrix: encoded barcode as binary matrix where true=black, false=white
   * @throws WriterException if encoding fails
   * @throws IllegalArgumentException if parameters are invalid
   */
  encode(
    contents: string,
    format: BarcodeFormat,
    width: number,
    height: number,
    hints?: Map<EncodeHintType, any>
  ): BitMatrix;
}

Implementation Examples:

import { Writer, BarcodeFormat, BitMatrix, EncodeHintType } from '@zxing/library';

// Using any Writer implementation
function encodeWithWriter(
  writer: Writer,
  contents: string,
  format: BarcodeFormat,
  width: number,
  height: number
): BitMatrix | null {
  try {
    const matrix: BitMatrix = writer.encode(contents, format, width, height, new Map());
    return matrix;
  } catch (error) {
    console.error('Encode failed:', error);
    return null;
  }
}

// With hints
function encodeWithWriterAndHints(
  writer: Writer,
  contents: string,
  format: BarcodeFormat,
  width: number,
  height: number,
  hints: Map<EncodeHintType, any>
): BitMatrix | null {
  try {
    const matrix: BitMatrix = writer.encode(contents, format, width, height, hints);
    return matrix;
  } catch (error) {
    console.error('Encode with hints failed:', error);
    return null;
  }
}

// Batch encoding with single writer instance
import { QRCodeWriter } from '@zxing/library';

function encodeBatch(contents: string[]): BitMatrix[] {
  const writer: Writer = new QRCodeWriter();
  const hints = new Map<EncodeHintType, any>();
  hints.set(EncodeHintType.ERROR_CORRECTION, 'M');
  hints.set(EncodeHintType.MARGIN, 2);

  return contents.map(content => {
    try {
      return writer.encode(content, BarcodeFormat.QR_CODE, 200, 200, hints);
    } catch (error) {
      console.error(`Failed to encode "${content}":`, error);
      return null;
    }
  }).filter((m): m is BitMatrix => m !== null);
}

const matrices: BitMatrix[] = encodeBatch([
  'https://example.com/1',
  'https://example.com/2',
  'https://example.com/3'
]);
console.log(`Encoded ${matrices.length} QR codes`);

Result Class

Encapsulates decoded barcode information including text, raw bytes, format, and metadata.

/**
 * Result of barcode decoding
 * Contains decoded text, raw bytes, format information, and metadata
 */
class Result {
  /**
   * Create decode result
   * @param text - string: decoded text content
   * @param rawBytes - Uint8Array: raw byte data from barcode (may be null for some formats)
   * @param numBits - number: number of valid bits in rawBytes (typically 8 * rawBytes.length)
   * @param resultPoints - ResultPoint[]: key detection points (corners, finder patterns, alignment patterns)
   * @param format - BarcodeFormat: detected barcode format
   * @param timestamp - number: decode timestamp in milliseconds since epoch
   */
  constructor(
    text: string,
    rawBytes: Uint8Array,
    numBits: number,
    resultPoints: ResultPoint[],
    format: BarcodeFormat,
    timestamp: number
  );

  /**
   * Get decoded text content
   * @returns string: the decoded text
   */
  getText(): string;

  /**
   * Get raw byte data from barcode
   * May be null for formats that don't preserve raw bytes
   * @returns Uint8Array: raw bytes or null
   */
  getRawBytes(): Uint8Array;

  /**
   * Get number of valid bits in raw bytes
   * For most formats this is 8 * rawBytes.length
   * @returns number: bit count
   */
  getNumBits(): number;

  /**
   * Get key points detected in barcode
   * Points may include: finder pattern centers, corner points, alignment patterns
   * @returns ResultPoint[]: array of detection points (may be empty)
   */
  getResultPoints(): ResultPoint[];

  /**
   * Get barcode format that was decoded
   * @returns BarcodeFormat: the detected format
   */
  getBarcodeFormat(): BarcodeFormat;

  /**
   * Get result metadata
   * Metadata may include: orientation, error correction level, byte segments, etc.
   * @returns Map<ResultMetadataType, Object>: metadata map (may be null or empty)
   */
  getResultMetadata(): Map<ResultMetadataType, Object>;

  /**
   * Get decode timestamp in milliseconds since Unix epoch
   * @returns number: timestamp when barcode was decoded
   */
  getTimestamp(): number;

  /**
   * Add single metadata entry to result
   * @param type - ResultMetadataType: metadata type identifier
   * @param value - Object: metadata value
   */
  putMetadata(type: ResultMetadataType, value: Object): void;

  /**
   * Add multiple metadata entries to result
   * @param metadata - Map<ResultMetadataType, Object>: metadata entries to add
   */
  putAllMetadata(metadata: Map<ResultMetadataType, Object>): void;
}

Usage Examples:

import {
  MultiFormatReader,
  Result,
  ResultPoint,
  ResultMetadataType,
  BarcodeFormat,
  BinaryBitmap
} from '@zxing/library';

const reader = new MultiFormatReader();
const result: Result = reader.decode(binaryBitmap);

// Access decoded data
console.log('Text:', result.getText());
console.log('Format:', result.getBarcodeFormat()); // e.g., BarcodeFormat.QR_CODE
console.log('Timestamp:', result.getTimestamp());
console.log('Num bits:', result.getNumBits());

// Access raw bytes (may be null)
const rawBytes: Uint8Array = result.getRawBytes();
if (rawBytes) {
  console.log('Raw bytes:', Array.from(rawBytes));
  console.log('Byte length:', rawBytes.length);
}

// Access result points (e.g., QR code finder patterns)
const points: ResultPoint[] = result.getResultPoints();
console.log(`Found ${points.length} result points`);
for (let i = 0; i < points.length; i++) {
  const point: ResultPoint = points[i];
  console.log(`Point ${i} at (${point.getX()}, ${point.getY()})`);
}

// Access metadata
const metadata = result.getResultMetadata();
if (metadata) {
  // Error correction level
  if (metadata.has(ResultMetadataType.ERROR_CORRECTION_LEVEL)) {
    const ecLevel = metadata.get(ResultMetadataType.ERROR_CORRECTION_LEVEL);
    console.log('Error correction level:', ecLevel);
  }

  // Orientation
  if (metadata.has(ResultMetadataType.ORIENTATION)) {
    const orientation: number = metadata.get(ResultMetadataType.ORIENTATION) as number;
    console.log(`Barcode rotated ${orientation} degrees clockwise`);
  }

  // Byte segments
  if (metadata.has(ResultMetadataType.BYTE_SEGMENTS)) {
    const byteSegments: Uint8Array[] = metadata.get(ResultMetadataType.BYTE_SEGMENTS) as Uint8Array[];
    console.log(`Has ${byteSegments.length} byte segments`);
  }

  // Structured append information
  if (metadata.has(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE)) {
    const sequence: number = metadata.get(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE) as number;
    const parity: number = metadata.get(ResultMetadataType.STRUCTURED_APPEND_PARITY) as number;
    console.log(`Part ${sequence} (parity: ${parity})`);
  }
}

Format-specific result processing:

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

function processResult(result: Result): void {
  const format: BarcodeFormat = result.getBarcodeFormat();

  switch (format) {
    case BarcodeFormat.QR_CODE:
      console.log('QR Code:', result.getText());
      // QR codes may have error correction level metadata
      const qrECLevel = result.getResultMetadata()?.get(ResultMetadataType.ERROR_CORRECTION_LEVEL);
      console.log('QR EC Level:', qrECLevel);
      break;

    case BarcodeFormat.EAN_13:
      const ean13: string = result.getText();
      if (ean13.length === 13) {
        console.log('Country:', ean13.substring(0, 3));
        console.log('Manufacturer:', ean13.substring(3, 8));
        console.log('Product:', ean13.substring(8, 13));
      }
      break;

    case BarcodeFormat.PDF_417:
      // PDF417 may have extra metadata
      const pdf417Meta = result.getResultMetadata()?.get(ResultMetadataType.PDF417_EXTRA_METADATA);
      if (pdf417Meta) {
        console.log('PDF417 segment:', pdf417Meta.getSegmentIndex());
        console.log('PDF417 file ID:', pdf417Meta.getFileId());
      }
      break;

    default:
      console.log(`${format}:`, result.getText());
  }
}

Result Point

Represents a key point in the barcode image (finder pattern, corner, alignment pattern).

/**
 * Point in barcode image representing finder pattern, corner, or alignment marker
 */
class ResultPoint {
  /**
   * Create result point
   * @param x - number: x coordinate in image
   * @param y - number: y coordinate in image
   */
  constructor(x: number, y: number);

  /**
   * Get X coordinate
   * @returns number: x position in pixels
   */
  getX(): number;

  /**
   * Get Y coordinate
   * @returns number: y position in pixels
   */
  getY(): number;

  /**
   * Calculate Euclidean distance between two points
   * @param pattern1 - ResultPoint: first point
   * @param pattern2 - ResultPoint: second point
   * @returns number: distance in pixels
   */
  static distance(pattern1: ResultPoint, pattern2: ResultPoint): number;

  /**
   * Order three patterns by distance from top-left
   * Modifies array in place to be [bottomLeft, topLeft, topRight]
   * @param patterns - ResultPoint[]: array of exactly 3 patterns
   * @throws IllegalArgumentException if array length is not 3
   */
  static orderBestPatterns(patterns: ResultPoint[]): void;
  
  /**
   * Check equality with another point
   * @param other - any: object to compare
   * @returns boolean: true if same coordinates
   */
  equals(other: any): boolean;
  
  /**
   * String representation
   * @returns string: formatted as "(x,y)"
   */
  toString(): string;
}

Usage Examples:

import { ResultPoint, Result, MultiFormatReader } from '@zxing/library';

const reader = new MultiFormatReader();
const result: Result = reader.decode(binaryBitmap);

// Access result points
const points: ResultPoint[] = result.getResultPoints();

if (points.length >= 3) {
  const point1: ResultPoint = points[0];
  const point2: ResultPoint = points[1];
  
  console.log(`Point 1: (${point1.getX()}, ${point1.getY()})`);
  console.log(`Point 2: (${point2.getX()}, ${point2.getY()})`);
  
  // Calculate distance between points
  const distance: number = ResultPoint.distance(point1, point2);
  console.log(`Distance: ${distance.toFixed(2)} pixels`);
}

// Order finder patterns (QR Code has 3 finder patterns)
if (points.length === 3) {
  // Make a copy before ordering (orderBestPatterns modifies in place)
  const orderedPoints: ResultPoint[] = [...points];
  ResultPoint.orderBestPatterns(orderedPoints);
  
  console.log('Bottom-left:', orderedPoints[0]);
  console.log('Top-left:', orderedPoints[1]);
  console.log('Top-right:', orderedPoints[2]);
}

// Calculate barcode dimensions
function calculateBarcodeSize(points: ResultPoint[]): { width: number; height: number } | null {
  if (points.length < 3) return null;

  const [p0, p1, p2] = points;
  const width = ResultPoint.distance(p1, p2);
  const height = ResultPoint.distance(p1, p0);

  return { width, height };
}

const size = calculateBarcodeSize(points);
if (size) {
  console.log(`Barcode size: ${size.width.toFixed(1)} x ${size.height.toFixed(1)} pixels`);
}

// Create custom result point
const customPoint = new ResultPoint(100, 150);
console.log(customPoint.toString()); // "(100.0, 150.0)"

// Compare points
const point1 = new ResultPoint(10, 20);
const point2 = new ResultPoint(10, 20);
const point3 = new ResultPoint(15, 25);

console.log(point1.equals(point2)); // true
console.log(point1.equals(point3)); // false

Result Point Callback

Callback interface for receiving intermediate result points during detection.

/**
 * Callback for result point detection during decoding
 * Allows tracking of finder patterns and other key points as they are detected
 */
interface ResultPointCallback {
  /**
   * Called when a possible result point is found
   * May be called multiple times during single decode operation
   * @param point - ResultPoint: detected point with x,y coordinates
   */
  foundPossibleResultPoint(point: ResultPoint): void;
}

Usage Examples:

import {
  ResultPointCallback,
  ResultPoint,
  MultiFormatReader,
  DecodeHintType,
  BinaryBitmap,
  Result
} from '@zxing/library';

// Implement callback to track detection progress
const callback: ResultPointCallback = {
  foundPossibleResultPoint(point: ResultPoint): void {
    console.log(`Found point at (${point.getX()}, ${point.getY()})`);
    
    // Could draw marker on canvas to show detection progress
    drawMarker(point.getX(), point.getY());
  }
};

// Use in hints
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.NEED_RESULT_POINT_CALLBACK, callback);

const reader = new MultiFormatReader();
try {
  const result: Result = reader.decode(binaryBitmap, hints);
  console.log('Decoded:', result.getText());
} catch (error) {
  console.error('Decode failed:', error);
}

// More advanced callback with visualization
class VisualizingCallback implements ResultPointCallback {
  private detectedPoints: ResultPoint[] = [];

  foundPossibleResultPoint(point: ResultPoint): void {
    this.detectedPoints.push(point);
    console.log(`Detection progress: ${this.detectedPoints.length} points`);
  }

  getDetectedPoints(): ResultPoint[] {
    return this.detectedPoints;
  }

  clear(): void {
    this.detectedPoints = [];
  }
}

// Usage
const vizCallback = new VisualizingCallback();
const vizHints = new Map<DecodeHintType, any>();
vizHints.set(DecodeHintType.NEED_RESULT_POINT_CALLBACK, vizCallback);

try {
  const result: Result = reader.decode(binaryBitmap, vizHints);
  console.log('Decoded:', result.getText());
  console.log('Total points detected:', vizCallback.getDetectedPoints().length);
} catch (error) {
  console.error('Failed, but detected points:', vizCallback.getDetectedPoints());
}

Decode Hints

Common decode hints for controlling reader behavior:

/**
 * Decode hint type enumeration
 * Used as keys in hints Map<DecodeHintType, any>
 */
enum DecodeHintType {
  OTHER,                          // any: unspecified application-specific hint
  PURE_BARCODE,                   // boolean: image contains only barcode, no border/rotation
  POSSIBLE_FORMATS,               // BarcodeFormat[]: limit decoding to specific formats
  TRY_HARDER,                     // boolean: spend more time for better accuracy
  CHARACTER_SET,                  // string: character encoding (e.g., "UTF-8", "ISO-8859-1")
  ALLOWED_LENGTHS,                // Int32Array: valid barcode lengths (for ITF)
  ASSUME_CODE_39_CHECK_DIGIT,     // boolean: validate Code 39 check digit
  ENABLE_CODE_39_EXTENDED_MODE,   // boolean: enable full ASCII for Code 39
  ASSUME_GS1,                     // boolean: treat as GS1 barcode (affects FNC1 handling)
  RETURN_CODABAR_START_END,       // boolean: include Codabar start/stop characters
  NEED_RESULT_POINT_CALLBACK,     // ResultPointCallback: receive detection callbacks
  ALLOWED_EAN_EXTENSIONS          // Int32Array: allowed UPC/EAN extension lengths ([2], [5], or [2,5])
}

Comprehensive Hints Example:

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

// Build comprehensive hints map
const hints = new Map<DecodeHintType, any>();

// Limit to specific formats (improves performance)
hints.set(DecodeHintType.POSSIBLE_FORMATS, [
  BarcodeFormat.QR_CODE,
  BarcodeFormat.EAN_13,
  BarcodeFormat.CODE_128
]);

// Enable accuracy mode (slower but more reliable)
hints.set(DecodeHintType.TRY_HARDER, true);

// Specify character encoding for text interpretation
hints.set(DecodeHintType.CHARACTER_SET, 'UTF-8');

// For pure barcode images (no background, no rotation)
// hints.set(DecodeHintType.PURE_BARCODE, true);

// 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 - allowed lengths (e.g., ITF-14)
// 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 progress
const callback: ResultPointCallback = {
  foundPossibleResultPoint: (point: ResultPoint) => {
    console.log(`Detected point at (${point.getX()}, ${point.getY()})`);
  }
};
hints.set(DecodeHintType.NEED_RESULT_POINT_CALLBACK, callback);

// Use hints with reader
const reader = new MultiFormatReader();
const result = reader.decode(binaryBitmap, hints);

Encode Hints

Common encode hints for controlling writer behavior:

/**
 * Encode hint type enumeration
 * Used as keys in hints Map<EncodeHintType, any>
 */
enum EncodeHintType {
  ERROR_CORRECTION,    // varies by format: ErrorCorrectionLevel (QR), number (Aztec %, PDF417 0-8)
  CHARACTER_SET,       // string: character encoding (e.g., "UTF-8", "ISO-8859-1", "Shift_JIS")
  DATA_MATRIX_SHAPE,   // SymbolShapeHint: FORCE_NONE|FORCE_SQUARE|FORCE_RECTANGLE
  DATA_MATRIX_COMPACT, // boolean: use MinimalEncoder for better compression
  MIN_SIZE,            // Dimension: minimum barcode size (deprecated)
  MAX_SIZE,            // Dimension: maximum barcode size (deprecated)
  MARGIN,              // number: margin/quiet zone in pixels
  PDF417_COMPACT,      // boolean: use compact PDF417 mode
  PDF417_COMPACTION,   // Compaction: TEXT|BYTE|NUMERIC
  PDF417_DIMENSIONS,   // Dimensions: min/max rows and columns
  AZTEC_LAYERS,        // number: layer count (negative=compact, 0=auto, positive=full)
  QR_VERSION,          // number: QR Code version (1-40)
  GS1_FORMAT,          // boolean: encode to GS1 standard with FNC1
  FORCE_C40            // boolean: force C40 encoding for Data Matrix
}

Comprehensive Hints Example:

import {
  EncodeHintType,
  BarcodeFormat,
  QRCodeDecoderErrorCorrectionLevel,
  SymbolShapeHint,
  MultiFormatWriter,
  BitMatrix
} from '@zxing/library';

const writer = new MultiFormatWriter();

// QR Code hints
const qrHints = new Map<EncodeHintType, any>();
qrHints.set(EncodeHintType.ERROR_CORRECTION, QRCodeDecoderErrorCorrectionLevel.H); // High (30%)
qrHints.set(EncodeHintType.CHARACTER_SET, 'UTF-8');
qrHints.set(EncodeHintType.MARGIN, 1); // Minimal quiet zone
// qrHints.set(EncodeHintType.QR_VERSION, 10); // Force version 10

const qrMatrix: BitMatrix = writer.encode(
  'QR Code with hints',
  BarcodeFormat.QR_CODE,
  300,
  300,
  qrHints
);

// Data Matrix hints
const dmHints = new Map<EncodeHintType, any>();
dmHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
dmHints.set(EncodeHintType.CHARACTER_SET, 'UTF-8');
// dmHints.set(EncodeHintType.DATA_MATRIX_COMPACT, true); // Use MinimalEncoder
// dmHints.set(EncodeHintType.FORCE_C40, true); // Force C40 mode
// dmHints.set(EncodeHintType.GS1_FORMAT, true); // GS1 encoding

const dmMatrix: BitMatrix = writer.encode(
  'Data Matrix',
  BarcodeFormat.DATA_MATRIX,
  200,
  200,
  dmHints
);

// Aztec hints
const aztecHints = new Map<EncodeHintType, any>();
aztecHints.set(EncodeHintType.ERROR_CORRECTION, 33); // 33% error correction
aztecHints.set(EncodeHintType.AZTEC_LAYERS, 0); // Auto-select layers
aztecHints.set(EncodeHintType.CHARACTER_SET, 'UTF-8');

const aztecMatrix: BitMatrix = writer.encode(
  'Aztec Code',
  BarcodeFormat.AZTEC,
  200,
  200,
  aztecHints
);

// Code 128 hints
const code128Hints = new Map<EncodeHintType, any>();
code128Hints.set(EncodeHintType.MARGIN, 10); // Horizontal margin
// code128Hints.set(EncodeHintType.GS1_FORMAT, true); // For GS1-128

const code128Matrix: BitMatrix = writer.encode(
  'CODE128',
  BarcodeFormat.CODE_128,
  300,
  100,
  code128Hints
);

Common Patterns

Decode with Multiple Strategies

import {
  MultiFormatReader,
  BinaryBitmap,
  HybridBinarizer,
  GlobalHistogramBinarizer,
  RGBLuminanceSource,
  DecodeHintType,
  BarcodeFormat,
  Result
} from '@zxing/library';

function decodeRobust(
  imageData: Uint8ClampedArray,
  width: number,
  height: number
): Result | null {
  const reader = new MultiFormatReader();

  // Strategy 1: HybridBinarizer with common formats
  try {
    const source1 = new RGBLuminanceSource(imageData, width, height);
    const bitmap1 = new BinaryBitmap(new HybridBinarizer(source1));
    
    const hints1 = new Map<DecodeHintType, any>();
    hints1.set(DecodeHintType.POSSIBLE_FORMATS, [
      BarcodeFormat.QR_CODE,
      BarcodeFormat.EAN_13,
      BarcodeFormat.CODE_128
    ]);
    
    return reader.decode(bitmap1, hints1);
  } catch (e) {
    console.debug('Strategy 1 failed');
  }

  // Strategy 2: GlobalHistogramBinarizer
  try {
    const source2 = new RGBLuminanceSource(imageData, width, height);
    const bitmap2 = new BinaryBitmap(new GlobalHistogramBinarizer(source2));
    
    const hints2 = new Map<DecodeHintType, any>();
    hints2.set(DecodeHintType.TRY_HARDER, true);
    
    return reader.decode(bitmap2, hints2);
  } catch (e) {
    console.debug('Strategy 2 failed');
  }

  // Strategy 3: Inverted image (white-on-black)
  try {
    const source3 = new RGBLuminanceSource(imageData, width, height);
    const inverted = source3.invert();
    const bitmap3 = new BinaryBitmap(new HybridBinarizer(inverted));
    
    return reader.decode(bitmap3);
  } catch (e) {
    console.debug('Strategy 3 failed');
  }

  // Strategy 4: Try all formats with maximum accuracy
  try {
    const source4 = new RGBLuminanceSource(imageData, width, height);
    const bitmap4 = new BinaryBitmap(new HybridBinarizer(source4));
    
    const hints4 = new Map<DecodeHintType, any>();
    hints4.set(DecodeHintType.TRY_HARDER, true);
    
    return reader.decode(bitmap4, hints4);
  } catch (e) {
    console.debug('All strategies failed');
  }

  return null;
}

Batch Processing

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

interface BatchResult {
  success: boolean;
  result?: Result;
  error?: Error;
}

function batchDecode(
  images: { data: Uint8ClampedArray; width: number; height: number }[]
): BatchResult[] {
  const reader = new MultiFormatReader();
  
  // Set hints once for all images
  const hints = new Map<DecodeHintType, any>();
  hints.set(DecodeHintType.TRY_HARDER, true);
  reader.setHints(hints);

  return images.map((img, index) => {
    try {
      const source = new RGBLuminanceSource(img.data, img.width, img.height);
      const bitmap = new BinaryBitmap(new HybridBinarizer(source));
      const result: Result = reader.decodeWithState(bitmap);
      
      console.log(`Image ${index}: ${result.getText()}`);
      
      return { success: true, result };
    } catch (error) {
      console.error(`Image ${index} failed:`, error);
      return { success: false, error: error as Error };
    }
  });
}

// Process results
const results: BatchResult[] = batchDecode(imageArray);
const successful = results.filter(r => r.success);
console.log(`Successfully decoded ${successful.length} of ${results.length} images`);

Format-Specific Decoding

import {
  QRCodeReader,
  DataMatrixReader,
  AztecCodeReader,
  Code128Reader,
  EAN13Reader,
  BinaryBitmap,
  Result
} from '@zxing/library';

// Use format-specific reader when format is known
function decodeKnownFormat(
  bitmap: BinaryBitmap,
  format: BarcodeFormat
): Result | null {
  try {
    switch (format) {
      case BarcodeFormat.QR_CODE:
        return new QRCodeReader().decode(bitmap);
      
      case BarcodeFormat.DATA_MATRIX:
        return new DataMatrixReader().decode(bitmap);
      
      case BarcodeFormat.AZTEC:
        return new AztecCodeReader().decode(bitmap);
      
      case BarcodeFormat.CODE_128:
        // For 1D barcodes, need to use decode() which scans rows
        return new Code128Reader().decode(bitmap);
      
      case BarcodeFormat.EAN_13:
        return new EAN13Reader().decode(bitmap);
      
      default:
        // Fall back to MultiFormatReader
        const hints = new Map<DecodeHintType, any>();
        hints.set(DecodeHintType.POSSIBLE_FORMATS, [format]);
        return new MultiFormatReader().decode(bitmap, hints);
    }
  } catch (error) {
    console.error(`Failed to decode as ${format}:`, error);
    return null;
  }
}

Performance Optimization

Reader Reuse

import { MultiFormatReader, BinaryBitmap, DecodeHintType } from '@zxing/library';

// GOOD: Reuse reader instance
const reader = new MultiFormatReader();
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.TRY_HARDER, true);
reader.setHints(hints);

for (const bitmap of bitmaps) {
  try {
    const result = reader.decodeWithState(bitmap);
    console.log('Decoded:', result.getText());
  } catch (error) {
    // Continue to next bitmap
  }
}

// BAD: Creating new reader each time (wasteful)
for (const bitmap of bitmaps) {
  const reader = new MultiFormatReader(); // DON'T DO THIS
  try {
    const result = reader.decode(bitmap);
    console.log('Decoded:', result.getText());
  } catch (error) {
    // Continue
  }
}

Hint Optimization

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

// GOOD: Specific formats (fast)
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.POSSIBLE_FORMATS, [BarcodeFormat.QR_CODE]);

// BAD: No hints (tries all formats, slower)
// const hints = new Map<DecodeHintType, any>();

// GOOD: setHints + decodeWithState for continuous scanning
reader.setHints(hints);
for (const bitmap of stream) {
  try {
    const result = reader.decodeWithState(bitmap); // Fast
  } catch (e) {}
}

// BAD: Passing hints every time
for (const bitmap of stream) {
  try {
    const result = reader.decode(bitmap, hints); // Slower
  } catch (e) {}
}

Related Documentation

  • QR Code API - QR Code specific reader/writer
  • Data Matrix API - Data Matrix specific reader/writer
  • Aztec API - Aztec specific reader/writer
  • PDF417 API - PDF417 reader
  • 1D Barcodes API - All 1D format readers
  • Image Processing API - BinaryBitmap, LuminanceSource, Binarizer
  • Types and Enums API - Detailed enum documentation
  • Common Utilities API - BitArray, BitMatrix utilities

Install with Tessl CLI

npx tessl i tessl/npm-zxing--library

docs

index.md

tile.json