From e157d6abec6211388622d0d91a024f48b2d2402a Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 8 Apr 2024 17:06:37 +1000 Subject: [PATCH 01/10] aztec: Add support for detecting Aztec Runes Runes are identical to the Core of a compact Aztec code, except that their bits are alternately flipped. They contain exactly 8 bits of data. We know that a compact Core is a Rune if: a) it fails a normal Reed-Solomon decode AND b) it passes when you flip every odd-numbered bit Once we know this, we can shortcut most of the rest of the decode logic. --- core/src/aztec/AZDecoder.cpp | 13 +++++++++++++ core/src/aztec/AZDetector.cpp | 28 +++++++++++++++++++++++----- core/src/aztec/AZDetectorResult.h | 9 +++++++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/core/src/aztec/AZDecoder.cpp b/core/src/aztec/AZDecoder.cpp index c33324afcf..ed1aa713f5 100644 --- a/core/src/aztec/AZDecoder.cpp +++ b/core/src/aztec/AZDecoder.cpp @@ -346,9 +346,22 @@ DecoderResult Decode(const BitArray& bits) return DecoderResult(std::move(res)).setStructuredAppend(sai); } +DecoderResult DecodeRune(const DetectorResult& detectorResult) { + Content res; + res.symbology = {'z', 'C', 3}; + + res.push_back(detectorResult.runeValue()); + + return DecoderResult(std::move(res)); +} + DecoderResult Decode(const DetectorResult& detectorResult) { try { + if (detectorResult.nbLayers() == 0) { + // This is a rune - just return the rune value + return DecodeRune(detectorResult); + } auto bits = CorrectBits(detectorResult, ExtractBits(detectorResult)); return Decode(bits); } catch (Error e) { diff --git a/core/src/aztec/AZDetector.cpp b/core/src/aztec/AZDetector.cpp index bd528d2b64..c9d63dbb0f 100644 --- a/core/src/aztec/AZDetector.cpp +++ b/core/src/aztec/AZDetector.cpp @@ -261,9 +261,10 @@ static uint32_t SampleOrientationBits(const BitMatrix& image, const PerspectiveT return bits; } -static int ModeMessage(const BitMatrix& image, const PerspectiveTransform& mod2Pix, int radius) +static int ModeMessage(const BitMatrix& image, const PerspectiveTransform& mod2Pix, int radius, bool& isRune) { const bool compact = radius == 5; + isRune = false; // read the bits between the corner bits along the 4 edges uint64_t bits = 0; @@ -291,7 +292,21 @@ static int ModeMessage(const BitMatrix& image, const PerspectiveTransform& mod2P words[i] = narrow_cast(bits & 0xF); bits >>= 4; } - if (!ReedSolomonDecode(GenericGF::AztecParam(), words, numECCodewords)) + + bool decodeResult = ReedSolomonDecode(GenericGF::AztecParam(), words, numECCodewords); + + if ((!decodeResult) && compact) { + // Is this a Rune? + for (int i = numCodewords - 1; i >= 0; --i) { + words[i] ^= 0b1010; + } + decodeResult = ReedSolomonDecode(GenericGF::AztecParam(), words, numECCodewords); + + if (decodeResult) + isRune = true; + } + + if (!decodeResult) return -1; int res = 0; @@ -350,6 +365,7 @@ DetectorResults Detect(const BitMatrix& image, bool isPure, bool tryHarder, int int mirror; // 0 or 1 int rotate; // [0..3] int modeMessage = -1; + bool isRune = false; [&]() { // 24778:2008(E) 14.3.3 reads: // In the outer layer of the Core Symbol, the 12 orientation bits at the corners are bitwise compared against the specified @@ -369,7 +385,7 @@ DetectorResults Detect(const BitMatrix& image, bool isPure, bool tryHarder, int rotate = FindRotation(bits, mirror); if (rotate == -1) continue; - modeMessage = ModeMessage(image, PerspectiveTransform(srcQuad, RotatedCorners(*fpQuad, rotate, mirror)), radius); + modeMessage = ModeMessage(image, PerspectiveTransform(srcQuad, RotatedCorners(*fpQuad, rotate, mirror)), radius, isRune); if (modeMessage != -1) return; } @@ -399,7 +415,9 @@ DetectorResults Detect(const BitMatrix& image, bool isPure, bool tryHarder, int int nbLayers = 0; int nbDataBlocks = 0; bool readerInit = false; - ExtractParameters(modeMessage, radius == 5, nbLayers, nbDataBlocks, readerInit); + if (!isRune) { + ExtractParameters(modeMessage, radius == 5, nbLayers, nbDataBlocks, readerInit); + } int dim = radius == 5 ? 4 * nbLayers + 11 : 4 * nbLayers + 2 * ((2 * nbLayers + 6) / 15) + 15; double low = dim / 2.0 + srcQuad[0].x; @@ -409,7 +427,7 @@ DetectorResults Detect(const BitMatrix& image, bool isPure, bool tryHarder, int if (!bits.isValid()) continue; - res.emplace_back(std::move(bits), radius == 5, nbDataBlocks, nbLayers, readerInit, mirror != 0); + res.emplace_back(std::move(bits), radius == 5, nbDataBlocks, nbLayers, readerInit, mirror != 0, isRune ? modeMessage : 0); if (Size(res) == maxSymbols) break; diff --git a/core/src/aztec/AZDetectorResult.h b/core/src/aztec/AZDetectorResult.h index cd65e9daab..f2cc4f50e2 100644 --- a/core/src/aztec/AZDetectorResult.h +++ b/core/src/aztec/AZDetectorResult.h @@ -19,6 +19,7 @@ class DetectorResult : public ZXing::DetectorResult int _nbLayers = 0; bool _readerInit = false; bool _isMirrored = false; + uint8_t _runeValue = 0; DetectorResult(const DetectorResult&) = delete; DetectorResult& operator=(const DetectorResult&) = delete; @@ -28,13 +29,14 @@ class DetectorResult : public ZXing::DetectorResult DetectorResult(DetectorResult&&) noexcept = default; DetectorResult& operator=(DetectorResult&&) noexcept = default; - DetectorResult(ZXing::DetectorResult&& result, bool isCompact, int nbDatablocks, int nbLayers, bool readerInit, bool isMirrored) + DetectorResult(ZXing::DetectorResult&& result, bool isCompact, int nbDatablocks, int nbLayers, bool readerInit, bool isMirrored, uint8_t runeValue) : ZXing::DetectorResult{std::move(result)}, _compact(isCompact), _nbDatablocks(nbDatablocks), _nbLayers(nbLayers), _readerInit(readerInit), - _isMirrored(isMirrored) + _isMirrored(isMirrored), + _runeValue(runeValue) {} bool isCompact() const { return _compact; } @@ -42,6 +44,9 @@ class DetectorResult : public ZXing::DetectorResult int nbLayers() const { return _nbLayers; } bool readerInit() const { return _readerInit; } bool isMirrored() const { return _isMirrored; } + + // Only meaningful is nbDatablocks == 0 + uint8_t runeValue() const { return _runeValue; } }; } // namespace ZXing::Aztec From bc537ba4e04d13c1f496c9805d9e3f9ea121c479 Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 9 Apr 2024 14:09:57 +1000 Subject: [PATCH 02/10] aztec: Add unit tests for Aztec Rune detector --- core/src/aztec/AZDetector.cpp | 2 +- test/unit/aztec/AZDecoderTest.cpp | 2 +- test/unit/aztec/AZDetectorTest.cpp | 60 ++++++++++++++++++++++++++ test/unit/aztec/AZEncodeDecodeTest.cpp | 2 +- 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/core/src/aztec/AZDetector.cpp b/core/src/aztec/AZDetector.cpp index c9d63dbb0f..dac3ee4b9b 100644 --- a/core/src/aztec/AZDetector.cpp +++ b/core/src/aztec/AZDetector.cpp @@ -114,7 +114,7 @@ static std::vector FindPureFinderPattern(const BitMatrix& ima PointF p(left + width / 2, top + height / 2); constexpr auto PATTERN = FixedPattern<7, 7>{1, 1, 1, 1, 1, 1, 1}; - if (auto pattern = LocateConcentricPattern(image, PATTERN, p, width / 2)) + if (auto pattern = LocateConcentricPattern(image, PATTERN, p, std::max(width / 2, 7))) return {*pattern}; else return {}; diff --git a/test/unit/aztec/AZDecoderTest.cpp b/test/unit/aztec/AZDecoderTest.cpp index beae00357c..2d85313e4a 100644 --- a/test/unit/aztec/AZDecoderTest.cpp +++ b/test/unit/aztec/AZDecoderTest.cpp @@ -25,7 +25,7 @@ using namespace ZXing; // Shorthand to call Decode() static DecoderResult parse(BitMatrix&& bits, bool compact, int nbDatablocks, int nbLayers) { - return Aztec::Decode({{std::move(bits), {}}, compact, nbDatablocks, nbLayers, false /*readerInit*/, false /*isMirrored*/}); + return Aztec::Decode({{std::move(bits), {}}, compact, nbDatablocks, nbLayers, false /*readerInit*/, false /*isMirrored*/, 0 /*runeValue*/}); } TEST(AZDecoderTest, AztecResult) diff --git a/test/unit/aztec/AZDetectorTest.cpp b/test/unit/aztec/AZDetectorTest.cpp index 242932f3b3..b58061e34e 100644 --- a/test/unit/aztec/AZDetectorTest.cpp +++ b/test/unit/aztec/AZDetectorTest.cpp @@ -426,3 +426,63 @@ TEST(AZDetectorTest, ReaderInitCompact) EXPECT_EQ(r.nbLayers(), 1); } } + +TEST(AZDetectorTest, Rune) +{ + { + auto r = Aztec::Detect(ParseBitMatrix( + "X X X X X X X \n" + "X X X X X X X X X X X \n" + " X X \n" + "X X X X X X X X X \n" + " X X X X \n" + "X X X X X X X \n" + " X X X X \n" + "X X X X X X X X X \n" + " X X \n" + " X X X X X X X X X X \n" + " X X X X \n" + ), false /*isPure*/, false /*tryHarder*/); + + EXPECT_TRUE(r.isValid()); + EXPECT_EQ(r.nbDatablocks(), 0); + EXPECT_EQ(r.runeValue(), 0); + } + { + auto r = Aztec::Detect(ParseBitMatrix( + "X X X X X X X \n" + "X X X X X X X X X X X \n" + " X X X \n" + " X X X X X X X X \n" + " X X X X \n" + "X X X X X X X \n" + "X X X X X X \n" + "X X X X X X X X \n" + "X X X X \n" + " X X X X X X X X X X \n" + " X X \n" + ), true /*isPure*/, false /*tryHarder*/); + + EXPECT_TRUE(r.isValid()); + EXPECT_EQ(r.nbDatablocks(), 0); + EXPECT_EQ(r.runeValue(), 25); + } + { + auto r = Aztec::Detect(ParseBitMatrix( + "X X X X \n" + "X X X X X X X X X X X \n" + " X X \n" + "X X X X X X X X \n" + " X X X X X \n" + " X X X X X \n" + " X X X X X \n" + " X X X X X X X X \n" + "X X X \n" + " X X X X X X X X X X \n" + " X X \n" + ), true /*isPure*/, false /*tryHarder*/); + + // This is just the core of a regular compact code, and not a valid rune + EXPECT_FALSE(r.isValid()); + } +} \ No newline at end of file diff --git a/test/unit/aztec/AZEncodeDecodeTest.cpp b/test/unit/aztec/AZEncodeDecodeTest.cpp index e07824f97b..47b9cb063b 100644 --- a/test/unit/aztec/AZEncodeDecodeTest.cpp +++ b/test/unit/aztec/AZEncodeDecodeTest.cpp @@ -35,7 +35,7 @@ namespace { // Shorthand to call Decode() static DecoderResult parse(BitMatrix&& bits, bool compact, int nbDatablocks, int nbLayers) { - return Aztec::Decode({{std::move(bits), {}}, compact, nbDatablocks, nbLayers, false /*readerInit*/, false /*isMirrored*/}); + return Aztec::Decode({{std::move(bits), {}}, compact, nbDatablocks, nbLayers, false /*readerInit*/, false /*isMirrored*/, 0 /*runeValue*/}); } void TestEncodeDecode(const std::string& data, bool compact, int layers) { From 5c26504192b48f8606c351662219d9e8a4284b62 Mon Sep 17 00:00:00 2001 From: Morgan Date: Wed, 10 Apr 2024 10:10:45 +1000 Subject: [PATCH 03/10] aztec: Fix pure detector bug LocateConcentricPattern starts at the middle and works out, but it still expects the range of the entire pattern, not half of it. The only reason this has worked so far is that non Rune Aztec codes are always at least twice the size of the target pattern. --- core/src/aztec/AZDetector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/aztec/AZDetector.cpp b/core/src/aztec/AZDetector.cpp index dac3ee4b9b..5e88a2c33b 100644 --- a/core/src/aztec/AZDetector.cpp +++ b/core/src/aztec/AZDetector.cpp @@ -114,7 +114,7 @@ static std::vector FindPureFinderPattern(const BitMatrix& ima PointF p(left + width / 2, top + height / 2); constexpr auto PATTERN = FixedPattern<7, 7>{1, 1, 1, 1, 1, 1, 1}; - if (auto pattern = LocateConcentricPattern(image, PATTERN, p, std::max(width / 2, 7))) + if (auto pattern = LocateConcentricPattern(image, PATTERN, p, width)) return {*pattern}; else return {}; From 2fe03cb6ff2860bd5142db5221b6f989d6363023 Mon Sep 17 00:00:00 2001 From: Morgan Date: Wed, 10 Apr 2024 10:11:57 +1000 Subject: [PATCH 04/10] aztec: Add blackbox tests for Rune detector also added the names of the expected failures... this should probably be handled better! Maybe pass in the names of the expected failures as a vector? --- test/blackbox/BlackboxTestRunner.cpp | 16 ++++++++++------ test/samples/aztec-1/rune-1.bin | 1 + test/samples/aztec-1/rune-1.png | Bin 0 -> 2039 bytes test/samples/aztec-1/rune-1.result.txt | 1 + test/samples/aztec-1/rune-64.bin | 1 + test/samples/aztec-1/rune-64.png | Bin 0 -> 1690 bytes 6 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 test/samples/aztec-1/rune-1.bin create mode 100644 test/samples/aztec-1/rune-1.png create mode 100644 test/samples/aztec-1/rune-1.result.txt create mode 100644 test/samples/aztec-1/rune-64.bin create mode 100644 test/samples/aztec-1/rune-64.png diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 226ea2e7ff..82f5efedde 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -334,12 +334,16 @@ int runBlackBoxTests(const fs::path& testPathPrefix, const std::set auto startTime = std::chrono::steady_clock::now(); // clang-format off - runTests("aztec-1", "Aztec", 27, { - { 26, 27, 0 }, - { 26, 27, 90 }, - { 26, 27, 180 }, - { 26, 27, 270 }, - { 25, 0, pure }, + + // Expected failures: + // abc-inverted.png (fast) - fast does not try inverted + // az-thick.png (pure) + runTests("aztec-1", "Aztec", 29, { + { 28, 29, 0 }, + { 28, 29, 90 }, + { 28, 29, 180 }, + { 28, 29, 270 }, + { 27, 0, pure }, }); runTests("aztec-2", "Aztec", 22, { diff --git a/test/samples/aztec-1/rune-1.bin b/test/samples/aztec-1/rune-1.bin new file mode 100644 index 0000000000..6b2aaa7640 --- /dev/null +++ b/test/samples/aztec-1/rune-1.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/samples/aztec-1/rune-1.png b/test/samples/aztec-1/rune-1.png new file mode 100644 index 0000000000000000000000000000000000000000..2536b51074d10bd5c1959bfe6dc092f35cf585a3 GIT binary patch literal 2039 zcmc&#U2GIp6doE(0Yj7k(P)}XrVolT|1CQ^bS!nZrK_E`DVtC3*Ju3a5nOQ@%( zZ=|TDXRY*bFs%2f5ZfFuv4ObIb_trIIyyraz!4PC2FhBF#w@&Xh@mZ0W45;Ig6<|z z&gz};(3Xk*G@KZLag*u1gYF1bLSUl+(4n1od^OaV60b_;(K64_B}g!$F zCKm**%Jaoykt@m^_OiSfkH>jI;w6bC2-Y8W0uZu}-&$ozA|HB|8(7$(BSv80LZC6k z*|G}TtmD@=I1)&Vpv1w(->p~R* zx&lh-#smTQTd)b$4EAh5BwIGfBHnef3|$MPn!tJN5yQkgx#Weet0~71fCEt~sWC(~ zXIZ8yZjclMBFGv@6xg;l7-N-KOktIb5sSr9Off`M-Jis;5aqVI-~5;R2Rw@$FOa`# zp6Jj;MWOauK1tVjTKKOk2z$Li!i!F2j7B z35vi&U0D*Xe^5|7ai5RQVp$2lSY+wlW#_gEC(R(5)*2CcsI@ZWkpAV7Ms?S&o=J*o zdLfnUN{7>@zU_M8J>mLIpS^hY;?^;K@Xb}H_Z?X{wYvG|sYjb<3io|^!-f3|=bO*; zyxdA}Z2BLD&U4rO_RT#%&EU5Wu@^4BcH-ezjjvbjX<0J2co>$C8=bSyhR;l0+HY;% zG`7@SJZ%4A+wK=D^AR=*%%W$ew}ZTXIs~P z@#G^XmmOI=yz?o0_@m9~`V3{xh!=E3aIG8>{)QPk^J*r#aQ#pM2@g?K}Sf=`f*# literal 0 HcmV?d00001 diff --git a/test/samples/aztec-1/rune-1.result.txt b/test/samples/aztec-1/rune-1.result.txt new file mode 100644 index 0000000000..2be1501c62 --- /dev/null +++ b/test/samples/aztec-1/rune-1.result.txt @@ -0,0 +1 @@ +symbologyIdentifier=]zC \ No newline at end of file diff --git a/test/samples/aztec-1/rune-64.bin b/test/samples/aztec-1/rune-64.bin new file mode 100644 index 0000000000..b516b2c489 --- /dev/null +++ b/test/samples/aztec-1/rune-64.bin @@ -0,0 +1 @@ +@ \ No newline at end of file diff --git a/test/samples/aztec-1/rune-64.png b/test/samples/aztec-1/rune-64.png new file mode 100644 index 0000000000000000000000000000000000000000..b67135933af8e6befbab783574fb50e0d3e5bb5f GIT binary patch literal 1690 zcmbVNO>Em_81@iIFtpPq4aUWCgv3<*pEUEQno*jLM4G#j2Ix4TeX+kJR&9UAb{D7P z1Q$SnKpO{2Ck{*qp$ahxR#ku|aR7=sU>gU6WojZt=p287iF znKva#Ve^_`Rk3PewVJz^RU}0fWkr;8yey%tg48_Q{cvC~uxhAW*wZx!Pde9#A|Huj zv)L4ysz8IfC~KM~N{Xl`JRtb6=wd z>^%lHZ7&I8=PDIaz!A|os9Tno;Hy>S9Fnp~miwT9lGK43)Us=>ze9H+DUam-HBjgq z3rF~0!Ip_?G;lG5Y`eHlMBl4(Y???kL>(G{Ven3Edtn%;dwR%d7^uAY_{D82%AZN>ztVsmRMZ(wSB`G=+HJB1W5m(+#Og*Yf%#iWUvm| z`VS2yg8O1Ji=9Zs^+C2}tLC-`hh>l)(?tXi=_(^0?5_Y8)muMKUuBq0drO7EN<6cC z;i2cAmbTr0dg0O^b58T6a`489nU%g1@xqsx!A~z{j$YR0(I@exkN!M7@nqri=a1aE zQ!UqyEf!yWS;^cD%W}-TIPzKkvDV{iyl0)5EPeCa*_DOwg}$xRhn?-9K-NIc?OI-3 zKEM6jJUMrM{+Tt*09e({~U@2d@EKOMS!>WAvXJx8wbzWB=Aw%K^;$on6^-SP37 z=-8q&u<+{(zpH(->m3DaXWm;mbRE%aSC&7Vzxw9f>lc1G89uU_u$=|6bj!O(rLXVG SAD>VDJxaqPg?An}@YG+Rzeyqh literal 0 HcmV?d00001 From f0b073d905ec16d8f8237a9f3f94e7450cdbe6b2 Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 15 Apr 2024 12:38:07 +1000 Subject: [PATCH 05/10] aztec: Fix an issue with runes 68 and 223 Because of the way runes are encoded with half their bits flipped, runes 68 and 223 have all white on their bottom row. Because of this, we need to make sure that our bounding box is square --- core/src/aztec/AZDetector.cpp | 9 +++++++-- test/blackbox/BlackboxTestRunner.cpp | 12 ++++++------ test/samples/aztec-1/rune-223.bin | 1 + test/samples/aztec-1/rune-223.png | Bin 0 -> 1950 bytes test/samples/aztec-1/rune-68.bin | 1 + test/samples/aztec-1/rune-68.png | Bin 0 -> 1778 bytes 6 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 test/samples/aztec-1/rune-223.bin create mode 100644 test/samples/aztec-1/rune-223.png create mode 100644 test/samples/aztec-1/rune-68.bin create mode 100644 test/samples/aztec-1/rune-68.png diff --git a/core/src/aztec/AZDetector.cpp b/core/src/aztec/AZDetector.cpp index 5e88a2c33b..7d047e888a 100644 --- a/core/src/aztec/AZDetector.cpp +++ b/core/src/aztec/AZDetector.cpp @@ -109,8 +109,13 @@ static std::optional LocateAztecCenter(const BitMatrix& image static std::vector FindPureFinderPattern(const BitMatrix& image) { int left, top, width, height; - if (!image.findBoundingBox(left, top, width, height, 11)) // 11 is the size of an Aztec Rune, see ISO/IEC 24778:2008(E) Annex A - return {}; + if (!image.findBoundingBox(left, top, width, height, 11)) { // 11 is the size of an Aztec Rune, see ISO/IEC 24778:2008(E) Annex A + // Runes 68 and 223 have none of their bits set on the bottom row + if (image.findBoundingBox(left, top, width, height, 10) && (width == 11) && (height == 10)) + height = 11; + else + return {}; + } PointF p(left + width / 2, top + height / 2); constexpr auto PATTERN = FixedPattern<7, 7>{1, 1, 1, 1, 1, 1, 1}; diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 82f5efedde..a3fed245b1 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -338,12 +338,12 @@ int runBlackBoxTests(const fs::path& testPathPrefix, const std::set // Expected failures: // abc-inverted.png (fast) - fast does not try inverted // az-thick.png (pure) - runTests("aztec-1", "Aztec", 29, { - { 28, 29, 0 }, - { 28, 29, 90 }, - { 28, 29, 180 }, - { 28, 29, 270 }, - { 27, 0, pure }, + runTests("aztec-1", "Aztec", 31, { + { 30, 31, 0 }, + { 30, 31, 90 }, + { 30, 31, 180 }, + { 30, 31, 270 }, + { 29, 0, pure }, }); runTests("aztec-2", "Aztec", 22, { diff --git a/test/samples/aztec-1/rune-223.bin b/test/samples/aztec-1/rune-223.bin new file mode 100644 index 0000000000..7136b4c89b --- /dev/null +++ b/test/samples/aztec-1/rune-223.bin @@ -0,0 +1 @@ +ß \ No newline at end of file diff --git a/test/samples/aztec-1/rune-223.png b/test/samples/aztec-1/rune-223.png new file mode 100644 index 0000000000000000000000000000000000000000..1168d6bf4942db98569522ccd57eef178d6238d5 GIT binary patch literal 1950 zcmcgtTWs4@7ZO%p;)GcJNn!|^R?Vz*u?Nm--TrL%@X(%38*kf4QPie%e`S^6H8SJgxHhOjY({{Nvnb-5HbGNVcaLuaIEg$ui}Hr0GMC;y!_bDVG7rTx zUbB;^VD!&8Xmn;M17{|otTR2k>26;k4ou_$+Bb`qtN1EY^{bF^@S0=jD#V*qncjeq z9@mEHBz6!jM+6q~yhz98h@J(K4y0`C9$Mr@i4#Olh_M2%L`6l4)AfrXgpQt5MpF0J z>BvlF3Z7>x99JrpA|)w;ojfPVvdr-!CyFdVux{D%fX`ZPN5ex3xzI6e&%hQPcm!EI z<*5t_wx+_gL${V&&lJfS=L4G)B7C5#3e;hUv!|S5m0X7$Dk2kEo=dPoh_wsY!)^hu z;X3?$6#>bvriC0WV=>K;!u9&5iHv$eTB6-d*+$$5a`BV{QQtHPvm;PrD@g|d4?7u* zi;Y?hH$tYxSfrEQp#f-Efry<~EI}#YA(bI@i?V!_6fGk}6<$(!VHYVN&)1+D){R`b zB{ZrCiL0Pw-{`;t{|eTjlEaP(h-AYAdBoXPo}t4;DoI?#4k0GdN!2JcO-Wm>2P}xv zDU~6rBZi?X0Cq}IUWRNg5fj*GBAQ@j9U``qj|nj;7Y95N8|zaTP6f4Xtk_)i-~S-<6-+f1z^j+n>8HeZ233H#+F9_Sc&Yf0Mkm z2fuJRy0FFG+JbBr{xtI0>7}>cd1>+Cms>_M`}n{qytuh?Z1Iyn7R2rR%7(Lt4=y*G z+viV=|8o8o>D*)ar4#|KMX3-4UM;|ThuWl9pcfd>z$ z*~OD%%ky33wF$l-tQ;9^kqDBUi-%(G#xMA z%xrcOlv*EzyaIojSWkflFXYeBYZ-_QNI01S1Cc{Z6HK-@V)(>!pKCxgvJ=Ai?S1C{q zLl4SwtyYWG^ceF?vYJdLWkr)UP2vbCn07-{m)u}yn;}gD?Au;wGgpilQIS={6yU)& zvv9l)tsAr|#cL+lkteG$CCaJ+B)Eg~s(z*6oM4$&s6*W_;8?YT^~x+{L7Clvy0d+q z172Oz?D$wU7RTwh2*S)1Poq_kRnb9V+M{xw2CV91nwjEZ?u@eW;Gj=Y$ov9hm9|!6 z?T|&yi1muQOoVMWO5%|fCNzygngU$6xTM6nXazM6RRikA9xkAwG@&LVwl%#fGzqod z>!7@E2nx~vf(eEe^Bu%fwjETWvgek7*eN6&WEJLf$2>Z{5rt{OoEwD5#Wa^r0iJct zwh1IuPb5g3NV?UhN^wFo3H8xlso0k!ii(Rm*0i>Ln&E1sZQGu3d#ve+WZW<$#j*@3 zjuDbjZ$go%f{eID`bbfsZTkbh&5swV+%!*g=%S{8Sv%lzO}Ea(IDNkLRI$ZIA3%ho z{!RfL2}=oRy|!1W!1^+1($>n9ldd6m6BaNltRbHclz6q)(NOY@!Vl2Y+QF|+zBPhh z*?>0}e5>voykmHPVMu#`%J#) z6+W}i=h6d(@{y&ZpLc&L-mC(Qf_ulvF@TLOz{?y4G2lv0Xn0xE>XgS7yTI|37hdm<;2hO}v04KH` z`D4fOHy>TTW6OAc_NC!X;M%YA2S2#{?c2&jb6xMJPt1M#=b5=fqi0*&$BvyJy7=Lp zoO#>s%+>neyMJpNE Date: Mon, 15 Apr 2024 12:39:07 +1000 Subject: [PATCH 06/10] aztec: Add capability to generate runes --- core/src/aztec/AZEncoder.cpp | 39 ++++++++++++++++---- core/src/aztec/AZEncoder.h | 1 + test/unit/aztec/AZEncodeDecodeTest.cpp | 15 ++++++++ test/unit/aztec/AZEncoderTest.cpp | 49 ++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 6 deletions(-) diff --git a/core/src/aztec/AZEncoder.cpp b/core/src/aztec/AZEncoder.cpp index f45eb000db..00b3108463 100644 --- a/core/src/aztec/AZEncoder.cpp +++ b/core/src/aztec/AZEncoder.cpp @@ -82,6 +82,19 @@ void GenerateModeMessage(bool compact, int layers, int messageSizeInWords, BitAr } } +ZXING_EXPORT_TEST_ONLY +void GenerateRuneMessage(uint8_t word, BitArray& runeMessage) +{ + runeMessage = BitArray(); + runeMessage.appendBits(word, 8); + GenerateCheckWords(runeMessage, 28, 4, runeMessage); + // Now flip every other bit + + BitArray xorBits; + xorBits.appendBits(0xAAAAAAAA, 28); + runeMessage.bitwiseXOR(xorBits); +} + static void DrawModeMessage(BitMatrix& matrix, bool compact, int matrixSize, const BitArray& modeMessage) { int center = matrixSize / 2; @@ -176,7 +189,13 @@ Encoder::Encode(const std::string& data, int minECCPercent, int userSpecifiedLay int totalBitsInLayer; int wordSize; BitArray stuffedBits; - if (userSpecifiedLayers != DEFAULT_AZTEC_LAYERS) { + if (userSpecifiedLayers == AZTEC_RUNE_LAYERS) { + compact = true; + layers = 0; + totalBitsInLayer = 0; + wordSize = 0; + stuffedBits = BitArray(0); + } else if (userSpecifiedLayers != DEFAULT_AZTEC_LAYERS) { compact = userSpecifiedLayers < 0; layers = std::abs(userSpecifiedLayers); if (layers > (compact ? MAX_NB_BITS_COMPACT : MAX_NB_BITS)) { @@ -225,13 +244,21 @@ Encoder::Encode(const std::string& data, int minECCPercent, int userSpecifiedLay } } } - BitArray messageBits; - GenerateCheckWords(stuffedBits, totalBitsInLayer, wordSize, messageBits); - // generate mode message - int messageSizeInWords = stuffedBits.size() / wordSize; + BitArray messageBits; BitArray modeMessage; - GenerateModeMessage(compact, layers, messageSizeInWords, modeMessage); + int messageSizeInWords; + + if (layers == 0) { + // This is a rune, and messageBits should be empty + messageBits = BitArray(0); + messageSizeInWords = 0; + GenerateRuneMessage(data[0], modeMessage); + } else { + GenerateCheckWords(stuffedBits, totalBitsInLayer, wordSize, messageBits); + messageSizeInWords = stuffedBits.size() / wordSize; + GenerateModeMessage(compact, layers, messageSizeInWords, modeMessage); + } // allocate symbol int baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines diff --git a/core/src/aztec/AZEncoder.h b/core/src/aztec/AZEncoder.h index 47311c0c90..b5cd7ff465 100644 --- a/core/src/aztec/AZEncoder.h +++ b/core/src/aztec/AZEncoder.h @@ -36,6 +36,7 @@ class Encoder public: static const int DEFAULT_EC_PERCENT = 33; // default minimal percentage of error check words static const int DEFAULT_AZTEC_LAYERS = 0; + static const int AZTEC_RUNE_LAYERS = 0xFF; static EncodeResult Encode(const std::string& data, int minECCPercent, int userSpecifiedLayers); }; diff --git a/test/unit/aztec/AZEncodeDecodeTest.cpp b/test/unit/aztec/AZEncodeDecodeTest.cpp index 47b9cb063b..8e84fe1a1d 100644 --- a/test/unit/aztec/AZEncodeDecodeTest.cpp +++ b/test/unit/aztec/AZEncodeDecodeTest.cpp @@ -10,6 +10,7 @@ #include "PseudoRandom.h" #include "TextEncoder.h" #include "aztec/AZDecoder.h" +#include "aztec/AZDetector.h" #include "aztec/AZDetectorResult.h" #include "aztec/AZEncoder.h" #include "aztec/AZWriter.h" @@ -228,3 +229,17 @@ TEST(AZEncodeDecodeTest, AztecWriter) Aztec::Encoder::DEFAULT_EC_PERCENT, Aztec::Encoder::DEFAULT_AZTEC_LAYERS); EXPECT_EQ(matrix, aztec.matrix); } + +TEST(AZEncodeDecodeTest, RunePure) +{ + for(uint8_t word = 0; word < 255; word++) { + std::string data(1, word); + Aztec::EncodeResult aztec = + Aztec::Encoder::Encode(data, 0, Aztec::Encoder::AZTEC_RUNE_LAYERS); + + auto result = Aztec::Detect(aztec.matrix, true, false); + EXPECT_TRUE(result.isValid()); + EXPECT_EQ(result.nbDatablocks(), 0); + EXPECT_EQ(result.runeValue(), word); + } +} \ No newline at end of file diff --git a/test/unit/aztec/AZEncoderTest.cpp b/test/unit/aztec/AZEncoderTest.cpp index 045f15e3f3..06acb2e641 100644 --- a/test/unit/aztec/AZEncoderTest.cpp +++ b/test/unit/aztec/AZEncoderTest.cpp @@ -200,3 +200,52 @@ TEST(AZEncoderTest, BorderCompact4Case) EXPECT_TRUE(aztec.compact); EXPECT_EQ(aztec.layers, 4); } + + +TEST(AZEncoderTest, Rune) +{ + { + Aztec::EncodeResult aztec = Aztec::Encoder::Encode("\x19", 0, Aztec::Encoder::AZTEC_RUNE_LAYERS); + + EXPECT_EQ(aztec.layers, 0); + EXPECT_EQ(aztec.matrix, ParseBitMatrix( + "X X X X X X X \n" + "X X X X X X X X X X X \n" + " X X X \n" + " X X X X X X X X \n" + " X X X X \n" + "X X X X X X X \n" + "X X X X X X \n" + "X X X X X X X X \n" + "X X X X \n" + " X X X X X X X X X X \n" + " X X \n" + )); + } + { + Aztec::EncodeResult aztec = Aztec::Encoder::Encode("\xFF", 0, Aztec::Encoder::AZTEC_RUNE_LAYERS); + + EXPECT_EQ(aztec.layers, 0); + EXPECT_EQ(aztec.matrix, ParseBitMatrix( + "X X X X X X \n" + "X X X X X X X X X X X \n" + " X X X \n" + "X X X X X X X X X \n" + "X X X X X X \n" + " X X X X X X \n" + " X X X X \n" + "X X X X X X X X X \n" + "X X X \n" + " X X X X X X X X X X \n" + " X X X X X \n" + )); + } + { + Aztec::EncodeResult aztec = Aztec::Encoder::Encode("\x44", 0, Aztec::Encoder::AZTEC_RUNE_LAYERS); + + std::cout << ToString(aztec.matrix, 'X', ' ', true); + } + + + +} \ No newline at end of file From 672e794e31cc9dddf410cefc6be2cc2e2237fa3e Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 15 Apr 2024 12:53:28 +1000 Subject: [PATCH 07/10] aztec: Conform to the spec Turns out, you're supposed to report rune values as a string of the decimal value...? Also runes don't support ECI. --- core/src/aztec/AZDecoder.cpp | 7 +++++-- test/samples/aztec-1/rune-1.bin | 1 - test/samples/aztec-1/rune-1.txt | 1 + test/samples/aztec-1/rune-223.bin | 1 - test/samples/aztec-1/rune-223.txt | 1 + test/samples/aztec-1/rune-64.bin | 1 - test/samples/aztec-1/rune-64.txt | 1 + test/samples/aztec-1/rune-68.bin | 1 - test/samples/aztec-1/rune-68.txt | 1 + 9 files changed, 9 insertions(+), 6 deletions(-) delete mode 100644 test/samples/aztec-1/rune-1.bin create mode 100644 test/samples/aztec-1/rune-1.txt delete mode 100644 test/samples/aztec-1/rune-223.bin create mode 100644 test/samples/aztec-1/rune-223.txt delete mode 100644 test/samples/aztec-1/rune-64.bin create mode 100644 test/samples/aztec-1/rune-64.txt delete mode 100644 test/samples/aztec-1/rune-68.bin create mode 100644 test/samples/aztec-1/rune-68.txt diff --git a/core/src/aztec/AZDecoder.cpp b/core/src/aztec/AZDecoder.cpp index ed1aa713f5..f38fbe3fef 100644 --- a/core/src/aztec/AZDecoder.cpp +++ b/core/src/aztec/AZDecoder.cpp @@ -14,6 +14,7 @@ #include "GenericGF.h" #include "ReedSolomonDecoder.h" #include "ZXTestSupport.h" +#include "ZXAlgorithms.h" #include #include @@ -348,9 +349,11 @@ DecoderResult Decode(const BitArray& bits) DecoderResult DecodeRune(const DetectorResult& detectorResult) { Content res; - res.symbology = {'z', 'C', 3}; + res.symbology = {'z', 'C', 0}; // Runes cannot have ECI - res.push_back(detectorResult.runeValue()); + // Bizarrely, this is what it says to do in the spec + auto runeString = ToString(detectorResult.runeValue(), 3); + res.append(runeString); return DecoderResult(std::move(res)); } diff --git a/test/samples/aztec-1/rune-1.bin b/test/samples/aztec-1/rune-1.bin deleted file mode 100644 index 6b2aaa7640..0000000000 --- a/test/samples/aztec-1/rune-1.bin +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/test/samples/aztec-1/rune-1.txt b/test/samples/aztec-1/rune-1.txt new file mode 100644 index 0000000000..0f3016682b --- /dev/null +++ b/test/samples/aztec-1/rune-1.txt @@ -0,0 +1 @@ +001 \ No newline at end of file diff --git a/test/samples/aztec-1/rune-223.bin b/test/samples/aztec-1/rune-223.bin deleted file mode 100644 index 7136b4c89b..0000000000 --- a/test/samples/aztec-1/rune-223.bin +++ /dev/null @@ -1 +0,0 @@ -ß \ No newline at end of file diff --git a/test/samples/aztec-1/rune-223.txt b/test/samples/aztec-1/rune-223.txt new file mode 100644 index 0000000000..fca7fbef0e --- /dev/null +++ b/test/samples/aztec-1/rune-223.txt @@ -0,0 +1 @@ +223 \ No newline at end of file diff --git a/test/samples/aztec-1/rune-64.bin b/test/samples/aztec-1/rune-64.bin deleted file mode 100644 index b516b2c489..0000000000 --- a/test/samples/aztec-1/rune-64.bin +++ /dev/null @@ -1 +0,0 @@ -@ \ No newline at end of file diff --git a/test/samples/aztec-1/rune-64.txt b/test/samples/aztec-1/rune-64.txt new file mode 100644 index 0000000000..06b7423029 --- /dev/null +++ b/test/samples/aztec-1/rune-64.txt @@ -0,0 +1 @@ +064 \ No newline at end of file diff --git a/test/samples/aztec-1/rune-68.bin b/test/samples/aztec-1/rune-68.bin deleted file mode 100644 index 02358d2358..0000000000 --- a/test/samples/aztec-1/rune-68.bin +++ /dev/null @@ -1 +0,0 @@ -D \ No newline at end of file diff --git a/test/samples/aztec-1/rune-68.txt b/test/samples/aztec-1/rune-68.txt new file mode 100644 index 0000000000..9c93a7313c --- /dev/null +++ b/test/samples/aztec-1/rune-68.txt @@ -0,0 +1 @@ +068 \ No newline at end of file From 39e3fe1c489f4d8b6927270a153f167ade43a1df Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 15 Apr 2024 13:11:46 +1000 Subject: [PATCH 08/10] aztec: Implement requested changes --- core/src/aztec/AZDetector.cpp | 8 ++++---- core/src/aztec/AZDetectorResult.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/aztec/AZDetector.cpp b/core/src/aztec/AZDetector.cpp index 7d047e888a..51975958d6 100644 --- a/core/src/aztec/AZDetector.cpp +++ b/core/src/aztec/AZDetector.cpp @@ -302,9 +302,9 @@ static int ModeMessage(const BitMatrix& image, const PerspectiveTransform& mod2P if ((!decodeResult) && compact) { // Is this a Rune? - for (int i = numCodewords - 1; i >= 0; --i) { - words[i] ^= 0b1010; - } + for (auto& word : words) + word ^= 0b1010; + decodeResult = ReedSolomonDecode(GenericGF::AztecParam(), words, numECCodewords); if (decodeResult) @@ -432,7 +432,7 @@ DetectorResults Detect(const BitMatrix& image, bool isPure, bool tryHarder, int if (!bits.isValid()) continue; - res.emplace_back(std::move(bits), radius == 5, nbDataBlocks, nbLayers, readerInit, mirror != 0, isRune ? modeMessage : 0); + res.emplace_back(std::move(bits), radius == 5, nbDataBlocks, nbLayers, readerInit, mirror != 0, isRune ? modeMessage : -1); if (Size(res) == maxSymbols) break; diff --git a/core/src/aztec/AZDetectorResult.h b/core/src/aztec/AZDetectorResult.h index f2cc4f50e2..da8248ed92 100644 --- a/core/src/aztec/AZDetectorResult.h +++ b/core/src/aztec/AZDetectorResult.h @@ -19,7 +19,7 @@ class DetectorResult : public ZXing::DetectorResult int _nbLayers = 0; bool _readerInit = false; bool _isMirrored = false; - uint8_t _runeValue = 0; + int _runeValue = 0; DetectorResult(const DetectorResult&) = delete; DetectorResult& operator=(const DetectorResult&) = delete; @@ -29,7 +29,7 @@ class DetectorResult : public ZXing::DetectorResult DetectorResult(DetectorResult&&) noexcept = default; DetectorResult& operator=(DetectorResult&&) noexcept = default; - DetectorResult(ZXing::DetectorResult&& result, bool isCompact, int nbDatablocks, int nbLayers, bool readerInit, bool isMirrored, uint8_t runeValue) + DetectorResult(ZXing::DetectorResult&& result, bool isCompact, int nbDatablocks, int nbLayers, bool readerInit, bool isMirrored, int runeValue) : ZXing::DetectorResult{std::move(result)}, _compact(isCompact), _nbDatablocks(nbDatablocks), @@ -46,7 +46,7 @@ class DetectorResult : public ZXing::DetectorResult bool isMirrored() const { return _isMirrored; } // Only meaningful is nbDatablocks == 0 - uint8_t runeValue() const { return _runeValue; } + int runeValue() const { return _runeValue; } }; } // namespace ZXing::Aztec From e56570f9c149d370ba599a04599b73a8b7229b2b Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 15 Apr 2024 13:17:32 +1000 Subject: [PATCH 09/10] aztec: tinify PNGs --- test/samples/aztec-1/rune-1.png | Bin 2039 -> 169 bytes test/samples/aztec-1/rune-223.png | Bin 1950 -> 169 bytes test/samples/aztec-1/rune-64.png | Bin 1690 -> 154 bytes test/samples/aztec-1/rune-68.png | Bin 1778 -> 147 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/samples/aztec-1/rune-1.png b/test/samples/aztec-1/rune-1.png index 2536b51074d10bd5c1959bfe6dc092f35cf585a3..3fbb06cd88be4087aad0100fd763b480408059f9 100644 GIT binary patch delta 153 zcmV;K0A~O952*o=7=Hl+00005R}29F000J1OjJex|Nj6009C@%egFUfUP(kjRCwC$ z(6I@?AQ(j90|#&Twu!d1(2!|+^P}bv zZOS26Nwo8`nuGTKnN8c;jdrwwwlz<*RdTHZP_}B&MWD-hf6rRt<00000NkvXX Hu0mjf5Ys_t literal 2039 zcmc&#U2GIp6doE(0Yj7k(P)}XrVolT|1CQ^bS!nZrK_E`DVtC3*Ju3a5nOQ@%( zZ=|TDXRY*bFs%2f5ZfFuv4ObIb_trIIyyraz!4PC2FhBF#w@&Xh@mZ0W45;Ig6<|z z&gz};(3Xk*G@KZLag*u1gYF1bLSUl+(4n1od^OaV60b_;(K64_B}g!$F zCKm**%Jaoykt@m^_OiSfkH>jI;w6bC2-Y8W0uZu}-&$ozA|HB|8(7$(BSv80LZC6k z*|G}TtmD@=I1)&Vpv1w(->p~R* zx&lh-#smTQTd)b$4EAh5BwIGfBHnef3|$MPn!tJN5yQkgx#Weet0~71fCEt~sWC(~ zXIZ8yZjclMBFGv@6xg;l7-N-KOktIb5sSr9Off`M-Jis;5aqVI-~5;R2Rw@$FOa`# zp6Jj;MWOauK1tVjTKKOk2z$Li!i!F2j7B z35vi&U0D*Xe^5|7ai5RQVp$2lSY+wlW#_gEC(R(5)*2CcsI@ZWkpAV7Ms?S&o=J*o zdLfnUN{7>@zU_M8J>mLIpS^hY;?^;K@Xb}H_Z?X{wYvG|sYjb<3io|^!-f3|=bO*; zyxdA}Z2BLD&U4rO_RT#%&EU5Wu@^4BcH-ezjjvbjX<0J2co>$C8=bSyhR;l0+HY;% zG`7@SJZ%4A+wK=D^AR=*%%W$ew}ZTXIs~P z@#G^XmmOI=yz?o0_@m9~`V3{xh!=E3aIG8>{)QPk^J*r#aQ#pM2@g?K}Sf=`f*# diff --git a/test/samples/aztec-1/rune-223.png b/test/samples/aztec-1/rune-223.png index 1168d6bf4942db98569522ccd57eef178d6238d5..784a0649c372897155a1dc440127eedb332b6697 100644 GIT binary patch delta 153 zcmV;K0A~N552*o=7=Hl+0002S|Iq#b000J1OjJex|Nj6009C@%egFUfUP(kjR9M69 z)iDadAPh#~zf+IVqvom}!^zYZkyz+#hW8CYc%udd?02}A)1T3#tI}qRXrUDiM*F^{ zuE~mMlfCPuKFlj^X?@T#+(Y`7X{WQbailFQ{^2wL0RG&PY!XVsXwWO}00000NkvXX Hu0mjfP8LQ| literal 1950 zcmcgtTWs4@7ZO%p;)GcJNn!|^R?Vz*u?Nm--TrL%@X(%38*kf4QPie%e`S^6H8SJgxHhOjY({{Nvnb-5HbGNVcaLuaIEg$ui}Hr0GMC;y!_bDVG7rTx zUbB;^VD!&8Xmn;M17{|otTR2k>26;k4ou_$+Bb`qtN1EY^{bF^@S0=jD#V*qncjeq z9@mEHBz6!jM+6q~yhz98h@J(K4y0`C9$Mr@i4#Olh_M2%L`6l4)AfrXgpQt5MpF0J z>BvlF3Z7>x99JrpA|)w;ojfPVvdr-!CyFdVux{D%fX`ZPN5ex3xzI6e&%hQPcm!EI z<*5t_wx+_gL${V&&lJfS=L4G)B7C5#3e;hUv!|S5m0X7$Dk2kEo=dPoh_wsY!)^hu z;X3?$6#>bvriC0WV=>K;!u9&5iHv$eTB6-d*+$$5a`BV{QQtHPvm;PrD@g|d4?7u* zi;Y?hH$tYxSfrEQp#f-Efry<~EI}#YA(bI@i?V!_6fGk}6<$(!VHYVN&)1+D){R`b zB{ZrCiL0Pw-{`;t{|eTjlEaP(h-AYAdBoXPo}t4;DoI?#4k0GdN!2JcO-Wm>2P}xv zDU~6rBZi?X0Cq}IUWRNg5fj*GBAQ@j9U``qj|nj;7Y95N8|zaTP6f4Xtk_)i-~S-<6-+f1z^j+n>8HeZ233H#+F9_Sc&Yf0Mkm z2fuJRy0FFG+JbBr{xtI0>7}>cd1>+Cms>_M`}n{qytuh?Z1Iyn7R2rR%7(Lt4=y*G z+viV=|8o8o>D*)ar4#|KMX3-4UM;|ThuWl9pcfd>z$ z*~OD%%ky33wF$l-tQ;9^kqDBUi-%(G#xMAF!XD=P(WKiUB zxyT>gpt`iw+l#R=vU8E{8GD{R(R_|~WnBCD-R&u`dhEe$6BKEm_81@iIFtpPq4aUWCgv3<*pEUEQno*jLM4G#j2Ix4TeX+kJR&9UAb{D7P z1Q$SnKpO{2Ck{*qp$ahxR#ku|aR7=sU>gU6WojZt=p287iF znKva#Ve^_`Rk3PewVJz^RU}0fWkr;8yey%tg48_Q{cvC~uxhAW*wZx!Pde9#A|Huj zv)L4ysz8IfC~KM~N{Xl`JRtb6=wd z>^%lHZ7&I8=PDIaz!A|os9Tno;Hy>S9Fnp~miwT9lGK43)Us=>ze9H+DUam-HBjgq z3rF~0!Ip_?G;lG5Y`eHlMBl4(Y???kL>(G{Ven3Edtn%;dwR%d7^uAY_{D82%AZN>ztVsmRMZ(wSB`G=+HJB1W5m(+#Og*Yf%#iWUvm| z`VS2yg8O1Ji=9Zs^+C2}tLC-`hh>l)(?tXi=_(^0?5_Y8)muMKUuBq0drO7EN<6cC z;i2cAmbTr0dg0O^b58T6a`489nU%g1@xqsx!A~z{j$YR0(I@exkN!M7@nqri=a1aE zQ!UqyEf!yWS;^cD%W}-TIPzKkvDV{iyl0)5EPeCa*_DOwg}$xRhn?-9K-NIc?OI-3 zKEM6jJUMrM{+Tt*09e({~U@2d@EKOMS!>WAvXJx8wbzWB=Aw%K^;$on6^-SP37 z=-8q&u<+{(zpH(->m3DaXWm;mbRE%aSC&7Vzxw9f>lc1G89uU_u$=|6bj!O(rLXVG SAD>VDJxaqPg?An}@YG+Rzeyqh diff --git a/test/samples/aztec-1/rune-68.png b/test/samples/aztec-1/rune-68.png index 23720bb3309730cc0e250b96bd2d10d991e33e27..bb7086941fa42bf9058d8525ce04695b9cc5ff84 100644 GIT binary patch delta 130 zcmeywJDG8UL^UHb0|SHigM#BgiY>q=#P$FG|3GHwq04nZ%EQyeF+}71)^mn@42m4A zfh)dA$XxxpOs?7M4`=IN6~CT6T?yL*x7zP*y&_mS>r%hSEyIa!$MO$8S?O4^{R-2o h*DHN2gG*h`TNx&s{kiYS_!ej;gQu&X%Q~loCIGYuH17Za literal 1778 zcmbVNTWB0r7@n3E($uK5qT;0vr;4?8c5XY_?6KPrvm1BQOd2;^8ZQr?J?G5skexZ> z%xrcOlv*EzyaIojSWkflFXYeBYZ-_QNI01S1Cc{Z6HK-@V)(>!pKCxgvJ=Ai?S1C{q zLl4SwtyYWG^ceF?vYJdLWkr)UP2vbCn07-{m)u}yn;}gD?Au;wGgpilQIS={6yU)& zvv9l)tsAr|#cL+lkteG$CCaJ+B)Eg~s(z*6oM4$&s6*W_;8?YT^~x+{L7Clvy0d+q z172Oz?D$wU7RTwh2*S)1Poq_kRnb9V+M{xw2CV91nwjEZ?u@eW;Gj=Y$ov9hm9|!6 z?T|&yi1muQOoVMWO5%|fCNzygngU$6xTM6nXazM6RRikA9xkAwG@&LVwl%#fGzqod z>!7@E2nx~vf(eEe^Bu%fwjETWvgek7*eN6&WEJLf$2>Z{5rt{OoEwD5#Wa^r0iJct zwh1IuPb5g3NV?UhN^wFo3H8xlso0k!ii(Rm*0i>Ln&E1sZQGu3d#ve+WZW<$#j*@3 zjuDbjZ$go%f{eID`bbfsZTkbh&5swV+%!*g=%S{8Sv%lzO}Ea(IDNkLRI$ZIA3%ho z{!RfL2}=oRy|!1W!1^+1($>n9ldd6m6BaNltRbHclz6q)(NOY@!Vl2Y+QF|+zBPhh z*?>0}e5>voykmHPVMu#`%J#) z6+W}i=h6d(@{y&ZpLc&L-mC(Qf_ulvF@TLOz{?y4G2lv0Xn0xE>XgS7yTI|37hdm<;2hO}v04KH` z`D4fOHy>TTW6OAc_NC!X;M%YA2S2#{?c2&jb6xMJPt1M#=b5=fqi0*&$BvyJy7=Lp zoO#>s%+>neyMJpNE Date: Tue, 16 Apr 2024 09:47:07 +1000 Subject: [PATCH 10/10] aztec: fix initial value for _runeValue in AZDetectorResult --- core/src/aztec/AZDetectorResult.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/aztec/AZDetectorResult.h b/core/src/aztec/AZDetectorResult.h index da8248ed92..37e60a1554 100644 --- a/core/src/aztec/AZDetectorResult.h +++ b/core/src/aztec/AZDetectorResult.h @@ -19,7 +19,7 @@ class DetectorResult : public ZXing::DetectorResult int _nbLayers = 0; bool _readerInit = false; bool _isMirrored = false; - int _runeValue = 0; + int _runeValue = -1; DetectorResult(const DetectorResult&) = delete; DetectorResult& operator=(const DetectorResult&) = delete; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy