Files
ANSLibs/QRCode/oned/ODCodabarReader.cpp

98 lines
3.4 KiB
C++

/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
* Copyright 2020 Axel Waggershauser
*/
// SPDX-License-Identifier: Apache-2.0
#include "ODCodabarReader.h"
#include "ReaderOptions.h"
#include "Barcode.h"
#include "ZXAlgorithms.h"
#include <string>
#include <memory>
namespace ZXing::OneD {
static const char ALPHABET[] = "0123456789-$:/.+ABCD";
// These represent the encodings of characters, as patterns of wide and narrow bars. The 7 least-significant bits of
// each int correspond to the pattern of wide and narrow, with 1s representing wide and 0s representing narrow.
static const int CHARACTER_ENCODINGS[] = {
0x03, 0x06, 0x09, 0x60, 0x12, 0x42, 0x21, 0x24, 0x30, 0x48, // 0-9
0x0c, 0x18, 0x45, 0x51, 0x54, 0x15, 0x1A, 0x29, 0x0B, 0x0E, // -$:/.+ABCD
};
static_assert(Size(ALPHABET) - 1 == Size(CHARACTER_ENCODINGS), "table size mismatch");
// some industries use a checksum standard but this is not part of the original codabar standard
// for more information see : http://www.mecsw.com/specs/codabar.html
// each character has 4 bars and 3 spaces
constexpr int CHAR_LEN = 7;
// quiet zone is half the width of a character symbol
constexpr float QUIET_ZONE_SCALE = 0.5f;
// official start and stop symbols are "ABCD"
// some codabar generator allow the codabar string to be closed by every
// character. This will cause lots of false positives!
bool IsLeftGuard(const PatternView& view, int spaceInPixel)
{
return spaceInPixel > view.sum() * QUIET_ZONE_SCALE &&
Contains({0x1A, 0x29, 0x0B, 0x0E}, RowReader::NarrowWideBitPattern(view));
}
Barcode CodabarReader::decodePattern(int rowNumber, PatternView& next, std::unique_ptr<DecodingState>&) const
{
// minimal number of characters that must be present (including start, stop and checksum characters)
// absolute minimum would be 2 (meaning 0 'content'). everything below 4 produces too many false
// positives.
const int minCharCount = 4;
auto isStartOrStopSymbol = [](char c) { return 'A' <= c && c <= 'D'; };
next = FindLeftGuard<CHAR_LEN>(next, minCharCount * CHAR_LEN, IsLeftGuard);
if (!next.isValid())
return {};
int xStart = next.pixelsInFront();
int maxInterCharacterSpace = next.sum() / 2; // spec actually says 1 narrow space, width/2 is about 4
std::string txt;
txt.reserve(20);
txt += DecodeNarrowWidePattern(next, CHARACTER_ENCODINGS, ALPHABET); // read off the start pattern
if (!isStartOrStopSymbol(txt.back()))
return {};
do {
// check remaining input width and inter-character space
if (!next.skipSymbol() || !next.skipSingle(maxInterCharacterSpace))
return {};
txt += DecodeNarrowWidePattern(next, CHARACTER_ENCODINGS, ALPHABET);
if (txt.back() == 0)
return {};
} while (!isStartOrStopSymbol(txt.back()));
// next now points to the last decoded symbol
// check txt length and whitespace after the last char. See also FindStartPattern.
if (Size(txt) < minCharCount || !next.hasQuietZoneAfter(QUIET_ZONE_SCALE))
return {};
// remove stop/start characters
if (!_opts.returnCodabarStartEnd())
txt = txt.substr(1, txt.size() - 2);
// symbology identifier ISO/IEC 15424:2008 4.4.9
// if checksum processing were implemented and checksum present and stripped then modifier would be 4
SymbologyIdentifier symbologyIdentifier = {'F', '0'};
int xStop = next.pixelsTillEnd();
return Barcode(txt, rowNumber, xStart, xStop, BarcodeFormat::Codabar, symbologyIdentifier);
}
} // namespace ZXing::OneD