TypeScript port of ZXing multi-format 1D/2D barcode image processing library
The QR Code module provides comprehensive support for encoding and decoding QR Codes, a popular 2D barcode format. It includes classes for reading QR Codes from images, generating QR Code matrices, and managing QR Code-specific features like error correction levels, versions, and encoding modes.
core/qrcode/)import {
// Reader/Writer
QRCodeReader,
QRCodeWriter,
// Error correction
ErrorCorrectionLevel,
QRCodeDecoderErrorCorrectionLevel,
// Encoding modes
Mode,
QRCodeMode,
// Version info
Version,
QRCodeVersion,
// Encoder/Decoder
Encoder as QRCodeEncoder,
Decoder as QRCodeDecoder,
// QR Code representation
QRCode as QRCodeEncoderQRCode,
ByteMatrix as QRCodeByteMatrix,
// Matrix utilities
MatrixUtil as QRCodeMatrixUtil,
MaskUtil as QRCodeMaskUtil,
// Data masks
DataMask,
DataMaskValues,
// Bit stream parser
QRCodeDecodedBitStreamParser,
// Detector
Detector as QRCodeDetector,
// Result types
BarcodeFormat,
EncodeHintType,
DecodeHintType,
Result,
BinaryBitmap
} from "@zxing/library";The QR Code module is organized into several key components:
QRCodeReader) and encoding (QRCodeWriter) QR CodesDecodes QR Codes from binary images, with support for rotation, skew, and partial occlusion.
/**
* QR Code decoder that locates and decodes QR Codes in images
* Implements the Reader interface for QR Code barcode decoding
*/
class QRCodeReader implements Reader {
/**
* Locates and decodes a QR code in an image
* @param image - BinaryBitmap: binary bitmap to decode
* @param hints - Map<DecodeHintType, any>: optional decoding hints
* - TRY_HARDER: boolean for better accuracy
* - CHARACTER_SET: string for text encoding
* - PURE_BARCODE: boolean if image contains only QR code
* - NEED_RESULT_POINT_CALLBACK: ResultPointCallback for detection tracking
* @returns Result: decoded text, raw bytes, and metadata
* @throws NotFoundException if QR code cannot be found
* @throws FormatException if QR code cannot be decoded (invalid structure)
* @throws ChecksumException if error correction fails (too many errors)
*/
decode(image: BinaryBitmap, hints?: Map<DecodeHintType, any>): Result;
/**
* Resets the reader state
* Currently a no-op for QR Code reader
*/
reset(): void;
/**
* Gets the decoder instance (internal use)
* @returns Decoder: internal QR Code Decoder instance
*/
protected getDecoder(): Decoder;
/**
* Extracts QR Code bits from a pure monochrome image
* Used when PURE_BARCODE hint is set
* @param image - BitMatrix: binary matrix containing pure QR Code
* @returns BitMatrix: extracted QR Code bits
* @throws NotFoundException if extraction fails
*/
static extractPureBits(image: BitMatrix): BitMatrix;
}Usage Examples:
import {
QRCodeReader,
BinaryBitmap,
HybridBinarizer,
RGBLuminanceSource,
DecodeHintType,
Result,
ResultMetadataType
} from "@zxing/library";
// Basic QR Code reading
const reader = new QRCodeReader();
const luminanceSource = new RGBLuminanceSource(imageData, width, height);
const binarizer = new HybridBinarizer(luminanceSource);
const bitmap = new BinaryBitmap(binarizer);
try {
const result: Result = reader.decode(bitmap);
console.log("Decoded text:", result.getText());
console.log("Format:", result.getBarcodeFormat()); // BarcodeFormat.QR_CODE
// Access result points (finder patterns and alignment patterns)
const points = result.getResultPoints();
console.log(`Found ${points.length} result points`);
} catch (error) {
console.error("QR decode failed:", error);
}
// Reading with hints
const hints = new Map<DecodeHintType, any>();
hints.set(DecodeHintType.TRY_HARDER, true);
hints.set(DecodeHintType.CHARACTER_SET, "UTF-8");
try {
const result2: Result = reader.decode(bitmap, hints);
console.log("Decoded with hints:", result2.getText());
} catch (error) {
console.error("QR decode with hints failed:", error);
}
// Reading pure QR Code (no border/rotation, faster)
const pureHints = new Map<DecodeHintType, any>();
pureHints.set(DecodeHintType.PURE_BARCODE, true);
try {
const result3: Result = reader.decode(bitmap, pureHints);
console.log("Pure QR decode:", result3.getText());
} catch (error) {
console.error("Pure QR decode failed:", error);
}
// Accessing metadata
const result: Result = reader.decode(bitmap);
const metadata = result.getResultMetadata();
if (metadata) {
const ecLevel = metadata.get(ResultMetadataType.ERROR_CORRECTION_LEVEL);
console.log("Error correction level:", ecLevel); // "L", "M", "Q", or "H"
const byteSegments = metadata.get(ResultMetadataType.BYTE_SEGMENTS);
if (byteSegments) {
console.log("Byte segments:", byteSegments);
}
const orientation = metadata.get(ResultMetadataType.ORIENTATION);
if (orientation !== undefined) {
console.log(`QR rotated ${orientation} degrees`);
}
}
// With result point callback for detection tracking
const callback: ResultPointCallback = {
foundPossibleResultPoint(point: ResultPoint): void {
console.log(`Found finder pattern at (${point.getX()}, ${point.getY()})`);
}
};
const trackingHints = new Map<DecodeHintType, any>();
trackingHints.set(DecodeHintType.NEED_RESULT_POINT_CALLBACK, callback);
const result4: Result = reader.decode(bitmap, trackingHints);Error Correction Levels | Decode Hints
Encodes content as QR Code bit matrices suitable for rendering.
/**
* QR Code encoder that generates QR Code bit matrices
* Implements the Writer interface for QR Code encoding
*/
class QRCodeWriter implements Writer {
/**
* Encodes content as a QR Code bit matrix
* @param contents - string: text content to encode
* @param format - BarcodeFormat: must be BarcodeFormat.QR_CODE
* @param width - number: desired width in pixels
* @param height - number: desired height in pixels
* @param hints - Map<EncodeHintType, any>: optional encoding hints
* - ERROR_CORRECTION: ErrorCorrectionLevel or string ("L"|"M"|"Q"|"H")
* - CHARACTER_SET: string (e.g., "UTF-8", "ISO-8859-1", "Shift_JIS")
* - QR_VERSION: number (1-40) to force specific version
* - MARGIN: number (quiet zone size in modules, default: 4)
* @returns BitMatrix: encoded QR Code as binary matrix
* @throws WriterException if encoding fails (data too large, invalid version)
* @throws IllegalArgumentException if format is not QR_CODE or dimensions invalid
*/
encode(
contents: string,
format: BarcodeFormat,
width: number,
height: number,
hints?: Map<EncodeHintType, any>
): BitMatrix;
/**
* Default quiet zone size (border) in modules
* Per ISO 18004, minimum is 4 modules
*/
static QUIET_ZONE_SIZE: number; // 4
/**
* Renders a QR Code to a bit matrix with specified dimensions
* Static utility for rendering QRCode instances
* @param code - QRCode: QRCode instance to render
* @param width - number: target width in pixels
* @param height - number: target height in pixels
* @param quietZone - number: quiet zone size in modules
* @returns BitMatrix: rendered QR Code suitable for display
* @throws WriterException if rendering fails
*/
static renderResult(
code: QRCode,
width: number,
height: number,
quietZone: number
): BitMatrix;
}Usage Examples:
import {
QRCodeWriter,
BarcodeFormat,
EncodeHintType,
ErrorCorrectionLevel,
QRCodeDecoderErrorCorrectionLevel,
BitMatrix
} from "@zxing/library";
const writer = new QRCodeWriter();
// Basic QR Code generation (defaults to error correction M)
const matrix1: BitMatrix = writer.encode(
"Hello, World!",
BarcodeFormat.QR_CODE,
300,
300
);
console.log(`Generated ${matrix1.getWidth()}×${matrix1.getHeight()} QR Code`);
// With error correction level
const hints = new Map<EncodeHintType, any>();
hints.set(EncodeHintType.ERROR_CORRECTION, QRCodeDecoderErrorCorrectionLevel.H);
hints.set(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.set(EncodeHintType.MARGIN, 2); // Quiet zone: 2 modules
const matrix2: BitMatrix = writer.encode(
"https://example.com",
BarcodeFormat.QR_CODE,
400,
400,
hints
);
// Encoding with specific version
const versionHints = new Map<EncodeHintType, any>();
versionHints.set(EncodeHintType.QR_VERSION, 10); // Force version 10 (57×57 modules)
versionHints.set(EncodeHintType.ERROR_CORRECTION, QRCodeDecoderErrorCorrectionLevel.M);
try {
const matrix3: BitMatrix = writer.encode(
"Data that must fit in version 10",
BarcodeFormat.QR_CODE,
500,
500,
versionHints
);
console.log("Version 10 encoding successful");
} catch (e) {
console.error("Data too large for version 10:", e);
}
// Encoding international text
const intlHints = new Map<EncodeHintType, any>();
intlHints.set(EncodeHintType.CHARACTER_SET, "UTF-8");
intlHints.set(EncodeHintType.ERROR_CORRECTION, "H"); // String also accepted
const matrix4: BitMatrix = writer.encode(
"Hello 世界 🌍",
BarcodeFormat.QR_CODE,
300,
300,
intlHints
);
// Minimal quiet zone for space-constrained applications
const minimalHints = new Map<EncodeHintType, any>();
minimalHints.set(EncodeHintType.MARGIN, 1); // Minimum 1 module
// Note: ISO 18004 recommends 4 modules, but 1 may work in controlled environments
const matrix5: BitMatrix = writer.encode(
"Minimal margins",
BarcodeFormat.QR_CODE,
250,
250,
minimalHints
);Render to canvas:
import { QRCodeWriter, BarcodeFormat, BitMatrix } from "@zxing/library";
function renderToCanvas(matrix: BitMatrix, canvas: HTMLCanvasElement): void {
const ctx = canvas.getContext("2d")!;
const width = matrix.getWidth();
const height = matrix.getHeight();
canvas.width = width;
canvas.height = height;
const imageData = ctx.createImageData(width, height);
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const offset = (y * width + x) * 4;
const color = matrix.get(x, y) ? 0 : 255; // Black or white
imageData.data[offset] = color; // R
imageData.data[offset + 1] = color; // G
imageData.data[offset + 2] = color; // B
imageData.data[offset + 3] = 255; // A
}
}
ctx.putImageData(imageData, 0, 0);
}
// Usage
const writer = new QRCodeWriter();
const matrix: BitMatrix = writer.encode("QR Code", BarcodeFormat.QR_CODE, 300, 300);
const canvas = document.getElementById("qr-canvas") as HTMLCanvasElement;
renderToCanvas(matrix, canvas);Render to image data URL:
import { QRCodeWriter, BarcodeFormat, BitMatrix } from "@zxing/library";
function renderToDataURL(
matrix: BitMatrix,
scale: number = 1
): string {
const width = matrix.getWidth() * scale;
const height = matrix.getHeight() * scale;
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d')!;
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = 'black';
for (let y = 0; y < matrix.getHeight(); y++) {
for (let x = 0; x < matrix.getWidth(); x++) {
if (matrix.get(x, y)) {
ctx.fillRect(x * scale, y * scale, scale, scale);
}
}
}
return canvas.toDataURL('image/png');
}
// Usage
const writer = new QRCodeWriter();
const matrix: BitMatrix = writer.encode("Data", BarcodeFormat.QR_CODE, 200, 200);
const dataURL: string = renderToDataURL(matrix, 4); // 4x scale
document.getElementById('qr-img')!.setAttribute('src', dataURL);Error Correction Levels | Encode Hints | QR Code Versions
Exported as: QRCodeDecoderErrorCorrectionLevel
QR Code error correction levels determine how much damage can be tolerated while still successfully decoding.
/**
* QR Code error correction levels (ISO 18004:2006, Section 6.5.1)
* Higher levels provide more error resilience but reduce data capacity
*/
class ErrorCorrectionLevel {
/**
* L = ~7% correction capacity
* Can recover from up to 7% data loss or damage
* Maximum data capacity, minimum error correction
*/
static L: ErrorCorrectionLevel;
/**
* M = ~15% correction capacity
* Can recover from up to 15% data loss or damage
* Balanced capacity and error correction (recommended default)
*/
static M: ErrorCorrectionLevel;
/**
* Q = ~25% correction capacity
* Can recover from up to 25% data loss or damage
*/
static Q: ErrorCorrectionLevel;
/**
* H = ~30% correction capacity
* Can recover from up to 30% data loss or damage
* Minimum data capacity, maximum error correction
*/
static H: ErrorCorrectionLevel;
/**
* Gets the error correction level numeric value
* @returns ErrorCorrectionLevelValues: enum value (0=L, 1=M, 2=Q, 3=H)
*/
getValue(): ErrorCorrectionLevelValues;
/**
* Gets the two-bit encoding for format information
* @returns number: bits representing this error correction level
* - 0x01 for L
* - 0x00 for M
* - 0x03 for Q
* - 0x02 for H
*/
getBits(): number;
/**
* Parses error correction level from string
* @param s - string: level string ("L", "M", "Q", or "H")
* @returns ErrorCorrectionLevel: corresponding level instance
* @throws IllegalArgumentException if string is invalid
*/
static fromString(s: string): ErrorCorrectionLevel;
/**
* Parses error correction level from format information bits
* @param bits - number: two bits encoding the level (0x00-0x03)
* @returns ErrorCorrectionLevel: corresponding level instance
* @throws IllegalArgumentException if bits are invalid
*/
static forBits(bits: number): ErrorCorrectionLevel;
/**
* String representation of the level
* @returns string: "L", "M", "Q", or "H"
*/
toString(): string;
/**
* Checks equality with another error correction level
* @param o - any: object to compare
* @returns boolean: true if equal
*/
equals(o: any): boolean;
}
/**
* Error correction level enum values
*/
enum ErrorCorrectionLevelValues {
L = 0, // ~7% correction capacity
M = 1, // ~15% correction capacity
Q = 2, // ~25% correction capacity
H = 3, // ~30% correction capacity
}Usage Examples:
import {
ErrorCorrectionLevel,
QRCodeDecoderErrorCorrectionLevel,
QRCodeWriter,
BarcodeFormat,
EncodeHintType,
BitMatrix
} from "@zxing/library";
// Using predefined levels
const levelL = ErrorCorrectionLevel.L; // Lowest correction, maximum data
const levelM = ErrorCorrectionLevel.M; // Medium correction (recommended default)
const levelQ = ErrorCorrectionLevel.Q; // Quartile correction
const levelH = ErrorCorrectionLevel.H; // Highest correction, minimum data
// Parsing from string
const level1: ErrorCorrectionLevel = ErrorCorrectionLevel.fromString("H");
console.log(level1.toString()); // "H"
const level2: ErrorCorrectionLevel = ErrorCorrectionLevel.fromString("M");
console.log(level2.getValue()); // 1 (ErrorCorrectionLevelValues.M)
// Getting bits for format information
const bits: number = ErrorCorrectionLevel.Q.getBits();
console.log("Q level bits:", bits.toString(2)); // "11" (0x03)
// Parsing from bits
const level3: ErrorCorrectionLevel = ErrorCorrectionLevel.forBits(0x00);
console.log(level3.toString()); // "M"
const level4: ErrorCorrectionLevel = ErrorCorrectionLevel.forBits(0x02);
console.log(level4.toString()); // "H"
// Comparing levels
if (levelH.equals(ErrorCorrectionLevel.H)) {
console.log("Highest error correction selected");
}
// Using in encoding
const hints = new Map<EncodeHintType, any>();
hints.set(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// Or using the exported alias:
// hints.set(EncodeHintType.ERROR_CORRECTION, QRCodeDecoderErrorCorrectionLevel.H);
const writer = new QRCodeWriter();
const matrix: BitMatrix = writer.encode(
"Important data",
BarcodeFormat.QR_CODE,
300,
300,
hints
);
// Trade-offs between levels
// L: ~7% correction - Maximum data capacity (e.g., 2953 bytes for version 40)
// Use for: Clean environments, high-quality printing
// M: ~15% correction - Balanced (recommended for most uses) (~2331 bytes for version 40)
// Use for: General purpose applications
// Q: ~25% correction - More robust (~1663 bytes for version 40)
// Use for: Moderate damage expected, outdoor applications
// H: ~30% correction - Maximum robustness (~1273 bytes for version 40)
// Use for: High damage expected, small print sizes, critical data
// Example: selecting level based on use case
function selectErrorCorrectionLevel(useCase: string): ErrorCorrectionLevel {
switch (useCase) {
case 'print-high-quality':
return ErrorCorrectionLevel.L;
case 'screen-display':
return ErrorCorrectionLevel.M;
case 'outdoor-signage':
return ErrorCorrectionLevel.Q;
case 'small-print':
case 'critical-data':
return ErrorCorrectionLevel.H;
default:
return ErrorCorrectionLevel.M;
}
}
const level: ErrorCorrectionLevel = selectErrorCorrectionLevel('outdoor-signage');
console.log("Selected level:", level.toString());Error correction capacity details:
import { ErrorCorrectionLevel, Version } from "@zxing/library";
// Calculate data capacity for different EC levels
function getDataCapacity(
version: Version,
ecLevel: ErrorCorrectionLevel
): number {
const totalCodewords: number = version.getTotalCodewords();
const ecBlocks = version.getECBlocksForLevel(ecLevel);
const ecCodewords: number = ecBlocks.getTotalECCodewords();
return totalCodewords - ecCodewords;
}
const version10 = Version.getVersionForNumber(10);
console.log("Version 10 capacities:");
console.log("L:", getDataCapacity(version10, ErrorCorrectionLevel.L), "codewords");
console.log("M:", getDataCapacity(version10, ErrorCorrectionLevel.M), "codewords");
console.log("Q:", getDataCapacity(version10, ErrorCorrectionLevel.Q), "codewords");
console.log("H:", getDataCapacity(version10, ErrorCorrectionLevel.H), "codewords");
// Approximate byte capacities for different versions and levels
// Version 1 (21×21): L=17 M=14 Q=11 H=7 bytes (numeric: L=41 M=34 Q=27 H=17)
// Version 10 (57×57): L=346 M=271 Q=195 H=156 bytes (numeric: L=1064 M=860 Q=624 H=482)
// Version 20 (97×97): L=858 M=666 Q=486 H=382 bytes (numeric: L=2670 M=2088 Q=1552 H=1226)
// Version 40 (177×177): L=2953 M=2331 Q=1663 H=1273 bytesExported as: QRCodeVersion
QR Code version information determines the symbol size and data capacity. Versions range from 1 (21×21 modules) to 40 (177×177 modules).
/**
* QR Code version information (ISO 18004:2006 Annex D)
* Versions 1-40, where version N has dimensions (17 + 4*N) × (17 + 4*N) modules
* Higher versions support more data but require larger physical size
*/
class Version {
/**
* Gets the version number
* @returns number: version number (1-40)
*/
getVersionNumber(): number;
/**
* Gets the coordinates of alignment pattern centers
* Version 1 has no alignment patterns, version 2+ have 1 or more
* @returns Int32Array: array of alignment pattern center coordinates in modules
*/
getAlignmentPatternCenters(): Int32Array;
/**
* Gets the total number of codewords (data + error correction) in this version
* @returns number: total codeword count
*/
getTotalCodewords(): number;
/**
* Gets the dimension (width/height) in modules for this version
* Formula: 17 + 4 * versionNumber
* @returns number: dimension in modules (e.g., 21 for version 1, 177 for version 40)
*/
getDimensionForVersion(): number;
/**
* Gets error correction blocks for specified error correction level
* @param ecLevel - ErrorCorrectionLevel: error correction level (L, M, Q, or H)
* @returns ECBlocks: error correction block information
*/
getECBlocksForLevel(ecLevel: ErrorCorrectionLevel): ECBlocks;
/**
* Deduces version from QR Code dimensions in modules
* @param dimension - number: dimension in modules (must be 21 + 4n where n >= 0)
* @returns Version: version for the given dimension
* @throws FormatException if dimension is not valid (must be 21, 25, 29, 33, ...)
*/
static getProvisionalVersionForDimension(dimension: number): Version;
/**
* Gets version by version number
* @param versionNumber - number: version number (1-40)
* @returns Version: version instance
* @throws IllegalArgumentException if version number is out of range
*/
static getVersionForNumber(versionNumber: number): Version;
/**
* Decodes version information from version bits (for versions 7+)
* Version info is 18 bits encoded with BCH error correction
* @param versionBits - number: version information bits
* @returns Version|null: decoded version or null if cannot be decoded
*/
static decodeVersionInformation(versionBits: number): Version;
/**
* Builds function pattern bit matrix for this version
* Marks positions of finder patterns, timing patterns, alignment patterns
* @returns BitMatrix: matrix with function patterns marked as true
*/
buildFunctionPattern(): BitMatrix;
/**
* String representation of version
* @returns string: version number as string
*/
toString(): string;
}Usage Examples:
import { Version, ErrorCorrectionLevel, ECBlocks } from "@zxing/library";
// Getting version by number
const version1: Version = Version.getVersionForNumber(1);
const version10: Version = Version.getVersionForNumber(10);
const version40: Version = Version.getVersionForNumber(40);
console.log("Version 1 dimension:", version1.getDimensionForVersion()); // 21 modules
console.log("Version 10 dimension:", version10.getDimensionForVersion()); // 57 modules
console.log("Version 40 dimension:", version40.getDimensionForVersion()); // 177 modules
// Getting version properties
console.log("Version:", version10.getVersionNumber()); // 10
console.log("Total codewords:", version10.getTotalCodewords()); // Total data + EC
console.log("Dimension:", version10.getDimensionForVersion(), "×", version10.getDimensionForVersion());
// Alignment pattern centers
const centers: Int32Array = version10.getAlignmentPatternCenters();
console.log("Alignment centers:", Array.from(centers)); // [6, 28, 50]
// Version 1 has no alignment patterns
const centers1: Int32Array = version1.getAlignmentPatternCenters();
console.log("Version 1 alignment centers:", Array.from(centers1)); // [] empty
// Version 40 has many alignment patterns
const centers40: Int32Array = version40.getAlignmentPatternCenters();
console.log("Version 40 alignment centers:", Array.from(centers40));
// Error correction blocks
const ecBlocks: ECBlocks = version10.getECBlocksForLevel(ErrorCorrectionLevel.H);
console.log("EC codewords per block:", ecBlocks.getECCodewordsPerBlock());
console.log("Number of EC blocks:", ecBlocks.getNumBlocks());
console.log("Total EC codewords:", ecBlocks.getTotalECCodewords());
// Deducing version from dimensions
const dimension = 57; // 57×57 modules
const deducedVersion: Version = Version.getProvisionalVersionForDimension(dimension);
console.log("Version from dimension 57:", deducedVersion.getVersionNumber()); // 10
// Validate dimension
try {
const invalid = Version.getProvisionalVersionForDimension(50); // Invalid (not 21+4n)
} catch (e) {
console.error("Invalid dimension:", e);
}
// Version capacity calculations
function getDataCapacity(version: Version, ecLevel: ErrorCorrectionLevel): number {
const totalCodewords: number = version.getTotalCodewords();
const ecBlocks: ECBlocks = version.getECBlocksForLevel(ecLevel);
const ecCodewords: number = ecBlocks.getTotalECCodewords();
return totalCodewords - ecCodewords;
}
console.log("Version 10-L capacity:", getDataCapacity(version10, ErrorCorrectionLevel.L), "codewords");
console.log("Version 10-M capacity:", getDataCapacity(version10, ErrorCorrectionLevel.M), "codewords");
console.log("Version 10-Q capacity:", getDataCapacity(version10, ErrorCorrectionLevel.Q), "codewords");
console.log("Version 10-H capacity:", getDataCapacity(version10, ErrorCorrectionLevel.H), "codewords");
// Build function pattern (for visualization or debugging)
const functionPattern: BitMatrix = version10.buildFunctionPattern();
console.log("Function pattern size:", functionPattern.getWidth(), "×", functionPattern.getHeight());
// Shows where finder patterns, timing patterns, and alignment patterns are located
// Version capacity reference table
const capacities = [
{ version: 1, dimension: 21, L: 25, M: 20, Q: 16, H: 10 }, // bytes
{ version: 5, dimension: 37, L: 108, M: 86, Q: 62, H: 48 },
{ version: 10, dimension: 57, L: 346, M: 271, Q: 195, H: 156 },
{ version: 20, dimension: 97, L: 858, M: 666, Q: 486, H: 382 },
{ version: 30, dimension: 137, L: 1542, M: 1193, Q: 865, H: 647 },
{ version: 40, dimension: 177, L: 2953, M: 2331, Q: 1663, H: 1273 }
];
// Select appropriate version for data size
function selectVersion(dataBytes: number, ecLevel: ErrorCorrectionLevel): Version | null {
for (let v = 1; v <= 40; v++) {
const version = Version.getVersionForNumber(v);
const capacity = getDataCapacity(version, ecLevel);
if (capacity >= dataBytes) {
return version;
}
}
return null; // Data too large
}
const requiredVersion = selectVersion(100, ErrorCorrectionLevel.M);
if (requiredVersion) {
console.log("Need at least version:", requiredVersion.getVersionNumber());
}Exported as: QRCodeMode
Encoding modes determine how data is encoded in the QR Code. Different modes are optimal for different types of data.
/**
* QR Code encoding modes (ISO 18004:2006, Section 6.4.1, Tables 2 and 3)
* Determines how data is encoded - different modes optimize for different character sets
*/
class Mode {
/**
* Terminator mode (end of data)
* Bits: 0000
*/
static TERMINATOR: Mode;
/**
* Numeric mode for digits 0-9
* Encoding: 3 digits per 10 bits = 3.33 bits per digit
* Character count bits: 10 (versions 1-9), 12 (10-26), 14 (27-40)
*/
static NUMERIC: Mode;
/**
* Alphanumeric mode for 0-9, A-Z (uppercase), space, and symbols: $ % * + - . / :
* Encoding: 2 characters per 11 bits = 5.5 bits per character
* Character count bits: 9 (versions 1-9), 11 (10-26), 13 (27-40)
*/
static ALPHANUMERIC: Mode;
/**
* Structured append mode (links multiple QR codes)
* Not supported for encoding in this implementation
*/
static STRUCTURED_APPEND: Mode;
/**
* Byte mode for 8-bit binary data
* Encoding: 8 bits per byte
* Character count bits: 8 (versions 1-9), 16 (10-26), 16 (27-40)
*/
static BYTE: Mode;
/**
* ECI (Extended Channel Interpretation) mode
* Allows switching character sets within QR Code
* Character counts don't apply
*/
static ECI: Mode;
/**
* Kanji mode for Shift JIS double-byte characters
* Encoding: 13 bits per character
* Character count bits: 8 (versions 1-9), 10 (10-26), 12 (27-40)
*/
static KANJI: Mode;
/**
* FNC1 in first position (GS1 mode for Application Identifiers)
*/
static FNC1_FIRST_POSITION: Mode;
/**
* FNC1 in second position (industry-specific applications)
*/
static FNC1_SECOND_POSITION: Mode;
/**
* Hanzi mode for GB 2312 Chinese characters
*/
static HANZI: Mode;
/**
* Parses mode from four-bit mode indicator
* @param bits - number: four bits encoding the mode (0x0-0xF)
* @returns Mode: corresponding mode instance
* @throws IllegalArgumentException if bits don't correspond to a known mode
*/
static forBits(bits: number): Mode;
/**
* Gets character count bits for this mode and version
* Number of bits used to encode the character/byte count
* @param version - Version: QR Code version (affects bit count)
* @returns number: bits needed to encode character count
*/
getCharacterCountBits(version: Version): number;
/**
* Gets the mode numeric value
* @returns ModeValues: enum value
*/
getValue(): ModeValues;
/**
* Gets the four-bit encoding for this mode
* Used in QR Code mode indicator
* @returns number: bits representing this mode (0x0-0xF)
*/
getBits(): number;
/**
* Checks equality with another mode
* @param o - any: object to compare
* @returns boolean: true if equal
*/
equals(o: any): boolean;
/**
* String representation of the mode
* @returns string: mode name (e.g., "NUMERIC", "BYTE", "KANJI")
*/
toString(): string;
}
/**
* Mode enum values
*/
enum ModeValues {
TERMINATOR, // End of data
NUMERIC, // Digits 0-9
ALPHANUMERIC, // 0-9, A-Z, space, $ % * + - . / :
STRUCTURED_APPEND, // Multi-QR linking
BYTE, // Binary/text data
ECI, // Character set switching
KANJI, // Shift JIS Kanji
FNC1_FIRST_POSITION, // GS1 format
FNC1_SECOND_POSITION, // Industry format
HANZI, // GB 2312 Chinese
}Usage Examples:
import { Mode, Version, ModeValues } from "@zxing/library";
// Mode constants
const numeric = Mode.NUMERIC; // For digits 0-9 only
const alphanumeric = Mode.ALPHANUMERIC; // For 0-9, A-Z, and limited symbols
const byte = Mode.BYTE; // For binary data and full Unicode
const kanji = Mode.KANJI; // For Shift JIS Kanji characters
console.log("Numeric mode:", numeric.toString()); // "NUMERIC"
console.log("Byte mode:", byte.toString()); // "BYTE"
// Getting character count bits (varies by version)
const version1 = Version.getVersionForNumber(1);
const version10 = Version.getVersionForNumber(10);
const version40 = Version.getVersionForNumber(40);
console.log("NUMERIC character count bits:");
console.log(" Version 1:", Mode.NUMERIC.getCharacterCountBits(version1)); // 10
console.log(" Version 10:", Mode.NUMERIC.getCharacterCountBits(version10)); // 12
console.log(" Version 40:", Mode.NUMERIC.getCharacterCountBits(version40)); // 14
console.log("ALPHANUMERIC character count bits:");
console.log(" Version 1:", Mode.ALPHANUMERIC.getCharacterCountBits(version1)); // 9
console.log(" Version 10:", Mode.ALPHANUMERIC.getCharacterCountBits(version10)); // 11
console.log(" Version 40:", Mode.ALPHANUMERIC.getCharacterCountBits(version40)); // 13
console.log("BYTE character count bits:");
console.log(" Version 1:", Mode.BYTE.getCharacterCountBits(version1)); // 8
console.log(" Version 10:", Mode.BYTE.getCharacterCountBits(version10)); // 16
console.log(" Version 40:", Mode.BYTE.getCharacterCountBits(version40)); // 16
console.log("KANJI character count bits:");
console.log(" Version 1:", Mode.KANJI.getCharacterCountBits(version1)); // 8
console.log(" Version 10:", Mode.KANJI.getCharacterCountBits(version10)); // 10
console.log(" Version 40:", Mode.KANJI.getCharacterCountBits(version40)); // 12
// Mode bit patterns
console.log("NUMERIC bits:", Mode.NUMERIC.getBits().toString(2).padStart(4, '0')); // "0001"
console.log("ALPHANUMERIC bits:", Mode.ALPHANUMERIC.getBits().toString(2).padStart(4, '0')); // "0010"
console.log("BYTE bits:", Mode.BYTE.getBits().toString(2).padStart(4, '0')); // "0100"
console.log("KANJI bits:", Mode.KANJI.getBits().toString(2).padStart(4, '0')); // "1000"
// Parsing from bits
const mode1: Mode = Mode.forBits(0x01); // NUMERIC
const mode2: Mode = Mode.forBits(0x02); // ALPHANUMERIC
const mode4: Mode = Mode.forBits(0x04); // BYTE
const mode8: Mode = Mode.forBits(0x08); // KANJI
console.log(mode1.toString()); // "NUMERIC"
console.log(mode2.toString()); // "ALPHANUMERIC"
console.log(mode4.toString()); // "BYTE"
console.log(mode8.toString()); // "KANJI"
// Mode selection guidelines and encoding efficiency:
// NUMERIC: Only digits 0-9 (most efficient for numbers)
// Example: "123456789012" (12 digits)
// Encoding: 3 digits per 10 bits = 40 bits total
// Best for: phone numbers, quantities, IDs
// ALPHANUMERIC: 0-9, A-Z (uppercase only), space, $ % * + - . / :
// Example: "HELLO WORLD" (11 characters)
// Encoding: 2 chars per 11 bits = 61 bits total
// Best for: product codes, URLs (limited), uppercase text
// BYTE: Any 8-bit data (most flexible)
// Example: "Hello, 世界!" (UTF-8 encoded: 16 bytes)
// Encoding: 8 bits per byte = 128 bits total
// Best for: mixed case text, Unicode, binary data
// KANJI: Shift JIS Kanji characters (efficient for Japanese)
// Example: "東京" (2 Kanji characters)
// Encoding: 13 bits per character = 26 bits total
// Best for: Japanese text in Shift_JIS encoding
// Comparing modes
if (numeric.equals(Mode.NUMERIC)) {
console.log("Mode is NUMERIC");
}
// Mode efficiency comparison
function calculateBits(data: string, mode: Mode, version: Version): number {
const countBits: number = mode.getCharacterCountBits(version);
const modeBits = 4;
switch (mode) {
case Mode.NUMERIC:
const numericBits = Math.ceil(data.length / 3) * 10;
return modeBits + countBits + numericBits;
case Mode.ALPHANUMERIC:
const alphaBits = Math.ceil(data.length / 2) * 11;
return modeBits + countBits + alphaBits;
case Mode.BYTE:
const byteBits = data.length * 8;
return modeBits + countBits + byteBits;
case Mode.KANJI:
const kanjiBits = data.length * 13;
return modeBits + countBits + kanjiBits;
default:
return 0;
}
}
const testData = "123456789012";
console.log(`"${testData}" bits needed:`);
console.log(" NUMERIC:", calculateBits(testData, Mode.NUMERIC, version1));
console.log(" BYTE:", calculateBits(testData, Mode.BYTE, version1));
// NUMERIC: 4 (mode) + 10 (count) + 40 (data) = 54 bits
// BYTE: 4 (mode) + 8 (count) + 96 (data) = 108 bits
// NUMERIC is much more efficient for digit-only dataMode Selection Helper:
import { Mode, Encoder } from "@zxing/library";
// The encoder automatically chooses the best mode
function determineBestMode(content: string): Mode {
// This is what the encoder does internally
return Encoder.chooseMode(content);
}
console.log("123456:", determineBestMode("123456").toString()); // "NUMERIC"
console.log("HELLO:", determineBestMode("HELLO").toString()); // "ALPHANUMERIC"
console.log("Hello:", determineBestMode("Hello").toString()); // "BYTE" (lowercase)
console.log("Hello, World!:", determineBestMode("Hello, World!").toString()); // "BYTE" (comma not in alphanumeric)
// Character set validation
function isNumericOnly(text: string): boolean {
return /^\d+$/.test(text);
}
function isAlphanumericOnly(text: string): boolean {
// Valid: 0-9, A-Z, space, $ % * + - . / :
return /^[0-9A-Z $%*+\-./:]+$/.test(text);
}
console.log("123456 is numeric:", isNumericOnly("123456")); // true
console.log("HELLO is alphanumeric:", isAlphanumericOnly("HELLO")); // true
console.log("Hello is alphanumeric:", isAlphanumericOnly("Hello")); // false (lowercase)
console.log("A-B is alphanumeric:", isAlphanumericOnly("A-B")); // true
console.log("A_B is alphanumeric:", isAlphanumericOnly("A_B")); // false (underscore not allowed)Exported as: QRCodeEncoder
High-level encoding logic that orchestrates QR Code generation from text content.
/**
* QR Code encoding logic and utilities
* Provides high-level encoding, mode selection, and matrix generation
*/
class Encoder {
/**
* Default character encoding for byte mode
*/
static DEFAULT_BYTE_MODE_ENCODING: string; // "UTF-8"
/**
* Encodes content as a QR Code with specified error correction
* @param content - string: text content to encode
* @param ecLevel - ErrorCorrectionLevel: error correction level (L, M, Q, H)
* @param hints - Map<EncodeHintType, any>: optional hints (CHARACTER_SET, QR_VERSION, MARGIN)
* @returns QRCode: encoded QR Code instance with matrix
* @throws WriterException if encoding fails (data too large, invalid version)
*/
static encode(
content: string,
ecLevel: ErrorCorrectionLevel,
hints?: Map<EncodeHintType, any>
): QRCode;
/**
* Chooses the best encoding mode for content
* Automatically selects NUMERIC, ALPHANUMERIC, BYTE, or KANJI
* @param content - string: content to encode
* @param encoding - string: optional character encoding hint (default: undefined)
* @returns Mode: best mode for the content
*/
static chooseMode(content: string, encoding?: string): Mode;
/**
* Gets alphanumeric code for a character
* Valid characters: 0-9, A-Z, space, $ % * + - . / :
* @param code - number: character code point
* @returns number: alphanumeric code (0-44) or -1 if not alphanumeric
*/
static getAlphanumericCode(code: number): number;
}Encoding Process:
The Encoder orchestrates the complete QR Code generation:
Usage Examples:
import {
Encoder,
ErrorCorrectionLevel,
QRCodeEncoderQRCode,
Mode,
EncodeHintType,
Version
} from "@zxing/library";
// Basic encoding
const qrCode: QRCodeEncoderQRCode = Encoder.encode(
"Hello, World!",
ErrorCorrectionLevel.M
);
console.log("QR Code version:", qrCode.getVersion().getVersionNumber());
console.log("Mode:", qrCode.getMode().toString());
console.log("Error correction:", qrCode.getECLevel().toString());
console.log("Mask pattern:", qrCode.getMaskPattern());
const matrix = qrCode.getMatrix();
console.log("Matrix size:", matrix.getWidth(), "×", matrix.getHeight());
// Encoding with hints
const hints = new Map<EncodeHintType, any>();
hints.set(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.set(EncodeHintType.QR_VERSION, 5); // Force version 5
const qrCode2: QRCodeEncoderQRCode = Encoder.encode(
"Data for version 5",
ErrorCorrectionLevel.H,
hints
);
// Choosing encoding mode
const mode1: Mode = Encoder.chooseMode("123456"); // NUMERIC
const mode2: Mode = Encoder.chooseMode("HELLO"); // ALPHANUMERIC
const mode3: Mode = Encoder.chooseMode("Hello, World!"); // BYTE (lowercase + comma)
const mode4: Mode = Encoder.chooseMode("こんにちは", "Shift_JIS"); // KANJI
console.log("123456 →", mode1.toString());
console.log("HELLO →", mode2.toString());
console.log("Hello, World! →", mode3.toString());
// Checking alphanumeric validity
function isValidAlphanumeric(text: string): boolean {
for (let i = 0; i < text.length; i++) {
if (Encoder.getAlphanumericCode(text.charCodeAt(i)) === -1) {
return false;
}
}
return true;
}
console.log("HELLO123 is alphanumeric:", isValidAlphanumeric("HELLO123")); // true
console.log("Hello123 is alphanumeric:", isValidAlphanumeric("Hello123")); // false (lowercase)
console.log("HELLO-WORLD is alphanumeric:", isValidAlphanumeric("HELLO-WORLD")); // true
console.log("HELLO_WORLD is alphanumeric:", isValidAlphanumeric("HELLO_WORLD")); // false (underscore)
// Valid alphanumeric characters
const validChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
console.log("Valid alphanumeric:", validChars);
// Get alphanumeric codes
console.log("'0' code:", Encoder.getAlphanumericCode('0'.charCodeAt(0))); // 0
console.log("'9' code:", Encoder.getAlphanumericCode('9'.charCodeAt(0))); // 9
console.log("'A' code:", Encoder.getAlphanumericCode('A'.charCodeAt(0))); // 10
console.log("'Z' code:", Encoder.getAlphanumericCode('Z'.charCodeAt(0))); // 35
console.log("' ' code:", Encoder.getAlphanumericCode(' '.charCodeAt(0))); // 36
console.log("'$' code:", Encoder.getAlphanumericCode('$'.charCodeAt(0))); // 37
console.log("'_' code:", Encoder.getAlphanumericCode('_'.charCodeAt(0))); // -1 (invalid)Encoding Efficiency:
import { Mode, Version } from "@zxing/library";
// Bits required for different content types
interface EncodingStats {
mode: string;
modeBits: number;
countBits: number;
dataBits: number;
totalBits: number;
}
function analyzeEncoding(content: string, mode: Mode, version: Version): EncodingStats {
const modeBits = 4;
const countBits = mode.getCharacterCountBits(version);
let dataBits = 0;
if (mode === Mode.NUMERIC) {
dataBits = Math.ceil(content.length / 3) * 10;
} else if (mode === Mode.ALPHANUMERIC) {
dataBits = Math.ceil(content.length / 2) * 11;
} else if (mode === Mode.BYTE) {
dataBits = content.length * 8;
} else if (mode === Mode.KANJI) {
dataBits = content.length * 13;
}
return {
mode: mode.toString(),
modeBits,
countBits,
dataBits,
totalBits: modeBits + countBits + dataBits
};
}
const version1 = Version.getVersionForNumber(1);
// Compare encoding efficiency
const numericData = "123456789012"; // 12 digits
console.log("Numeric data:", numericData);
console.log(analyzeEncoding(numericData, Mode.NUMERIC, version1));
// { mode: "NUMERIC", modeBits: 4, countBits: 10, dataBits: 40, totalBits: 54 }
console.log(analyzeEncoding(numericData, Mode.BYTE, version1));
// { mode: "BYTE", modeBits: 4, countBits: 8, dataBits: 96, totalBits: 108 }
// NUMERIC saves 54 bits (50% more efficient)
const alphaData = "HELLO WORLD"; // 11 characters
console.log("Alphanumeric data:", alphaData);
console.log(analyzeEncoding(alphaData, Mode.ALPHANUMERIC, version1));
// { mode: "ALPHANUMERIC", modeBits: 4, countBits: 9, dataBits: 61, totalBits: 74 }
console.log(analyzeEncoding(alphaData, Mode.BYTE, version1));
// { mode: "BYTE", modeBits: 4, countBits: 8, dataBits: 88, totalBits: 100 }
// ALPHANUMERIC saves 26 bits (26% more efficient)QR Code Mode | Error Correction Levels
Exported as: QRCodeEncoderQRCode
Represents a QR Code with all its properties and matrix.
/**
* Represents a QR Code with its configuration and matrix
* Container for encoded QR Code data, metadata, and rendering matrix
*/
class QRCode {
/**
* Number of mask patterns defined in QR Code standard
*/
static NUM_MASK_PATTERNS: number; // 8
/**
* Create empty QR Code
*/
constructor();
/**
* Gets the encoding mode
* @returns Mode: encoding mode used (NUMERIC, ALPHANUMERIC, BYTE, etc.)
*/
getMode(): Mode;
/**
* Sets the encoding mode
* @param value - Mode: mode to set
*/
setMode(value: Mode): void;
/**
* Gets the error correction level
* @returns ErrorCorrectionLevel: EC level (L, M, Q, or H)
*/
getECLevel(): ErrorCorrectionLevel;
/**
* Sets the error correction level
* @param value - ErrorCorrectionLevel: error correction level to set
*/
setECLevel(value: ErrorCorrectionLevel): void;
/**
* Gets the QR Code version
* @returns Version: version (1-40)
*/
getVersion(): Version;
/**
* Sets the QR Code version
* @param version - Version: version to set (1-40)
*/
setVersion(version: Version): void;
/**
* Gets the mask pattern (0-7)
* @returns number: mask pattern index (0-7, or -1 if not set)
*/
getMaskPattern(): number;
/**
* Sets the mask pattern
* @param value - number: mask pattern index (0-7)
* @throws WriterException if mask pattern is invalid
*/
setMaskPattern(value: number): void;
/**
* Gets the byte matrix containing the QR Code
* @returns ByteMatrix: matrix with QR Code modules
*/
getMatrix(): ByteMatrix;
/**
* Sets the byte matrix
* @param value - ByteMatrix: matrix to set
*/
setMatrix(value: ByteMatrix): void;
/**
* Validates mask pattern value
* @param maskPattern - number: mask pattern to validate
* @returns boolean: true if mask pattern is valid (0-7), false otherwise
*/
static isValidMaskPattern(maskPattern: number): boolean;
/**
* String representation of QR Code with all properties
* @returns string: formatted string showing mode, EC level, version, mask pattern, and matrix
*/
toString(): string;
}Usage Examples:
import {
QRCode,
QRCodeEncoderQRCode,
Encoder,
ErrorCorrectionLevel,
Mode,
Version,
ByteMatrix
} from "@zxing/library";
// Creating QR Code through encoder (typical usage)
const qrCode: QRCodeEncoderQRCode = Encoder.encode(
"Hello, World!",
ErrorCorrectionLevel.M
);
// Accessing properties
console.log("Mode:", qrCode.getMode().toString()); // "BYTE"
console.log("Error Correction:", qrCode.getECLevel().toString()); // "M"
console.log("Version:", qrCode.getVersion().getVersionNumber()); // e.g., 1
console.log("Mask Pattern:", qrCode.getMaskPattern()); // e.g., 2 (0-7)
// Getting matrix for rendering
const matrix: ByteMatrix = qrCode.getMatrix();
console.log("Matrix dimensions:", matrix.getWidth(), "×", matrix.getHeight());
// Reading module values from matrix
for (let y = 0; y < matrix.getHeight(); y++) {
for (let x = 0; x < matrix.getWidth(); x++) {
const value: number = matrix.get(x, y);
// value: -1 = not set, 0 = white/light module, 1 = black/dark module
}
}
// Manually creating QR Code (advanced usage)
const manualQR = new QRCode();
manualQR.setMode(Mode.ALPHANUMERIC);
manualQR.setECLevel(ErrorCorrectionLevel.H);
manualQR.setVersion(Version.getVersionForNumber(5));
manualQR.setMaskPattern(3);
const manualMatrix = new ByteMatrix(37, 37); // Version 5 is 37×37
// ... populate matrix ...
manualQR.setMatrix(manualMatrix);
// Validating mask pattern
console.log("Is 5 valid mask?", QRCode.isValidMaskPattern(5)); // true
console.log("Is 8 valid mask?", QRCode.isValidMaskPattern(8)); // false
console.log("Is -1 valid mask?", QRCode.isValidMaskPattern(-1)); // false
// Valid mask patterns: 0, 1, 2, 3, 4, 5, 6, 7
for (let i = 0; i < 8; i++) {
console.log(`Mask ${i}:`, QRCode.isValidMaskPattern(i)); // All true
}
// Debug output
console.log(qrCode.toString());
// Output format:
// <<
// mode: BYTE
// ecLevel: M
// version: 1
// maskPattern: 2
// matrix:
// [matrix visualization]
// >>
// Analyze QR Code
function analyzeQRCode(qr: QRCode): {
version: number;
dimension: number;
mode: string;
ecLevel: string;
maskPattern: number;
totalModules: number;
} {
const version = qr.getVersion();
const dimension = version.getDimensionForVersion();
return {
version: version.getVersionNumber(),
dimension,
mode: qr.getMode().toString(),
ecLevel: qr.getECLevel().toString(),
maskPattern: qr.getMaskPattern(),
totalModules: dimension * dimension
};
}
const analysis = analyzeQRCode(qrCode);
console.log("QR Code analysis:", analysis);Mask Patterns:
QR Code uses 8 different mask patterns to break up patterns and improve readability. The encoder tests all 8 and selects the one with the lowest penalty score.
// Mask pattern formulas (applied to data region only):
// Pattern 0: (x + y) mod 2 == 0 (checkerboard)
// Pattern 1: y mod 2 == 0 (horizontal stripes)
// Pattern 2: x mod 3 == 0 (vertical stripes, 1:2 ratio)
// Pattern 3: (x + y) mod 3 == 0 (diagonal stripes, 1:2 ratio)
// Pattern 4: (floor(y/2) + floor(x/3)) mod 2 == 0 (larger blocks)
// Pattern 5: ((x*y) mod 2) + ((x*y) mod 3) == 0 (pattern based on x*y)
// Pattern 6: (((x*y) mod 2) + ((x*y) mod 3)) mod 2 == 0
// Pattern 7: (((x+y) mod 2) + ((x*y) mod 3)) mod 2 == 0
// The encoder calculates penalty for each mask pattern:
// Penalty 1: Consecutive runs of same-colored modules (horizontal and vertical)
// Penalty 2: 2×2 blocks of same color
// Penalty 3: Patterns resembling finder patterns (false positives)
// Penalty 4: Ratio of dark to light modules (ideal is 50:50)QR Code Mode | Error Correction Levels | Byte Matrix
Exported as: QRCodeByteMatrix
2D array of bytes representing the QR Code modules.
/**
* 2D matrix of bytes for QR Code representation
* Values: -1 (not set/reserved), 0 (white/light module), 1 (black/dark module)
*/
class ByteMatrix {
/**
* Constructs a byte matrix
* @param width - number: width in modules
* @param height - number: height in modules
*/
constructor(width: number, height: number);
/**
* Gets the matrix height
* @returns number: height in modules
*/
getHeight(): number;
/**
* Gets the matrix width
* @returns number: width in modules
*/
getWidth(): number;
/**
* Gets the byte value at position
* @param x - number: x coordinate (column)
* @param y - number: y coordinate (row)
* @returns number: byte value (-1, 0, or 1)
*/
get(x: number, y: number): number;
/**
* Gets the internal array representation
* Access pattern: array[y][x]
* @returns Array<Uint8Array>: array of rows
*/
getArray(): Array<Uint8Array>;
/**
* Sets a numeric value at position
* @param x - number: x coordinate
* @param y - number: y coordinate
* @param value - number: byte value to set (-1, 0, or 1)
*/
setNumber(x: number, y: number, value: number): void;
/**
* Sets a boolean value at position
* @param x - number: x coordinate
* @param y - number: y coordinate
* @param value - boolean: true sets 1 (black), false sets 0 (white)
*/
setBoolean(x: number, y: number, value: boolean): void;
/**
* Clears matrix with specified value
* @param value - number: value to fill matrix with (typically -1 or 0)
*/
clear(value: number): void;
/**
* Checks equality with another matrix
* @param o - any: object to compare
* @returns boolean: true if dimensions and all values are equal
*/
equals(o: any): boolean;
/**
* String representation for debugging
* @returns string: formatted string showing matrix (0s, 1s, and spaces for -1)
*/
toString(): string;
}Module Value Meanings:
-1: Not set / reserved (for function patterns, format info, etc.)0: White/light module1: Black/dark moduleUsage Examples:
import { ByteMatrix, Encoder, ErrorCorrectionLevel, QRCodeEncoderQRCode } from "@zxing/library";
// Getting matrix from encoded QR Code
const qrCode: QRCodeEncoderQRCode = Encoder.encode("Hello", ErrorCorrectionLevel.M);
const matrix: ByteMatrix = qrCode.getMatrix();
console.log("Width:", matrix.getWidth());
console.log("Height:", matrix.getHeight());
// Reading module values
const topLeftModule: number = matrix.get(0, 0);
console.log("Top-left module:", topLeftModule); // Typically 1 (black, part of finder pattern)
// Creating custom matrix
const customMatrix = new ByteMatrix(25, 25);
// Clearing matrix
customMatrix.clear(-1); // Set all to "not set"
customMatrix.clear(0); // Set all to white
// Setting individual modules
customMatrix.setNumber(10, 10, 1); // Set black module
customMatrix.setBoolean(11, 10, true); // Set black module (boolean)
customMatrix.setBoolean(12, 10, false); // Set white module
// Drawing a 7×7 finder pattern at top-left (0,0)
for (let x = 0; x < 7; x++) {
for (let y = 0; y < 7; y++) {
// Finder pattern: border and 3×3 center are black
if (
x === 0 || x === 6 || // Left and right borders
y === 0 || y === 6 || // Top and bottom borders
(x >= 2 && x <= 4 && y >= 2 && y <= 4) // 3×3 center
) {
customMatrix.setNumber(x, y, 1);
} else {
customMatrix.setNumber(x, y, 0);
}
}
}
// Accessing internal array (for performance-critical operations)
const array: Array<Uint8Array> = matrix.getArray();
for (let y = 0; y < matrix.getHeight(); y++) {
const row: Uint8Array = array[y];
for (let x = 0; x < matrix.getWidth(); x++) {
const value: number = row[x];
// Process module
}
}
// Rendering to canvas with module scaling
function renderMatrixToCanvas(
matrix: ByteMatrix,
canvas: HTMLCanvasElement,
moduleSize: number
): void {
const ctx = canvas.getContext("2d")!;
canvas.width = matrix.getWidth() * moduleSize;
canvas.height = matrix.getHeight() * moduleSize;
// White background
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw black modules
ctx.fillStyle = "black";
for (let y = 0; y < matrix.getHeight(); y++) {
for (let x = 0; x < matrix.getWidth(); x++) {
const value: number = matrix.get(x, y);
if (value === 1) {
ctx.fillRect(x * moduleSize, y * moduleSize, moduleSize, moduleSize);
}
}
}
}
// Usage
const canvas = document.getElementById('qr-canvas') as HTMLCanvasElement;
renderMatrixToCanvas(matrix, canvas, 10); // 10 pixels per module
// Comparing matrices
const qrCode2: QRCodeEncoderQRCode = Encoder.encode("Hello", ErrorCorrectionLevel.M);
const matrix2: ByteMatrix = qrCode2.getMatrix();
console.log("Matrices equal:", matrix.equals(matrix2)); // true (same input and EC level)
// Debug output (shows matrix structure)
console.log(matrix.toString());
// Shows matrix as text:
// 1 1 1 1 1 1 1 0 ...
// 1 0 0 0 0 0 1 0 ...
// 1 0 1 1 1 0 1 0 ...
// ...import {
Encoder,
ErrorCorrectionLevel,
QRCodeEncoderQRCode,
Mode,
Version,
BitArray,
EncodeHintType
} from "@zxing/library";
// Complete custom encoding process
function customEncode(content: string): QRCodeEncoderQRCode {
// Step 1: Choose mode
const mode: Mode = Encoder.chooseMode(content);
console.log("Step 1 - Mode:", mode.toString());
// Step 2: Determine version and EC level
const ecLevel = ErrorCorrectionLevel.M;
// Step 3: Encode (encoder handles version selection automatically)
const hints = new Map<EncodeHintType, any>();
hints.set(EncodeHintType.CHARACTER_SET, "UTF-8");
const qrCode: QRCodeEncoderQRCode = Encoder.encode(content, ecLevel, hints);
console.log("Step 2 - Version:", qrCode.getVersion().getVersionNumber());
console.log("Step 3 - Mask:", qrCode.getMaskPattern());
return qrCode;
}
const encoded = customEncode("Custom encoding test");import {
QRCodeReader,
QRCodeWriter,
BarcodeFormat,
BinaryBitmap,
NotFoundException,
FormatException,
ChecksumException,
WriterException,
IllegalArgumentException,
ErrorCorrectionLevel,
BitMatrix
} from "@zxing/library";
// Reading errors
function safeRead(bitmap: BinaryBitmap): string | null {
const reader = new QRCodeReader();
try {
const result = reader.decode(bitmap);
return result.getText();
} catch (error) {
if (error instanceof NotFoundException) {
console.error("No QR code found in image");
// Image may not contain QR code, or QR code is too small/damaged
} else if (error instanceof FormatException) {
console.error("QR code format is invalid");
// QR code structure is malformed
} else if (error instanceof ChecksumException) {
console.error("QR code error correction failed");
// Too many errors for current error correction level
} else {
console.error("Unknown read error:", error);
}
return null;
}
}
// Writing errors
function safeWrite(contents: string): BitMatrix | null {
const writer = new QRCodeWriter();
try {
const matrix: BitMatrix = writer.encode(
contents,
BarcodeFormat.QR_CODE,
300,
300
);
return matrix;
} catch (error) {
if (error instanceof WriterException) {
console.error("QR code encoding failed:", error.message);
// Data may be too large for QR code, or invalid version specified
} else if (error instanceof IllegalArgumentException) {
console.error("Invalid parameters:", error.message);
// Check format, dimensions, or hint values
} else {
console.error("Unknown write error:", error);
}
return null;
}
}
// Version-specific encoding
import { EncodeHintType } from "@zxing/library";
function encodeWithVersionFallback(
content: string,
preferredVersion: number
): BitMatrix | null {
const writer = new QRCodeWriter();
const hints = new Map<EncodeHintType, any>();
hints.set(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
// Try preferred version first
hints.set(EncodeHintType.QR_VERSION, preferredVersion);
try {
return writer.encode(content, BarcodeFormat.QR_CODE, 300, 300, hints);
} catch (e) {
console.warn(`Version ${preferredVersion} failed, trying auto-select`);
}
// Fall back to automatic version selection
hints.delete(EncodeHintType.QR_VERSION);
try {
return writer.encode(content, BarcodeFormat.QR_CODE, 300, 300, hints);
} catch (e) {
console.error("Encoding failed even with auto-select:", e);
return null;
}
}Hints that can be passed to QR Code readers:
/**
* Decode hints for QR Code reading
*/
interface QRCodeDecodeHints {
/**
* PURE_BARCODE: boolean
* Set to true if image contains only QR code (no border, no rotation)
* Enables faster extraction without detection
*/
[DecodeHintType.PURE_BARCODE]?: boolean;
/**
* TRY_HARDER: boolean
* Spend more time to find QR code
* Tries more detection strategies and rotation angles
*/
[DecodeHintType.TRY_HARDER]?: boolean;
/**
* CHARACTER_SET: string
* Character encoding for text interpretation
* Examples: "UTF-8", "ISO-8859-1", "Shift_JIS", "GB2312"
*/
[DecodeHintType.CHARACTER_SET]?: string;
/**
* NEED_RESULT_POINT_CALLBACK: ResultPointCallback
* Callback for finder pattern and alignment pattern detection
*/
[DecodeHintType.NEED_RESULT_POINT_CALLBACK]?: ResultPointCallback;
}Hint Usage Examples:
import { QRCodeReader, DecodeHintType, BinaryBitmap, Result } from "@zxing/library";
const reader = new QRCodeReader();
// Pure barcode (fastest)
const pureHints = new Map<DecodeHintType, any>();
pureHints.set(DecodeHintType.PURE_BARCODE, true);
const pureResult: Result = reader.decode(pureBitmap, pureHints);
// Try harder (most accurate)
const hardHints = new Map<DecodeHintType, any>();
hardHints.set(DecodeHintType.TRY_HARDER, true);
const hardResult: Result = reader.decode(difficultBitmap, hardHints);
// Character set specification
const utf8Hints = new Map<DecodeHintType, any>();
utf8Hints.set(DecodeHintType.CHARACTER_SET, "UTF-8");
const utf8Result: Result = reader.decode(bitmap, utf8Hints);
// Shift JIS for Japanese text
const sjisHints = new Map<DecodeHintType, any>();
sjisHints.set(DecodeHintType.CHARACTER_SET, "Shift_JIS");
const sjisResult: Result = reader.decode(japaneseBitmap, sjisHints);Hints that can be passed to QR Code writers:
/**
* Encode hints for QR Code writing
*/
interface QRCodeEncodeHints {
/**
* ERROR_CORRECTION: ErrorCorrectionLevel or string
* Error correction level: L (~7%), M (~15%), Q (~25%), H (~30%)
* Can be ErrorCorrectionLevel instance or string "L"|"M"|"Q"|"H"
*/
[EncodeHintType.ERROR_CORRECTION]?: ErrorCorrectionLevel | string;
/**
* CHARACTER_SET: string
* Character encoding for text data
* Examples: "UTF-8", "ISO-8859-1", "Shift_JIS"
*/
[EncodeHintType.CHARACTER_SET]?: string;
/**
* QR_VERSION: number
* Force specific QR Code version (1-40)
* If data doesn't fit, encoding will fail
* Omit to let encoder auto-select optimal version
*/
[EncodeHintType.QR_VERSION]?: number;
/**
* MARGIN: number
* Quiet zone size in modules (default: 4)
* ISO 18004 specifies minimum of 4 modules
* Smaller values may work but violate standard
*/
[EncodeHintType.MARGIN]?: number;
}Hint Usage Examples:
import {
QRCodeWriter,
BarcodeFormat,
EncodeHintType,
ErrorCorrectionLevel,
BitMatrix
} from "@zxing/library";
const writer = new QRCodeWriter();
// Maximum error correction
const maxECHints = new Map<EncodeHintType, any>();
maxECHints.set(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
const maxECMatrix: BitMatrix = writer.encode(
"Critical data",
BarcodeFormat.QR_CODE,
300,
300,
maxECHints
);
// UTF-8 for international text
const utf8Hints = new Map<EncodeHintType, any>();
utf8Hints.set(EncodeHintType.CHARACTER_SET, "UTF-8");
utf8Hints.set(EncodeHintType.ERROR_CORRECTION, "M");
const utf8Matrix: BitMatrix = writer.encode(
"Hello 世界 🌍",
BarcodeFormat.QR_CODE,
300,
300,
utf8Hints
);
// Force specific version
const versionHints = new Map<EncodeHintType, any>();
versionHints.set(EncodeHintType.QR_VERSION, 5);
versionHints.set(EncodeHintType.ERROR_CORRECTION, "Q");
const versionMatrix: BitMatrix = writer.encode(
"Version 5 data",
BarcodeFormat.QR_CODE,
300,
300,
versionHints
);
// Minimal margin (space-constrained)
const minMarginHints = new Map<EncodeHintType, any>();
minMarginHints.set(EncodeHintType.MARGIN, 1); // Minimum 1 module
const minMarginMatrix: BitMatrix = writer.encode(
"Compact QR",
BarcodeFormat.QR_CODE,
200,
200,
minMarginHints
);
// Combined hints
const combinedHints = new Map<EncodeHintType, any>();
combinedHints.set(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
combinedHints.set(EncodeHintType.CHARACTER_SET, "UTF-8");
combinedHints.set(EncodeHintType.MARGIN, 2);
// Omit QR_VERSION to let encoder auto-select
const optimizedMatrix: BitMatrix = writer.encode(
"Optimized QR Code",
BarcodeFormat.QR_CODE,
400,
400,
combinedHints
);Install with Tessl CLI
npx tessl i tessl/npm-zxing--library