0
# Result Processing
1
2
ZXing-C++ provides comprehensive result analysis and metadata extraction through the `Result` (aliased as `Barcode`) class. This includes detailed barcode information, position data, error handling, and support for structured append sequences.
3
4
## Result Class
5
6
The `Result` class (typedef'd as `Barcode`) encapsulates all information about a decoded barcode:
7
8
```cpp { .api }
9
class Result {
10
// Constructors
11
Result() = default;
12
Result(const std::string& text, int y, int xStart, int xStop,
13
BarcodeFormat format, SymbologyIdentifier si, Error error = {},
14
bool readerInit = false);
15
16
// Validity and error checking
17
bool isValid() const;
18
const Error& error() const;
19
20
// Basic barcode information
21
BarcodeFormat format() const;
22
std::string text() const;
23
std::string text(TextMode mode) const;
24
const ByteArray& bytes() const;
25
ByteArray bytesECI() const;
26
27
// Content analysis
28
ContentType contentType() const;
29
bool hasECI() const;
30
31
// Position and orientation
32
const Position& position() const;
33
void setPosition(Position pos);
34
int orientation() const;
35
bool isMirrored() const;
36
bool isInverted() const;
37
38
// Technical metadata
39
std::string ecLevel() const;
40
std::string version() const;
41
std::string symbologyIdentifier() const;
42
bool readerInit() const;
43
int lineCount() const;
44
45
// Structured append support
46
int sequenceSize() const;
47
int sequenceIndex() const;
48
std::string sequenceId() const;
49
bool isLastInSequence() const;
50
bool isPartOfSequence() const;
51
52
// Experimental API extensions
53
#ifdef ZXING_EXPERIMENTAL_API
54
ImageView symbol() const;
55
zint_symbol* zint() const;
56
#endif
57
58
// Comparison
59
bool operator==(const Result& o) const;
60
};
61
62
// Type aliases
63
using Barcode = Result;
64
using Barcodes = std::vector<Barcode>;
65
using Position = QuadrilateralI;
66
```
67
68
## Basic Result Analysis
69
70
### Validity Checking
71
72
```cpp
73
auto result = ZXing::ReadBarcode(image);
74
75
if (result.isValid()) {
76
std::cout << "Successfully decoded barcode" << std::endl;
77
std::cout << "Content: " << result.text() << std::endl;
78
std::cout << "Format: " << ZXing::ToString(result.format()) << std::endl;
79
} else {
80
std::cout << "Failed to decode barcode" << std::endl;
81
if (result.error()) {
82
std::cout << "Error: " << result.error().msg() << std::endl;
83
}
84
}
85
```
86
87
### Content Access
88
89
```cpp
90
auto result = ZXing::ReadBarcode(image);
91
if (result.isValid()) {
92
// Get text with default mode
93
std::string defaultText = result.text();
94
95
// Get text with specific modes
96
std::string plainText = result.text(ZXing::TextMode::Plain);
97
std::string eciText = result.text(ZXing::TextMode::ECI);
98
std::string hriText = result.text(ZXing::TextMode::HRI);
99
std::string hexText = result.text(ZXing::TextMode::Hex);
100
std::string escapedText = result.text(ZXing::TextMode::Escaped);
101
102
// Access raw bytes
103
const ZXing::ByteArray& rawBytes = result.bytes();
104
ZXing::ByteArray eciBytes = result.bytesECI();
105
106
std::cout << "Raw bytes size: " << rawBytes.size() << std::endl;
107
std::cout << "Hex representation: " << hexText << std::endl;
108
}
109
```
110
111
## Content Type Analysis
112
113
### Content Classification
114
115
```cpp { .api }
116
enum class ContentType {
117
Text, Binary, Mixed, GS1, ISO15434, UnknownECI
118
};
119
```
120
121
```cpp
122
auto result = ZXing::ReadBarcode(image);
123
if (result.isValid()) {
124
ZXing::ContentType contentType = result.contentType();
125
126
switch (contentType) {
127
case ZXing::ContentType::Text:
128
std::cout << "Plain text content" << std::endl;
129
break;
130
case ZXing::ContentType::Binary:
131
std::cout << "Binary data content" << std::endl;
132
break;
133
case ZXing::ContentType::Mixed:
134
std::cout << "Mixed text and binary content" << std::endl;
135
break;
136
case ZXing::ContentType::GS1:
137
std::cout << "GS1 formatted data" << std::endl;
138
// Parse GS1 Application Identifiers
139
parseGS1Content(result.text());
140
break;
141
case ZXing::ContentType::ISO15434:
142
std::cout << "ISO 15434 formatted data" << std::endl;
143
break;
144
case ZXing::ContentType::UnknownECI:
145
std::cout << "Unknown ECI encoding" << std::endl;
146
break;
147
}
148
149
// Check for Extended Channel Interpretation
150
if (result.hasECI()) {
151
std::cout << "Contains ECI information" << std::endl;
152
}
153
}
154
```
155
156
### GS1 Data Processing
157
158
```cpp
159
void parseGS1Content(const std::string& gs1Data) {
160
// GS1 data uses Application Identifiers (AIs)
161
// Format: (AI)data(AI)data...
162
163
std::regex aiPattern(R"(\((\d{2,4})\)([^(]*))");
164
std::sregex_iterator iter(gs1Data.begin(), gs1Data.end(), aiPattern);
165
std::sregex_iterator end;
166
167
std::map<std::string, std::string> applicationIdentifiers;
168
169
for (; iter != end; ++iter) {
170
std::string ai = (*iter)[1].str();
171
std::string data = (*iter)[2].str();
172
applicationIdentifiers[ai] = data;
173
174
// Common AIs
175
if (ai == "01") {
176
std::cout << "GTIN: " << data << std::endl;
177
} else if (ai == "10") {
178
std::cout << "Batch/Lot: " << data << std::endl;
179
} else if (ai == "17") {
180
std::cout << "Expiry Date: " << data << std::endl;
181
} else if (ai == "21") {
182
std::cout << "Serial Number: " << data << std::endl;
183
}
184
}
185
}
186
```
187
188
## Position and Orientation Analysis
189
190
### Position Information
191
192
```cpp
193
auto result = ZXing::ReadBarcode(image);
194
if (result.isValid()) {
195
const ZXing::Position& position = result.position();
196
197
// Position is a QuadrilateralI with four corner points
198
auto topLeft = position.topLeft();
199
auto topRight = position.topRight();
200
auto bottomLeft = position.bottomLeft();
201
auto bottomRight = position.bottomRight();
202
203
std::cout << "Barcode corners:" << std::endl;
204
std::cout << " Top-left: (" << topLeft.x << ", " << topLeft.y << ")" << std::endl;
205
std::cout << " Top-right: (" << topRight.x << ", " << topRight.y << ")" << std::endl;
206
std::cout << " Bottom-left: (" << bottomLeft.x << ", " << bottomLeft.y << ")" << std::endl;
207
std::cout << " Bottom-right: (" << bottomRight.x << ", " << bottomRight.y << ")" << std::endl;
208
209
// Orientation in degrees
210
int orientation = result.orientation();
211
std::cout << "Orientation: " << orientation << " degrees" << std::endl;
212
213
// Check for transformations
214
if (result.isMirrored()) {
215
std::cout << "Barcode is mirrored" << std::endl;
216
}
217
218
if (result.isInverted()) {
219
std::cout << "Barcode is inverted (negative)" << std::endl;
220
}
221
}
222
```
223
224
### Geometric Calculations
225
226
```cpp
227
#include <cmath>
228
229
struct BarcodeGeometry {
230
double width;
231
double height;
232
double centerX;
233
double centerY;
234
double area;
235
};
236
237
BarcodeGeometry analyzeBarcodeGeometry(const ZXing::Position& position) {
238
auto tl = position.topLeft();
239
auto tr = position.topRight();
240
auto bl = position.bottomLeft();
241
auto br = position.bottomRight();
242
243
// Calculate dimensions (approximate for non-rectangular barcodes)
244
double topWidth = std::sqrt(std::pow(tr.x - tl.x, 2) + std::pow(tr.y - tl.y, 2));
245
double bottomWidth = std::sqrt(std::pow(br.x - bl.x, 2) + std::pow(br.y - bl.y, 2));
246
double leftHeight = std::sqrt(std::pow(bl.x - tl.x, 2) + std::pow(bl.y - tl.y, 2));
247
double rightHeight = std::sqrt(std::pow(br.x - tr.x, 2) + std::pow(br.y - tr.y, 2));
248
249
// Calculate center point
250
double centerX = (tl.x + tr.x + bl.x + br.x) / 4.0;
251
double centerY = (tl.y + tr.y + bl.y + br.y) / 4.0;
252
253
// Calculate area using shoelace formula
254
double area = 0.5 * std::abs(
255
(tl.x * tr.y - tr.x * tl.y) +
256
(tr.x * br.y - br.x * tr.y) +
257
(br.x * bl.y - bl.x * br.y) +
258
(bl.x * tl.y - tl.x * bl.y)
259
);
260
261
return {
262
(topWidth + bottomWidth) / 2.0, // width
263
(leftHeight + rightHeight) / 2.0, // height
264
centerX,
265
centerY,
266
area
267
};
268
}
269
270
// Usage
271
auto result = ZXing::ReadBarcode(image);
272
if (result.isValid()) {
273
auto geometry = analyzeBarcodeGeometry(result.position());
274
std::cout << "Barcode size: " << geometry.width << " x " << geometry.height << std::endl;
275
std::cout << "Center: (" << geometry.centerX << ", " << geometry.centerY << ")" << std::endl;
276
std::cout << "Area: " << geometry.area << " square pixels" << std::endl;
277
}
278
```
279
280
## Technical Metadata
281
282
### Format-Specific Information
283
284
```cpp
285
auto result = ZXing::ReadBarcode(image);
286
if (result.isValid()) {
287
// Error correction level (format-dependent)
288
std::string ecLevel = result.ecLevel();
289
if (!ecLevel.empty()) {
290
std::cout << "Error correction level: " << ecLevel << std::endl;
291
}
292
293
// Version information (QR Code, DataMatrix, etc.)
294
std::string version = result.version();
295
if (!version.empty()) {
296
std::cout << "Version: " << version << std::endl;
297
}
298
299
// Symbology identifier (ISO/IEC 15424)
300
std::string symbologyId = result.symbologyIdentifier();
301
if (!symbologyId.empty()) {
302
std::cout << "Symbology identifier: " << symbologyId << std::endl;
303
304
// Parse symbology identifier
305
if (symbologyId.length() >= 3) {
306
char code = symbologyId[1]; // Symbology code
307
char modifier = symbologyId[2]; // Modifier character
308
309
std::cout << "Code: " << code << ", Modifier: " << modifier << std::endl;
310
}
311
}
312
313
// Reader initialization flag
314
if (result.readerInit()) {
315
std::cout << "Reader initialization symbol" << std::endl;
316
}
317
318
// Line count (linear barcodes only)
319
int lineCount = result.lineCount();
320
if (lineCount > 0) {
321
std::cout << "Confirmed by " << lineCount << " scan lines" << std::endl;
322
}
323
}
324
```
325
326
### Quality Assessment
327
328
```cpp
329
struct BarcodeQuality {
330
bool isHighQuality;
331
std::vector<std::string> qualityIssues;
332
double confidence;
333
};
334
335
BarcodeQuality assessBarcodeQuality(const ZXing::Barcode& barcode) {
336
BarcodeQuality quality;
337
quality.isHighQuality = true;
338
quality.confidence = 1.0;
339
340
if (!barcode.isValid()) {
341
quality.isHighQuality = false;
342
quality.confidence = 0.0;
343
quality.qualityIssues.push_back("Invalid barcode");
344
return quality;
345
}
346
347
// Check line count for linear barcodes
348
if (barcode.lineCount() > 0 && barcode.lineCount() < 2) {
349
quality.isHighQuality = false;
350
quality.confidence *= 0.7;
351
quality.qualityIssues.push_back("Low line count confirmation");
352
}
353
354
// Check for inversions (may indicate poor image quality)
355
if (barcode.isInverted()) {
356
quality.confidence *= 0.9;
357
quality.qualityIssues.push_back("Inverted barcode detected");
358
}
359
360
// Check for mirroring (unusual)
361
if (barcode.isMirrored()) {
362
quality.confidence *= 0.8;
363
quality.qualityIssues.push_back("Mirrored barcode detected");
364
}
365
366
// Check error correction level
367
std::string ecLevel = barcode.ecLevel();
368
if (!ecLevel.empty()) {
369
// Lower error correction levels indicate less redundancy
370
if (ecLevel == "L" || ecLevel == "0") {
371
quality.confidence *= 0.95;
372
}
373
}
374
375
quality.isHighQuality = quality.confidence > 0.8;
376
return quality;
377
}
378
```
379
380
## Structured Append Processing
381
382
### Sequence Detection
383
384
```cpp
385
void analyzeSequence(const ZXing::Barcode& barcode) {
386
if (barcode.isPartOfSequence()) {
387
int size = barcode.sequenceSize();
388
int index = barcode.sequenceIndex();
389
std::string id = barcode.sequenceId();
390
391
std::cout << "Part of structured append sequence:" << std::endl;
392
std::cout << " Position: " << (index + 1) << " of " << size << std::endl;
393
std::cout << " Sequence ID: " << id << std::endl;
394
395
if (barcode.isLastInSequence()) {
396
std::cout << " This is the last part" << std::endl;
397
}
398
399
// Handle unknown sequence size (PDF417)
400
if (size == 0) {
401
std::cout << " Unknown total sequence size" << std::endl;
402
}
403
} else {
404
std::cout << "Single barcode (not part of sequence)" << std::endl;
405
}
406
}
407
```
408
409
### Sequence Collection and Merging
410
411
```cpp
412
class SequenceCollector {
413
private:
414
std::map<std::string, std::vector<ZXing::Barcode>> sequences_;
415
416
public:
417
void addBarcode(const ZXing::Barcode& barcode) {
418
if (!barcode.isPartOfSequence()) {
419
// Process single barcode immediately
420
processSingleBarcode(barcode);
421
return;
422
}
423
424
std::string sequenceId = barcode.sequenceId();
425
sequences_[sequenceId].push_back(barcode);
426
427
// Check if sequence is complete
428
if (isSequenceComplete(sequenceId)) {
429
processCompleteSequence(sequenceId);
430
}
431
}
432
433
private:
434
bool isSequenceComplete(const std::string& sequenceId) {
435
auto& sequence = sequences_[sequenceId];
436
437
if (sequence.empty()) return false;
438
439
int expectedSize = sequence[0].sequenceSize();
440
if (expectedSize == 0) {
441
// Unknown size - check for last marker
442
return std::any_of(sequence.begin(), sequence.end(),
443
[](const ZXing::Barcode& b) { return b.isLastInSequence(); });
444
}
445
446
// Known size - check if we have all parts
447
if (static_cast<int>(sequence.size()) != expectedSize) {
448
return false;
449
}
450
451
// Verify we have all indices
452
std::set<int> indices;
453
for (const auto& barcode : sequence) {
454
indices.insert(barcode.sequenceIndex());
455
}
456
457
return static_cast<int>(indices.size()) == expectedSize &&
458
*indices.begin() == 0 &&
459
*indices.rbegin() == expectedSize - 1;
460
}
461
462
void processCompleteSequence(const std::string& sequenceId) {
463
auto& sequence = sequences_[sequenceId];
464
465
// Sort by sequence index
466
std::sort(sequence.begin(), sequence.end(),
467
[](const ZXing::Barcode& a, const ZXing::Barcode& b) {
468
return a.sequenceIndex() < b.sequenceIndex();
469
});
470
471
// Merge sequence using library function
472
auto merged = ZXing::MergeStructuredAppendSequence(sequence);
473
474
if (merged.isValid()) {
475
std::cout << "Successfully merged sequence " << sequenceId << std::endl;
476
std::cout << "Merged content: " << merged.text() << std::endl;
477
478
// Process merged result
479
processSingleBarcode(merged);
480
} else {
481
std::cout << "Failed to merge sequence " << sequenceId << std::endl;
482
}
483
484
// Clean up
485
sequences_.erase(sequenceId);
486
}
487
488
void processSingleBarcode(const ZXing::Barcode& barcode) {
489
// Your barcode processing logic here
490
std::cout << "Processing: " << barcode.text() << std::endl;
491
}
492
};
493
494
// Usage
495
SequenceCollector collector;
496
auto results = ZXing::ReadBarcodes(image);
497
498
for (const auto& result : results) {
499
collector.addBarcode(result);
500
}
501
```
502
503
### Automatic Sequence Merging
504
505
```cpp
506
// Simplified approach using library functions
507
std::vector<ZXing::Barcode> processImageWithSequenceMerging(const ZXing::ImageView& image) {
508
// Read all barcodes
509
auto allResults = ZXing::ReadBarcodes(image);
510
511
// Automatically merge structured append sequences
512
auto mergedResults = ZXing::MergeStructuredAppendSequences(allResults);
513
514
std::cout << "Found " << allResults.size() << " individual barcodes" << std::endl;
515
std::cout << "After merging: " << mergedResults.size() << " results" << std::endl;
516
517
return mergedResults;
518
}
519
```
520
521
## Error Handling and Analysis
522
523
### Comprehensive Error Analysis
524
525
```cpp
526
void analyzeErrors(const std::vector<ZXing::Barcode>& results) {
527
std::map<ZXing::Error::Type, int> errorCounts;
528
std::vector<ZXing::Barcode> validResults;
529
std::vector<ZXing::Barcode> errorResults;
530
531
for (const auto& result : results) {
532
if (result.isValid()) {
533
validResults.push_back(result);
534
} else {
535
errorResults.push_back(result);
536
errorCounts[result.error().type()]++;
537
}
538
}
539
540
std::cout << "Results summary:" << std::endl;
541
std::cout << " Valid: " << validResults.size() << std::endl;
542
std::cout << " Errors: " << errorResults.size() << std::endl;
543
544
if (!errorResults.empty()) {
545
std::cout << "Error breakdown:" << std::endl;
546
for (const auto& [type, count] : errorCounts) {
547
std::string typeName;
548
switch (type) {
549
case ZXing::Error::Format: typeName = "Format"; break;
550
case ZXing::Error::Checksum: typeName = "Checksum"; break;
551
case ZXing::Error::Unsupported: typeName = "Unsupported"; break;
552
default: typeName = "Unknown"; break;
553
}
554
std::cout << " " << typeName << ": " << count << std::endl;
555
}
556
}
557
}
558
```
559
560
## Performance Monitoring
561
562
### Result Processing Metrics
563
564
```cpp
565
struct ProcessingMetrics {
566
std::chrono::milliseconds detectionTime;
567
int totalBarcodes;
568
int validBarcodes;
569
int errorBarcodes;
570
std::map<ZXing::BarcodeFormat, int> formatCounts;
571
};
572
573
ProcessingMetrics processImageWithMetrics(const ZXing::ImageView& image) {
574
auto start = std::chrono::high_resolution_clock::now();
575
576
auto results = ZXing::ReadBarcodes(image);
577
578
auto end = std::chrono::high_resolution_clock::now();
579
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
580
581
ProcessingMetrics metrics;
582
metrics.detectionTime = duration;
583
metrics.totalBarcodes = results.size();
584
585
for (const auto& result : results) {
586
if (result.isValid()) {
587
metrics.validBarcodes++;
588
metrics.formatCounts[result.format()]++;
589
} else {
590
metrics.errorBarcodes++;
591
}
592
}
593
594
return metrics;
595
}
596
597
void printMetrics(const ProcessingMetrics& metrics) {
598
std::cout << "Processing completed in " << metrics.detectionTime.count() << "ms" << std::endl;
599
std::cout << "Total barcodes: " << metrics.totalBarcodes << std::endl;
600
std::cout << "Valid: " << metrics.validBarcodes << std::endl;
601
std::cout << "Errors: " << metrics.errorBarcodes << std::endl;
602
603
if (!metrics.formatCounts.empty()) {
604
std::cout << "Format distribution:" << std::endl;
605
for (const auto& [format, count] : metrics.formatCounts) {
606
std::cout << " " << ZXing::ToString(format) << ": " << count << std::endl;
607
}
608
}
609
}
610
```
611
612
## Structured Append Utility Functions
613
614
```cpp { .api }
615
/**
616
* Merge a list of Barcodes from one Structured Append sequence to a single barcode
617
*/
618
Barcode MergeStructuredAppendSequence(const Barcodes& results);
619
620
/**
621
* Automatically merge all Structured Append sequences found in the given list of barcodes
622
*/
623
Barcodes MergeStructuredAppendSequences(const Barcodes& barcodes);
624
```