Read barcodes from a PDF
Pdftools SDK detects barcodes and QR codes on the pages of a PDF document. The barcode engine reads each page that you submit, recognizes the barcodes it finds, and returns the value, type, page number, and bounding box of every barcode. You can either embed the results in the document’s XMP metadata or write them to a separate XML stream.
Barcode recognition is available only on Windows x86 and x64. The barcode engine relies on the DTKBarReader native library, which ships for Windows only. On other platforms, creating the barcode engine fails.
How barcode recognition works
Barcode recognition reuses the OCR pipeline. Instead of an OCR text engine, you create a dedicated barcode engine and configure the BarcodeOptions sub-object of OcrOptions. The barcode engine analyzes each page image that the Processor submits and reports every barcode it recognizes.
Setting the barcode mode alone has no effect. To run barcode recognition, you must do the following:
- Create the barcode engine. Pass
"barcodes"toEngine.Create. The barcode engine takes no creation parameters and no languages. - Set the barcode mode. Set
BarcodeOptions.ModetoEmbedorExtract(see Output modes). - Submit pages to the engine. Configure
PageOptions(orImageOptions) so that the processor renders the pages and hands them to the engine — typicallyPageOptions.Mode = All, which submits every non-empty page.
Output modes
The BarcodeHandling mode controls where the engine writes recognized barcodes.
| Mode | Description |
|---|---|
None | Don’t process barcodes. This is the default. |
Embed | Embed the recognized barcodes into the output document’s XMP metadata. |
Extract | Write the recognized barcodes as XML to the stream set on BarcodeOptions.XmlOutputStream. The XmlOutputStream is required if and only if the mode is Extract. |
When you use Extract, Pdftools SDK writes an XML document with one <barcode> element per detection. Each element carries the page number, the bounding box (x, y, w, h in PDF points), the barcode type, and the decoded value as text content:
<?xml version="1.0" encoding="utf-8"?>
<barcodes xmlns="http://www.pdf-tools.com/barcodes/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.pdf-tools.com/barcodes/ barcodes.xsd">
<barcode page="1" x="201.95" y="692.03" w="202.96" h="57.31" type="Code128">DVD0123456789</barcode>
<barcode page="2" x="201.86" y="713.62" w="183.08" h="51.90" type="Code128">FIB0123456789</barcode>
<barcode page="4" x="242.80" y="176.13" w="134.11" h="134.13" type="QRCode">Lorem Ipsum is simply dummy text.</barcode>
</barcodes>
Pdftools SDK writes barcodes whose payload isn’t valid text (for example, binary DataMatrix or QR payloads) as a hexadecimal string instead of plain text.
Supported barcode types
By default the engine detects all supported symbologies. You can restrict detection to the types you expect with the BarcodeTypes engine parameter, which improves speed and reduces false positives. See Configure the barcode engine.
| Group | Types |
|---|---|
| Convenience | All, All_1D, All_2D |
| 1D (linear) | Code11, Code39, Code39Extended, Code93, Code128, Codabar, Inter2of5, PatchCode, EAN8, EAN13, UPCA, UPCE, Plus2, Plus5, UCC128, PharmaCode, RSS14, RSSLimited, RSSExpanded |
| 2D (matrix) | PDF417, DataMatrix, QRCode, MicroQRCode |
| Postal | Postnet, Planet, RM4SCC, AustraliaPost, IntelligentMail |
Read barcodes from a document
Steps to read barcodes from a document:
- Initialize the Pdftools SDK license
- Create the barcode engine
- Open the input document
- Configure barcode options
- Process the document
1. Initialize the Pdftools SDK license
Before you begin, Initialize the Pdftools SDK license. Without a license key, Pdftools SDK runs in evaluation mode and watermarks the output document.
2. Create the barcode engine
Create an Engine instance with the name "barcodes". The barcode engine takes no creation parameters, doesn’t connect to a service, and doesn’t use recognition languages. You can reuse one engine across multiple documents, but only one thread may use an Engine instance at a time.
- .NET
- Java
- Python
- C
// Create the barcode reader engine
using var engine = Engine.Create("barcodes");
// Create the barcode reader engine
Engine engine = Engine.create("barcodes");
# Create the barcode reader engine
engine = Engine.create("barcodes")
// Create the barcode reader engine
pEngine = PdfToolsOcr_Engine_Create(_T("barcodes"));
3. Open the input document
Load the input PDF from the file system into a read-only Document.
- .NET
- Java
- Python
- C
// Open input document
using var inStr = File.OpenRead(inPath);
using var inDoc = Document.Open(inStr);
// Open input document
FileStream inStr = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStr);
# Open input document
in_stream = io.FileIO(input_path, 'rb')
input_document = Document.open(in_stream)
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
TPdfToolsSys_StreamDescriptor inDesc;
PdfToolsSysCreateFILEStreamDescriptor(&inDesc, pInStream, 0);
pInDoc = PdfToolsPdf_Document_Open(&inDesc, _T(""));
4. Configure barcode options
Create an OcrOptions object, set the barcode mode on its BarcodeOptions sub-object, and submit pages to the engine through PageOptions. The example below uses Extract and writes the barcodes to an XML stream. To embed the results in the output document instead, set the mode to Embed and omit the XML stream.
- .NET
- Java
- Python
- C
var options = new OcrOptions();
// Extract detected barcodes as XML
using var barcodesStr = File.Create(barcodesPath);
options.BarcodeOptions.Mode = BarcodeHandling.Extract;
options.BarcodeOptions.XmlOutputStream = barcodesStr;
// Submit every non-empty page to the barcode engine
options.PageOptions.Mode = PageProcessingMode.All;
OcrOptions options = new OcrOptions();
// Extract detected barcodes as XML
FileStream barcodesStr = new FileStream(barcodesPath, FileStream.Mode.READ_WRITE_NEW);
options.getBarcodeOptions().setMode(BarcodeHandling.EXTRACT);
options.getBarcodeOptions().setXmlOutputStream(barcodesStr);
// Submit every non-empty page to the barcode engine
options.getPageOptions().setMode(PageProcessingMode.ALL);
options = OcrOptions()
# Extract detected barcodes as XML
barcodes_stream = io.FileIO(barcodes_path, 'wb+')
options.barcode_options.mode = BarcodeHandling.EXTRACT
options.barcode_options.xml_output_stream = barcodes_stream
# Submit every non-empty page to the barcode engine
options.page_options.mode = PageProcessingMode.ALL
pOptions = PdfToolsOcr_OcrOptions_New();
// Extract detected barcodes as XML
pBarcodesStream = _tfopen(szBarcodesPath, _T("wb+"));
TPdfToolsSys_StreamDescriptor barcodesDesc;
PdfToolsSysCreateFILEStreamDescriptor(&barcodesDesc, pBarcodesStream, 0);
pBarcodeOptions = PdfToolsOcr_OcrOptions_GetBarcodeOptions(pOptions);
PdfToolsOcr_BarcodeOptions_SetMode(pBarcodeOptions, ePdfToolsOcr_BarcodeHandling_Extract);
PdfToolsOcr_BarcodeOptions_SetXmlOutputStream(pBarcodeOptions, &barcodesDesc);
// Submit every non-empty page to the barcode engine
pPageOptions = PdfToolsOcr_OcrOptions_GetPageOptions(pOptions);
PdfToolsOcr_PageOptions_SetMode(pPageOptions, ePdfToolsOcr_PageProcessingMode_All);
5. Process the document
Create a Processor, optionally register a warning handler, and call Process. The processor renders each submitted page, runs barcode recognition, and writes the (visually unchanged) output document. When the mode is Extract, the processor writes the barcodes to the XML stream; when it’s Embed, it writes them to the output document’s XMP metadata.
- .NET
- Java
- Python
- C
// Create the processor and add a warning handler
var processor = new Processor();
processor.Warning += (s, e) =>
Console.WriteLine("- {0}: {1} ({2}{3})",
e.Category, e.Message, e.Context, e.PageNo > 0 ? " page " + e.PageNo : "");
// Create stream for output PDF
using var outStr = File.Create(outPath);
// Process the document: detect barcodes
using var outDoc = processor.Process(inDoc, engine, outStr, options);
// Create the processor and add a warning handler
Processor processor = new Processor();
processor.addWarningListener(event ->
System.out.println(String.format("- %s: %s (%s%s)",
event.getCategory(), event.getMessage(), event.getContext(),
event.getPageNo() > 0 ? " page " + event.getPageNo() : "")));
// Create stream for output PDF
FileStream outStr = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW);
// Process the document: detect barcodes
Document outDoc = processor.process(inDoc, engine, outStr, options, null);
def warning_handler(message: str, category, page_no: int, context: str):
if page_no > 0:
print(f"- {category.name}: {message} ({context} page {page_no})")
else:
print(f"- {category.name}: {message} ({context})")
# Create the processor and add a warning handler
processor = Processor()
processor.add_warning_handler(warning_handler)
# Create stream for output PDF
with io.FileIO(output_path, 'wb+') as output_stream:
# Process the document: detect barcodes
processor.process(input_document, engine, output_stream, options)
// Create the processor and add a warning handler
pProcessor = PdfToolsOcr_Processor_New();
PdfToolsOcr_Processor_AddWarningHandler(pProcessor, NULL, WarningHandler);
// Create stream for output PDF
pOutStream = _tfopen(szOutPath, _T("wb+"));
TPdfToolsSys_StreamDescriptor outDesc;
PdfToolsSysCreateFILEStreamDescriptor(&outDesc, pOutStream, 0);
// Process the document: detect barcodes
pOutDoc = PdfToolsOcr_Processor_Process(pProcessor, pInDoc, pEngine, &outDesc, pOptions, NULL);
Processing a signed PDF invalidates and removes existing digital signatures, because the processor rewrites the document. The processor emits a SignedDocument warning when this happens. If preserving signatures matters, treat that warning as an error.
Configure the barcode engine
You tune recognition by passing engine parameters as a semicolon-separated list of key=value pairs to the Engine.Parameters property. The barcode engine forwards these to its internal recognition DSL. Restricting the symbologies and orientation to what you actually expect is the single most effective way to speed up recognition and avoid spurious detections.
Keys are case-sensitive. Unknown keys or invalid values cause engine configuration to fail with an error.
- .NET
- Java
- Python
- C
using var engine = Engine.Create("barcodes");
// Detect only Code128 and QR codes, in any orientation
engine.Parameters = "BarcodeTypes=Code128,QRCode;BarcodeOrientation=All";
Engine engine = Engine.create("barcodes");
// Detect only Code128 and QR codes, in any orientation
engine.setParameters("BarcodeTypes=Code128,QRCode;BarcodeOrientation=All");
engine = Engine.create("barcodes")
# Detect only Code128 and QR codes, in any orientation
engine.parameters = "BarcodeTypes=Code128,QRCode;BarcodeOrientation=All"
pEngine = PdfToolsOcr_Engine_Create(_T("barcodes"));
// Detect only Code128 and QR codes, in any orientation
PdfToolsOcr_Engine_SetParameters(pEngine, _T("BarcodeTypes=Code128,QRCode;BarcodeOrientation=All"));
Recognition parameters
| Parameter | Value | Description |
|---|---|---|
BarcodeTypes | Comma-separated list of types | Symbologies to detect. Default: All. Restrict this to the types you expect to speed up recognition and reduce false positives — for example, BarcodeTypes=Code128,QRCode. |
BarcodeOrientation | Comma-separated list of LeftToRight, RightToLeft, TopToBottom, BottomToTop, All | Orientation(s) in which the engine scans barcodes. Default: All. Limiting orientation speeds up recognition when the barcodes always face the same way. |
BarcodesToRead | Integer | Maximum number of barcodes to read per page. Recognition stops once the engine finds this many. Lower it when you know how many barcodes a page contains. |
RecognitionTimeout | Integer (milliseconds) | Maximum time the engine spends on a single page before giving up. Use it to bound processing time on difficult images. |
ScanInterval | Integer (pixels) | Spacing between the scan lines the engine uses to find barcodes. A smaller interval scans more lines — higher detection rate, but slower. |
Binarization parameters
The engine converts each rendered page to black and white before locating barcodes. These parameters control how the engine chooses that threshold and are useful for low-contrast or noisy scans.
| Parameter | Value | Description |
|---|---|---|
ThresholdMode | Automatic, Fixed, Multiple, Adaptive | How the engine determines the binarization threshold. Automatic picks a threshold per image; Fixed uses the Threshold value; Multiple tries several thresholds; Adaptive varies the threshold locally across the image. |
Threshold | Integer (0–255) | The fixed gray level used when ThresholdMode=Fixed. |
ThresholdCount | Integer | The number of threshold values to try when ThresholdMode=Multiple. |
ThresholdStep | Integer | The step between threshold values when ThresholdMode=Multiple. |
QuietZoneSize | ExtraSmall, Small, Normal, Large | The expected size of the blank quiet zone surrounding a barcode. Use a smaller value to detect barcodes printed with little surrounding margin. |
Image preprocessing filters
These are boolean filters applied to the page image before recognition. Include the key to enable the filter; the engine ignores the value, so ImageDespeckle and ImageDespeckle=true are equivalent. Combine them with other parameters, for example ImageDespeckle;ImageSharp.
| Parameter | Description |
|---|---|
ImageDespeckle | Remove isolated noise pixels (speckles) before recognition. Helpful for noisy scans. |
ImageDilate | Apply a dilation filter that thickens dark regions. Helps recover thin or broken bars. |
ImageErode | Apply an erosion filter that thins dark regions. Helps separate bars that have merged. |
ImageSharp | Apply a sharpening filter to enhance edges in blurry images. |
Best practices
- Reuse the engine. Create one barcode
Engineand reuse it across documents. Only one thread may use anEngineinstance at a time. - Narrow the symbologies. Set
BarcodeTypes(andBarcodeOrientation) to what you expect. Scanning for all types in all orientations is the slowest configuration. - Submit only the pages you need. Barcode recognition runs only on pages submitted to the engine.
PageOptions.Mode = Allsubmits every page; restrict it if you know where the barcodes are. - Manage resources in the right order. When using
Extract, dispose the outputDocumentreturned byProcessbefore closing the output stream, and keep the XML output stream open until processing completes. In .NET useusing, in Java try-with-resources, and in Pythonwithcontext managers. - Tune preprocessing for difficult scans. If the engine doesn’t detect barcodes on low-quality scans, experiment with the binarization parameters and the image preprocessing filters.
Related topics
- OCR with Pdftools SDK: the OCR pipeline that barcode recognition builds on, including page, image, and text processing dimensions.
- Getting started with Pdftools SDK: installation and licensing for each language.