TypeScript port of ZXing multi-format 1D/2D barcode image processing library
The Data Matrix module provides comprehensive support for encoding and decoding Data Matrix 2D barcodes, following the ISO/IEC 16022:2000(E) standard. Data Matrix is a two-dimensional barcode format that can encode large amounts of data in a compact space with robust error correction capabilities (ECC200 Reed-Solomon).
import {
// Reader/Writer
DataMatrixReader,
DataMatrixWriter,
// Symbol information
SymbolInfo,
SymbolShapeHint,
Dimension,
// Encoders
HighLevelEncoder as DataMatrixHighLevelEncoder,
MinimalEncoder as DataMatrixMinimalEncoder,
// Placement and error correction
DefaultPlacement as DataMatrixDefaultPlacement,
ErrorCorrection as DataMatrixErrorCorrection,
// Decoder components
Decoder as DataMatrixDecoder,
Detector as DataMatrixDetector,
Version as DataMatrixVersion,
DecodedBitStreamParser as DataMatrixDecodedBitStreamParser,
// Supporting types
BarcodeFormat,
EncodeHintType,
DecodeHintType,
Result,
BinaryBitmap,
BitMatrix
} from "@zxing/library";import {
DataMatrixReader,
BinaryBitmap,
HybridBinarizer,
RGBLuminanceSource,
DecodeHintType,
Result
} from "@zxing/library";
// Create luminance source from image data
const luminanceSource = new RGBLuminanceSource(
imageData, // Uint8ClampedArray: image pixel data
width, // number: image width
height // number: image height
);
// Create binary bitmap
const binaryBitmap = new BinaryBitmap(
new HybridBinarizer(luminanceSource)
);
// Decode Data Matrix
const reader = new DataMatrixReader();
try {
const result: Result = reader.decode(binaryBitmap);
console.log("Decoded text:", result.getText());
console.log("Format:", result.getBarcodeFormat()); // BarcodeFormat.DATA_MATRIX
console.log("Raw bytes:", result.getRawBytes());
// Access result points (corners)
const points = result.getResultPoints();
console.log(`Detected at ${points.length} corner points`);
} catch (error) {
console.error("Data Matrix decode failed:", error);
}import {
DataMatrixWriter,
BarcodeFormat,
EncodeHintType,
SymbolShapeHint,
BitMatrix
} from "@zxing/library";
const writer = new DataMatrixWriter();
// Basic encoding with square preference
const hints = new Map<EncodeHintType, any>();
hints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
hints.set(EncodeHintType.CHARACTER_SET, "UTF-8");
const bitMatrix: BitMatrix = writer.encode(
"Hello, Data Matrix!",
BarcodeFormat.DATA_MATRIX,
200, // width: number
200, // height: number
hints // Map<EncodeHintType, any>
);
// Render BitMatrix to canvas/image
const width: number = bitMatrix.getWidth();
const height: number = bitMatrix.getHeight();
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const isBlack: boolean = bitMatrix.get(x, y);
// Draw pixel at (x, y) - black if true, white if false
}
}The Data Matrix module is organized into several key components:
DataMatrixReader, DataMatrixWriter) for decoding and encodingHighLevelEncoder: Fast greedy algorithm for most use casesMinimalEncoder: Graph-based optimization for minimal encoding lengthDecodes Data Matrix codes from binary bitmap images, with support for both pure barcodes and complex image detection.
/**
* Data Matrix barcode reader
* Decodes Data Matrix 2D barcodes from images using pattern detection and error correction
*/
class DataMatrixReader implements Reader {
/**
* Locates and decodes a Data Matrix code in an image
* @param image - BinaryBitmap: binary representation of the image
* @param hints - Map<DecodeHintType, any>: optional decode hints
* - PURE_BARCODE: boolean for pure barcode extraction (faster)
* - CHARACTER_SET: string for text encoding
* @returns Result: decoded text, raw bytes, and metadata
* @throws NotFoundException if Data Matrix code cannot be found
* @throws FormatException if Data Matrix code cannot be decoded
* @throws ChecksumException if error correction fails (too many errors)
*/
decode(image: BinaryBitmap, hints?: Map<DecodeHintType, any>): Result;
/**
* Resets any internal state (currently no-op for Data Matrix)
*/
reset(): void;
}Usage Examples:
import {
DataMatrixReader,
BinaryBitmap,
HybridBinarizer,
RGBLuminanceSource,
DecodeHintType,
Result,
ResultMetadataType,
BarcodeFormat
} from "@zxing/library";
// Standard decoding with automatic detection
const reader = new DataMatrixReader();
const luminanceSource = new RGBLuminanceSource(imageData, width, height);
const binarizer = new HybridBinarizer(luminanceSource);
const binaryBitmap = new BinaryBitmap(binarizer);
try {
const result: Result = reader.decode(binaryBitmap);
console.log("Text:", result.getText());
console.log("Format:", result.getBarcodeFormat()); // BarcodeFormat.DATA_MATRIX
console.log("Timestamp:", result.getTimestamp());
// Access metadata
const metadata = result.getResultMetadata();
if (metadata && metadata.has(ResultMetadataType.ERROR_CORRECTION_LEVEL)) {
const ecLevel = metadata.get(ResultMetadataType.ERROR_CORRECTION_LEVEL);
console.log("EC Level:", ecLevel);
}
// Get detected corner points
const points = result.getResultPoints();
points.forEach((point, i) => {
console.log(`Corner ${i}: (${point.getX()}, ${point.getY()})`);
});
// Access raw bytes
const rawBytes = result.getRawBytes();
if (rawBytes) {
console.log("Raw bytes length:", rawBytes.length);
}
} catch (error) {
console.error("Data Matrix decode failed:", error);
}
// Pure barcode mode (faster, requires clean image with no rotation)
const pureHints = new Map<DecodeHintType, any>();
pureHints.set(DecodeHintType.PURE_BARCODE, true);
try {
const pureResult: Result = reader.decode(binaryBitmap, pureHints);
console.log("Pure barcode decode:", pureResult.getText());
} catch (error) {
console.error("Pure barcode decode failed:", error);
}
// Character set specification
const utf8Hints = new Map<DecodeHintType, any>();
utf8Hints.set(DecodeHintType.CHARACTER_SET, "UTF-8");
try {
const utf8Result: Result = reader.decode(binaryBitmap, utf8Hints);
console.log("UTF-8 decoded:", utf8Result.getText());
} catch (error) {
console.error("UTF-8 decode failed:", error);
}Decode Hints:
DecodeHintType.PURE_BARCODE: Set to true for pure, unrotated barcodes (faster processing, no detection needed)DecodeHintType.CHARACTER_SET: Specify character encoding (e.g., "UTF-8", "ISO-8859-1", "Windows-1252")Encodes text and binary data into Data Matrix barcode format with configurable size and shape constraints.
/**
* Data Matrix barcode writer
* Encodes text and data into Data Matrix 2D barcode format
*/
class DataMatrixWriter implements Writer {
/**
* Encodes content as a Data Matrix barcode
* @param contents - string: text or data to encode
* @param format - BarcodeFormat: must be BarcodeFormat.DATA_MATRIX
* @param width - number: desired width in pixels (minimum enforced by symbol size)
* @param height - number: desired height in pixels (minimum enforced by symbol size)
* @param hints - Map<EncodeHintType, unknown>: optional encoding hints
* - DATA_MATRIX_SHAPE: SymbolShapeHint (FORCE_NONE|FORCE_SQUARE|FORCE_RECTANGLE)
* - MIN_SIZE: Dimension (minimum symbol dimensions)
* - MAX_SIZE: Dimension (maximum symbol dimensions)
* - DATA_MATRIX_COMPACT: boolean (use MinimalEncoder)
* - FORCE_C40: boolean (force C40 encoding mode)
* - CHARACTER_SET: string (character encoding)
* - GS1_FORMAT: boolean (enable GS1 encoding with FNC1)
* @returns BitMatrix: encoded barcode as binary matrix
* @throws Error if contents is empty, format is wrong, or dimensions are negative
* @throws WriterException if encoding fails
*/
encode(
contents: string,
format: BarcodeFormat,
width: number,
height: number,
hints?: Map<EncodeHintType, unknown>
): BitMatrix;
}Encoding Hints:
DATA_MATRIX_SHAPE: Control symbol shape (SymbolShapeHint enum)MIN_SIZE: Minimum symbol size as Dimension objectMAX_SIZE: Maximum symbol size as Dimension objectDATA_MATRIX_COMPACT: Use MinimalEncoder for optimal compression (boolean)FORCE_C40: Force C40 encoding mode (boolean)CHARACTER_SET: Character set for encoding (string)GS1_FORMAT: Enable GS1 format encoding with FNC1 (boolean)Usage Examples:
import {
DataMatrixWriter,
BarcodeFormat,
EncodeHintType,
SymbolShapeHint,
Dimension,
BitMatrix
} from "@zxing/library";
const writer = new DataMatrixWriter();
// Square symbol (most common)
const squareHints = new Map<EncodeHintType, any>();
squareHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
squareHints.set(EncodeHintType.CHARACTER_SET, "UTF-8");
const squareMatrix: BitMatrix = writer.encode(
"https://example.com/product/12345",
BarcodeFormat.DATA_MATRIX,
200,
200,
squareHints
);
// Rectangular symbol with size constraints
const rectHints = new Map<EncodeHintType, any>();
rectHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_RECTANGLE);
rectHints.set(EncodeHintType.MIN_SIZE, new Dimension(10, 10));
rectHints.set(EncodeHintType.MAX_SIZE, new Dimension(48, 48));
const rectMatrix: BitMatrix = writer.encode(
"Compact data",
BarcodeFormat.DATA_MATRIX,
300,
200,
rectHints
);
// Minimal encoding for better compression
const compactHints = new Map<EncodeHintType, any>();
compactHints.set(EncodeHintType.DATA_MATRIX_COMPACT, true);
const compactMatrix: BitMatrix = writer.encode(
"ABCDEF123456",
BarcodeFormat.DATA_MATRIX,
150,
150,
compactHints
);
// GS1 format encoding with FNC1 character
const gs1Hints = new Map<EncodeHintType, any>();
gs1Hints.set(EncodeHintType.GS1_FORMAT, true);
gs1Hints.set(EncodeHintType.DATA_MATRIX_COMPACT, true);
const gs1Matrix: BitMatrix = writer.encode(
"01095012345678903310ABC123", // GS1 Application Identifiers
BarcodeFormat.DATA_MATRIX,
200,
200,
gs1Hints
);
// Force C40 encoding mode for uppercase text
const c40Hints = new Map<EncodeHintType, any>();
c40Hints.set(EncodeHintType.FORCE_C40, true);
const c40Matrix: BitMatrix = writer.encode(
"UPPER CASE TEXT 123",
BarcodeFormat.DATA_MATRIX,
180,
180,
c40Hints
);
// Auto-select shape (optimal for data)
const autoHints = new Map<EncodeHintType, any>();
autoHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_NONE);
const autoMatrix: BitMatrix = writer.encode(
"Auto-selected shape",
BarcodeFormat.DATA_MATRIX,
200,
200,
autoHints
);
// Render BitMatrix to canvas
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;
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);
}
// Error handling
try {
const matrix: BitMatrix = writer.encode("Data", BarcodeFormat.DATA_MATRIX, 100, 100);
const canvas = document.getElementById("dm-canvas") as HTMLCanvasElement;
renderToCanvas(matrix, canvas);
} catch (error) {
console.error("Encoding or rendering failed:", error);
}Provides symbol size information, capacity, and error correction parameters for Data Matrix codes.
/**
* Data Matrix symbol information
* Provides size, capacity, and error correction details for each symbol variant
*/
class SymbolInfo {
/**
* Looks up the appropriate symbol info for given data capacity
* Selects smallest symbol that fits data with specified constraints
* @param dataCodewords - number: number of data codewords to encode
* @param shape - SymbolShapeHint: shape preference (FORCE_NONE|FORCE_SQUARE|FORCE_RECTANGLE)
* @param minSize - Dimension: optional minimum symbol dimensions
* @param maxSize - Dimension: optional maximum symbol dimensions
* @param fail - boolean: whether to throw error if no symbol found (default: true)
* @returns SymbolInfo: appropriate symbol for the data
* @throws Error if no suitable symbol found and fail=true
*/
static lookup(
dataCodewords: number,
shape?: SymbolShapeHint,
minSize?: Dimension,
maxSize?: Dimension,
fail?: boolean
): SymbolInfo;
/**
* Gets the width of the data region in modules (excludes borders)
* @returns number: data region width
*/
getSymbolDataWidth(): number;
/**
* Gets the height of the data region in modules (excludes borders)
* @returns number: data region height
*/
getSymbolDataHeight(): number;
/**
* Gets the total symbol width including borders in modules
* @returns number: total width including finder patterns
*/
getSymbolWidth(): number;
/**
* Gets the total symbol height including borders in modules
* @returns number: total height including finder patterns
*/
getSymbolHeight(): number;
/**
* Gets the total number of codewords (data + error correction)
* @returns number: total codewords in symbol
*/
getCodewordCount(): number;
/**
* Gets the number of interleaved blocks for this symbol
* Larger symbols use multiple interleaved blocks
* @returns number: block count (1 or 2)
*/
getInterleavedBlockCount(): number;
/**
* Gets the data capacity in codewords (excludes error correction)
* @returns number: data codewords
*/
getDataCapacity(): number;
/**
* Gets the number of error correction codewords
* @returns number: error correction codewords
*/
getErrorCodewords(): number;
/**
* Gets the data length for a specific interleaved block
* @param index - number: block index (1-based)
* @returns number: data codewords in block
*/
getDataLengthForInterleavedBlock(index: number): number;
/**
* Gets the error correction length for a specific interleaved block
* @param index - number: block index (1-based)
* @returns number: error correction codewords in block
*/
getErrorLengthForInterleavedBlock(index: number): number;
}Usage Examples:
import {
SymbolInfo,
SymbolShapeHint,
Dimension
} from "@zxing/library";
// Find smallest square symbol for 10 data codewords
const squareSymbol: SymbolInfo = SymbolInfo.lookup(10, SymbolShapeHint.FORCE_SQUARE);
console.log(`Symbol size: ${squareSymbol.getSymbolWidth()} × ${squareSymbol.getSymbolHeight()}`);
console.log(`Data region: ${squareSymbol.getSymbolDataWidth()} × ${squareSymbol.getSymbolDataHeight()}`);
console.log(`Data capacity: ${squareSymbol.getDataCapacity()} codewords`);
console.log(`Error correction: ${squareSymbol.getErrorCodewords()} codewords`);
console.log(`Total codewords: ${squareSymbol.getCodewordCount()}`);
// Find rectangular symbol with size constraints
const minSize = new Dimension(10, 10);
const maxSize = new Dimension(24, 24);
const rectSymbol: SymbolInfo = SymbolInfo.lookup(
15,
SymbolShapeHint.FORCE_RECTANGLE,
minSize,
maxSize
);
console.log(`Rectangle: ${rectSymbol.getSymbolWidth()} × ${rectSymbol.getSymbolHeight()}`);
// Check interleaved blocks
const blockCount: number = rectSymbol.getInterleavedBlockCount();
console.log(`Interleaved blocks: ${blockCount}`);
if (blockCount > 1) {
for (let i = 1; i <= blockCount; i++) {
const dataLen: number = rectSymbol.getDataLengthForInterleavedBlock(i);
const errorLen: number = rectSymbol.getErrorLengthForInterleavedBlock(i);
console.log(`Block ${i}: ${dataLen} data + ${errorLen} error codewords`);
}
}
// Check if symbol supports required capacity
function findSymbolForData(requiredDataCodewords: number): SymbolInfo | null {
try {
const symbol: SymbolInfo = SymbolInfo.lookup(
requiredDataCodewords,
SymbolShapeHint.FORCE_NONE
);
console.log(`Found symbol: ${symbol.getSymbolWidth()}×${symbol.getSymbolHeight()}`);
console.log(`Capacity: ${symbol.getDataCapacity()} codewords`);
return symbol;
} catch (e) {
console.error(`No symbol found for ${requiredDataCodewords} codewords`);
return null;
}
}
// Test different capacities
[5, 10, 50, 100, 200].forEach(capacity => {
const symbol = findSymbolForData(capacity);
if (symbol) {
console.log(`${capacity} codewords → ${symbol.getSymbolWidth()}×${symbol.getSymbolHeight()}`);
}
});Available Symbol Sizes:
The library supports all standard Data Matrix symbol sizes defined in ISO/IEC 16022:
Square Symbols:
Rectangular Symbols:
Enumeration for controlling Data Matrix symbol shape preference during encoding.
/**
* Symbol shape hint enumeration
* Controls whether encoder prefers square or rectangular symbols
*/
enum SymbolShapeHint {
/**
* No shape preference - encoder chooses optimal shape for data
* May select square or rectangular based on data characteristics
*/
FORCE_NONE = 0,
/**
* Force square symbol shape
* Only considers square symbols (10×10, 12×12, 14×14, etc.)
*/
FORCE_SQUARE = 1,
/**
* Force rectangular symbol shape
* Only considers rectangular symbols (8×18, 8×32, 12×26, etc.)
*/
FORCE_RECTANGLE = 2,
}Usage Examples:
import {
DataMatrixWriter,
BarcodeFormat,
EncodeHintType,
SymbolShapeHint,
BitMatrix
} from "@zxing/library";
const writer = new DataMatrixWriter();
// Let encoder choose optimal shape (may be square or rectangular)
const autoHints = new Map<EncodeHintType, any>();
autoHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_NONE);
const autoMatrix: BitMatrix = writer.encode(
"AUTO",
BarcodeFormat.DATA_MATRIX,
200,
200,
autoHints
);
console.log(`Auto shape: ${autoMatrix.getWidth()}×${autoMatrix.getHeight()}`);
// Force square shape
const squareHints = new Map<EncodeHintType, any>();
squareHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
const squareMatrix: BitMatrix = writer.encode(
"SQUARE",
BarcodeFormat.DATA_MATRIX,
200,
200,
squareHints
);
console.log(`Square: ${squareMatrix.getWidth()}×${squareMatrix.getHeight()}`);
// Force rectangular shape
const rectHints = new Map<EncodeHintType, any>();
rectHints.set(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_RECTANGLE);
const rectMatrix: BitMatrix = writer.encode(
"RECT",
BarcodeFormat.DATA_MATRIX,
200,
200,
rectHints
);
console.log(`Rectangle: ${rectMatrix.getWidth()}×${rectMatrix.getHeight()}`);
// Compare encoding efficiency
const testData = "TEST DATA 123456";
const noneMatrix: BitMatrix = writer.encode(
testData,
BarcodeFormat.DATA_MATRIX,
200,
200,
new Map([[EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_NONE]])
);
const sqMatrix: BitMatrix = writer.encode(
testData,
BarcodeFormat.DATA_MATRIX,
200,
200,
new Map([[EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE]])
);
const rectMatrix2: BitMatrix = writer.encode(
testData,
BarcodeFormat.DATA_MATRIX,
200,
200,
new Map([[EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_RECTANGLE]])
);
console.log(`Auto: ${noneMatrix.getWidth()}×${noneMatrix.getHeight()}`);
console.log(`Square: ${sqMatrix.getWidth()}×${sqMatrix.getHeight()}`);
console.log(`Rectangle: ${rectMatrix2.getWidth()}×${rectMatrix2.getHeight()}`);High-level encoder that converts input text to Data Matrix codewords using optimal encoding modes (ASCII, C40, TEXT, X12, EDIFACT, BASE256).
/**
* High-level Data Matrix encoder
* Implements ISO/IEC 16022:2000(E) Annex P encoding algorithm
* Uses greedy lookahead to select optimal encoding modes
*/
class HighLevelEncoder {
/**
* Performs message encoding using the algorithm described in ISO/IEC 16022:2000(E) Annex P
* Automatically selects between ASCII, C40, TEXT, X12, EDIFACT, and BASE256 modes
* @param msg - string: message to encode
* @param shape - SymbolShapeHint: optional shape preference (default: FORCE_NONE)
* @param minSize - Dimension: optional minimum symbol size (default: null)
* @param maxSize - Dimension: optional maximum symbol size (default: null)
* @param forceC40 - boolean: optional force C40 encoding mode (default: false)
* @returns string: encoded message as codeword string (char values 0-255)
* @throws WriterException if encoding fails or data doesn't fit constraints
*/
static encodeHighLevel(
msg: string,
shape?: SymbolShapeHint,
minSize?: Dimension,
maxSize?: Dimension,
forceC40?: boolean
): string;
/**
* Determines the number of consecutive digits in the message
* @param msg - string: message to analyze
* @param startpos - number: starting position (default: 0)
* @returns number: count of consecutive digits from start position
*/
static determineConsecutiveDigitCount(
msg: string,
startpos?: number
): number;
/**
* Checks if character is a digit (0-9)
* @param ch - number: character code
* @returns boolean: true if digit
*/
static isDigit(ch: number): boolean;
/**
* Checks if character is extended ASCII (128-255)
* @param ch - number: character code
* @returns boolean: true if extended ASCII
*/
static isExtendedASCII(ch: number): boolean;
/**
* Checks if character is native to C40 encoding
* C40 native: space, digits 0-9, uppercase A-Z
* @param ch - number: character code
* @returns boolean: true if native to C40
*/
static isNativeC40(ch: number): boolean;
/**
* Checks if character is native to Text encoding
* Text native: space, digits 0-9, lowercase a-z
* @param ch - number: character code
* @returns boolean: true if native to Text
*/
static isNativeText(ch: number): boolean;
/**
* Checks if character is native to X12 encoding
* X12 native: CR, *, >, space, digits 0-9, uppercase A-Z
* @param ch - number: character code
* @returns boolean: true if native to X12
*/
static isNativeX12(ch: number): boolean;
/**
* Checks if character is native to EDIFACT encoding
* EDIFACT native: ASCII 32-94 (space through ^)
* @param ch - number: character code
* @returns boolean: true if native to EDIFACT
*/
static isNativeEDIFACT(ch: number): boolean;
}Encoding Modes:
The encoder automatically selects between these modes for optimal compression:
| Mode | Characters | Bits per Char | Best For |
|---|---|---|---|
| ASCII | 0-127, digit pairs | 8 bits, or 4 bits per digit pair | Mixed content, ASCII text |
| C40 | Space, digits, uppercase | 5.33 bits (3 chars in 2 codewords) | Uppercase text |
| TEXT | Space, digits, lowercase | 5.33 bits (3 chars in 2 codewords) | Lowercase text |
| X12 | ANSI X12 EDI subset | 5.33 bits (3 chars in 2 codewords) | EDI data |
| EDIFACT | ASCII 32-94 | 6 bits (4 chars in 3 codewords) | EDI messages |
| BASE256 | Binary data (0-255) | 8 bits | Binary data, non-ASCII |
Special ASCII Mode Features:
Usage Examples:
import {
HighLevelEncoder,
SymbolShapeHint,
Dimension
} from "@zxing/library";
// Basic encoding with automatic mode selection
const encoded: string = HighLevelEncoder.encodeHighLevel("Hello123");
console.log(`Encoded to ${encoded.length} codewords`);
// Encoding with shape constraint
const squareEncoded: string = HighLevelEncoder.encodeHighLevel(
"SQUARE DATA",
SymbolShapeHint.FORCE_SQUARE
);
console.log(`Square encoding: ${squareEncoded.length} codewords`);
// Encoding with size constraints
const minSize = new Dimension(12, 12);
const maxSize = new Dimension(24, 24);
const constrained: string = HighLevelEncoder.encodeHighLevel(
"Constrained encoding",
SymbolShapeHint.FORCE_NONE,
minSize,
maxSize
);
console.log(`Constrained: ${constrained.length} codewords`);
// Force C40 encoding for uppercase text
const c40Encoded: string = HighLevelEncoder.encodeHighLevel(
"UPPERCASE TEXT WITH NUMBERS 12345",
SymbolShapeHint.FORCE_NONE,
undefined,
undefined,
true // forceC40
);
console.log(`C40 encoding: ${c40Encoded.length} codewords`);
// Analyze character types
const testChars = ["A", "a", "5", " ", "!", "ü"];
testChars.forEach(char => {
const code = char.charCodeAt(0);
console.log(`'${char}' (${code}):`);
console.log(` Digit: ${HighLevelEncoder.isDigit(code)}`);
console.log(` C40 native: ${HighLevelEncoder.isNativeC40(code)}`);
console.log(` Text native: ${HighLevelEncoder.isNativeText(code)}`);
console.log(` X12 native: ${HighLevelEncoder.isNativeX12(code)}`);
console.log(` EDIFACT native: ${HighLevelEncoder.isNativeEDIFACT(code)}`);
console.log(` Extended ASCII: ${HighLevelEncoder.isExtendedASCII(code)}`);
});
// Count consecutive digits (for ASCII digit pair optimization)
const msg1 = "ABC12345XYZ";
const digitCount1: number = HighLevelEncoder.determineConsecutiveDigitCount(msg1, 3);
console.log(`Consecutive digits at position 3: ${digitCount1}`); // 5
const msg2 = "12345678";
const digitCount2: number = HighLevelEncoder.determineConsecutiveDigitCount(msg2, 0);
console.log(`Consecutive digits from start: ${digitCount2}`); // 8
// Encoding efficiency comparison
function compareEncodings(text: string): void {
const encoded = HighLevelEncoder.encodeHighLevel(text);
const rawBytes = new TextEncoder().encode(text).length;
const encodedCodewords = encoded.length;
console.log(`Text: "${text}"`);
console.log(` Raw bytes: ${rawBytes}`);
console.log(` Encoded codewords: ${encodedCodewords}`);
console.log(` Efficiency: ${encodedCodewords <= rawBytes ? 'Better' : 'Worse'}`);
}
compareEncodings("123456789012"); // ASCII digit pairs: very efficient
compareEncodings("UPPERCASE TEXT"); // C40 mode: efficient
compareEncodings("lowercase text"); // TEXT mode: efficient
compareEncodings("Mixed Case 123"); // Mixed modes: moderate efficiencyMacro Characters:
Data Matrix supports special macro headers for compact encoding of common message structures:
// Macro 05 format: [)>\u001E05\u001D ... \u001E\u0004
// Macro 06 format: [)>\u001E06\u001D ... \u001E\u0004
// The encoder automatically detects and optimizes these patterns
const macro05 = "[)>\\u001E05\\u001DData\\u001E\\u0004";
const macro06 = "[)>\\u001E06\\u001DData\\u001E\\u0004";
// Macros save several codewords compared to raw encodingAdvanced encoder that produces minimal-length encodings using sophisticated graph-based optimization algorithms.
/**
* Minimal Data Matrix encoder
* Uses graph-based optimization to find shortest possible encoding
* More complex but produces better compression than HighLevelEncoder
*/
class MinimalEncoder {
/**
* Performs minimal-length message encoding
* Uses graph search algorithm to find optimal encoding path
* @param msg - string: message to encode
* @param priorityCharset - Charset: optional preferred character set (default: null)
* @param fnc1 - number: FNC1 character code or -1 for non-GS1 (default: -1)
* @param shape - SymbolShapeHint: optional shape preference (default: FORCE_NONE)
* @returns string: encoded message with minimal codeword count
* @throws WriterException if encoding fails
*/
static encodeHighLevel(
msg: string,
priorityCharset?: Charset,
fnc1?: number,
shape?: SymbolShapeHint
): string;
/**
* Checks if character is extended ASCII
* @param ch - number: character code
* @param fnc1 - number: FNC1 character code
* @returns boolean: true if extended ASCII
*/
static isExtendedASCII(ch: number, fnc1: number): boolean;
/**
* Checks if character is in C40 Shift 1 set
* @param ch - number: character code
* @returns boolean: true if in C40 Shift 1
*/
static isInC40Shift1Set(ch: number): boolean;
/**
* Checks if character is in C40 Shift 2 set
* @param ch - number: character code
* @param fnc1 - number: FNC1 character code
* @returns boolean: true if in C40 Shift 2
*/
static isInC40Shift2Set(ch: number, fnc1: number): boolean;
/**
* Checks if character is in Text Shift 1 set
* @param ch - number: character code
* @returns boolean: true if in Text Shift 1
*/
static isInTextShift1Set(ch: number): boolean;
/**
* Checks if character is in Text Shift 2 set
* @param ch - number: character code
* @param fnc1 - number: FNC1 character code
* @returns boolean: true if in Text Shift 2
*/
static isInTextShift2Set(ch: number, fnc1: number): boolean;
}Usage Examples:
import {
MinimalEncoder,
HighLevelEncoder,
SymbolShapeHint,
Charset,
SymbolInfo,
ErrorCorrection
} from "@zxing/library";
// Minimal encoding with automatic charset selection
const message = "Mixed Content: ABC123abc!@#";
const minimalEncoded: string = MinimalEncoder.encodeHighLevel(message);
console.log(`Minimal encoding: ${minimalEncoded.length} codewords`);
// Compare with standard encoder
const standardEncoded: string = HighLevelEncoder.encodeHighLevel(message);
console.log(`Standard encoding: ${standardEncoded.length} codewords`);
console.log(`Saved: ${standardEncoded.length - minimalEncoded.length} codewords`);
// Encoding with priority charset
const utf8Charset = Charset.forName("UTF-8");
const utf8Encoded: string = MinimalEncoder.encodeHighLevel(
"Prioritized UTF-8 encoding",
utf8Charset
);
console.log(`UTF-8 prioritized: ${utf8Encoded.length} codewords`);
// GS1 format encoding with FNC1
const gs1Message = "01095012345678903310ABC123";
const gs1Encoded: string = MinimalEncoder.encodeHighLevel(
gs1Message,
undefined, // No priority charset
0x1D, // FNC1 character (ASCII 29)
SymbolShapeHint.FORCE_SQUARE
);
console.log(`GS1 encoded: ${gs1Encoded.length} codewords`);
// Encoding with shape preference
const rectEncoded: string = MinimalEncoder.encodeHighLevel(
"Rectangular preference",
undefined,
-1,
SymbolShapeHint.FORCE_RECTANGLE
);
console.log(`Rectangular: ${rectEncoded.length} codewords`);
// Character set analysis
const testChar = "!".charCodeAt(0);
const fnc1 = 0x1D;
console.log(`Character '!' (${testChar}):`);
console.log(` Extended ASCII: ${MinimalEncoder.isExtendedASCII(testChar, fnc1)}`);
console.log(` C40 Shift1: ${MinimalEncoder.isInC40Shift1Set(testChar)}`);
console.log(` C40 Shift2: ${MinimalEncoder.isInC40Shift2Set(testChar, fnc1)}`);
console.log(` Text Shift1: ${MinimalEncoder.isInTextShift1Set(testChar)}`);
console.log(` Text Shift2: ${MinimalEncoder.isInTextShift2Set(testChar, fnc1)}`);
// Complete encoding pipeline with MinimalEncoder
function encodeWithMinimal(text: string): string {
const encoded: string = MinimalEncoder.encodeHighLevel(
text,
undefined,
-1,
SymbolShapeHint.FORCE_NONE
);
const symbolInfo: SymbolInfo = SymbolInfo.lookup(encoded.length);
const withEC: string = ErrorCorrection.encodeECC200(encoded, symbolInfo);
return withEC;
}
const finalCodewords: string = encodeWithMinimal("Optimized encoding!");
console.log(`Final codewords: ${finalCodewords.length}`);MinimalEncoder vs HighLevelEncoder:
| Feature | MinimalEncoder | HighLevelEncoder |
|---|---|---|
| Algorithm | Graph-based optimization | Greedy lookahead |
| Compression | Better (finds optimal path) | Good (local optimum) |
| Speed | Slower (explores multiple paths) | Faster (single pass) |
| Complexity | Higher | Lower |
| Charset Support | Multiple charsets | Single charset |
| Use Case | Maximum compression needed | General purpose, speed priority |
| Activation | Set DATA_MATRIX_COMPACT hint | Default in DataMatrixWriter |
Choose MinimalEncoder by setting EncodeHintType.DATA_MATRIX_COMPACT to true.
Implements Reed-Solomon ECC200 error correction for Data Matrix codes.
/**
* Data Matrix error correction implementation
* Implements Reed-Solomon ECC200 per ISO/IEC 16022
*/
class ErrorCorrection {
/**
* Creates ECC200 error correction codewords for an encoded message
* Adds Reed-Solomon error correction with proper interleaving
* @param codewords - string: data codewords to protect (encoded message)
* @param symbolInfo - SymbolInfo: symbol information with EC parameters
* @returns string: complete codeword string with interleaved error correction
* @throws Error if codeword count doesn't match symbol data capacity
*/
static encodeECC200(codewords: string, symbolInfo: SymbolInfo): string;
}Usage Examples:
import {
ErrorCorrection,
HighLevelEncoder,
SymbolInfo,
SymbolShapeHint
} from "@zxing/library";
// Encode message and add error correction
const message = "Data Matrix ECC200";
// Step 1: High-level encoding
const encoded: string = HighLevelEncoder.encodeHighLevel(
message,
SymbolShapeHint.FORCE_SQUARE
);
console.log(`Data codewords: ${encoded.length}`);
// Step 2: Get symbol information
const symbolInfo: SymbolInfo = SymbolInfo.lookup(encoded.length);
console.log(`Symbol: ${symbolInfo.getSymbolWidth()}×${symbolInfo.getSymbolHeight()}`);
console.log(`Data capacity: ${symbolInfo.getDataCapacity()} codewords`);
console.log(`EC codewords: ${symbolInfo.getErrorCodewords()}`);
// Step 3: Add error correction
const withEC: string = ErrorCorrection.encodeECC200(encoded, symbolInfo);
console.log(`Total codewords: ${withEC.length}`);
console.log(`Expected total: ${symbolInfo.getCodewordCount()}`);
// Verify correct length
if (withEC.length === symbolInfo.getCodewordCount()) {
console.log("✓ Error correction added successfully");
console.log(`Final: ${symbolInfo.getDataCapacity()} data + ${symbolInfo.getErrorCodewords()} EC = ${withEC.length} total`);
} else {
console.error("✗ Codeword count mismatch");
}
// For interleaved symbols (larger Data Matrix symbols)
const largeMessage = "A".repeat(100);
const largeEncoded: string = HighLevelEncoder.encodeHighLevel(largeMessage);
const largeSymbol: SymbolInfo = SymbolInfo.lookup(largeEncoded.length);
console.log(`Large symbol interleaved blocks: ${largeSymbol.getInterleavedBlockCount()}`);
const largeWithEC: string = ErrorCorrection.encodeECC200(largeEncoded, largeSymbol);
// Extract data and EC portions
const dataLength: number = largeSymbol.getDataCapacity();
const dataPortion: string = largeWithEC.substring(0, dataLength);
const ecPortion: string = largeWithEC.substring(dataLength);
console.log(`Data portion: ${dataPortion.length} codewords`);
console.log(`EC portion: ${ecPortion.length} codewords`);
// Error correction parameters vary by symbol size
// Small symbols: 5, 7, 10, 12, or 14 EC codewords
// Large symbols: 18, 20, 24, 28, 36, 42, 48, 56, 62, or 68 EC codewords
// Interleaving improves error resilience for burst errors
if (largeSymbol.getInterleavedBlockCount() > 1) {
console.log("Symbol uses interleaving for better error distribution");
}Error Correction Parameters:
Data Matrix ECC200 uses Reed-Solomon coding with predefined polynomial factors:
| Symbol Size | EC Codewords | Can Correct (Symbols) |
|---|---|---|
| 10×10 to 16×16 | 5 | 2 |
| 18×18 to 20×20 | 7 | 3 |
| 22×22 | 10 | 5 |
| 24×24 to 26×26 | 12 | 6 |
| 32×32 | 14 | 7 |
| 36×36 to 40×40 | 18 | 9 |
| 44×44 | 20 | 10 |
| 48×48 to 52×52 | 24 | 12 |
| 64×64 to 72×72 | 28 | 14 |
| 80×80 to 88×88 | 36 | 18 |
| 96×96 to 104×104 | 42 | 21 |
| 120×120 | 48 | 24 |
| 132×132 | 56 | 28 |
| 144×144 | 62 | 31 |
Interleaving:
Larger symbols use 2 interleaved blocks for better burst error resilience:
Install with Tessl CLI
npx tessl i tessl/npm-zxing--library@0.21.14