decodeRow method
Result
decodeRow(
- int rowNumber,
- BitArray row,
- DecodeHint? hints, [
- List<
int> ? startGuardRange,
override
Like {@link #decodeRow(int, BitArray, Map)}, but allows caller to inform method about where the UPC/EAN start pattern is found. This allows this to be computed once and reused across many implementations.
@param rowNumber row index into the image @param row encoding of the row of the barcode image @param startGuardRange start/end column where the opening start pattern was found @param hints optional hints that influence decoding @return Result encapsulating the result of decoding a barcode in the row @throws NotFoundException if no potential barcode is found @throws ChecksumException if a potential barcode is found but does not pass its checksum @throws FormatException if a potential barcode is found but format is invalid
Implementation
@override
Result decodeRow(
int rowNumber,
BitArray row,
DecodeHint? hints, [
List<int>? startGuardRange,
]) {
startGuardRange ??= findStartGuardPattern(row);
final resultPointCallback = hints?.needResultPointCallback;
int symbologyIdentifier = 0;
if (resultPointCallback != null) {
resultPointCallback.foundPossibleResultPoint(
ResultPoint(
(startGuardRange[0] + startGuardRange[1]) / 2.0,
rowNumber.toDouble(),
),
);
}
final result = _decodeRowStringBuffer;
result.clear();
final endStart = decodeMiddle(row, startGuardRange, result);
if (resultPointCallback != null) {
resultPointCallback.foundPossibleResultPoint(
ResultPoint(endStart.toDouble(), rowNumber.toDouble()),
);
}
final endRange = decodeEnd(row, endStart);
if (resultPointCallback != null) {
resultPointCallback.foundPossibleResultPoint(
ResultPoint((endRange[0] + endRange[1]) / 2.0, rowNumber.toDouble()),
);
}
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
// spec might want more whitespace, but in practice this is the maximum we can count on.
final end = endRange[1];
final quietEnd = end + (end - endRange[0]);
if (quietEnd >= row.size || !row.isRange(end, quietEnd, false)) {
throw NotFoundException.instance;
}
final resultString = result.toString();
// UPC/EAN should never be less than 8 chars anyway
if (resultString.length < 8) {
throw FormatsException.instance;
}
if (!checkChecksum(resultString)) {
throw ChecksumException.getChecksumInstance();
}
final left = (startGuardRange[1] + startGuardRange[0]) / 2.0;
final right = (endRange[1] + endRange[0]) / 2.0;
final format = barcodeFormat;
final decodeResult = Result(
resultString,
null, // no natural byte representation for these barcodes
[
ResultPoint(left, rowNumber.toDouble()),
ResultPoint(right, rowNumber.toDouble())
],
format,
);
int extensionLength = 0;
try {
final extensionResult =
_extensionReader.decodeRow(rowNumber, row, endRange[1]);
decodeResult.putMetadata(
ResultMetadataType.upcEanExtension,
extensionResult.text,
);
decodeResult.putAllMetadata(extensionResult.resultMetadata);
decodeResult.addResultPoints(extensionResult.resultPoints);
extensionLength = extensionResult.text.length;
} on ReaderException catch (_) {
// continue
}
final allowedExtensions = hints?.allowedEanExtensions;
if (allowedExtensions != null) {
bool valid = false;
for (int length in allowedExtensions) {
if (extensionLength == length) {
valid = true;
break;
}
}
if (!valid) {
throw NotFoundException.instance;
}
}
if (format == BarcodeFormat.ean13 || format == BarcodeFormat.upcA) {
final countryID = _eanManSupport.lookupCountryIdentifier(resultString);
if (countryID != null) {
decodeResult.putMetadata(
ResultMetadataType.possibleCountry,
countryID,
);
}
}
if (format == BarcodeFormat.ean8) {
symbologyIdentifier = 4;
}
decodeResult.putMetadata(
ResultMetadataType.symbologyIdentifier,
']E$symbologyIdentifier',
);
return decodeResult;
}