Core barcode encoding/decoding library supporting 17 formats including QR Code, Data Matrix, Aztec, PDF 417, and various 1D barcodes
—
Support for detecting and decoding multiple barcodes from a single image. GenericMultipleBarcodeReader works with any Reader implementation by recursively scanning image regions, while QRCodeMultiReader provides QR-specific multi-detection. Additional utility ByQuadrantReader divides images into quadrants for improved detection in certain scenarios.
Interface for reading multiple barcodes from a single image. Returns an array of Result objects, one for each detected barcode.
/**
* Interface for reading multiple barcodes from a single image.
* Implementations detect and decode all barcodes present in the image.
*/
public interface MultipleBarcodeReader {
/**
* Decodes multiple barcodes from an image.
*
* @param image Binary bitmap representation of the image
* @return Array of Result objects (one per barcode), may be empty
* @throws NotFoundException If no barcodes are found
*/
Result[] decodeMultiple(BinaryBitmap image) throws NotFoundException;
/**
* Decodes multiple barcodes from an image with configuration hints.
*
* @param image Binary bitmap representation of the image
* @param hints Map of DecodeHintType to configuration values
* @return Array of Result objects (one per barcode), may be empty
* @throws NotFoundException If no barcodes are found
*/
Result[] decodeMultiple(BinaryBitmap image, Map<DecodeHintType,?> hints) throws NotFoundException;
}Generic implementation that wraps any single-barcode Reader to detect multiple barcodes. Uses recursive region scanning to find additional barcodes after each successful decode.
/**
* Generic multiple barcode reader implementation.
* Wraps any single-barcode Reader (1D or 2D) and recursively scans
* image regions to find additional barcodes.
*
* Algorithm:
* 1. Decode barcode using delegate reader
* 2. "Erase" found barcode region by setting bits to white
* 3. Recursively scan remaining image for more barcodes
* 4. Repeat until no more barcodes found
*
* Works with any barcode format supported by delegate reader.
*/
public final class GenericMultipleBarcodeReader implements MultipleBarcodeReader {
/**
* Creates a generic multiple barcode reader.
*
* @param delegate Single-barcode reader to use for detection
* (e.g., MultiFormatReader, QRCodeReader, etc.)
*/
public GenericMultipleBarcodeReader(Reader delegate);
/**
* Decodes multiple barcodes from image.
*
* @param image Binary bitmap to scan
* @return Array of Result objects (may be empty if none found)
* @throws NotFoundException If no barcodes found in image
*/
@Override
public Result[] decodeMultiple(BinaryBitmap image) throws NotFoundException;
/**
* Decodes multiple barcodes with hints.
*
* @param image Binary bitmap to scan
* @param hints Decode hints for delegate reader
* @return Array of Result objects
* @throws NotFoundException If no barcodes found
*/
@Override
public Result[] decodeMultiple(BinaryBitmap image, Map<DecodeHintType,?> hints)
throws NotFoundException;
}Usage Example:
import com.google.zxing.*;
import com.google.zxing.common.*;
import com.google.zxing.multi.*;
import java.util.*;
// Create image with multiple barcodes
BinaryBitmap bitmap = ...;
// Create multi-barcode reader with any delegate
Reader delegate = new MultiFormatReader();
MultipleBarcodeReader multiReader = new GenericMultipleBarcodeReader(delegate);
try {
// Decode all barcodes in image
Result[] results = multiReader.decodeMultiple(bitmap);
System.out.println("Found " + results.length + " barcodes:");
for (int i = 0; i < results.length; i++) {
Result r = results[i];
System.out.println(" " + (i+1) + ". " + r.getBarcodeFormat() +
": " + r.getText());
// Get location of each barcode
ResultPoint[] points = r.getResultPoints();
System.out.println(" Location: " + Arrays.toString(points));
}
} catch (NotFoundException e) {
System.out.println("No barcodes found");
}QR Code-specific implementation for detecting multiple QR codes. Optimized for QR Code finder patterns and supports structured append sequences.
/**
* QR Code-specific multiple barcode reader.
* Extends QRCodeReader to detect multiple QR codes in a single image.
* More efficient than GenericMultipleBarcodeReader for QR codes because
* it uses QR-specific finder pattern detection.
*
* Supports:
* - Multiple independent QR codes
* - Structured append sequences (multiple QR codes forming one message)
*/
public final class QRCodeMultiReader extends QRCodeReader
implements MultipleBarcodeReader {
/**
* Creates a QR Code multi-reader.
*/
public QRCodeMultiReader();
/**
* Decodes multiple QR codes from image.
*
* @param image Binary bitmap to scan
* @return Array of Result objects (one per QR code)
* @throws NotFoundException If no QR codes found
*/
@Override
public Result[] decodeMultiple(BinaryBitmap image) throws NotFoundException;
/**
* Decodes multiple QR codes with hints.
*
* @param image Binary bitmap to scan
* @param hints Decode hints (PURE_BARCODE, CHARACTER_SET, etc.)
* @return Array of Result objects
* @throws NotFoundException If no QR codes found
*/
@Override
public Result[] decodeMultiple(BinaryBitmap image, Map<DecodeHintType,?> hints)
throws NotFoundException;
// Also inherits single QR code methods from QRCodeReader
@Override
public Result decode(BinaryBitmap image) throws NotFoundException, FormatException;
@Override
public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints)
throws NotFoundException, FormatException;
}Usage Example:
import com.google.zxing.*;
import com.google.zxing.common.*;
import com.google.zxing.multi.qrcode.QRCodeMultiReader;
import java.util.*;
// Create image with multiple QR codes
BinaryBitmap bitmap = ...;
// Use QR-specific multi-reader for better performance
MultipleBarcodeReader qrMultiReader = new QRCodeMultiReader();
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
try {
Result[] results = qrMultiReader.decodeMultiple(bitmap, hints);
System.out.println("Found " + results.length + " QR codes:");
for (Result r : results) {
System.out.println(" " + r.getText());
// Check for structured append metadata
Map<ResultMetadataType, Object> metadata = r.getResultMetadata();
if (metadata != null &&
metadata.containsKey(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE)) {
int sequence = (Integer) metadata.get(
ResultMetadataType.STRUCTURED_APPEND_SEQUENCE);
int parity = (Integer) metadata.get(
ResultMetadataType.STRUCTURED_APPEND_PARITY);
System.out.println(" Part " + sequence +
" of structured append (parity: " + parity + ")");
}
}
} catch (NotFoundException e) {
System.out.println("No QR codes found");
}Utility reader that divides the image into quadrants and attempts detection in each. Useful for images with barcodes in specific regions or when standard scanning struggles.
/**
* Attempts to decode by dividing image into quadrants.
* Useful when:
* - Barcode may be in any corner of image
* - Standard full-image scan is struggling
* - Image is very large
*
* Not a MultipleBarcodeReader - returns first barcode found.
* Divides image into 4 quadrants and tries each separately.
*/
public final class ByQuadrantReader implements Reader {
/**
* Creates a by-quadrant reader.
*
* @param delegate Single-barcode reader to use in each quadrant
*/
public ByQuadrantReader(Reader delegate);
/**
* Attempts to decode by scanning quadrants.
*
* @param image Binary bitmap to scan
* @return First barcode found
* @throws NotFoundException If no barcode found in any quadrant
* @throws ChecksumException If barcode found but checksum failed
* @throws FormatException If barcode found but format invalid
*/
@Override
public Result decode(BinaryBitmap image)
throws NotFoundException, ChecksumException, FormatException;
/**
* Attempts to decode with hints.
*
* @param image Binary bitmap to scan
* @param hints Decode hints for delegate
* @return First barcode found
* @throws NotFoundException If no barcode found
* @throws ChecksumException If checksum failed
* @throws FormatException If format invalid
*/
@Override
public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints)
throws NotFoundException, ChecksumException, FormatException;
@Override
public void reset();
}Usage Example:
import com.google.zxing.*;
import com.google.zxing.common.*;
import com.google.zxing.multi.ByQuadrantReader;
// For difficult images where standard scanning fails
BinaryBitmap bitmap = ...;
// Try quadrant-by-quadrant
Reader quadrantReader = new ByQuadrantReader(new MultiFormatReader());
try {
Result result = quadrantReader.decode(bitmap);
System.out.println("Found in quadrant: " + result.getText());
} catch (NotFoundException e) {
System.out.println("Not found in any quadrant");
}// Scanning sheet with multiple QR codes
QRCodeMultiReader qrMulti = new QRCodeMultiReader();
Result[] qrCodes = qrMulti.decodeMultiple(bitmap);
// Process all QR codes
for (Result qr : qrCodes) {
processQRCode(qr.getText());
}// Scanning document with mixed barcode types
MultiFormatReader singleReader = new MultiFormatReader();
GenericMultipleBarcodeReader multiReader =
new GenericMultipleBarcodeReader(singleReader);
Result[] allBarcodes = multiReader.decodeMultiple(bitmap);
// Process by format
for (Result result : allBarcodes) {
switch (result.getBarcodeFormat()) {
case QR_CODE:
processQRCode(result.getText());
break;
case CODE_128:
processShippingLabel(result.getText());
break;
case EAN_13:
processProduct(result.getText());
break;
}
}public Result[] scanMultipleWithRetry(BinaryBitmap bitmap) {
// Try 1: Fast scan
try {
MultipleBarcodeReader reader = new GenericMultipleBarcodeReader(
new MultiFormatReader());
return reader.decodeMultiple(bitmap);
} catch (NotFoundException e) {
// Try 2: With TRY_HARDER
try {
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
return reader.decodeMultiple(bitmap, hints);
} catch (NotFoundException e2) {
return new Result[0]; // Empty array
}
}
}// Collect parts of structured append sequence
Map<Integer, Result> parts = new TreeMap<>();
for (Result result : results) {
Map<ResultMetadataType, Object> metadata = result.getResultMetadata();
if (metadata != null &&
metadata.containsKey(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE)) {
int sequence = (Integer) metadata.get(
ResultMetadataType.STRUCTURED_APPEND_SEQUENCE);
parts.put(sequence, result);
}
}
// Reconstruct complete message
StringBuilder fullMessage = new StringBuilder();
for (Result part : parts.values()) {
fullMessage.append(part.getText());
}
System.out.println("Complete message: " + fullMessage);Algorithm Complexity:
Memory Usage:
Optimization Tips:
GenericMultipleBarcodeReader:
QRCodeMultiReader:
Best Results:
When to Use:
When Not to Use:
Recommendations: