Simplified QrCode.getPenalty() in all language versions except Rust, related to commit 1439e8e4a5.

pull/84/head
Project Nayuki 6 years ago
parent ae22a368bb
commit 13a25580a3

@ -74,7 +74,7 @@ static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qr
static long getPenaltyScore(const uint8_t qrcode[]); static long getPenaltyScore(const uint8_t qrcode[]);
static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize); static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize);
static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, 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 bool getModule(const uint8_t qrcode[], int x, int y);
testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack); 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; bool runColor = false;
int runX = 0; int runX = 0;
int runHistory[7] = {0}; int runHistory[7] = {0};
int padRun = qrsize; // Add white border to initial run
for (int x = 0; x < qrsize; x++) { for (int x = 0; x < qrsize; x++) {
if (getModule(qrcode, x, y) == runColor) { if (getModule(qrcode, x, y) == runColor) {
runX++; runX++;
@ -651,22 +650,20 @@ static long getPenaltyScore(const uint8_t qrcode[]) {
else if (runX > 5) else if (runX > 5)
result++; result++;
} else { } else {
finderPenaltyAddHistory(runX + padRun, runHistory); finderPenaltyAddHistory(runX, runHistory, qrsize);
padRun = 0;
if (!runColor) if (!runColor)
result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3;
runColor = getModule(qrcode, x, y); runColor = getModule(qrcode, x, y);
runX = 1; 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 // Adjacent modules in column having same color, and finder-like patterns
for (int x = 0; x < qrsize; x++) { for (int x = 0; x < qrsize; x++) {
bool runColor = false; bool runColor = false;
int runY = 0; int runY = 0;
int runHistory[7] = {0}; int runHistory[7] = {0};
int padRun = qrsize; // Add white border to initial run
for (int y = 0; y < qrsize; y++) { for (int y = 0; y < qrsize; y++) {
if (getModule(qrcode, x, y) == runColor) { if (getModule(qrcode, x, y) == runColor) {
runY++; runY++;
@ -675,15 +672,14 @@ static long getPenaltyScore(const uint8_t qrcode[]) {
else if (runY > 5) else if (runY > 5)
result++; result++;
} else { } else {
finderPenaltyAddHistory(runY + padRun, runHistory); finderPenaltyAddHistory(runY, runHistory, qrsize);
padRun = 0;
if (!runColor) if (!runColor)
result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3;
runColor = getModule(qrcode, x, y); runColor = getModule(qrcode, x, y);
runY = 1; 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 // 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(). // 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) { static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize) {
if (currentRunColor) { // Terminate black run if (currentRunColor) { // Terminate black run
finderPenaltyAddHistory(currentRunLength, runHistory); finderPenaltyAddHistory(currentRunLength, runHistory, qrsize);
currentRunLength = 0; currentRunLength = 0;
} }
currentRunLength += qrsize; // Add white border to final run currentRunLength += qrsize; // Add white border to final run
finderPenaltyAddHistory(currentRunLength, runHistory); finderPenaltyAddHistory(currentRunLength, runHistory, qrsize);
return finderPenaltyCountPatterns(runHistory, qrsize); return finderPenaltyCountPatterns(runHistory, qrsize);
} }
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). // 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])); memmove(&runHistory[1], &runHistory[0], 6 * sizeof(runHistory[0]));
runHistory[0] = currentRunLength; runHistory[0] = currentRunLength;
} }

@ -625,7 +625,6 @@ long QrCode::getPenaltyScore() const {
bool runColor = false; bool runColor = false;
int runX = 0; int runX = 0;
std::array<int,7> runHistory = {}; std::array<int,7> runHistory = {};
int padRun = size; // Add white border to initial run
for (int x = 0; x < size; x++) { for (int x = 0; x < size; x++) {
if (module(x, y) == runColor) { if (module(x, y) == runColor) {
runX++; runX++;
@ -634,22 +633,20 @@ long QrCode::getPenaltyScore() const {
else if (runX > 5) else if (runX > 5)
result++; result++;
} else { } else {
finderPenaltyAddHistory(runX + padRun, runHistory); finderPenaltyAddHistory(runX, runHistory);
padRun = 0;
if (!runColor) if (!runColor)
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
runColor = module(x, y); runColor = module(x, y);
runX = 1; 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 // Adjacent modules in column having same color, and finder-like patterns
for (int x = 0; x < size; x++) { for (int x = 0; x < size; x++) {
bool runColor = false; bool runColor = false;
int runY = 0; int runY = 0;
std::array<int,7> runHistory = {}; std::array<int,7> runHistory = {};
int padRun = size; // Add white border to initial run
for (int y = 0; y < size; y++) { for (int y = 0; y < size; y++) {
if (module(x, y) == runColor) { if (module(x, y) == runColor) {
runY++; runY++;
@ -658,15 +655,14 @@ long QrCode::getPenaltyScore() const {
else if (runY > 5) else if (runY > 5)
result++; result++;
} else { } else {
finderPenaltyAddHistory(runY + padRun, runHistory); finderPenaltyAddHistory(runY, runHistory);
padRun = 0;
if (!runColor) if (!runColor)
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
runColor = module(x, y); runColor = module(x, y);
runY = 1; 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 // 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<int,7> &runHistory) { void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &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()); std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
runHistory.at(0) = currentRunLength; runHistory.at(0) = currentRunLength;
} }

@ -482,7 +482,7 @@ class QrCode final {
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). // 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<int,7> &runHistory); private: void finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const;
// Returns true iff the i'th bit of x is set to 1. // Returns true iff the i'th bit of x is set to 1.

@ -600,7 +600,6 @@ public final class QrCode {
boolean runColor = false; boolean runColor = false;
int runX = 0; int runX = 0;
int[] runHistory = new int[7]; int[] runHistory = new int[7];
int padRun = size; // Add white border to initial run
for (int x = 0; x < size; x++) { for (int x = 0; x < size; x++) {
if (modules[y][x] == runColor) { if (modules[y][x] == runColor) {
runX++; runX++;
@ -609,22 +608,20 @@ public final class QrCode {
else if (runX > 5) else if (runX > 5)
result++; result++;
} else { } else {
finderPenaltyAddHistory(runX + padRun, runHistory); finderPenaltyAddHistory(runX, runHistory);
padRun = 0;
if (!runColor) if (!runColor)
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
runColor = modules[y][x]; runColor = modules[y][x];
runX = 1; 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 // Adjacent modules in column having same color, and finder-like patterns
for (int x = 0; x < size; x++) { for (int x = 0; x < size; x++) {
boolean runColor = false; boolean runColor = false;
int runY = 0; int runY = 0;
int[] runHistory = new int[7]; int[] runHistory = new int[7];
int padRun = size; // Add white border to initial run
for (int y = 0; y < size; y++) { for (int y = 0; y < size; y++) {
if (modules[y][x] == runColor) { if (modules[y][x] == runColor) {
runY++; runY++;
@ -633,15 +630,14 @@ public final class QrCode {
else if (runY > 5) else if (runY > 5)
result++; result++;
} else { } else {
finderPenaltyAddHistory(runY + padRun, runHistory); finderPenaltyAddHistory(runY, runHistory);
padRun = 0;
if (!runColor) if (!runColor)
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
runColor = modules[y][x]; runColor = modules[y][x];
runY = 1; 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 // 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(). // 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); System.arraycopy(runHistory, 0, runHistory, 1, runHistory.length - 1);
runHistory[0] = currentRunLength; runHistory[0] = currentRunLength;
} }

@ -467,7 +467,6 @@ class QrCode(object):
runcolor = False runcolor = False
runx = 0 runx = 0
runhistory = collections.deque([0] * 7, 7) runhistory = collections.deque([0] * 7, 7)
padrun = size # Add white border to initial run
for x in range(size): for x in range(size):
if modules[y][x] == runcolor: if modules[y][x] == runcolor:
runx += 1 runx += 1
@ -476,19 +475,17 @@ class QrCode(object):
elif runx > 5: elif runx > 5:
result += 1 result += 1
else: else:
runhistory.appendleft(runx + padrun) self._finder_penalty_add_history(runx, runhistory)
padrun = 0
if not runcolor: if not runcolor:
result += self._finder_penalty_count_patterns(runhistory) * QrCode._PENALTY_N3 result += self._finder_penalty_count_patterns(runhistory) * QrCode._PENALTY_N3
runcolor = modules[y][x] runcolor = modules[y][x]
runx = 1 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 # Adjacent modules in column having same color, and finder-like patterns
for x in range(size): for x in range(size):
runcolor = False runcolor = False
runy = 0 runy = 0
runhistory = collections.deque([0] * 7, 7) runhistory = collections.deque([0] * 7, 7)
padrun = size # Add white border to initial run
for y in range(size): for y in range(size):
if modules[y][x] == runcolor: if modules[y][x] == runcolor:
runy += 1 runy += 1
@ -497,13 +494,12 @@ class QrCode(object):
elif runy > 5: elif runy > 5:
result += 1 result += 1
else: else:
runhistory.appendleft(runy + padrun) self._finder_penalty_add_history(runy, runhistory)
padrun = 0
if not runcolor: if not runcolor:
result += self._finder_penalty_count_patterns(runhistory) * QrCode._PENALTY_N3 result += self._finder_penalty_count_patterns(runhistory) * QrCode._PENALTY_N3
runcolor = modules[y][x] runcolor = modules[y][x]
runy = 1 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 # 2*2 blocks of modules having same color
for y in range(size - 1): for y in range(size - 1):
@ -628,13 +624,19 @@ class QrCode(object):
def _finder_penalty_terminate_and_count(self, currentruncolor, currentrunlength, runhistory): 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().""" """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 if currentruncolor: # Terminate black run
runhistory.appendleft(currentrunlength) self._finder_penalty_add_history(currentrunlength, runhistory)
currentrunlength = 0 currentrunlength = 0
currentrunlength += self._size # Add white border to final run 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) 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 ---- # ---- Constants and tables ----
MIN_VERSION = 1 # The minimum version number supported in the QR Code Model 2 standard MIN_VERSION = 1 # The minimum version number supported in the QR Code Model 2 standard

@ -515,7 +515,6 @@ namespace qrcodegen {
let runColor = false; let runColor = false;
let runX = 0; let runX = 0;
let runHistory = [0,0,0,0,0,0,0]; let runHistory = [0,0,0,0,0,0,0];
let padRun = this.size;
for (let x = 0; x < this.size; x++) { for (let x = 0; x < this.size; x++) {
if (this.modules[y][x] == runColor) { if (this.modules[y][x] == runColor) {
runX++; runX++;
@ -524,22 +523,20 @@ namespace qrcodegen {
else if (runX > 5) else if (runX > 5)
result++; result++;
} else { } else {
QrCode.finderPenaltyAddHistory(runX + padRun, runHistory); this.finderPenaltyAddHistory(runX, runHistory);
padRun = 0;
if (!runColor) if (!runColor)
result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3; result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3;
runColor = this.modules[y][x]; runColor = this.modules[y][x];
runX = 1; 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 // Adjacent modules in column having same color, and finder-like patterns
for (let x = 0; x < this.size; x++) { for (let x = 0; x < this.size; x++) {
let runColor = false; let runColor = false;
let runY = 0; let runY = 0;
let runHistory = [0,0,0,0,0,0,0]; let runHistory = [0,0,0,0,0,0,0];
let padRun = this.size;
for (let y = 0; y < this.size; y++) { for (let y = 0; y < this.size; y++) {
if (this.modules[y][x] == runColor) { if (this.modules[y][x] == runColor) {
runY++; runY++;
@ -548,15 +545,14 @@ namespace qrcodegen {
else if (runY > 5) else if (runY > 5)
result++; result++;
} else { } else {
QrCode.finderPenaltyAddHistory(runY + padRun, runHistory); this.finderPenaltyAddHistory(runY, runHistory);
padRun = 0;
if (!runColor) if (!runColor)
result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3; result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3;
runColor = this.modules[y][x]; runColor = this.modules[y][x];
runY = 1; 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 // 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(). // 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>): int { private finderPenaltyTerminateAndCount(currentRunColor: boolean, currentRunLength: int, runHistory: Array<int>): int {
if (currentRunColor) { // Terminate black run if (currentRunColor) { // Terminate black run
QrCode.finderPenaltyAddHistory(currentRunLength, runHistory); this.finderPenaltyAddHistory(currentRunLength, runHistory);
currentRunLength = 0; currentRunLength = 0;
} }
currentRunLength += this.size; // Add white border to final run currentRunLength += this.size; // Add white border to final run
QrCode.finderPenaltyAddHistory(currentRunLength, runHistory); this.finderPenaltyAddHistory(currentRunLength, runHistory);
return this.finderPenaltyCountPatterns(runHistory); return this.finderPenaltyCountPatterns(runHistory);
} }
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
private static finderPenaltyAddHistory(currentRunLength: int, runHistory: Array<int>): void { private finderPenaltyAddHistory(currentRunLength: int, runHistory: Array<int>): void {
if (runHistory[0] == 0)
currentRunLength += this.size; // Add white border to initial run
runHistory.pop(); runHistory.pop();
runHistory.unshift(currentRunLength); runHistory.unshift(currentRunLength);
} }

Loading…
Cancel
Save