From 13a25580a3e2a29b2b6653802d58d39056f3eaf2 Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Wed, 29 Jan 2020 17:52:21 +0000 Subject: [PATCH] Simplified QrCode.getPenalty() in all language versions except Rust, related to commit 1439e8e4a5a9. --- c/qrcodegen.c | 22 +++++++++---------- cpp/QrCode.cpp | 16 ++++++-------- cpp/QrCode.hpp | 2 +- .../main/java/io/nayuki/qrcodegen/QrCode.java | 16 ++++++-------- python/qrcodegen.py | 22 ++++++++++--------- typescript-javascript/qrcodegen.ts | 20 ++++++++--------- 6 files changed, 46 insertions(+), 52 deletions(-) diff --git a/c/qrcodegen.c b/c/qrcodegen.c index cf7cd64..31219a7 100644 --- a/c/qrcodegen.c +++ b/c/qrcodegen.c @@ -74,7 +74,7 @@ static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qr static long getPenaltyScore(const uint8_t qrcode[]); static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize); static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize); -static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7]); +static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize); testable bool getModule(const uint8_t qrcode[], int x, int y); testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack); @@ -642,7 +642,6 @@ static long getPenaltyScore(const uint8_t qrcode[]) { bool runColor = false; int runX = 0; int runHistory[7] = {0}; - int padRun = qrsize; // Add white border to initial run for (int x = 0; x < qrsize; x++) { if (getModule(qrcode, x, y) == runColor) { runX++; @@ -651,22 +650,20 @@ static long getPenaltyScore(const uint8_t qrcode[]) { else if (runX > 5) result++; } else { - finderPenaltyAddHistory(runX + padRun, runHistory); - padRun = 0; + finderPenaltyAddHistory(runX, runHistory, qrsize); if (!runColor) result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; runColor = getModule(qrcode, x, y); runX = 1; } } - result += finderPenaltyTerminateAndCount(runColor, runX + padRun, runHistory, qrsize) * PENALTY_N3; + result += finderPenaltyTerminateAndCount(runColor, runX, runHistory, qrsize) * PENALTY_N3; } // Adjacent modules in column having same color, and finder-like patterns for (int x = 0; x < qrsize; x++) { bool runColor = false; int runY = 0; int runHistory[7] = {0}; - int padRun = qrsize; // Add white border to initial run for (int y = 0; y < qrsize; y++) { if (getModule(qrcode, x, y) == runColor) { runY++; @@ -675,15 +672,14 @@ static long getPenaltyScore(const uint8_t qrcode[]) { else if (runY > 5) result++; } else { - finderPenaltyAddHistory(runY + padRun, runHistory); - padRun = 0; + finderPenaltyAddHistory(runY, runHistory, qrsize); if (!runColor) result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; runColor = getModule(qrcode, x, y); runY = 1; } } - result += finderPenaltyTerminateAndCount(runColor, runY + padRun, runHistory, qrsize) * PENALTY_N3; + result += finderPenaltyTerminateAndCount(runColor, runY, runHistory, qrsize) * PENALTY_N3; } // 2*2 blocks of modules having same color @@ -729,17 +725,19 @@ static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize) { // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize) { if (currentRunColor) { // Terminate black run - finderPenaltyAddHistory(currentRunLength, runHistory); + finderPenaltyAddHistory(currentRunLength, runHistory, qrsize); currentRunLength = 0; } currentRunLength += qrsize; // Add white border to final run - finderPenaltyAddHistory(currentRunLength, runHistory); + finderPenaltyAddHistory(currentRunLength, runHistory, qrsize); return finderPenaltyCountPatterns(runHistory, qrsize); } // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). -static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7]) { +static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize) { + if (runHistory[0] == 0) + currentRunLength += qrsize; // Add white border to initial run memmove(&runHistory[1], &runHistory[0], 6 * sizeof(runHistory[0])); runHistory[0] = currentRunLength; } diff --git a/cpp/QrCode.cpp b/cpp/QrCode.cpp index ad1fa74..b9de862 100644 --- a/cpp/QrCode.cpp +++ b/cpp/QrCode.cpp @@ -625,7 +625,6 @@ long QrCode::getPenaltyScore() const { bool runColor = false; int runX = 0; std::array runHistory = {}; - int padRun = size; // Add white border to initial run for (int x = 0; x < size; x++) { if (module(x, y) == runColor) { runX++; @@ -634,22 +633,20 @@ long QrCode::getPenaltyScore() const { else if (runX > 5) result++; } else { - finderPenaltyAddHistory(runX + padRun, runHistory); - padRun = 0; + finderPenaltyAddHistory(runX, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; runColor = module(x, y); runX = 1; } } - result += finderPenaltyTerminateAndCount(runColor, runX + padRun, runHistory) * PENALTY_N3; + result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; } // Adjacent modules in column having same color, and finder-like patterns for (int x = 0; x < size; x++) { bool runColor = false; int runY = 0; std::array runHistory = {}; - int padRun = size; // Add white border to initial run for (int y = 0; y < size; y++) { if (module(x, y) == runColor) { runY++; @@ -658,15 +655,14 @@ long QrCode::getPenaltyScore() const { else if (runY > 5) result++; } else { - finderPenaltyAddHistory(runY + padRun, runHistory); - padRun = 0; + finderPenaltyAddHistory(runY, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; runColor = module(x, y); runY = 1; } } - result += finderPenaltyTerminateAndCount(runColor, runY + padRun, runHistory) * PENALTY_N3; + result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; } // 2*2 blocks of modules having same color @@ -807,7 +803,9 @@ int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunL } -void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) { +void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const { + if (runHistory.at(0) == 0) + currentRunLength += size; // Add white border to initial run std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end()); runHistory.at(0) = currentRunLength; } diff --git a/cpp/QrCode.hpp b/cpp/QrCode.hpp index bcc0426..7341e41 100644 --- a/cpp/QrCode.hpp +++ b/cpp/QrCode.hpp @@ -482,7 +482,7 @@ class QrCode final { // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). - private: static void finderPenaltyAddHistory(int currentRunLength, std::array &runHistory); + private: void finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const; // Returns true iff the i'th bit of x is set to 1. diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java index c0a8871..ea0196c 100644 --- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java +++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java @@ -600,7 +600,6 @@ public final class QrCode { boolean runColor = false; int runX = 0; int[] runHistory = new int[7]; - int padRun = size; // Add white border to initial run for (int x = 0; x < size; x++) { if (modules[y][x] == runColor) { runX++; @@ -609,22 +608,20 @@ public final class QrCode { else if (runX > 5) result++; } else { - finderPenaltyAddHistory(runX + padRun, runHistory); - padRun = 0; + finderPenaltyAddHistory(runX, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; runColor = modules[y][x]; runX = 1; } } - result += finderPenaltyTerminateAndCount(runColor, runX + padRun, runHistory) * PENALTY_N3; + result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; } // Adjacent modules in column having same color, and finder-like patterns for (int x = 0; x < size; x++) { boolean runColor = false; int runY = 0; int[] runHistory = new int[7]; - int padRun = size; // Add white border to initial run for (int y = 0; y < size; y++) { if (modules[y][x] == runColor) { runY++; @@ -633,15 +630,14 @@ public final class QrCode { else if (runY > 5) result++; } else { - finderPenaltyAddHistory(runY + padRun, runHistory); - padRun = 0; + finderPenaltyAddHistory(runY, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; runColor = modules[y][x]; runY = 1; } } - result += finderPenaltyTerminateAndCount(runColor, runY + padRun, runHistory) * PENALTY_N3; + result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; } // 2*2 blocks of modules having same color @@ -814,7 +810,9 @@ public final class QrCode { // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). - private static void finderPenaltyAddHistory(int currentRunLength, int[] runHistory) { + private void finderPenaltyAddHistory(int currentRunLength, int[] runHistory) { + if (runHistory[0] == 0) + currentRunLength += size; // Add white border to initial run System.arraycopy(runHistory, 0, runHistory, 1, runHistory.length - 1); runHistory[0] = currentRunLength; } diff --git a/python/qrcodegen.py b/python/qrcodegen.py index 93c0e85..260ace8 100644 --- a/python/qrcodegen.py +++ b/python/qrcodegen.py @@ -467,7 +467,6 @@ class QrCode(object): runcolor = False runx = 0 runhistory = collections.deque([0] * 7, 7) - padrun = size # Add white border to initial run for x in range(size): if modules[y][x] == runcolor: runx += 1 @@ -476,19 +475,17 @@ class QrCode(object): elif runx > 5: result += 1 else: - runhistory.appendleft(runx + padrun) - padrun = 0 + self._finder_penalty_add_history(runx, runhistory) if not runcolor: result += self._finder_penalty_count_patterns(runhistory) * QrCode._PENALTY_N3 runcolor = modules[y][x] runx = 1 - result += self._finder_penalty_terminate_and_count(runcolor, runx + padrun, runhistory) * QrCode._PENALTY_N3 + result += self._finder_penalty_terminate_and_count(runcolor, runx, runhistory) * QrCode._PENALTY_N3 # Adjacent modules in column having same color, and finder-like patterns for x in range(size): runcolor = False runy = 0 runhistory = collections.deque([0] * 7, 7) - padrun = size # Add white border to initial run for y in range(size): if modules[y][x] == runcolor: runy += 1 @@ -497,13 +494,12 @@ class QrCode(object): elif runy > 5: result += 1 else: - runhistory.appendleft(runy + padrun) - padrun = 0 + self._finder_penalty_add_history(runy, runhistory) if not runcolor: result += self._finder_penalty_count_patterns(runhistory) * QrCode._PENALTY_N3 runcolor = modules[y][x] runy = 1 - result += self._finder_penalty_terminate_and_count(runcolor, runy + padrun, runhistory) * QrCode._PENALTY_N3 + result += self._finder_penalty_terminate_and_count(runcolor, runy, runhistory) * QrCode._PENALTY_N3 # 2*2 blocks of modules having same color for y in range(size - 1): @@ -628,13 +624,19 @@ class QrCode(object): def _finder_penalty_terminate_and_count(self, currentruncolor, currentrunlength, runhistory): """Must be called at the end of a line (row or column) of modules. A helper function for _get_penalty_score().""" if currentruncolor: # Terminate black run - runhistory.appendleft(currentrunlength) + self._finder_penalty_add_history(currentrunlength, runhistory) currentrunlength = 0 currentrunlength += self._size # Add white border to final run - runhistory.appendleft(currentrunlength) + self._finder_penalty_add_history(currentrunlength, runhistory) return self._finder_penalty_count_patterns(runhistory) + def _finder_penalty_add_history(self, currentrunlength, runhistory): + if runhistory[0] == 0: + currentrunlength += self._size # Add white border to initial run + runhistory.appendleft(currentrunlength) + + # ---- Constants and tables ---- MIN_VERSION = 1 # The minimum version number supported in the QR Code Model 2 standard diff --git a/typescript-javascript/qrcodegen.ts b/typescript-javascript/qrcodegen.ts index 6480f4a..88663ee 100644 --- a/typescript-javascript/qrcodegen.ts +++ b/typescript-javascript/qrcodegen.ts @@ -515,7 +515,6 @@ namespace qrcodegen { let runColor = false; let runX = 0; let runHistory = [0,0,0,0,0,0,0]; - let padRun = this.size; for (let x = 0; x < this.size; x++) { if (this.modules[y][x] == runColor) { runX++; @@ -524,22 +523,20 @@ namespace qrcodegen { else if (runX > 5) result++; } else { - QrCode.finderPenaltyAddHistory(runX + padRun, runHistory); - padRun = 0; + this.finderPenaltyAddHistory(runX, runHistory); if (!runColor) result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3; runColor = this.modules[y][x]; runX = 1; } } - result += this.finderPenaltyTerminateAndCount(runColor, runX + padRun, runHistory) * QrCode.PENALTY_N3; + result += this.finderPenaltyTerminateAndCount(runColor, runX, runHistory) * QrCode.PENALTY_N3; } // Adjacent modules in column having same color, and finder-like patterns for (let x = 0; x < this.size; x++) { let runColor = false; let runY = 0; let runHistory = [0,0,0,0,0,0,0]; - let padRun = this.size; for (let y = 0; y < this.size; y++) { if (this.modules[y][x] == runColor) { runY++; @@ -548,15 +545,14 @@ namespace qrcodegen { else if (runY > 5) result++; } else { - QrCode.finderPenaltyAddHistory(runY + padRun, runHistory); - padRun = 0; + this.finderPenaltyAddHistory(runY, runHistory); if (!runColor) result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3; runColor = this.modules[y][x]; runY = 1; } } - result += this.finderPenaltyTerminateAndCount(runColor, runY + padRun, runHistory) * QrCode.PENALTY_N3; + result += this.finderPenaltyTerminateAndCount(runColor, runY, runHistory) * QrCode.PENALTY_N3; } // 2*2 blocks of modules having same color @@ -705,17 +701,19 @@ namespace qrcodegen { // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). private finderPenaltyTerminateAndCount(currentRunColor: boolean, currentRunLength: int, runHistory: Array): int { if (currentRunColor) { // Terminate black run - QrCode.finderPenaltyAddHistory(currentRunLength, runHistory); + this.finderPenaltyAddHistory(currentRunLength, runHistory); currentRunLength = 0; } currentRunLength += this.size; // Add white border to final run - QrCode.finderPenaltyAddHistory(currentRunLength, runHistory); + this.finderPenaltyAddHistory(currentRunLength, runHistory); return this.finderPenaltyCountPatterns(runHistory); } // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). - private static finderPenaltyAddHistory(currentRunLength: int, runHistory: Array): void { + private finderPenaltyAddHistory(currentRunLength: int, runHistory: Array): void { + if (runHistory[0] == 0) + currentRunLength += this.size; // Add white border to initial run runHistory.pop(); runHistory.unshift(currentRunLength); }