#include "ODITFReader.h"
#include "ReaderOptions.h"
#include "GTIN.h"
#include "Barcode.h"
#include "BarcodeData.h"
#include "SymbologyIdentifier.h"
#include "ZXAlgorithms.h"
namespace ZXing::OneD {
BarcodeData ITFReader::decodePattern(int rowNumber, PatternView& next, std::unique_ptr<DecodingState>&) const
{
const int minCharCount = _opts.formats().size() == 1 ? 4 : 6; const int minQuietZone = 6;
next = FindLeftGuard(next, 4 + 10 + 3, FixedPattern<4, 4>{1, 1, 1, 1}, minQuietZone);
if (!next.isValid())
return {};
auto threshold = NarrowWideThreshold(next.subView(4, 10));
if (!threshold.isValid())
return {};
for (int i = 0; i < 4; ++i)
if (next[i] > threshold[i])
return {};
constexpr int weights[] = {1, 2, 4, 7, 0};
int xStart = next.pixelsInFront();
bool startsAtFirstBar = next.isAtFirstBar();
next = next.subView(4, 10);
std::string txt;
txt.reserve(20);
while (next.isValid()) {
if (next[3] > threshold.space * 3)
break;
BarAndSpace<int> digits, numWide;
bool bad = false;
for (int i = 0; i < 10; ++i) {
bad |= next[i] > threshold[i] * 3 || next[i] < threshold[i] / 3;
numWide[i] += next[i] > threshold[i];
digits[i] += weights[i/2] * (next[i] > threshold[i]);
}
if (bad || numWide.bar != 2 || numWide.space != 2)
break;
for (int i = 0; i < 2; ++i)
txt.push_back(ToDigit(digits[i] == 11 ? 0 : digits[i]));
threshold = NarrowWideThreshold(next);
next.skipSymbol();
}
next = next.subView(0, 3);
if (!next.isValid() || !threshold.isValid()
|| next[0] < threshold[0] || next[1] > threshold[1] || next[2] > threshold[2])
return {};
if (!(std::min((int)next[3], xStart) > minQuietZone * (threshold.bar + threshold.space) / 3
|| (next.isAtLastBar() && startsAtFirstBar && std::max(xStart, (int)next[3]) < 2 * std::min(xStart, (int)next[3]) + 2)))
return {};
if (Size(txt) < (startsAtFirstBar && next.isAtLastBar() ? (minCharCount / 2) : minCharCount))
return {};
Error error = _opts.validateOptionalChecksum() && !GTIN::IsCheckDigitValid(txt) ? ChecksumError() : Error();
SymbologyIdentifier symbologyIdentifier = {'I', GTIN::IsCheckDigitValid(txt) ? '1' : '0'};
int xStop = next.pixelsTillEnd();
return LinearBarcode(BarcodeFormat::ITF, txt, rowNumber, xStart, xStop, symbologyIdentifier, error);
}
}