forked from zxing-cpp/zxing-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add reader support for DataBarLimited
This fixes zxing-cpp#534. Writing is also supported if the new zint backend is enabled. This work has been fully sponsored by EUREKAM(@glebaccon-eurekam). Note: the new code uses a c++20 feature, so it is only enabled when compiled with a c++20 compiler.
- Loading branch information
Showing
32 changed files
with
303 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* | ||
* Copyright 2024 Axel Waggershauser | ||
*/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#include "ODDataBarLimitedReader.h" | ||
|
||
#include "BarcodeFormat.h" | ||
#include "GTIN.h" | ||
#include "ODDataBarCommon.h" | ||
#include "Barcode.h" | ||
|
||
//#define PRINT_DEBUG | ||
#ifndef PRINT_DEBUG | ||
#define printf(...){} | ||
#define printv(...){} | ||
#else | ||
#define printv(fmt, ...) \ | ||
for (auto v : __VA_ARGS__) \ | ||
printf(fmt, v); | ||
#endif | ||
|
||
namespace ZXing::OneD { | ||
|
||
using namespace DataBar; | ||
|
||
constexpr int CHAR_LEN = 14; | ||
constexpr int SYMBOL_LEN = 1 + 3 * CHAR_LEN + 2; | ||
|
||
// elements() determines the element widths of an (n,k) character with | ||
// at least one even-numbered element that's just one module wide. | ||
// (Note: even-numbered elements - 2nd, 4th, 6th, etc., have odd indexes) | ||
// for DataBarLimited: SUM=26/18, LEN=14 | ||
template <int LEN, int SUM> | ||
std::array<int, LEN> NormalizedPatternFromE2E(const PatternView& view) | ||
{ | ||
auto e2e = NormalizedE2EPattern<LEN, SUM>(view); | ||
std::array<int, LEN> widths; | ||
|
||
// derive element widths from normalized edge-to-similar-edge measurements | ||
int barSum = widths[0] = 1; // first assume 1st bar is 1 | ||
for (int i = 0; i < Size(e2e); i++) { | ||
widths[i + 1] = e2e[i] - widths[i]; | ||
barSum += widths[i + 1]; | ||
} | ||
widths.back() = SUM - barSum; // last even element makes SUM modules | ||
|
||
int minEven = widths[1]; | ||
for (int i = 3; i < Size(widths); i += 2) | ||
minEven = std::min(minEven, widths[i]); | ||
|
||
if (minEven > 1) { | ||
// minimum even width is too big, readjust so minimum even is 1 | ||
for (int i = 0; i < Size(widths); i += 2) { | ||
widths[i] += minEven - 1; | ||
widths[i + 1] -= minEven - 1; | ||
} | ||
} | ||
|
||
return widths; | ||
} | ||
|
||
static Character ReadDataCharacter(const PatternView& view) | ||
{ | ||
constexpr int G_SUM[] = {0, 183064, 820064, 1000776, 1491021, 1979845, 1996939}; | ||
constexpr int T_EVEN[] = {28, 728, 6454, 203, 2408, 1, 16632}; | ||
constexpr int ODD_SUM[] = {17, 13, 9, 15, 11, 19, 7}; | ||
constexpr int ODD_WIDEST[] = {6, 5, 3, 5, 4, 8, 1}; | ||
|
||
auto pattern = NormalizedPatternFromE2E<14, 26>(view); | ||
|
||
int checkSum = 0; | ||
for (auto it = pattern.rbegin(); it != pattern.rend(); ++it) | ||
checkSum = 3 * checkSum + *it; | ||
|
||
using Array7I = std::array<int, 7>; | ||
Array7I oddPattern = {}, evnPattern = {}; | ||
OddEven<Array7I&> res = {oddPattern, evnPattern}; | ||
|
||
for (int i = 0; i < Size(pattern); ++i) | ||
res[i % 2][i / 2] = pattern[i]; | ||
|
||
printf(" o: "); | ||
printv("%d ", oddPattern); | ||
printf(" e: "); | ||
printv("%d ", evnPattern); | ||
|
||
int group = IndexOf(ODD_SUM, Reduce(oddPattern)); | ||
if (group == -1) | ||
return {}; | ||
|
||
int oddWidest = ODD_WIDEST[group]; | ||
int evnWidest = 9 - oddWidest; | ||
#ifndef __cpp_lib_span | ||
#pragma message("DataBarLimited not supported without std::span<> (c++20 feature)") | ||
int vOdd = 0; | ||
int vEvn = 0; | ||
#else | ||
int vOdd = GetValue(oddPattern, oddWidest, false); | ||
int vEvn = GetValue(evnPattern, evnWidest, true); | ||
#endif | ||
int tEvn = T_EVEN[group]; | ||
int gSum = G_SUM[group]; | ||
|
||
return {vOdd * tEvn + vEvn + gSum, checkSum}; | ||
} | ||
|
||
static std::string ConstructText(Character left, Character right) | ||
{ | ||
auto symVal = 2'013'571LL * left.value + right.value; | ||
|
||
// Strip 2D linkage flag (GS1 Composite) if any (ISO/IEC 24724:2011 Section 6.2.3) | ||
if (symVal >= 2'015'133'531'096LL) { | ||
symVal -= 2'015'133'531'096LL; | ||
assert(symVal <= 1'999'999'999'999LL); // 13 digits | ||
} | ||
auto txt = ToString(symVal, 13); | ||
return "01" + txt + GTIN::ComputeCheckDigit(txt); | ||
} | ||
|
||
static inline bool Has26to18Ratio(int v26, int v18) | ||
{ | ||
return v26 + 1.5 * v26 / 26 > v18 / 18. * 26. && v26 - 1.5 * v26 / 26 < v18 / 18. * 26.; | ||
} | ||
|
||
std::array<int, 89> CheckChars = { | ||
0b10'10101010'11100010, 0b10'10101010'01110010, 0b10'10101010'00111010, 0b10'10101001'01110010, 0b10'10101001'00111010, | ||
0b10'10101000'10111010, 0b10'10100101'01110010, 0b10'10100101'00111010, 0b10'10100100'10111010, 0b10'10100010'10111010, | ||
0b10'10010101'01110010, 0b10'10010101'00111010, 0b10'10010100'10111010, 0b10'10010010'10111010, 0b10'10001010'10111010, | ||
0b10'01010101'01110010, 0b10'01010101'00111010, 0b10'01010100'10111010, 0b10'01010010'10111010, 0b10'01001010'10111010, | ||
0b10'00101010'10111010, 0b10'10101011'01100010, 0b10'10101011'00110010, 0b10'10101011'00011010, 0b10'10101001'10110010, | ||
0b10'10101001'10011010, 0b10'10101000'11011010, 0b10'10100101'10110010, 0b10'10100101'10011010, 0b10'10100100'11011010, | ||
0b10'10100010'11011010, 0b10'10010101'10110010, 0b10'10010101'10011010, 0b10'10010100'11011010, 0b10'10010010'11011010, | ||
0b10'10001010'11011010, 0b10'01010101'10110010, 0b10'01010101'10011010, 0b10'01010100'11011010, 0b10'01010010'11011010, | ||
0b10'01001010'11011010, 0b10'00101010'11011010, 0b10'10101011'10100010, 0b10'10101011'10010010, 0b10'10101001'11010010, | ||
0b10'10010101'11010010, 0b10'01010101'11010010, 0b10'10101101'01100010, 0b10'10101101'00110010, 0b10'10101101'00011010, | ||
0b10'10101100'10110010, 0b10'10010110'10110010, 0b10'10010110'10011010, 0b10'10010110'01011010, 0b10'10010011'01011010, | ||
0b10'10001011'01011010, 0b10'01010110'10110010, 0b10'01010110'10011010, 0b10'01001011'01011010, 0b10'10110101'01100010, | ||
0b10'10110101'00110010, 0b10'10110101'00011010, 0b10'10110100'10110010, 0b10'10110100'10011010, 0b10'10110010'10110010, | ||
0b10'01011010'10110010, 0b10'01011010'10011010, 0b10'01011010'01011010, 0b10'01011001'01011010, 0b10'01001101'01011010, | ||
0b10'00101101'01011010, 0b10'11010101'01100010, 0b10'11010101'00110010, 0b10'11010101'00011010, 0b10'11010100'10110010, | ||
0b10'11010100'10011010, 0b10'11010100'01011010, 0b10'11010010'10110010, 0b10'11010010'10011010, 0b10'11001010'10110010, | ||
0b11'01010101'00110010, 0b11'01010101'00011010, 0b11'01010100'10110010, 0b11'01010100'10011010, 0b11'01010100'01011010, | ||
0b11'01010010'10011010, 0b11'01010010'01011010, 0b11'01001010'10011010, 0b11'01010101'10010010, | ||
}; | ||
|
||
Barcode DataBarLimitedReader::decodePattern(int rowNumber, PatternView& next, std::unique_ptr<RowReader::DecodingState>&) const | ||
{ | ||
next = next.subView(-2, SYMBOL_LEN); | ||
while (next.shift(2)) { | ||
if (!IsGuard(next[27], next[43])) | ||
continue; | ||
auto spaceSize = (next[27] + next[43]) / 2; | ||
if ((!next.isAtFirstBar() && next[-1] < spaceSize) || (!next.isAtLastBar() && next[SYMBOL_LEN] < 4 * spaceSize)) | ||
continue; | ||
auto [mBar, MBar] = std::minmax({next[0], next[28], next[44]}); | ||
if (MBar > mBar * 4 / 3 + 1) | ||
continue; | ||
|
||
auto leftView = next.subView(1 + 0 * CHAR_LEN, CHAR_LEN); | ||
auto checkView = next.subView(1 + 1 * CHAR_LEN, CHAR_LEN); | ||
auto rightView = next.subView(1 + 2 * CHAR_LEN, CHAR_LEN); | ||
auto leftWidth = leftView.sum(); | ||
auto checkWith = checkView.sum(); | ||
auto rightWidth = rightView.sum(); | ||
if (!Has26to18Ratio(leftWidth, checkWith) || !Has26to18Ratio(rightWidth, checkWith)) | ||
continue; | ||
|
||
auto modSize = double(leftWidth + checkWith + rightWidth) / (26 + 18 + 26); | ||
if ((!next.isAtFirstBar() && next[-1] < modSize) || (!next.isAtLastBar() && next[SYMBOL_LEN] < 5 * modSize)) | ||
continue; | ||
|
||
auto checkCharPattern = ToInt(NormalizedPatternFromE2E<CHAR_LEN, 18>(checkView)); | ||
int checkSum = IndexOf(CheckChars, checkCharPattern); | ||
if (checkSum == -1) | ||
continue; | ||
|
||
printf("%f - ", modSize); | ||
printv("%d ", NormalizedPatternFromE2E<CHAR_LEN, 18>(checkView)); | ||
|
||
auto left = ReadDataCharacter(leftView); | ||
auto right = ReadDataCharacter(rightView); | ||
|
||
printf("- %d, %d, %d\n", checkSum, left.value, right.value); | ||
|
||
if ((left.checksum + 20 * right.checksum) % 89 != checkSum) | ||
continue; | ||
|
||
return {ConstructText(left, right), rowNumber, next.pixelsInFront(), next.pixelsTillEnd(), | ||
BarcodeFormat::DataBarLimited, {'e', '0'}}; | ||
} | ||
|
||
// guarantee progress (see loop in ODReader.cpp) | ||
next = {}; | ||
|
||
return {}; | ||
} | ||
|
||
} // namespace ZXing::OneD |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* Copyright 2024 Axel Waggershauser | ||
*/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#pragma once | ||
|
||
#include "ODRowReader.h" | ||
|
||
namespace ZXing::OneD { | ||
|
||
/** | ||
* Decodes DataBarLimited sybmols. See ISO/IEC 24724:2011. | ||
*/ | ||
class DataBarLimitedReader : public RowReader | ||
{ | ||
public: | ||
using RowReader::RowReader; | ||
|
||
Barcode decodePattern(int rowNumber, PatternView& next, std::unique_ptr<DecodingState>& state) const override; | ||
}; | ||
|
||
} // namespace ZXing::OneD |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.