decodeRow method

  1. @override
Result decodeRow(
  1. int rowNumber,
  2. BitArray row,
  3. DecodeHint? hints, [
  4. 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;
}