find method
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);
}