TypeScript port of ZXing multi-format 1D/2D barcode image processing library
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.
core/oned/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");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);The 1D barcode reading system is built around several key components:
OneDReader provides common functionality for all 1D barcode formats including row scanning, pattern matching, and rotation supportMultiFormatOneDReader attempts to decode using multiple format-specific readersAbstract 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:
TRY_HARDER hint is enabledUsage 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 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:
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 doneEAN-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:
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 (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:
Implementation Notes:
UPCAReader delegates to an internal EAN-13 reader and converts 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 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:
Compression Rules:
The last data digit determines how zeros are suppressed:
| Last Digit | UPC-E Format | UPC-A Expansion |
|---|---|---|
| 0, 1, 2 | XXXYY0-2 | XXX00-00YY0-2 |
| 3 | XXXXY3 | XXXX00000Y |
| 4 | XXXXZ4 | XXXXX0000Z |
| 5-9 | XXXXXV5-9 | XXXXX0000V |
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
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:
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
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:
Encoding Details:
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
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:
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)$: Dollar (code 39)/: Slash (code 40)+: Plus (code 41)%: Percent (code 42)Extended Code 39 uses combinations:
+A = 'a', +Z = 'z'%A = SOH, %Z = SUB/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 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:
Check Digit Calculation:
Code 93 uses two check digits (C and K):
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 charactersInterleaved 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:
Interleaving Explanation:
ITF encodes two digits simultaneously:
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 digitsCodabar Reader | RSS-14 Reader
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:
Start/Stop Character Meanings:
By convention in some 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
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:
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 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:
Status Warning:
⚠️ RSS Expanded reader is EXPERIMENTAL and NOT production-ready
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)");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);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;
}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
// ...
}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;
}
}
}| Format | Type | Characters | Check Digit | Typical Length | Use Case |
|---|---|---|---|---|---|
| EAN-13 | Numeric | 0-9 | Yes (mod 10) | 13 digits | Retail products worldwide |
| EAN-8 | Numeric | 0-9 | Yes (mod 10) | 8 digits | Small packages |
| UPC-A | Numeric | 0-9 | Yes (mod 10) | 12 digits | Retail products (US/Canada) |
| UPC-E | Numeric | 0-9 | Yes (mod 10) | 8 digits | Small packages (compressed) |
| Code 128 | Full ASCII | ASCII 0-127 | Yes (mod 103) | Variable | Shipping, logistics, general |
| Code 39 | Alphanumeric | 0-9, A-Z, 7 symbols | Optional (mod 43) | Variable | Industrial, automotive |
| Code 93 | Full ASCII | Full ASCII via shifts | Yes (2 digits) | Variable | Logistics, postal |
| ITF | Numeric | 0-9 | Optional | Even length | Distribution, warehousing |
| Codabar | Numeric + symbols | 0-9, 6 symbols | No | Variable | Libraries, blood banks |
| RSS-14 | Numeric | 14 digits (GTIN) | Yes (mod 10) | 14 digits | Small items, fresh food |
| RSS Expanded | Alphanumeric | Variable | Yes | Variable | Variable data (experimental) |
Install with Tessl CLI
npx tessl i tessl/npm-zxing--library@0.21.14