TypeScript port of ZXing multi-format 1D/2D barcode image processing library
Comprehensive API documentation for Aztec 2D barcode encoding and decoding in @zxing/library. Aztec Code is a high-capacity 2D matrix barcode symbology that can encode large amounts of data in a compact space with configurable error correction.
The Aztec module provides complete functionality for:
Aztec codes support both compact (up to 4 layers, 5-ring bulls-eye) and full (up to 32 layers, 7-ring bulls-eye) formats, with automatic format selection based on data size and error correction requirements.
core/aztec/)import {
// Reader/Writer
AztecCodeReader,
AztecCodeWriter,
// Results and detection
AztecDetectorResult,
AztecCode,
// Encoder/Decoder
Encoder as AztecEncoder,
Decoder as AztecDecoder,
HighLevelEncoder as AztecHighLevelEncoder,
// Detector
Detector as AztecDetector,
Point as AztecPoint,
// Supporting types
BinaryBitmap,
BitMatrix,
BitArray,
DecodeHintType,
EncodeHintType,
BarcodeFormat,
Result
} from '@zxing/library';import {
AztecCodeReader,
BinaryBitmap,
HybridBinarizer,
RGBLuminanceSource,
Result
} from '@zxing/library';
// Create luminance source from image data
const luminanceSource = new RGBLuminanceSource(imageData, width, height);
const binarizer = new HybridBinarizer(luminanceSource);
const bitmap = new BinaryBitmap(binarizer);
// Decode the Aztec code
const reader = new AztecCodeReader();
try {
const result: Result = reader.decode(bitmap);
console.log('Decoded text:', result.getText());
console.log('Format:', result.getBarcodeFormat()); // BarcodeFormat.AZTEC
console.log('Result points:', result.getResultPoints());
// Access metadata
const metadata = result.getResultMetadata();
if (metadata) {
const ecLevel = metadata.get(ResultMetadataType.ERROR_CORRECTION_LEVEL);
console.log('Error correction:', ecLevel);
}
} catch (error) {
console.error('Aztec decode failed:', error);
}import {
AztecCodeWriter,
BarcodeFormat,
EncodeHintType,
BitMatrix
} from '@zxing/library';
const writer = new AztecCodeWriter();
// Basic encoding (auto-sized)
const matrix: BitMatrix = writer.encode(
'Hello, Aztec!',
BarcodeFormat.AZTEC,
0, // Width: 0 = auto-size based on data
0 // Height: 0 = auto-size
);
console.log(`Generated ${matrix.getWidth()}×${matrix.getHeight()} Aztec code`);
// Encoding with hints for custom configuration
const hints = new Map<EncodeHintType, any>();
hints.set(EncodeHintType.ERROR_CORRECTION, 33); // 33% error correction
hints.set(EncodeHintType.AZTEC_LAYERS, 5); // Force 5 layers
hints.set(EncodeHintType.CHARACTER_SET, 'UTF-8');
const matrixWithHints: BitMatrix = writer.encode(
'Data with hints',
BarcodeFormat.AZTEC,
200, // Fixed width
200, // Fixed height
hints
);The main class for decoding Aztec codes from binary bitmap images. Implements automatic detection of both normal and mirrored codes with comprehensive error recovery.
/**
* Decodes Aztec codes from binary bitmap images
* Implements the Reader interface for Aztec barcode decoding
* Automatically handles normal and mirrored orientations
*/
class AztecCodeReader implements Reader {
/**
* Locates and decodes an Aztec code in an image
* Attempts both normal and mirrored orientations automatically
* @param image - BinaryBitmap: binary image containing the Aztec code
* @param hints - Map<DecodeHintType, any>: optional decode hints
* - NEED_RESULT_POINT_CALLBACK: ResultPointCallback for detection tracking
* @returns Result: decoded text, raw bytes, and metadata
* @throws NotFoundException if no Aztec code is found
* @throws FormatException if code structure is invalid or cannot be decoded
*/
decode(image: BinaryBitmap, hints?: Map<DecodeHintType, any>): Result;
/**
* Resets any internal state (no-op for Aztec reader)
*/
reset(): void;
}Usage Examples:
import {
AztecCodeReader,
BinaryBitmap,
HybridBinarizer,
RGBLuminanceSource,
DecodeHintType,
ResultPointCallback,
ResultPoint,
Result,
ResultMetadataType
} from '@zxing/library';
// Set up image source
const luminanceSource = new RGBLuminanceSource(pixels, width, height);
const binarizer = new HybridBinarizer(luminanceSource);
const bitmap = new BinaryBitmap(binarizer);
// Decode with result point callback to track detection
const hints = new Map<DecodeHintType, any>();
const callback: ResultPointCallback = {
foundPossibleResultPoint: (point: ResultPoint) => {
console.log(`Found point at (${point.getX()}, ${point.getY()})`);
// Could draw marker on canvas to visualize detection
}
};
hints.set(DecodeHintType.NEED_RESULT_POINT_CALLBACK, callback);
const reader = new AztecCodeReader();
try {
const result: Result = reader.decode(bitmap, hints);
console.log('Decoded:', result.getText());
// Access metadata
const metadata = result.getResultMetadata();
if (metadata) {
const errorLevel = metadata.get(ResultMetadataType.ERROR_CORRECTION_LEVEL);
const byteSegments = metadata.get(ResultMetadataType.BYTE_SEGMENTS);
if (errorLevel !== undefined) {
console.log('Error correction level:', errorLevel);
}
if (byteSegments) {
console.log('Byte segments:', byteSegments);
}
}
// Access raw bytes
const rawBytes: Uint8Array = result.getRawBytes();
if (rawBytes) {
console.log('Raw bytes length:', rawBytes.length);
}
// Access result points (bulls-eye corners)
const points = result.getResultPoints();
console.log(`Bulls-eye detected at ${points.length} points`);
} catch (error) {
if (error instanceof NotFoundException) {
console.error('No Aztec code found in image');
} else if (error instanceof FormatException) {
console.error('Aztec code structure is invalid:', error.message);
} else {
console.error('Decoding failed:', error);
}
}
// Continuous scanning
const reader2 = new AztecCodeReader();
for (const frame of videoFrames) {
try {
const result: Result = reader2.decode(frame);
console.log('Scanned:', result.getText());
break; // Stop on first success
} catch (error) {
// Continue to next frame
}
}Key Features:
Generates Aztec codes from text or binary data with configurable error correction and size parameters. Supports both compact and full-size format generation.
/**
* Encodes data as Aztec 2D barcode
* Implements the Writer interface for Aztec barcode encoding
* Automatically selects optimal format (compact/full) unless specified
*/
class AztecCodeWriter implements Writer {
/**
* Encodes content as an Aztec barcode
* @param contents - string: text content to encode
* @param format - BarcodeFormat: must be BarcodeFormat.AZTEC
* @param width - number: desired width in pixels (or 0 for auto-size)
* @param height - number: desired height in pixels (or 0 for auto-size)
* @returns BitMatrix: encoded Aztec barcode
* @throws IllegalArgumentException if format is not AZTEC
* @throws WriterException if encoding fails
*/
encode(
contents: string,
format: BarcodeFormat,
width: number,
height: number
): BitMatrix;
/**
* Encodes content with encoding hints for customization
* @param contents - string: text content to encode
* @param format - BarcodeFormat: must be BarcodeFormat.AZTEC
* @param width - number: desired width (0 for auto-size)
* @param height - number: desired height (0 for auto-size)
* @param hints - Map<EncodeHintType, any>: encoding hints
* - ERROR_CORRECTION: number (percentage 0-100, default 33)
* - AZTEC_LAYERS: number (negative=compact, 0=auto, positive=full)
* - CHARACTER_SET: string (e.g., "UTF-8", "ISO-8859-1")
* @returns BitMatrix: encoded Aztec barcode
* @throws IllegalArgumentException if parameters invalid
* @throws WriterException if encoding fails (data too large)
*/
encode(
contents: string,
format: BarcodeFormat,
width: number,
height: number,
hints: Map<EncodeHintType, any>
): BitMatrix;
}Encoding Hints:
| Hint | Type | Description | Default | Valid Range |
|---|---|---|---|---|
ERROR_CORRECTION | number | Error correction percentage | 33% | 0-100% (recommended: 23-50%) |
AZTEC_LAYERS | number | Number of layers | 0 (auto) | -4 to -1 (compact), 0 (auto), 1 to 32 (full) |
CHARACTER_SET | string | Character encoding | "ISO-8859-1" | Any valid encoding |
Usage Examples:
import {
AztecCodeWriter,
BarcodeFormat,
EncodeHintType,
BitMatrix
} from '@zxing/library';
const writer = new AztecCodeWriter();
// Auto-sized encoding (optimal dimensions)
const matrix1: BitMatrix = writer.encode(
'Simple text',
BarcodeFormat.AZTEC,
0, // Auto-size
0
);
console.log(`Auto-sized: ${matrix1.getWidth()}×${matrix1.getHeight()} pixels`);
// Fixed-size encoding with scaling
const matrix2: BitMatrix = writer.encode(
'Fixed size',
BarcodeFormat.AZTEC,
300, // Fixed 300×300
300
);
// High error correction (50%)
const highEccHints = new Map<EncodeHintType, any>();
highEccHints.set(EncodeHintType.ERROR_CORRECTION, 50);
const matrix3: BitMatrix = writer.encode(
'Critical data requiring high reliability',
BarcodeFormat.AZTEC,
0,
0,
highEccHints
);
// Force compact format (negative layers: -1 to -4)
const compactHints = new Map<EncodeHintType, any>();
compactHints.set(EncodeHintType.AZTEC_LAYERS, -3); // Compact with 3 layers
compactHints.set(EncodeHintType.ERROR_CORRECTION, 33);
const matrix4: BitMatrix = writer.encode(
'Compact',
BarcodeFormat.AZTEC,
0,
0,
compactHints
);
// Force full format with 10 layers
const fullHints = new Map<EncodeHintType, any>();
fullHints.set(EncodeHintType.AZTEC_LAYERS, 10); // Full format, 10 layers
fullHints.set(EncodeHintType.ERROR_CORRECTION, 25);
const matrix5: BitMatrix = writer.encode(
'Large data requiring full format',
BarcodeFormat.AZTEC,
0,
0,
fullHints
);
// UTF-8 encoding for international text
const utf8Hints = new Map<EncodeHintType, any>();
utf8Hints.set(EncodeHintType.CHARACTER_SET, 'UTF-8');
utf8Hints.set(EncodeHintType.ERROR_CORRECTION, 33);
const matrix6: BitMatrix = writer.encode(
'Hello 世界 🌍',
BarcodeFormat.AZTEC,
0,
0,
utf8Hints
);
// Low error correction for maximum capacity
const maxCapacityHints = new Map<EncodeHintType, any>();
maxCapacityHints.set(EncodeHintType.ERROR_CORRECTION, 23); // ISO minimum
const matrix7: BitMatrix = writer.encode(
'Maximum data capacity',
BarcodeFormat.AZTEC,
0,
0,
maxCapacityHints
);
// Render to canvas
function renderToCanvas(matrix: BitMatrix, canvas: HTMLCanvasElement): void {
const ctx = canvas.getContext('2d')!;
canvas.width = matrix.getWidth();
canvas.height = matrix.getHeight();
for (let y = 0; y < matrix.getHeight(); y++) {
for (let x = 0; x < matrix.getWidth(); x++) {
ctx.fillStyle = matrix.get(x, y) ? '#000000' : '#FFFFFF';
ctx.fillRect(x, y, 1, 1);
}
}
}
// Error handling
try {
const tooLargeHints = new Map<EncodeHintType, any>();
tooLargeHints.set(EncodeHintType.AZTEC_LAYERS, 2); // Only 2 layers
const matrix8: BitMatrix = writer.encode(
'Very large data that won\'t fit in 2 layers'.repeat(10),
BarcodeFormat.AZTEC,
0,
0,
tooLargeHints
);
} catch (error) {
console.error('Data too large for specified layers:', error);
}Layer Configuration:
Extends DetectorResult with Aztec-specific information about the detected code including format type, layer count, and data block information.
/**
* Contains results of Aztec code detection with format-specific metadata
* Extends DetectorResult with compact flag, layer count, and data blocks
*/
class AztecDetectorResult extends DetectorResult {
/**
* Creates a new Aztec detection result
* @param bits - BitMatrix: decoded bit matrix
* @param points - ResultPoint[]: corner points of detected code (4 corners)
* @param compact - boolean: true if compact format (5-ring), false if full (7-ring)
* @param nbDatablocks - number: number of data codewords
* @param nbLayers - number: number of layers in the code (1-4 compact, 1-32 full)
*/
constructor(
bits: BitMatrix,
points: ResultPoint[],
compact: boolean,
nbDatablocks: number,
nbLayers: number
);
/**
* Get number of layers in the Aztec code
* @returns number: layer count (1-4 for compact, 1-32 for full)
*/
getNbLayers(): number;
/**
* Get number of data codewords (blocks)
* @returns number: count of data codewords
*/
getNbDatablocks(): number;
/**
* Check if code uses compact format
* @returns boolean: true if compact (5-ring bulls-eye), false if full (7-ring)
*/
isCompact(): boolean;
// Inherited from DetectorResult
/**
* Get the decoded bit matrix
* @returns BitMatrix: extracted Aztec code bits
*/
getBits(): BitMatrix;
/**
* Get corner points of the detected code
* @returns ResultPoint[]: 4 corner points in order [topRight, bottomRight, bottomLeft, topLeft]
*/
getPoints(): ResultPoint[];
}Usage Examples:
import {
AztecDetector,
BitMatrix,
AztecDetectorResult,
ResultPoint
} from '@zxing/library';
// Detect Aztec code in bit matrix
const detector = new AztecDetector(bitMatrix);
try {
const detectorResult: AztecDetectorResult = detector.detect();
// Access detection information
console.log('Format:', detectorResult.isCompact() ? 'Compact' : 'Full');
console.log('Layers:', detectorResult.getNbLayers());
console.log('Data blocks:', detectorResult.getNbDatablocks());
// Access corner points
const points: ResultPoint[] = detectorResult.getPoints();
console.log('Top-right corner:', points[0].getX(), points[0].getY());
console.log('Bottom-right corner:', points[1].getX(), points[1].getY());
console.log('Bottom-left corner:', points[2].getX(), points[2].getY());
console.log('Top-left corner:', points[3].getX(), points[3].getY());
// Get the decoded bits
const bits: BitMatrix = detectorResult.getBits();
console.log(`Bit matrix: ${bits.getWidth()}×${bits.getHeight()}`);
// Calculate capacity
const capacity = calculateCapacity(detectorResult);
console.log('Total capacity:', capacity, 'bits');
} catch (error) {
console.error('Detection failed:', error);
}
function calculateCapacity(result: AztecDetectorResult): number {
const layers: number = result.getNbLayers();
const compact: boolean = result.isCompact();
// Formula for bit capacity:
// Compact: (88 + 16 * layers) * layers
// Full: (112 + 16 * layers) * layers
return ((compact ? 88 : 112) + 16 * layers) * layers;
}Format Details:
Compact Format:
Full Format:
Internal representation of an Aztec code containing all metadata and the encoded bit matrix. Used during encoding to track code properties.
/**
* Represents an Aztec 2D code with metadata
* Container for encoded data and format information
*/
class AztecCode {
/**
* Check if code uses compact format
* @returns boolean: true if compact (5-ring), false if full (7-ring)
*/
isCompact(): boolean;
/**
* Set the format type
* @param compact - boolean: true for compact, false for full
*/
setCompact(compact: boolean): void;
/**
* Get size in pixels (width and height are equal for Aztec)
* @returns number: size in pixels
*/
getSize(): number;
/**
* Set the matrix size
* @param size - number: size in pixels
*/
setSize(size: number): void;
/**
* Get number of layers
* @returns number: layer count (1-4 for compact, 1-32 for full)
*/
getLayers(): number;
/**
* Set the number of layers
* @param layers - number: layer count
*/
setLayers(layers: number): void;
/**
* Get number of data codewords
* @returns number: data codeword count
*/
getCodeWords(): number;
/**
* Set the number of data codewords
* @param codeWords - number: data codeword count
*/
setCodeWords(codeWords: number): void;
/**
* Get the encoded symbol as a bit matrix
* @returns BitMatrix: encoded Aztec code
*/
getMatrix(): BitMatrix;
/**
* Set the encoded matrix
* @param matrix - BitMatrix: bit matrix containing the encoded symbol
*/
setMatrix(matrix: BitMatrix): void;
}Usage Examples:
import {
AztecEncoder,
AztecCode,
BitMatrix
} from '@zxing/library';
// Encode data to get AztecCode object
const data = new TextEncoder().encode('Example data');
const aztecCode: AztecCode = AztecEncoder.encode(data, 33, 0);
// Access code properties
console.log('Format:', aztecCode.isCompact() ? 'Compact (5-ring)' : 'Full (7-ring)');
console.log('Size:', aztecCode.getSize(), 'pixels');
console.log('Layers:', aztecCode.getLayers());
console.log('Data codewords:', aztecCode.getCodeWords());
// Get the bit matrix for rendering
const matrix: BitMatrix = aztecCode.getMatrix();
console.log(`Matrix dimensions: ${matrix.getWidth()}×${matrix.getHeight()}`);
// Calculate total bit capacity
const layers: number = aztecCode.getLayers();
const compact: boolean = aztecCode.isCompact();
const totalBits = ((compact ? 88 : 112) + 16 * layers) * layers;
console.log('Total capacity:', totalBits, 'bits');
// Analyze code structure
interface AztecAnalysis {
format: string;
layers: number;
size: number;
bullsEyeSize: number;
hasAlignmentMarks: boolean;
dataCodewords: number;
totalCapacityBits: number;
}
function analyzeAztecCode(code: AztecCode): AztecAnalysis {
const compact = code.isCompact();
const layers = code.getLayers();
const size = code.getSize();
const codeWords = code.getCodeWords();
const capacity = ((compact ? 88 : 112) + 16 * layers) * layers;
return {
format: compact ? 'Compact' : 'Full',
layers,
size,
bullsEyeSize: compact ? 5 : 7,
hasAlignmentMarks: !compact && layers >= 8,
dataCodewords: codeWords,
totalCapacityBits: capacity
};
}
const analysis: AztecAnalysis = analyzeAztecCode(aztecCode);
console.log('Analysis:', analysis);
// Manually create and configure Aztec code (advanced)
const customCode = new AztecCode();
customCode.setCompact(false); // Full format
customCode.setLayers(8); // 8 layers
customCode.setSize(67); // 67×67 pixels
customCode.setCodeWords(100); // 100 data codewords
const customMatrix = new BitMatrix(67);
// ... populate matrix with encoded data ...
customCode.setMatrix(customMatrix);Core encoding engine that converts binary data into Aztec codes with error correction, bit stuffing, and matrix generation.
/**
* Generates Aztec 2D barcodes from binary data
* Low-level encoder with complete control over format and error correction
* Provides static methods for encoding with various configurations
*/
class AztecEncoder {
/**
* Default error correction percentage
* Provides good balance between capacity and error resilience
*/
static readonly DEFAULT_EC_PERCENT: number = 33;
/**
* Default layers value (auto-select optimal size)
*/
static readonly DEFAULT_AZTEC_LAYERS: number = 0;
/**
* Encodes binary data with default settings (33% ECC, auto-size)
* @param data - Uint8Array: raw byte data to encode
* @returns AztecCode: encoded Aztec code with default configuration
* @throws IllegalArgumentException if data is empty or too large
*/
static encodeBytes(data: Uint8Array): AztecCode;
/**
* Encodes binary data with custom error correction and layer specification
* @param data - Uint8Array: raw byte data to encode
* @param minECCPercent - number: minimum error correction percentage (recommended: 23% + 3 words)
* @param userSpecifiedLayers - number: layer count
* - 0: auto-select optimal format and layers
* - negative (-1 to -4): compact format with specified layers
* - positive (1 to 32): full format with specified layers
* @returns AztecCode: encoded code with specified configuration
* @throws IllegalArgumentException if parameters are invalid or data too large for layers
*/
static encode(
data: Uint8Array,
minECCPercent: number,
userSpecifiedLayers: number
): AztecCode;
}Usage Examples:
import { AztecEncoder, AztecCode, BitMatrix } from '@zxing/library';
// Encode with defaults (33% ECC, auto-size)
const data1 = new TextEncoder().encode('Quick data');
const code1: AztecCode = AztecEncoder.encodeBytes(data1);
console.log('Default encoding:', code1.getLayers(), 'layers,', code1.getSize(), 'pixels');
// Encode with high error correction (50%)
const data2 = new TextEncoder().encode('Critical data requiring high reliability');
const code2: AztecCode = AztecEncoder.encode(data2, 50, 0);
console.log('High ECC code:', code2.getLayers(), 'layers');
// Force compact format with 3 layers
const data3 = new TextEncoder().encode('Compact');
const code3: AztecCode = AztecEncoder.encode(data3, 33, -3);
console.log('Compact format:', code3.isCompact()); // true
console.log('Layers:', code3.getLayers()); // 3
console.log('Size:', code3.getSize(), 'pixels'); // 21×21 (15 + 2*3)
// Force full format with 8 layers
const data4 = new TextEncoder().encode('Full format data');
const code4: AztecCode = AztecEncoder.encode(data4, 33, 8);
console.log('Full format:', !code4.isCompact()); // true
console.log('Layers:', code4.getLayers()); // 8
console.log('Size:', code4.getSize(), 'pixels'); // 51×51 (19 + 2*16)
// Auto-select optimal format and layers
const data5 = new TextEncoder().encode('Auto-select optimal format and size based on data length');
const code5: AztecCode = AztecEncoder.encode(data5, 33, 0);
console.log('Auto-selected format:', code5.isCompact() ? 'Compact' : 'Full');
console.log('Auto-selected layers:', code5.getLayers());
// Binary data encoding (non-text)
const binaryData = new Uint8Array([0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD]);
const binaryCode: AztecCode = AztecEncoder.encode(binaryData, 25, 0);
console.log('Binary data encoded');
// Large data encoding
const largeData = new TextEncoder().encode('A'.repeat(1000));
try {
const largeCode: AztecCode = AztecEncoder.encode(largeData, 33, 0);
console.log('Large data encoded with', largeCode.getLayers(), 'layers');
console.log('Format:', largeCode.isCompact() ? 'Compact' : 'Full');
console.log('Size:', largeCode.getSize(), '×', largeCode.getSize());
} catch (error) {
console.error('Data too large even for version 32:', error);
}
// Calculate required layers for data
function calculateRequiredLayers(
dataLength: number,
eccPercent: number,
compact: boolean
): number {
const maxLayers = compact ? 4 : 32;
for (let layers = 1; layers <= maxLayers; layers++) {
const capacity = ((compact ? 88 : 112) + 16 * layers) * layers;
const dataCapacity = Math.floor(capacity * (100 - eccPercent) / 100);
const requiredBits = dataLength * 8;
if (requiredBits <= dataCapacity) {
return layers;
}
}
return -1; // Data too large
}
// Example: how many layers needed?
const dataBytes = 100;
const compactLayers = calculateRequiredLayers(dataBytes, 33, true);
const fullLayers = calculateRequiredLayers(dataBytes, 33, false);
console.log(`${dataBytes} bytes with 33% ECC requires:`);
console.log(` Compact: ${compactLayers} layers${compactLayers === -1 ? ' (too large)' : ''}`);
console.log(` Full: ${fullLayers} layers`);Error Correction Recommendations:
| ECC % | Use Case | Pros | Cons |
|---|---|---|---|
| 23% | Clean environments, maximum capacity | Most data | Less damage tolerance |
| 33% | General purpose (default) | Good balance | Standard capacity |
| 40% | Outdoor, moderate damage expected | Good reliability | Reduced capacity |
| 50% | High damage, small print | High reliability | Significantly reduced capacity |
| >50% | Critical data, extreme conditions | Maximum reliability | Minimal capacity |
Layer Selection Guide:
| Data Size | Recommended Layers | Format | Approx. Capacity (33% ECC) |
|---|---|---|---|
| < 20 bytes | 1-2 | Compact | 10-30 bytes |
| 20-50 bytes | 2-3 | Compact | 30-70 bytes |
| 50-100 bytes | 3-4 | Compact or Full | 70-140 bytes |
| 100-500 bytes | 4-12 | Full | 140-700 bytes |
| 500-1500 bytes | 12-24 | Full | 700-2100 bytes |
| 1500+ bytes | 24-32 | Full | 2100-4500 bytes |
Optimizes text encoding by automatically selecting the best encoding modes (UPPER, LOWER, MIXED, DIGIT, PUNCT, BINARY) for minimal bit usage.
/**
* High-level encoder that optimizes text encoding
* Uses dynamic programming to find near-optimal encoding sequences
* Minimizes bit count by choosing best mode switches
*/
class HighLevelEncoder {
/**
* Creates encoder for the given text data
* @param text - Uint8Array: raw byte data to encode
*/
constructor(text: Uint8Array);
/**
* Encodes the text using optimal mode switching
* Uses dynamic programming to minimize total bit count
* @returns BitArray: encoded data bits
*/
encode(): BitArray;
}Encoding Modes:
| Mode | Characters | Bits/Char | Usage |
|---|---|---|---|
| UPPER | A-Z, space | 5 | Uppercase text |
| LOWER | a-z, space | 5 | Lowercase text |
| MIXED | Control chars, punctuation | 5 | Special characters |
| DIGIT | 0-9, comma, period | 4 | Numeric data (most efficient for numbers) |
| PUNCT | Punctuation marks | 5 | Punctuation |
| BINARY | All bytes | 8 | Binary data, Unicode, incompatible characters |
Special Character Pairs:
The encoder recognizes and optimizes these two-character sequences:
\r\n - Carriage return + line feed (single 5-bit PUNCT token). - Period + space (single 5-bit PUNCT token), - Comma + space (single 5-bit PUNCT token): - Colon + space (single 5-bit PUNCT token)Usage Examples:
import { HighLevelEncoder, BitArray } from '@zxing/library';
// Encode simple uppercase text
const text1 = new TextEncoder().encode('HELLO');
const encoder1 = new HighLevelEncoder(text1);
const bits1: BitArray = encoder1.encode();
console.log('HELLO encoded to', bits1.getSize(), 'bits');
// Efficient: uses UPPER mode (5 bits per character)
// Encode mixed-case text (uses mode switching)
const text2 = new TextEncoder().encode('Hello World');
const encoder2 = new HighLevelEncoder(text2);
const bits2: BitArray = encoder2.encode();
console.log('Hello World encoded to', bits2.getSize(), 'bits');
// Uses UPPER mode for 'H', switches to LOWER for 'ello', etc.
// Encode numeric data (optimized for DIGIT mode)
const text3 = new TextEncoder().encode('1234567890');
const encoder3 = new HighLevelEncoder(text3);
const bits3: BitArray = encoder3.encode();
console.log('1234567890 encoded to', bits3.getSize(), 'bits');
// Most efficient: ~4 bits per digit = ~40 bits for 10 digits
// Encode binary data
const binaryData = new Uint8Array([0xFF, 0xFE, 0xFD, 0xFC]);
const encoder4 = new HighLevelEncoder(binaryData);
const bits4: BitArray = encoder4.encode();
console.log('Binary data encoded to', bits4.getSize(), 'bits');
// Uses BINARY mode: 8 bits per byte
// Compare encoding efficiency
interface EncodingComparison {
text: string;
bytes: number;
rawBits: number;
encodedBits: number;
efficiency: number;
}
function compareEncoding(text: string): EncodingComparison {
const data = new TextEncoder().encode(text);
const encoder = new HighLevelEncoder(data);
const bits = encoder.encode();
const rawBits = data.length * 8;
const encodedBits = bits.getSize();
const efficiency = ((rawBits - encodedBits) / rawBits * 100);
return {
text,
bytes: data.length,
rawBits,
encodedBits,
efficiency
};
}
console.log("Encoding efficiency:");
console.log(compareEncoding('UPPERCASE TEXT')); // Best with UPPER mode
console.log(compareEncoding('lowercase text')); // Best with LOWER mode
console.log(compareEncoding('1234567890')); // Best with DIGIT mode
console.log(compareEncoding('Mix3d T3xt 123')); // Uses multiple modes
console.log(compareEncoding('Hello, World! 123')); // Mixed modes with optimal switchesOptimization Strategy:
The encoder uses a sophisticated dynamic programming algorithm:
Example Encoding Strategy:
Text: "Hello123"
Position | Char | Best Mode | Action | Cumulative Bits
---------|------|-----------|----------------|----------------
0 | H | UPPER | Start UPPER | 5
1 | e | LOWER | Latch→LOWER | 10 (5+5)
2 | l | LOWER | Stay in LOWER | 15 (10+5)
3 | l | LOWER | Stay in LOWER | 20 (15+5)
4 | o | LOWER | Stay in LOWER | 25 (20+5)
5 | 1 | DIGIT | Latch→DIGIT | 34 (25+5+4)
6 | 2 | DIGIT | Stay in DIGIT | 38 (34+4)
7 | 3 | DIGIT | Stay in DIGIT | 42 (38+4)
Total: 42 bits (vs 64 bits for pure binary = 34% savings)Internal decoder that extracts data from detected Aztec codes, performs error correction, and decodes the bit stream into text.
/**
* Decodes the data content from Aztec detection results
* Handles bit extraction, Reed-Solomon error correction, and character decoding
*/
class Decoder {
/**
* Decodes an Aztec code from detection result
* @param detectorResult - AztecDetectorResult: result from Aztec detector with bits and metadata
* @returns DecoderResult: decoded text, raw bytes, and metadata
* @throws FormatException if decoding fails or too many errors detected
*/
decode(detectorResult: AztecDetectorResult): DecoderResult;
/**
* High-level decode from error-corrected bits (testing utility)
* @param correctedBits - boolean[]: error-corrected boolean bit array
* @returns string: decoded text
* @throws FormatException if bit stream cannot be decoded
*/
static highLevelDecode(correctedBits: boolean[]): string;
/**
* Converts boolean bit array to byte array
* @param boolArr - boolean[]: boolean array (bits)
* @returns Uint8Array: packed bytes (8 bits per byte)
*/
static convertBoolArrayToByteArray(boolArr: boolean[]): Uint8Array;
}Usage Examples:
import {
Decoder as AztecDecoder,
AztecDetector,
AztecDetectorResult,
DecoderResult,
BitMatrix
} from '@zxing/library';
// Detect and decode Aztec code (complete pipeline)
const detector = new AztecDetector(bitMatrix);
try {
const detectorResult: AztecDetectorResult = detector.detect();
console.log('Detected:', detectorResult.isCompact() ? 'Compact' : 'Full');
console.log('Layers:', detectorResult.getNbLayers());
console.log('Data blocks:', detectorResult.getNbDatablocks());
const decoder = new AztecDecoder();
const decoderResult: DecoderResult = decoder.decode(detectorResult);
// Access decoded data
console.log('Decoded text:', decoderResult.getText());
console.log('Raw bytes length:', decoderResult.getRawBytes()?.length);
console.log('Num bits:', decoderResult.getNumBits());
console.log('EC level:', decoderResult.getECLevel());
// Check for byte segments (binary data)
const byteSegments: Uint8Array[] | null = decoderResult.getByteSegments();
if (byteSegments && byteSegments.length > 0) {
console.log('Has byte segments:', byteSegments.length);
byteSegments.forEach((segment, i) => {
console.log(`Segment ${i}: ${segment.length} bytes`);
});
}
// Error correction statistics
const errorsCorrected = decoderResult.getErrorsCorrected();
if (errorsCorrected !== undefined && errorsCorrected !== null) {
console.log('Errors corrected:', errorsCorrected);
}
const erasures = decoderResult.getErasures();
if (erasures !== undefined && erasures !== null) {
console.log('Erasures:', erasures);
}
} catch (error) {
console.error('Aztec decode failed:', error);
}
// Direct high-level decoding from corrected bits (advanced/testing)
const correctedBits: boolean[] = [
true, false, true, true, false, // ... bit sequence ...
];
try {
const decoded: string = AztecDecoder.highLevelDecode(correctedBits);
console.log('Decoded from bits:', decoded);
} catch (error) {
console.error('High-level decode failed:', error);
}
// Convert boolean array to bytes
const boolArray: boolean[] = [
true, false, true, false, true, false, true, false, // Byte 1: 0xAA
true, true, false, false, true, true, false, false // Byte 2: 0xCC
];
const bytes: Uint8Array = AztecDecoder.convertBoolArrayToByteArray(boolArray);
console.log('Converted bytes:', Array.from(bytes)); // [170, 204] (0xAA, 0xCC)Decoding Process:
Locates and extracts Aztec codes from binary bitmap images by identifying the distinctive bulls-eye center pattern and computing corner positions.
/**
* Detects Aztec codes in binary bitmap images
* Locates bulls-eye pattern (5 or 7 concentric rings) and determines code boundaries
*/
class Detector {
/**
* Creates detector for the given image
* @param image - BitMatrix: binary bit matrix to scan
*/
constructor(image: BitMatrix);
/**
* Detects an Aztec code in the image
* Attempts both normal and mirrored orientations automatically
* @returns AztecDetectorResult: detected code with position and format info
* @throws NotFoundException if no valid Aztec code found
*/
detect(): AztecDetectorResult;
/**
* Detects with explicit mirror handling
* @param isMirror - boolean: true to detect mirrored code, false for normal
* @returns AztecDetectorResult: detected code with position and format info
* @throws NotFoundException if no valid Aztec code found in specified orientation
*/
detectMirror(isMirror: boolean): AztecDetectorResult;
}Usage Examples:
import {
AztecDetector,
BitMatrix,
AztecDetectorResult,
NotFoundException,
ResultPoint
} from '@zxing/library';
// Create detector
const detector = new AztecDetector(bitMatrix);
// Automatic detection (tries both orientations)
try {
const result: AztecDetectorResult = detector.detect();
console.log('Detected:', result.isCompact() ? 'Compact (5-ring)' : 'Full (7-ring)');
console.log('Layers:', result.getNbLayers());
console.log('Data blocks:', result.getNbDatablocks());
// Get corner points
const points: ResultPoint[] = result.getPoints();
console.log('Corner points:');
points.forEach((p, i) => {
console.log(` Point ${i}: (${p.getX()}, ${p.getY()})`);
});
// Get extracted bits
const bits: BitMatrix = result.getBits();
console.log('Extracted matrix:', bits.getWidth(), '×', bits.getHeight());
// Calculate capacity
const layers = result.getNbLayers();
const compact = result.isCompact();
const capacity = ((compact ? 88 : 112) + 16 * layers) * layers;
console.log('Total capacity:', capacity, 'bits');
console.log('Data blocks:', result.getNbDatablocks(), 'codewords');
} catch (error) {
if (error instanceof NotFoundException) {
console.log('No Aztec code found in image');
} else {
console.error('Detection error:', error);
throw error;
}
}
// Manual mirror detection (explicit orientation)
try {
// Try normal orientation first
const normalResult: AztecDetectorResult = detector.detectMirror(false);
console.log('Found in normal orientation');
console.log('Compact:', normalResult.isCompact());
console.log('Layers:', normalResult.getNbLayers());
} catch (normalError) {
try {
// Fall back to mirrored orientation
const mirrorResult: AztecDetectorResult = detector.detectMirror(true);
console.log('Found in mirrored orientation');
console.log('Compact:', mirrorResult.isCompact());
console.log('Layers:', mirrorResult.getNbLayers());
} catch (mirrorError) {
console.log('No Aztec code found in either orientation');
}
}Detection Algorithm:
The bulls-eye pattern structure:
Exported as: AztecPoint
Simple coordinate point class used during Aztec code detection for tracking positions and performing geometric calculations.
/**
* Represents a coordinate point in Aztec detection
* Simple helper class for geometric calculations during detection
*/
class Point {
/**
* Creates a new point
* @param x - number: x coordinate
* @param y - number: y coordinate
*/
constructor(x: number, y: number);
/**
* Get X coordinate
* @returns number: x position
*/
getX(): number;
/**
* Get Y coordinate
* @returns number: y position
*/
getY(): number;
/**
* Converts to ResultPoint for result reporting
* @returns ResultPoint: result point with same coordinates
*/
toResultPoint(): ResultPoint;
}import { AztecEncoder, AztecCode } from '@zxing/library';
// Strategy 1: Minimum viable ECC (maximum capacity)
function encodeMinimalECC(data: Uint8Array): AztecCode {
return AztecEncoder.encode(data, 23, 0); // ISO minimum 23%
}
// Strategy 2: Balanced for typical use
function encodeBalanced(data: Uint8Array): AztecCode {
return AztecEncoder.encode(data, 33, 0); // Default 33%
}
// Strategy 3: Maximum reliability (reduced capacity)
function encodeMaxReliability(data: Uint8Array): AztecCode {
return AztecEncoder.encode(data, 50, 0); // High 50% ECC
}
// Strategy 4: Size-constrained encoding
function encodeConstrained(data: Uint8Array, maxSize: number): AztecCode | null {
// Try increasing ECC until size limit reached
for (let ecc = 23; ecc <= 50; ecc += 5) {
try {
const code: AztecCode = AztecEncoder.encode(data, ecc, 0);
if (code.getSize() <= maxSize) {
console.log(`Encoded with ${ecc}% ECC, size: ${code.getSize()}`);
return code;
}
} catch (error) {
// Data too large even with lower ECC
}
}
// Fall back to minimum ECC
try {
return AztecEncoder.encode(data, 23, 0);
} catch (error) {
console.error('Data too large even with minimum ECC');
return null;
}
}
// Usage
const testData = new TextEncoder().encode('Test data for encoding');
const minimalCode = encodeMinimalECC(testData);
const balancedCode = encodeBalanced(testData);
const reliableCode = encodeMaxReliability(testData);
console.log('Minimal ECC size:', minimalCode.getSize());
console.log('Balanced size:', balancedCode.getSize());
console.log('Reliable size:', reliableCode.getSize());
const constrainedCode = encodeConstrained(testData, 50);
if (constrainedCode) {
console.log('Constrained encoding successful');
}import { AztecEncoder, AztecCode } from '@zxing/library';
interface FormatSelection {
format: 'compact' | 'full';
layers: number;
totalCapacityBits: number;
dataCapacityBits: number;
size: number;
}
function selectOptimalFormat(
dataLengthBytes: number,
eccPercent: number
): FormatSelection | null {
const requiredDataBits = dataLengthBytes * 8;
const minTotalBits = Math.ceil(requiredDataBits / (1 - eccPercent / 100));
// Try compact first (more efficient for small data)
for (let layers = 1; layers <= 4; layers++) {
const totalCapacity = (88 + 16 * layers) * layers;
const dataCapacity = Math.floor(totalCapacity * (100 - eccPercent) / 100);
if (dataCapacity >= requiredDataBits) {
return {
format: 'compact',
layers,
totalCapacityBits: totalCapacity,
dataCapacityBits: dataCapacity,
size: 15 + 2 * layers // Compact: 15 + 2n
};
}
}
// Try full format
for (let layers = 1; layers <= 32; layers++) {
const totalCapacity = (112 + 16 * layers) * layers;
const dataCapacity = Math.floor(totalCapacity * (100 - eccPercent) / 100);
if (dataCapacity >= requiredDataBits) {
return {
format: 'full',
layers,
totalCapacityBits: totalCapacity,
dataCapacityBits: dataCapacity,
size: 19 + 4 * layers - 2 // Full: 19 + 4n - 2
};
}
}
return null; // Data too large for Aztec code
}
// Usage examples
console.log('Format selection for 100 bytes with 33% ECC:');
const selection = selectOptimalFormat(100, 33);
if (selection) {
console.log(`Use ${selection.format} format with ${selection.layers} layers`);
console.log(`Size: ${selection.size}×${selection.size} modules`);
console.log(`Data capacity: ${selection.dataCapacityBits} bits (${Math.floor(selection.dataCapacityBits / 8)} bytes)`);
}
// Compare formats for various data sizes
const dataSizes = [20, 50, 100, 200, 500, 1000];
dataSizes.forEach(size => {
const sel = selectOptimalFormat(size, 33);
if (sel) {
console.log(`${size} bytes: ${sel.format} ${sel.layers} layers, ${sel.size}×${sel.size} modules`);
} else {
console.log(`${size} bytes: too large for Aztec`);
}
});import { AztecEncoder, AztecCode, AztecCodeWriter, BarcodeFormat, BitMatrix } from '@zxing/library';
// Encode binary data directly
function encodeBinaryData(data: Uint8Array): AztecCode {
return AztecEncoder.encode(data, 33, 0);
}
// Example: Encode image thumbnail
const imageThumbnail = new Uint8Array([/* JPEG bytes */]);
const imageCode: AztecCode = encodeBinaryData(imageThumbnail);
console.log('Encoded', imageThumbnail.length, 'bytes in', imageCode.getSize(), '×', imageCode.getSize(), 'matrix');
// Encode structured binary data
interface BinaryPacket {
type: number;
length: number;
data: Uint8Array;
}
function encodeBinaryPacket(packet: BinaryPacket): AztecCode {
// Serialize packet
const serialized = new Uint8Array(2 + packet.data.length);
serialized[0] = packet.type;
serialized[1] = packet.length;
serialized.set(packet.data, 2);
return AztecEncoder.encode(serialized, 33, 0);
}
const packet: BinaryPacket = {
type: 1,
length: 10,
data: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
};
const packetCode: AztecCode = encodeBinaryPacket(packet);
// Decode and parse binary packet
function decodeBinaryPacket(result: Result): BinaryPacket | null {
const rawBytes = result.getRawBytes();
if (!rawBytes || rawBytes.length < 2) return null;
return {
type: rawBytes[0],
length: rawBytes[1],
data: rawBytes.slice(2)
};
}import {
AztecCodeReader,
AztecCodeWriter,
BinaryBitmap,
HybridBinarizer,
RGBLuminanceSource,
Result,
BarcodeFormat,
BitMatrix
} from '@zxing/library';
// Reuse reader instances for continuous scanning
class AztecScanner {
private reader: AztecCodeReader = new AztecCodeReader();
decode(bitmap: BinaryBitmap): Result | null {
try {
return this.reader.decode(bitmap);
} catch (error) {
return null;
}
}
// Reset not strictly needed for Aztec, but good practice
reset(): void {
this.reader.reset();
}
}
// Batch encoding with shared writer instance
class AztecBatchEncoder {
private writer: AztecCodeWriter = new AztecCodeWriter();
encodeMultiple(contents: string[]): BitMatrix[] {
return contents.map(content => {
try {
return this.writer.encode(content, BarcodeFormat.AZTEC, 0, 0);
} catch (error) {
console.error(`Failed to encode "${content}":`, error);
return null;
}
}).filter((m): m is BitMatrix => m !== null);
}
}
// Optimized binarization for Aztec
function optimizedBinarize(
imageData: Uint8ClampedArray,
width: number,
height: number
): BinaryBitmap {
const source = new RGBLuminanceSource(imageData, width, height);
// HybridBinarizer works better than GlobalHistogramBinarizer for Aztec
// due to the bulls-eye pattern requiring good local contrast
const binarizer = new HybridBinarizer(source);
return new BinaryBitmap(binarizer);
}
// Adaptive encoding based on data size
function adaptiveEncode(data: string): BitMatrix {
const writer = new AztecCodeWriter();
const bytes = new TextEncoder().encode(data);
// Select ECC based on data size
const hints = new Map<EncodeHintType, any>();
if (bytes.length < 50) {
hints.set(EncodeHintType.ERROR_CORRECTION, 40); // High ECC for small data
} else if (bytes.length < 200) {
hints.set(EncodeHintType.ERROR_CORRECTION, 33); // Balanced
} else {
hints.set(EncodeHintType.ERROR_CORRECTION, 25); // Lower ECC for large data
}
return writer.encode(data, BarcodeFormat.AZTEC, 0, 0, hints);
}import {
AztecCodeReader,
AztecCodeWriter,
NotFoundException,
FormatException,
WriterException,
IllegalArgumentException,
BinaryBitmap,
BarcodeFormat
} from '@zxing/library';
// Comprehensive error handling for reading
function safeAztecDecode(bitmap: BinaryBitmap): string | null {
const reader = new AztecCodeReader();
try {
const result = reader.decode(bitmap);
return result.getText();
} catch (error) {
if (error instanceof NotFoundException) {
console.error('No Aztec code found in image');
// Image may not contain Aztec code, or bulls-eye is obscured
} else if (error instanceof FormatException) {
console.error('Aztec code structure is invalid');
// Code is damaged or not a valid Aztec code
} else {
console.error('Unknown decode error:', error);
}
return null;
}
}
// Comprehensive error handling for writing
function safeAztecEncode(
contents: string,
errorCorrection?: number,
layers?: number
): BitMatrix | null {
const writer = new AztecCodeWriter();
try {
const hints = new Map<EncodeHintType, any>();
if (errorCorrection !== undefined) {
if (errorCorrection < 0 || errorCorrection > 100) {
throw new IllegalArgumentException('Error correction must be 0-100%');
}
hints.set(EncodeHintType.ERROR_CORRECTION, errorCorrection);
}
if (layers !== undefined) {
if (layers < -4 || layers > 32 || layers === 0) {
// layers can be -4 to -1, 0 (auto), or 1 to 32
// Note: 0 is valid (auto-select)
}
hints.set(EncodeHintType.AZTEC_LAYERS, layers);
}
return writer.encode(contents, BarcodeFormat.AZTEC, 0, 0, hints);
} catch (error) {
if (error instanceof WriterException) {
console.error('Aztec encoding failed:', error.message);
// Data may be too large for specified layers
} else if (error instanceof IllegalArgumentException) {
console.error('Invalid parameters:', error.message);
// Check error correction percentage, layers, or format
} else {
console.error('Unknown encode error:', error);
}
return null;
}
}
// Retry with fallback options
function encodeWithFallback(contents: string): BitMatrix | null {
const writer = new AztecCodeWriter();
const strategies = [
{ ecc: 33, layers: 0 }, // Balanced auto
{ ecc: 25, layers: 0 }, // Lower ECC
{ ecc: 33, layers: -4 }, // Compact mode
{ ecc: 23, layers: 0 }, // Minimum ECC
];
for (const strategy of strategies) {
try {
const hints = new Map<EncodeHintType, any>();
hints.set(EncodeHintType.ERROR_CORRECTION, strategy.ecc);
hints.set(EncodeHintType.AZTEC_LAYERS, strategy.layers);
return writer.encode(contents, BarcodeFormat.AZTEC, 0, 0, hints);
} catch (error) {
console.debug(`Strategy ${strategy.ecc}% ECC, layers ${strategy.layers} failed`);
}
}
console.error('All encoding strategies failed');
return null;
}Compact Format (5-ring bulls-eye):
| Layers | Size | Total Bits | Data Bits (33% ECC) | Approx Bytes (33% ECC) |
|---|---|---|---|---|
| 1 | 15×15 | 88 | 59 | 7 |
| 2 | 17×17 | 240 | 161 | 20 |
| 3 | 19×19 | 456 | 305 | 38 |
| 4 | 21×21 | 736 | 493 | 61 |
Full Format (7-ring bulls-eye):
| Layers | Size | Total Bits | Data Bits (33% ECC) | Approx Bytes (33% ECC) |
|---|---|---|---|---|
| 1 | 19×19 | 128 | 86 | 10 |
| 2 | 23×23 | 288 | 193 | 24 |
| 4 | 31×31 | 672 | 450 | 56 |
| 8 | 47×47 | 1568 | 1051 | 131 |
| 12 | 63×63 | 2736 | 1833 | 229 |
| 16 | 79×79 | 4176 | 2798 | 349 |
| 20 | 95×95 | 5888 | 3945 | 493 |
| 24 | 111×111 | 7872 | 5274 | 659 |
| 28 | 127×127 | 10128 | 6786 | 848 |
| 32 | 143×143 | 12656 | 8480 | 1060 |
Capacity Calculation Formula:
function calculateAztecCapacity(layers: number, compact: boolean, eccPercent: number): {
totalBits: number;
dataBits: number;
dataBytes: number;
} {
const totalBits = ((compact ? 88 : 112) + 16 * layers) * layers;
const dataBits = Math.floor(totalBits * (100 - eccPercent) / 100);
const dataBytes = Math.floor(dataBits / 8);
return { totalBits, dataBits, dataBytes };
}
// Examples
console.log('Compact 2 layers, 33% ECC:', calculateAztecCapacity(2, true, 33));
console.log('Full 8 layers, 33% ECC:', calculateAztecCapacity(8, false, 33));
console.log('Full 32 layers, 25% ECC:', calculateAztecCapacity(32, false, 25));Install with Tessl CLI
npx tessl i tessl/npm-zxing--library