find method

FinderPatternInfo find([
  1. DecodeHint? hints
])

Implementation

FinderPatternInfo find([DecodeHint? hints]) {
  final tryHarder = hints?.tryHarder ?? false;
  final maxI = _image.height;
  final maxJ = _image.width;
  // We are looking for black/white/black/white/black modules in
  // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far

  // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
  // image, and then account for the center being 3 modules in size. This gives the smallest
  // number of pixels the center could be, so skip this often. When trying harder, look for all
  // QR versions regardless of how dense they are.
  int iSkip = (3 * maxI) ~/ (4 * maxModules);
  if (iSkip < minSkip || tryHarder) {
    iSkip = minSkip;
  }

  bool done = false;
  final stateCount = [0, 0, 0, 0, 0];
  for (int i = iSkip - 1; i < maxI && !done; i += iSkip) {
    // Get a row of black/white values
    doClearCounts(stateCount);
    int currentState = 0;
    for (int j = 0; j < maxJ; j++) {
      if (_image.get(j, i)) {
        // Black pixel
        if ((currentState & 1) == 1) {
          // Counting white pixels
          currentState++;
        }
        stateCount[currentState]++;
      } else {
        // White pixel
        if ((currentState & 1) == 0) {
          // Counting black pixels
          if (currentState == 4) {
            // A winner?
            if (foundPatternCross(stateCount)) {
              // Yes
              final confirmed = handlePossibleCenter(stateCount, i, j);
              if (confirmed) {
                // Start examining every other line. Checking each line turned out to be too
                // expensive and didn't improve performance.
                iSkip = 2;
                if (_hasSkipped) {
                  done = _haveMultiplyConfirmedCenters();
                } else {
                  final rowSkip = _findRowSkip();
                  if (rowSkip > stateCount[2]) {
                    // Skip rows between row of lower confirmed center
                    // and top of presumed third confirmed center
                    // but back up a bit to get a full chance of detecting
                    // it, entire width of center of finder pattern

                    // Skip by rowSkip, but back off by stateCount[2] (size of last center
                    // of pattern we saw) to be conservative, and also back off by iSkip which
                    // is about to be re-added
                    i += rowSkip - stateCount[2] - iSkip;
                    j = maxJ - 1;
                  }
                }
              } else {
                doShiftCounts2(stateCount);
                currentState = 3;
                continue;
              }
              // Clear state to start looking again
              currentState = 0;
              doClearCounts(stateCount);
            } else {
              // No, shift counts back by two
              doShiftCounts2(stateCount);
              currentState = 3;
            }
          } else {
            stateCount[++currentState]++;
          }
        } else {
          // Counting white pixels
          stateCount[currentState]++;
        }
      }
    }
    if (foundPatternCross(stateCount)) {
      final confirmed = handlePossibleCenter(stateCount, i, maxJ);
      if (confirmed) {
        iSkip = stateCount[0];
        if (_hasSkipped) {
          // Found a third one
          done = _haveMultiplyConfirmedCenters();
        }
      }
    }
  }

  final patternInfo = _selectBestPatterns();
  ResultPoint.orderBestPatterns(patternInfo);

  return FinderPatternInfo(patternInfo);
}