From 9a7a01c9a6b6fb76744eacb2e6fab11eccedfabd Mon Sep 17 00:00:00 2001
From: minsu4107 <32637512+minsu4107@users.noreply.github.com>
Date: Sun, 24 May 2020 16:24:44 +0900
Subject: [PATCH 01/28] test commit
---
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 2 --
1 file changed, 2 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index ea0196c..58c4534 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -198,8 +198,6 @@ public final class QrCode {
return new QrCode(version, ecl, dataCodewords, mask);
}
-
-
/*---- Instance fields ----*/
// Public immutable scalar parameters:
From ce24efed3ccacc18570a16b5a1ac728c116a3fef Mon Sep 17 00:00:00 2001
From: minsu4107 <32637512+minsu4107@users.noreply.github.com>
Date: Mon, 25 May 2020 08:40:17 +0900
Subject: [PATCH 02/28] 1. Extract Method 2. QrSegmenetAdvanced 3. THis class's
'if condition' is so complex, changed more intelligiblement.
---
.../io/nayuki/qrcodegen/QrSegmentAdvanced.java | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
index 1efe7b5..3230d9b 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
@@ -64,14 +64,14 @@ public final class QrSegmentAdvanced {
// Check arguments
Objects.requireNonNull(text);
Objects.requireNonNull(ecl);
- if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION))
+ if (not_Valid_Version(minVersion, maxVersion))
throw new IllegalArgumentException("Invalid value");
// Iterate through version numbers, and make tentative segments
List segs = null;
int[] codePoints = toCodePoints(text);
for (int version = minVersion; ; version++) {
- if (version == minVersion || version == 10 || version == 27)
+ if (is_valid_version(minVersion, version))
segs = makeSegmentsOptimally(codePoints, version);
assert segs != null;
@@ -88,6 +88,16 @@ public final class QrSegmentAdvanced {
}
}
}
+
+
+ private static boolean is_valid_version(int minVersion, int version) {
+ return version == minVersion || version == 10 || version == 27;
+ }
+
+
+ private static boolean not_Valid_Version(int minVersion, int maxVersion) {
+ return !(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION);
+ }
// Returns a new list of segments that is optimal for the given text at the given version number.
@@ -277,8 +287,7 @@ public final class QrSegmentAdvanced {
*/
public static boolean isEncodableAsKanji(String text) {
Objects.requireNonNull(text);
- return text.chars().allMatch(
- c -> isKanji((char)c));
+ return text.chars().allMatch(c -> isKanji((char)c));
}
From 92b35766fbfe960a5fde58f731817ebb475b75fb Mon Sep 17 00:00:00 2001
From: wslbal
Date: Mon, 25 May 2020 10:29:57 +0900
Subject: [PATCH 03/28] =?UTF-8?q?0525=20=EB=A6=AC=ED=8E=99=ED=86=A0?=
=?UTF-8?q?=EB=A7=81=20=EC=A7=84=ED=96=89=ED=95=A0=20=EB=A9=94=EC=86=8C?=
=?UTF-8?q?=EB=93=9C=EC=97=90=20=EC=A3=BC=EC=84=9D=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index ea0196c..c12da77 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -542,7 +542,7 @@ public final class QrCode {
// The function modules must be marked and the codeword bits must be drawn
// before masking. Due to the arithmetic of XOR, calling applyMask() with
// the same mask value a second time will undo the mask. A final well-formed
- // QR Code needs exactly one (not zero, two, etc.) mask applied.
+ // QR Code needs exactly one (not zero, two, etc.) mask applied. switch-statement refactoring
private void applyMask(int msk) {
if (msk < 0 || msk > 7)
throw new IllegalArgumentException("Mask value out of range");
@@ -589,9 +589,9 @@ public final class QrCode {
return msk; // The caller shall assign this value to the final-declared field
}
-
+
// Calculates and returns the penalty score based on state of this QR Code's current modules.
- // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
+ // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. duplication code extract
private int getPenaltyScore() {
int result = 0;
@@ -600,6 +600,7 @@ public final class QrCode {
boolean runColor = false;
int runX = 0;
int[] runHistory = new int[7];
+ result += havingSameColor();
for (int x = 0; x < size; x++) {
if (modules[y][x] == runColor) {
runX++;
@@ -640,7 +641,7 @@ public final class QrCode {
result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
}
- // 2*2 blocks of modules having same color
+ // 2*2 blocks of modules having same color. extract method to reduce method size
for (int y = 0; y < size - 1; y++) {
for (int x = 0; x < size - 1; x++) {
boolean color = modules[y][x];
@@ -694,7 +695,7 @@ public final class QrCode {
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
- // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
+ // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. replace integer to understandable word
private static int getNumRawDataModules(int ver) {
if (ver < MIN_VERSION || ver > MAX_VERSION)
throw new IllegalArgumentException("Version number out of range");
From 750c8ba7aedb55c1a7b1ed6439dac731ac6a5240 Mon Sep 17 00:00:00 2001
From: minsu4107 <32637512+minsu4107@users.noreply.github.com>
Date: Mon, 25 May 2020 14:34:59 +0900
Subject: [PATCH 04/28] 1. Extract Method, introduce explain value 2.
QrSegmenetAdvanced.java 3. THis class had many function. So, declare more
method.
---
.../nayuki/qrcodegen/QrSegmentAdvanced.java | 23 ++++++++++++++-----
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
index 3230d9b..6480897 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
@@ -133,22 +133,22 @@ public final class QrSegmentAdvanced {
// Calculate costs using dynamic programming
for (int i = 0; i < codePoints.length; i++) {
- int c = codePoints[i];
+ int cPoint = codePoints[i];
int[] curCosts = new int[numModes];
{ // Always extend a byte mode segment
- curCosts[0] = prevCosts[0] + countUtf8Bytes(c) * 8 * 6;
+ curCosts[0] = prevCosts[0] + countUtf8Bytes(cPoint) * 8 * 6;
charModes[i][0] = modeTypes[0];
}
// Extend a segment if possible
- if (QrSegment.ALPHANUMERIC_CHARSET.indexOf(c) != -1) { // Is alphanumeric
+ if (is_alphanumeric(cPoint)) { // Is alphanumeric
curCosts[1] = prevCosts[1] + 33; // 5.5 bits per alphanumeric char
charModes[i][1] = modeTypes[1];
}
- if ('0' <= c && c <= '9') { // Is numeric
+ if (is_numeric(cPoint)) { // Is numeric
curCosts[2] = prevCosts[2] + 20; // 3.33 bits per digit
charModes[i][2] = modeTypes[2];
}
- if (isKanji(c)) {
+ if (isKanji(cPoint)) {
curCosts[3] = prevCosts[3] + 78; // 13 bits per Shift JIS char
charModes[i][3] = modeTypes[3];
}
@@ -157,7 +157,8 @@ public final class QrSegmentAdvanced {
for (int j = 0; j < numModes; j++) { // To mode
for (int k = 0; k < numModes; k++) { // From mode
int newCost = (curCosts[k] + 5) / 6 * 6 + headCosts[j];
- if (charModes[i][k] != null && (charModes[i][j] == null || newCost < curCosts[j])) {
+ boolean is_notNull_or_lower = charModes[i][k] != null && (charModes[i][j] == null || newCost < curCosts[j]);
+ if (is_notNull_or_lower) {
curCosts[j] = newCost;
charModes[i][j] = modeTypes[k];
}
@@ -189,6 +190,16 @@ public final class QrSegmentAdvanced {
}
return result;
}
+
+
+ private static boolean is_numeric(int c) {
+ return '0' <= c && c <= '9';
+ }
+
+
+ private static boolean is_alphanumeric(int c) {
+ return QrSegment.ALPHANUMERIC_CHARSET.indexOf(c) != -1;
+ }
// Returns a new list of segments based on the given text and modes, such that
From 8e33477b7447068dcda23c8d552bc132a6d97103 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B9=80=EA=B2=BD=EC=A7=84?= <김경진@DESKTOP-6URC5U8>
Date: Wed, 27 May 2020 09:59:35 +0900
Subject: [PATCH 05/28] Refactoring
Rename
Constructor of QrCode class
Not using abbrebiations
---
.../main/java/io/nayuki/qrcodegen/QrCode.java | 30 +++++++++----------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index ea0196c..fe05d48 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -238,32 +238,32 @@ public final class QrCode {
* error correction level, data codeword bytes, and mask number.
*
This is a low-level API that most users should not use directly. A mid-level
* API is the {@link #encodeSegments(List,Ecc,int,int,int,boolean)} function.
- * @param ver the version number to use, which must be in the range 1 to 40 (inclusive)
- * @param ecl the error correction level to use
+ * @param version the version number to use, which must be in the range 1 to 40 (inclusive)
+ * @param errorCorrectionLevel the error correction level to use
* @param dataCodewords the bytes representing segments to encode (without ECC)
- * @param msk the mask pattern to use, which is either −1 for automatic choice or from 0 to 7 for fixed choice
+ * @param mask the mask pattern to use, which is either −1 for automatic choice or from 0 to 7 for fixed choice
* @throws NullPointerException if the byte array or error correction level is {@code null}
* @throws IllegalArgumentException if the version or mask value is out of range,
* or if the data is the wrong length for the specified version and error correction level
*/
- public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int msk) {
+ public QrCode(int version, Ecc errorCorrectionLevel, byte[] dataCodewords, int mask) {
// Check arguments and initialize fields
- if (ver < MIN_VERSION || ver > MAX_VERSION)
+ if (version < MIN_VERSION || version > MAX_VERSION)
throw new IllegalArgumentException("Version value out of range");
- if (msk < -1 || msk > 7)
+ if (mask < -1 || mask > 7)
throw new IllegalArgumentException("Mask value out of range");
- version = ver;
- size = ver * 4 + 17;
- errorCorrectionLevel = Objects.requireNonNull(ecl);
+ this.version = version;
+ this.size = version * 4 + 17;
+ this.errorCorrectionLevel = Objects.requireNonNull(errorCorrectionLevel);
Objects.requireNonNull(dataCodewords);
- modules = new boolean[size][size]; // Initially all white
- isFunction = new boolean[size][size];
+ this.modules = new boolean[size][size]; // Initially all white
+ this.isFunction = new boolean[size][size];
// Compute ECC, draw modules, do masking
drawFunctionPatterns();
byte[] allCodewords = addEccAndInterleave(dataCodewords);
drawCodewords(allCodewords);
- this.mask = handleConstructorMasking(msk);
+ this.mask = handleConstructorMasking(mask);
isFunction = null;
}
@@ -543,7 +543,7 @@ public final class QrCode {
// before masking. Due to the arithmetic of XOR, calling applyMask() with
// the same mask value a second time will undo the mask. A final well-formed
// QR Code needs exactly one (not zero, two, etc.) mask applied.
- private void applyMask(int msk) {
+ private void applyMask(int msk) {
if (msk < 0 || msk > 7)
throw new IllegalArgumentException("Mask value out of range");
for (int y = 0; y < size; y++) {
@@ -592,7 +592,7 @@ public final class QrCode {
// Calculates and returns the penalty score based on state of this QR Code's current modules.
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
- private int getPenaltyScore() {
+ private int getPenaltyScore() {
int result = 0;
// Adjacent modules in row having same color, and finder-like patterns
@@ -695,7 +695,7 @@ public final class QrCode {
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
- private static int getNumRawDataModules(int ver) {
+ private static int getNumRawDataModules(int ver) {
if (ver < MIN_VERSION || ver > MAX_VERSION)
throw new IllegalArgumentException("Version number out of range");
From 15f548220b098a799ef97b3c74a27233147b8963 Mon Sep 17 00:00:00 2001
From: wslbal
Date: Wed, 27 May 2020 10:18:04 +0900
Subject: [PATCH 06/28] =?UTF-8?q?0527=20extract=20method=20=EC=A0=81?=
=?UTF-8?q?=EC=9A=A9=20/=20switch=20=EB=AC=B8=EC=9E=A5=20Command=20pattern?=
=?UTF-8?q?=20=EC=A0=81=EC=9A=A9=ED=95=A0=20=EC=98=88=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../main/java/io/nayuki/qrcodegen/QrCode.java | 432 +++++++++---------
1 file changed, 220 insertions(+), 212 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index c12da77..fbc50d9 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -51,9 +51,9 @@ import java.util.Objects;
* @see QrSegment
*/
public final class QrCode {
-
+
/*---- Static factory functions (high level) ----*/
-
+
/**
* Returns a QR Code representing the specified Unicode text string at the specified error correction level.
* As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
@@ -73,8 +73,8 @@ public final class QrCode {
List segs = QrSegment.makeSegments(text);
return encodeSegments(segs, ecl);
}
-
-
+
+
/**
* Returns a QR Code representing the specified binary data at the specified error correction level.
* This function always encodes using the binary segment mode, not any text mode. The maximum number of
@@ -93,10 +93,10 @@ public final class QrCode {
QrSegment seg = QrSegment.makeBytes(data);
return encodeSegments(Arrays.asList(seg), ecl);
}
-
-
+
+
/*---- Static factory functions (mid level) ----*/
-
+
/**
* Returns a QR Code representing the specified segments at the specified error correction
* level. The smallest possible QR Code version is automatically chosen for the output. The ECC level
@@ -115,8 +115,8 @@ public final class QrCode {
public static QrCode encodeSegments(List segs, Ecc ecl) {
return encodeSegments(segs, ecl, MIN_VERSION, MAX_VERSION, -1, true);
}
-
-
+
+
/**
* Returns a QR Code representing the specified segments with the specified encoding parameters.
* The smallest possible QR Code version within the specified range is automatically
@@ -146,7 +146,7 @@ public final class QrCode {
Objects.requireNonNull(ecl);
if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
throw new IllegalArgumentException("Invalid value");
-
+
// Find the minimal version number to use
int version, dataUsedBits;
for (version = minVersion; ; version++) {
@@ -162,13 +162,13 @@ public final class QrCode {
}
}
assert dataUsedBits != -1;
-
+
// Increase the error correction level while the data still fits in the current version number
for (Ecc newEcl : Ecc.values()) { // From low to high
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
ecl = newEcl;
}
-
+
// Concatenate all segments to create the data bit string
BitBuffer bb = new BitBuffer();
for (QrSegment seg : segs) {
@@ -177,62 +177,62 @@ public final class QrCode {
bb.appendData(seg.data);
}
assert bb.bitLength() == dataUsedBits;
-
+
// Add terminator and pad up to a byte if applicable
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
assert bb.bitLength() <= dataCapacityBits;
bb.appendBits(0, Math.min(4, dataCapacityBits - bb.bitLength()));
bb.appendBits(0, (8 - bb.bitLength() % 8) % 8);
assert bb.bitLength() % 8 == 0;
-
+
// Pad with alternating bytes until data capacity is reached
for (int padByte = 0xEC; bb.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
bb.appendBits(padByte, 8);
-
+
// Pack bits into bytes in big endian
byte[] dataCodewords = new byte[bb.bitLength() / 8];
for (int i = 0; i < bb.bitLength(); i++)
dataCodewords[i >>> 3] |= bb.getBit(i) << (7 - (i & 7));
-
+
// Create the QR Code object
return new QrCode(version, ecl, dataCodewords, mask);
}
-
-
-
+
+
+
/*---- Instance fields ----*/
-
+
// Public immutable scalar parameters:
-
+
/** The version number of this QR Code, which is between 1 and 40 (inclusive).
* This determines the size of this barcode. */
public final int version;
-
+
/** The width and height of this QR Code, measured in modules, between
* 21 and 177 (inclusive). This is equal to version × 4 + 17. */
public final int size;
-
+
/** The error correction level used in this QR Code, which is not {@code null}. */
public final Ecc errorCorrectionLevel;
-
+
/** The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
*
Even if a QR Code is created with automatic masking requested (mask =
* −1), the resulting object still has a mask value between 0 and 7. */
public final int mask;
-
+
// Private grids of modules/pixels, with dimensions of size*size:
-
+
// The modules of this QR Code (false = white, true = black).
// Immutable after constructor finishes. Accessed through getModule().
private boolean[][] modules;
-
+
// Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
private boolean[][] isFunction;
-
-
-
+
+
+
/*---- Constructor (low level) ----*/
-
+
/**
* Constructs a QR Code with the specified version number,
* error correction level, data codeword bytes, and mask number.
@@ -258,7 +258,7 @@ public final class QrCode {
Objects.requireNonNull(dataCodewords);
modules = new boolean[size][size]; // Initially all white
isFunction = new boolean[size][size];
-
+
// Compute ECC, draw modules, do masking
drawFunctionPatterns();
byte[] allCodewords = addEccAndInterleave(dataCodewords);
@@ -266,11 +266,11 @@ public final class QrCode {
this.mask = handleConstructorMasking(msk);
isFunction = null;
}
-
-
-
+
+
+
/*---- Public instance methods ----*/
-
+
/**
* Returns the color of the module (pixel) at the specified coordinates, which is {@code false}
* for white or {@code true} for black. The top left corner has the coordinates (x=0, y=0).
@@ -283,8 +283,8 @@ public final class QrCode {
public boolean getModule(int x, int y) {
return 0 <= x && x < size && 0 <= y && y < size && modules[y][x];
}
-
-
+
+
/**
* Returns a raster image depicting this QR Code, with the specified module scale and border modules.
*
For example, toImage(scale=10, border=4) means to pad the QR Code with 4 white
@@ -301,7 +301,7 @@ public final class QrCode {
throw new IllegalArgumentException("Value out of range");
if (border > Integer.MAX_VALUE / 2 || size + border * 2L > Integer.MAX_VALUE / scale)
throw new IllegalArgumentException("Scale or border too large");
-
+
BufferedImage result = new BufferedImage((size + border * 2) * scale, (size + border * 2) * scale, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < result.getHeight(); y++) {
for (int x = 0; x < result.getWidth(); x++) {
@@ -311,8 +311,8 @@ public final class QrCode {
}
return result;
}
-
-
+
+
/**
* Returns a string of SVG code for an image depicting this QR Code, with the specified number
* of border modules. The string always uses Unix newlines (\n), regardless of the platform.
@@ -325,12 +325,12 @@ public final class QrCode {
throw new IllegalArgumentException("Border must be non-negative");
long brd = border;
StringBuilder sb = new StringBuilder()
- .append("\n")
- .append("\n")
- .append(String.format("\n")
+ .toString();
}
-
-
-
+
+
+
/*---- Private helper methods for constructor: Drawing function modules ----*/
-
+
// Reads this object's version field, and draws and marks all function modules.
private void drawFunctionPatterns() {
// Draw horizontal and vertical timing patterns
@@ -357,12 +357,12 @@ public final class QrCode {
setFunctionModule(6, i, i % 2 == 0);
setFunctionModule(i, 6, i % 2 == 0);
}
-
+
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
drawFinderPattern(3, 3);
drawFinderPattern(size - 4, 3);
drawFinderPattern(3, size - 4);
-
+
// Draw numerous alignment patterns
int[] alignPatPos = getAlignmentPatternPositions();
int numAlign = alignPatPos.length;
@@ -373,13 +373,13 @@ public final class QrCode {
drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
}
}
-
+
// Draw configuration data
drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
drawVersion();
}
-
-
+
+
// Draws two copies of the format bits (with its own error correction code)
// based on the given mask and this object's error correction level field.
private void drawFormatBits(int msk) {
@@ -390,7 +390,7 @@ public final class QrCode {
rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
int bits = (data << 10 | rem) ^ 0x5412; // uint15
assert bits >>> 15 == 0;
-
+
// Draw first copy
for (int i = 0; i <= 5; i++)
setFunctionModule(8, i, getBit(bits, i));
@@ -399,7 +399,7 @@ public final class QrCode {
setFunctionModule(7, 8, getBit(bits, 8));
for (int i = 9; i < 15; i++)
setFunctionModule(14 - i, 8, getBit(bits, i));
-
+
// Draw second copy
for (int i = 0; i < 8; i++)
setFunctionModule(size - 1 - i, 8, getBit(bits, i));
@@ -407,21 +407,21 @@ public final class QrCode {
setFunctionModule(8, size - 15 + i, getBit(bits, i));
setFunctionModule(8, size - 8, true); // Always black
}
-
-
+
+
// Draws two copies of the version bits (with its own error correction code),
// based on this object's version field, iff 7 <= version <= 40.
private void drawVersion() {
if (version < 7)
return;
-
+
// Calculate error correction code and pack bits
int rem = version; // version is uint6, in the range [7, 40]
for (int i = 0; i < 12; i++)
rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);
int bits = version << 12 | rem; // uint18
assert bits >>> 18 == 0;
-
+
// Draw two copies
for (int i = 0; i < 18; i++) {
boolean bit = getBit(bits, i);
@@ -431,8 +431,8 @@ public final class QrCode {
setFunctionModule(b, a, bit);
}
}
-
-
+
+
// Draws a 9*9 finder pattern including the border separator,
// with the center module at (x, y). Modules can be out of bounds.
private void drawFinderPattern(int x, int y) {
@@ -445,8 +445,8 @@ public final class QrCode {
}
}
}
-
-
+
+
// Draws a 5*5 alignment pattern, with the center module
// at (x, y). All modules must be in bounds.
private void drawAlignmentPattern(int x, int y) {
@@ -455,32 +455,32 @@ public final class QrCode {
setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) != 1);
}
}
-
-
+
+
// Sets the color of a module and marks it as a function module.
// Only used by the constructor. Coordinates must be in bounds.
private void setFunctionModule(int x, int y, boolean isBlack) {
modules[y][x] = isBlack;
isFunction[y][x] = true;
}
-
-
+
+
/*---- Private helper methods for constructor: Codewords and masking ----*/
-
+
// Returns a new byte string representing the given data with the appropriate error correction
// codewords appended to it, based on this object's version and error correction level.
private byte[] addEccAndInterleave(byte[] data) {
Objects.requireNonNull(data);
if (data.length != getNumDataCodewords(version, errorCorrectionLevel))
throw new IllegalArgumentException();
-
+
// Calculate parameter numbers
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal()][version];
int blockEccLen = ECC_CODEWORDS_PER_BLOCK [errorCorrectionLevel.ordinal()][version];
int rawCodewords = getNumRawDataModules(version) / 8;
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
int shortBlockLen = rawCodewords / numBlocks;
-
+
// Split data into blocks and append ECC to each block
byte[][] blocks = new byte[numBlocks][];
byte[] rsDiv = reedSolomonComputeDivisor(blockEccLen);
@@ -492,7 +492,7 @@ public final class QrCode {
System.arraycopy(ecc, 0, block, block.length - blockEccLen, ecc.length);
blocks[i] = block;
}
-
+
// Interleave (not concatenate) the bytes from every block into a single sequence
byte[] result = new byte[rawCodewords];
for (int i = 0, k = 0; i < blocks[0].length; i++) {
@@ -506,15 +506,15 @@ public final class QrCode {
}
return result;
}
-
-
+
+
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
// data area of this QR Code. Function modules need to be marked off before this is called.
private void drawCodewords(byte[] data) {
Objects.requireNonNull(data);
if (data.length != getNumRawDataModules(version) / 8)
throw new IllegalArgumentException();
-
+
int i = 0; // Bit index into the data
// Do the funny zigzag scan
for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
@@ -536,13 +536,13 @@ public final class QrCode {
}
assert i == data.length * 8;
}
-
-
+
+
// XORs the codeword modules in this QR Code with the given mask pattern.
// The function modules must be marked and the codeword bits must be drawn
// before masking. Due to the arithmetic of XOR, calling applyMask() with
// the same mask value a second time will undo the mask. A final well-formed
- // QR Code needs exactly one (not zero, two, etc.) mask applied. switch-statement refactoring
+ // QR Code needs exactly one (not zero, two, etc.) mask applied. Command pattern
private void applyMask(int msk) {
if (msk < 0 || msk > 7)
throw new IllegalArgumentException("Mask value out of range");
@@ -550,38 +550,28 @@ public final class QrCode {
for (int x = 0; x < size; x++) {
boolean invert;
switch (msk) {
- case 0: invert = (x + y) % 2 == 0; break;
- case 1: invert = y % 2 == 0; break;
- case 2: invert = x % 3 == 0; break;
- case 3: invert = (x + y) % 3 == 0; break;
- case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
- case 5: invert = x * y % 2 + x * y % 3 == 0; break;
- case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
- case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
- default: throw new AssertionError();
+ case 0: invert = (x + y) % 2 == 0; break;
+ case 1: invert = y % 2 == 0; break;
+ case 2: invert = x % 3 == 0; break;
+ case 3: invert = (x + y) % 3 == 0; break;
+ case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
+ case 5: invert = x * y % 2 + x * y % 3 == 0; break;
+ case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
+ case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
+ default: throw new AssertionError();
}
modules[y][x] ^= invert & !isFunction[y][x];
}
}
}
-
-
+
+
// A messy helper function for the constructor. This QR Code must be in an unmasked state when this
// method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
// This method applies and returns the actual mask chosen, from 0 to 7.
private int handleConstructorMasking(int msk) {
if (msk == -1) { // Automatically choose best mask
- int minPenalty = Integer.MAX_VALUE;
- for (int i = 0; i < 8; i++) {
- applyMask(i);
- drawFormatBits(i);
- int penalty = getPenaltyScore();
- if (penalty < minPenalty) {
- msk = i;
- minPenalty = penalty;
- }
- applyMask(i); // Undoes the mask due to XOR
- }
+ msk = chooseBestMask(msk);
}
assert 0 <= msk && msk <= 7;
applyMask(msk); // Apply the final choice of mask
@@ -589,32 +579,67 @@ public final class QrCode {
return msk; // The caller shall assign this value to the final-declared field
}
-
+ private int chooseBestMask(int msk) {
+ int minPenalty = Integer.MAX_VALUE;
+ for (int i = 0; i < 8; i++) {
+ applyMask(i);
+ drawFormatBits(i);
+ int penalty = getPenaltyScore();
+ if (penalty < minPenalty) {
+ msk = i;
+ minPenalty = penalty;
+ }
+ applyMask(i); // Undoes the mask due to XOR
+ }
+ return msk;
+ }
+
+ private int havingSameColor(int run, boolean runColor, int[] runHistory, int result, int y, int x) {
+ if (modules[y][x] == runColor) {
+ run++;
+ if (run == 5)
+ result += PENALTY_N1;
+ else if (run > 5)
+ result++;
+ } else {
+ finderPenaltyAddHistory(run, runHistory);
+ if (!runColor)
+ result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
+ runColor = modules[y][x];
+ run = 1;
+ }
+
+ return result;
+ }
+
+ private int twobytwoHavingSameColor(boolean[][] modules) {
+ int result = 0;
+ // 2*2 blocks of modules having same color.
+ for (int y = 0; y < size - 1; y++) {
+ for (int x = 0; x < size - 1; x++) {
+ boolean color = modules[y][x];
+ if ( color == modules[y][x + 1] &&
+ color == modules[y + 1][x] &&
+ color == modules[y + 1][x + 1])
+ result += PENALTY_N2;
+ }
+ }
+ return result;
+ }
+
// Calculates and returns the penalty score based on state of this QR Code's current modules.
- // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. duplication code extract
+ // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
private int getPenaltyScore() {
- int result = 0;
+ int result = 0;
+
// Adjacent modules in row having same color, and finder-like patterns
for (int y = 0; y < size; y++) {
boolean runColor = false;
int runX = 0;
int[] runHistory = new int[7];
- result += havingSameColor();
for (int x = 0; x < size; x++) {
- if (modules[y][x] == runColor) {
- runX++;
- if (runX == 5)
- result += PENALTY_N1;
- else if (runX > 5)
- result++;
- } else {
- finderPenaltyAddHistory(runX, runHistory);
- if (!runColor)
- result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
- runColor = modules[y][x];
- runX = 1;
- }
+ result += havingSameColor(runX, runColor, runHistory, result, y, x);
}
result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
}
@@ -624,34 +649,14 @@ public final class QrCode {
int runY = 0;
int[] runHistory = new int[7];
for (int y = 0; y < size; y++) {
- if (modules[y][x] == runColor) {
- runY++;
- if (runY == 5)
- result += PENALTY_N1;
- else if (runY > 5)
- result++;
- } else {
- finderPenaltyAddHistory(runY, runHistory);
- if (!runColor)
- result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
- runColor = modules[y][x];
- runY = 1;
- }
+ result += havingSameColor(runY, runColor, runHistory, result, y, x);
}
result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
}
-
- // 2*2 blocks of modules having same color. extract method to reduce method size
- for (int y = 0; y < size - 1; y++) {
- for (int x = 0; x < size - 1; x++) {
- boolean color = modules[y][x];
- if ( color == modules[y][x + 1] &&
- color == modules[y + 1][x] &&
- color == modules[y + 1][x + 1])
- result += PENALTY_N2;
- }
- }
-
+
+ result += twobytwoHavingSameColor(modules);
+
+
// Balance of black and white modules
int black = 0;
for (boolean[] row : modules) {
@@ -666,11 +671,9 @@ public final class QrCode {
result += k * PENALTY_N4;
return result;
}
-
-
-
+
/*---- Private helper functions ----*/
-
+
// Returns an ascending list of positions of alignment patterns for this version number.
// Each position is in the range [0,177), and are used on both the x and y axes.
// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
@@ -691,15 +694,22 @@ public final class QrCode {
return result;
}
}
-
-
+
+
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
- // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. replace integer to understandable word
+ // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
private static int getNumRawDataModules(int ver) {
if (ver < MIN_VERSION || ver > MAX_VERSION)
throw new IllegalArgumentException("Version number out of range");
-
+
+ int result = calculateNumOfModules(ver);
+
+ assert 208 <= result && result <= 29648;
+ return result;
+ }
+
+ private static int calculateNumOfModules(int ver) {
int size = ver * 4 + 17;
int result = size * size; // Number of modules in the whole QR Code square
result -= 8 * 8 * 3; // Subtract the three finders with separators
@@ -714,11 +724,9 @@ public final class QrCode {
if (ver >= 7)
result -= 6 * 3 * 2; // Subtract version information
}
- assert 208 <= result && result <= 29648;
return result;
}
-
-
+
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
private static byte[] reedSolomonComputeDivisor(int degree) {
@@ -728,7 +736,7 @@ public final class QrCode {
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
byte[] result = new byte[degree];
result[degree - 1] = 1; // Start off with the monomial x^0
-
+
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// and drop the highest monomial term which is always 1x^degree.
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
@@ -744,8 +752,8 @@ public final class QrCode {
}
return result;
}
-
-
+
+
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
private static byte[] reedSolomonComputeRemainder(byte[] data, byte[] divisor) {
Objects.requireNonNull(data);
@@ -760,33 +768,33 @@ public final class QrCode {
}
return result;
}
-
-
+
+
// Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
private static int reedSolomonMultiply(int x, int y) {
assert x >> 8 == 0 && y >> 8 == 0;
- // Russian peasant multiplication
- int z = 0;
- for (int i = 7; i >= 0; i--) {
- z = (z << 1) ^ ((z >>> 7) * 0x11D);
- z ^= ((y >>> i) & 1) * x;
- }
- assert z >>> 8 == 0;
- return z;
+ // Russian peasant multiplication
+ int z = 0;
+ for (int i = 7; i >= 0; i--) {
+ z = (z << 1) ^ ((z >>> 7) * 0x11D);
+ z ^= ((y >>> i) & 1) * x;
+ }
+ assert z >>> 8 == 0;
+ return z;
}
-
-
+
+
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
// QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
static int getNumDataCodewords(int ver, Ecc ecl) {
return getNumRawDataModules(ver) / 8
- - ECC_CODEWORDS_PER_BLOCK [ecl.ordinal()][ver]
- * NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal()][ver];
+ - ECC_CODEWORDS_PER_BLOCK [ecl.ordinal()][ver]
+ * NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal()][ver];
}
-
-
+
+
// Can only be called immediately after a white run is added, and
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
private int finderPenaltyCountPatterns(int[] runHistory) {
@@ -794,10 +802,10 @@ public final class QrCode {
assert n <= size * 3;
boolean core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;
return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0)
- + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
+ + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
}
-
-
+
+
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
private int finderPenaltyTerminateAndCount(boolean currentRunColor, int currentRunLength, int[] runHistory) {
if (currentRunColor) { // Terminate black run
@@ -808,8 +816,8 @@ public final class QrCode {
finderPenaltyAddHistory(currentRunLength, runHistory);
return finderPenaltyCountPatterns(runHistory);
}
-
-
+
+
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
private void finderPenaltyAddHistory(int currentRunLength, int[] runHistory) {
if (runHistory[0] == 0)
@@ -817,52 +825,52 @@ public final class QrCode {
System.arraycopy(runHistory, 0, runHistory, 1, runHistory.length - 1);
runHistory[0] = currentRunLength;
}
-
-
+
+
// Returns true iff the i'th bit of x is set to 1.
static boolean getBit(int x, int i) {
return ((x >>> i) & 1) != 0;
}
-
-
+
+
/*---- Constants and tables ----*/
-
+
/** The minimum version number (1) supported in the QR Code Model 2 standard. */
public static final int MIN_VERSION = 1;
-
+
/** The maximum version number (40) supported in the QR Code Model 2 standard. */
public static final int MAX_VERSION = 40;
-
-
+
+
// For use in getPenaltyScore(), when evaluating which mask is best.
private static final int PENALTY_N1 = 3;
private static final int PENALTY_N2 = 3;
private static final int PENALTY_N3 = 40;
private static final int PENALTY_N4 = 10;
-
-
+
+
private static final byte[][] ECC_CODEWORDS_PER_BLOCK = {
- // Version: (note that index 0 is for padding, and is set to an illegal value)
- //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
- {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
- {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
- {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
- {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
+ // Version: (note that index 0 is for padding, and is set to an illegal value)
+ //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
+ {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
+ {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
+ {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
+ {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
};
-
+
private static final byte[][] NUM_ERROR_CORRECTION_BLOCKS = {
- // Version: (note that index 0 is for padding, and is set to an illegal value)
- //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
- {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
- {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
- {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
- {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
+ // Version: (note that index 0 is for padding, and is set to an illegal value)
+ //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
+ {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
+ {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
+ {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
+ {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
};
-
-
-
+
+
+
/*---- Public helper enumeration ----*/
-
+
/**
* The error correction level in a QR Code symbol.
*/
@@ -873,14 +881,14 @@ public final class QrCode {
/** The QR Code can tolerate about 15% erroneous codewords. */ MEDIUM(0),
/** The QR Code can tolerate about 25% erroneous codewords. */ QUARTILE(3),
/** The QR Code can tolerate about 30% erroneous codewords. */ HIGH(2);
-
+
// In the range 0 to 3 (unsigned 2-bit integer).
final int formatBits;
-
+
// Constructor.
private Ecc(int fb) {
formatBits = fb;
}
}
-
+
}
From c8c3b46c75fa775672fb2f746349f1cbee66b4e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B9=80=EA=B2=BD=EC=A7=84?= <김경진@DESKTOP-6URC5U8>
Date: Wed, 27 May 2020 10:40:22 +0900
Subject: [PATCH 07/28] Refactoring
Replace Magic Number with Symbolic Constant
drawFunctionPatterns()
Not to use magic number
---
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index fe05d48..512e314 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -354,8 +354,9 @@ public final class QrCode {
private void drawFunctionPatterns() {
// Draw horizontal and vertical timing patterns
for (int i = 0; i < size; i++) {
- setFunctionModule(6, i, i % 2 == 0);
- setFunctionModule(i, 6, i % 2 == 0);
+ final boolean isBlack = i % 2 == 0;
+ setFunctionModule(6, i, isBlack);
+ setFunctionModule(i, 6, isBlack);
}
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
From bd9e5f3882fe6b56e71633e37529fbc95dc762ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B9=80=EA=B2=BD=EC=A7=84?= <김경진@DESKTOP-6URC5U8>
Date: Wed, 27 May 2020 10:45:15 +0900
Subject: [PATCH 08/28] Refactoring
Replace Magic Number with Symbolic Constant
drawFunctionPatterns()
Not to use magic number
---
.../main/java/io/nayuki/qrcodegen/QrCode.java | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index 512e314..7013ed7 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -52,6 +52,12 @@ import java.util.Objects;
*/
public final class QrCode {
+ private static final int FINDER_SIZE = 3;
+
+ private static final int TIMING_COORDINATE = 6;
+
+
+
/*---- Static factory functions (high level) ----*/
/**
@@ -354,15 +360,14 @@ public final class QrCode {
private void drawFunctionPatterns() {
// Draw horizontal and vertical timing patterns
for (int i = 0; i < size; i++) {
- final boolean isBlack = i % 2 == 0;
- setFunctionModule(6, i, isBlack);
- setFunctionModule(i, 6, isBlack);
+ setFunctionModule(TIMING_COORDINATE, i, i % 2 == 0);
+ setFunctionModule(i, TIMING_COORDINATE, i % 2 == 0);
}
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
- drawFinderPattern(3, 3);
- drawFinderPattern(size - 4, 3);
- drawFinderPattern(3, size - 4);
+ drawFinderPattern(FINDER_SIZE, FINDER_SIZE);
+ drawFinderPattern(size - 1 - FINDER_SIZE, FINDER_SIZE);
+ drawFinderPattern(FINDER_SIZE, size - 1 - FINDER_SIZE);
// Draw numerous alignment patterns
int[] alignPatPos = getAlignmentPatternPositions();
From 52ee4d068f351079b8b5de8ec366b5d3f476ebbc Mon Sep 17 00:00:00 2001
From: minsu4107 <32637512+minsu4107@users.noreply.github.com>
Date: Wed, 27 May 2020 11:02:04 +0900
Subject: [PATCH 09/28] 1. Too long String extracted text file 2.
QrSegmenetAdvanced.java 3. The String PACKED_QR_KANJI_TO_UNICODE is too long.
So extract to outside. But it spend at least 3 seconds. So, think about that
using text scanner.
---
.../nayuki/qrcodegen/QrSegmentAdvanced.java | 94 +++++++++++++------
1 file changed, 67 insertions(+), 27 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
index 6480897..19a32c1 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
@@ -23,12 +23,20 @@
package io.nayuki.qrcodegen;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
+import java.util.Scanner;
+
import io.nayuki.qrcodegen.QrSegment.Mode;
@@ -132,6 +140,20 @@ public final class QrSegmentAdvanced {
int[] prevCosts = headCosts.clone();
// Calculate costs using dynamic programming
+ prevCosts = calculate_cost(codePoints, modeTypes, numModes, headCosts, charModes, prevCosts);
+
+ // Find optimal ending mode
+ Mode curMode = find_optimal(modeTypes, numModes, prevCosts);
+
+ // Get optimal mode for each code point by tracing backwards
+ Mode[] result = new Mode[charModes.length];
+ get_optimal(modeTypes, numModes, charModes, curMode, result);
+ return result;
+ }
+
+
+ private static int[] calculate_cost(int[] codePoints, final Mode[] modeTypes, final int numModes,
+ final int[] headCosts, Mode[][] charModes, int[] prevCosts) {
for (int i = 0; i < codePoints.length; i++) {
int cPoint = codePoints[i];
int[] curCosts = new int[numModes];
@@ -157,8 +179,8 @@ public final class QrSegmentAdvanced {
for (int j = 0; j < numModes; j++) { // To mode
for (int k = 0; k < numModes; k++) { // From mode
int newCost = (curCosts[k] + 5) / 6 * 6 + headCosts[j];
- boolean is_notNull_or_lower = charModes[i][k] != null && (charModes[i][j] == null || newCost < curCosts[j]);
- if (is_notNull_or_lower) {
+ boolean is_lower = charModes[i][k] != null && (charModes[i][j] == null || newCost < curCosts[j]);
+ if (is_lower) {
curCosts[j] = newCost;
charModes[i][j] = modeTypes[k];
}
@@ -167,18 +189,12 @@ public final class QrSegmentAdvanced {
prevCosts = curCosts;
}
-
- // Find optimal ending mode
- Mode curMode = null;
- for (int i = 0, minCost = 0; i < numModes; i++) {
- if (curMode == null || prevCosts[i] < minCost) {
- minCost = prevCosts[i];
- curMode = modeTypes[i];
- }
- }
-
- // Get optimal mode for each code point by tracing backwards
- Mode[] result = new Mode[charModes.length];
+ return prevCosts;
+ }
+
+
+ private static void get_optimal(final Mode[] modeTypes, final int numModes, Mode[][] charModes, Mode curMode,
+ Mode[] result) {
for (int i = result.length - 1; i >= 0; i--) {
for (int j = 0; j < numModes; j++) {
if (modeTypes[j] == curMode) {
@@ -188,7 +204,18 @@ public final class QrSegmentAdvanced {
}
}
}
- return result;
+ }
+
+
+ private static Mode find_optimal(final Mode[] modeTypes, final int numModes, int[] prevCosts) {
+ Mode curMode = null;
+ for (int i = 0, minCost = 0; i < numModes; i++) {
+ if (curMode == null || prevCosts[i] < minCost) {
+ minCost = prevCosts[i];
+ curMode = modeTypes[i];
+ }
+ }
+ return curMode;
}
@@ -247,12 +274,12 @@ public final class QrSegmentAdvanced {
// Returns the number of UTF-8 bytes needed to encode the given Unicode code point.
- private static int countUtf8Bytes(int cp) {
- if (cp < 0) throw new IllegalArgumentException("Invalid code point");
- else if (cp < 0x80) return 1;
- else if (cp < 0x800) return 2;
- else if (cp < 0x10000) return 3;
- else if (cp < 0x110000) return 4;
+ private static int countUtf8Bytes(int currentPoint) {
+ if (currentPoint < 0) throw new IllegalArgumentException("Invalid code point");
+ else if (currentPoint < 0x80) return 1;
+ else if (currentPoint < 0x800) return 2;
+ else if (currentPoint < 0x10000) return 3;
+ else if (currentPoint < 0x110000) return 4;
else throw new IllegalArgumentException("Invalid code point");
}
@@ -306,8 +333,8 @@ public final class QrSegmentAdvanced {
return c < UNICODE_TO_QR_KANJI.length && UNICODE_TO_QR_KANJI[c] != -1;
}
-
- // Data derived from ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
+// Data derived from ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
+// private static final String PACKED_QR_KANJI_TO_UNICODE = readPacked_KANJI();
private static final String PACKED_QR_KANJI_TO_UNICODE =
"MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZA" +
"ALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA///////////////////" +
@@ -427,14 +454,27 @@ public final class QrSegmentAdvanced {
Arrays.fill(UNICODE_TO_QR_KANJI, (short)-1);
byte[] bytes = Base64.getDecoder().decode(PACKED_QR_KANJI_TO_UNICODE);
for (int i = 0; i < bytes.length; i += 2) {
- char c = (char)(((bytes[i] & 0xFF) << 8) | (bytes[i + 1] & 0xFF));
- if (c == 0xFFFF)
+ char convertChar = (char)(((bytes[i] & 0xFF) << 8) | (bytes[i + 1] & 0xFF));
+ if (convertChar == 0xFFFF)
continue;
- assert UNICODE_TO_QR_KANJI[c] == -1;
- UNICODE_TO_QR_KANJI[c] = (short)(i / 2);
+ assert UNICODE_TO_QR_KANJI[convertChar] == -1;
+ UNICODE_TO_QR_KANJI[convertChar] = (short)(i / 2);
}
}
+// private static String readPacked_KANJI() {
+// String str = "";
+// try {
+// File file = new File("./packet_KanJI.txt");
+// Scanner scan = new Scanner(file);
+// str +=scan.nextLine();
+// scan.close();
+// }
+// catch(FileNotFoundException e){
+// }
+//
+// return str;
+// }
/*---- Miscellaneous ----*/
From e82e40f30ca3c09a630a1424a0e2475f867d5b4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B9=80=EA=B2=BD=EC=A7=84?= <김경진@DESKTOP-6URC5U8>
Date: Sun, 31 May 2020 21:25:14 +0900
Subject: [PATCH 10/28] 1. Extract Variable 2. drawFunctionPatterns() in QrCode
3. To improve readability of conditional expression
---
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index 7013ed7..6920c32 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -374,8 +374,11 @@ public final class QrCode {
int numAlign = alignPatPos.length;
for (int i = 0; i < numAlign; i++) {
for (int j = 0; j < numAlign; j++) {
- // Don't draw on the three finder corners
- if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0))
+ final boolean isLeftTop = i == 0 && j == 0;
+ final boolean isLeftBottom = i == 0 && j == numAlign - 1;
+ final boolean isRightTop = i == numAlign - 1 && j == 0;
+ final boolean onThreeFinderCorners = isLeftTop || isLeftBottom || isRightTop;
+ if (!onThreeFinderCorners)
drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
}
}
From 580485c189e35b8a6ef3b5cee2a42d6d13f2d35b Mon Sep 17 00:00:00 2001
From: gerzees
Date: Sun, 31 May 2020 22:23:00 +0900
Subject: [PATCH 11/28] 1. Rename, Extract Variable 2. encodSegments() in
QrCode 3. To improve readability of conditional expressions and variable
names
---
.../main/java/io/nayuki/qrcodegen/QrCode.java | 63 ++++++++++---------
1 file changed, 33 insertions(+), 30 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index a0afaa6..bf3a11a 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -134,8 +134,8 @@ public final class QrCode {
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)}
* and {@link #encodeBinary(byte[],Ecc)}.
- * @param segs the segments to encode
- * @param ecl the error correction level to use (not {@code null}) (boostable)
+ * @param segments the segments to encode
+ * @param errorCorrectionLevel the error correction level to use (not {@code null}) (boostable)
* @param minVersion the minimum allowed version of the QR Code (at least 1)
* @param maxVersion the maximum allowed version of the QR Code (at most 40)
* @param mask the mask number to use (between 0 and 7 (inclusive)), or −1 for automatic mask
@@ -147,61 +147,64 @@ public final class QrCode {
* @throws DataTooLongException if the segments fail to fit in
* the maxVersion QR Code at the ECL, which means they are too long
*/
- public static QrCode encodeSegments(List segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) {
- Objects.requireNonNull(segs);
- Objects.requireNonNull(ecl);
- if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
+ public static QrCode encodeSegments(List segments, Ecc errorCorrectionLevel, int minVersion, int maxVersion, int mask, boolean boostEcl) {
+ Objects.requireNonNull(segments);
+ Objects.requireNonNull(errorCorrectionLevel);
+ final boolean isVersionInRange = MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION;
+ final boolean isMaskValid = mask < -1 || mask > 7;
+ if (!isVersionInRange || isMaskValid)
throw new IllegalArgumentException("Invalid value");
// Find the minimal version number to use
int version, dataUsedBits;
for (version = minVersion; ; version++) {
- int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
- dataUsedBits = QrSegment.getTotalBits(segs, version);
+ int dataCapacityBits = getNumDataCodewords(version, errorCorrectionLevel) * 8; // Number of data bits available
+ dataUsedBits = QrSegment.getTotalBits(segments, version);
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
break; // This version number is found to be suitable
if (version >= maxVersion) { // All versions in the range could not fit the given data
- String msg = "Segment too long";
+ String message = "Segment too long";
if (dataUsedBits != -1)
- msg = String.format("Data length = %d bits, Max capacity = %d bits", dataUsedBits, dataCapacityBits);
- throw new DataTooLongException(msg);
+ message = String.format("Data length = %d bits, Max capacity = %d bits", dataUsedBits, dataCapacityBits);
+ throw new DataTooLongException(message);
}
}
assert dataUsedBits != -1;
// Increase the error correction level while the data still fits in the current version number
for (Ecc newEcl : Ecc.values()) { // From low to high
- if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
- ecl = newEcl;
+ final boolean canIncreaseErrorCorrectionLevel = dataUsedBits <= getNumDataCodewords(version, newEcl) * 8;
+ if (boostEcl && canIncreaseErrorCorrectionLevel)
+ errorCorrectionLevel = newEcl;
}
// Concatenate all segments to create the data bit string
- BitBuffer bb = new BitBuffer();
- for (QrSegment seg : segs) {
- bb.appendBits(seg.mode.modeBits, 4);
- bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
- bb.appendData(seg.data);
+ BitBuffer bitBuffer = new BitBuffer();
+ for (QrSegment segment : segments) {
+ bitBuffer.appendBits(segment.mode.modeBits, 4);
+ bitBuffer.appendBits(segment.numChars, segment.mode.numCharCountBits(version));
+ bitBuffer.appendData(segment.data);
}
- assert bb.bitLength() == dataUsedBits;
+ assert bitBuffer.bitLength() == dataUsedBits;
// Add terminator and pad up to a byte if applicable
- int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
- assert bb.bitLength() <= dataCapacityBits;
- bb.appendBits(0, Math.min(4, dataCapacityBits - bb.bitLength()));
- bb.appendBits(0, (8 - bb.bitLength() % 8) % 8);
- assert bb.bitLength() % 8 == 0;
+ int dataCapacityBits = getNumDataCodewords(version, errorCorrectionLevel) * 8;
+ assert bitBuffer.bitLength() <= dataCapacityBits;
+ bitBuffer.appendBits(0, Math.min(4, dataCapacityBits - bitBuffer.bitLength()));
+ bitBuffer.appendBits(0, (8 - bitBuffer.bitLength() % 8) % 8);
+ assert bitBuffer.bitLength() % 8 == 0;
// Pad with alternating bytes until data capacity is reached
- for (int padByte = 0xEC; bb.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
- bb.appendBits(padByte, 8);
+ for (int padByte = 0xEC; bitBuffer.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ bitBuffer.appendBits(padByte, 8);
// Pack bits into bytes in big endian
- byte[] dataCodewords = new byte[bb.bitLength() / 8];
- for (int i = 0; i < bb.bitLength(); i++)
- dataCodewords[i >>> 3] |= bb.getBit(i) << (7 - (i & 7));
+ byte[] dataCodewords = new byte[bitBuffer.bitLength() / 8];
+ for (int i = 0; i < bitBuffer.bitLength(); i++)
+ dataCodewords[i >>> 3] |= bitBuffer.getBit(i) << (7 - (i & 7));
// Create the QR Code object
- return new QrCode(version, ecl, dataCodewords, mask);
+ return new QrCode(version, errorCorrectionLevel, dataCodewords, mask);
}
/*---- Instance fields ----*/
From d99f534b6120aefc6cfcee4236f06061faf85d68 Mon Sep 17 00:00:00 2001
From: wslbal
Date: Mon, 1 Jun 2020 09:18:12 +0900
Subject: [PATCH 12/28] 1) extract method 2) getPenaltyScore,
handleConstructorMasking, getNumRawDataModules 3) method is too long
---
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index fbc50d9..437a16c 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -614,7 +614,7 @@ public final class QrCode {
private int twobytwoHavingSameColor(boolean[][] modules) {
int result = 0;
- // 2*2 blocks of modules having same color.
+ // 2*2 blocks of modules having same color
for (int y = 0; y < size - 1; y++) {
for (int x = 0; x < size - 1; x++) {
boolean color = modules[y][x];
From ef3a6f70213c31a13f791ee3209b4717258eb070 Mon Sep 17 00:00:00 2001
From: gerzees
Date: Mon, 1 Jun 2020 10:20:17 +0900
Subject: [PATCH 13/28] 1. Extract Method 2. encodeSegments() in QrCode 3.
encodeSegments() is long method
---
.../main/java/io/nayuki/qrcodegen/QrCode.java | 116 ++++++++++++------
1 file changed, 80 insertions(+), 36 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index bf3a11a..2c65b16 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -155,7 +155,85 @@ public final class QrCode {
if (!isVersionInRange || isMaskValid)
throw new IllegalArgumentException("Invalid value");
- // Find the minimal version number to use
+
+ int version = findMinimalVersion(segments, errorCorrectionLevel, minVersion, maxVersion);
+
+ int dataUsedBits = QrSegment.getTotalBits(segments, version);
+
+ errorCorrectionLevel = findMaximalErrorCorrectionLevel(errorCorrectionLevel, boostEcl, version, dataUsedBits);
+
+
+ BitBuffer bitBuffer = segmentsToBitBuffer(segments, version);
+ assert bitBuffer.bitLength() == dataUsedBits;
+
+
+ int dataCapacityBits = getNumDataCodewords(version, errorCorrectionLevel) * 8;
+ assert bitBuffer.bitLength() <= dataCapacityBits;
+ addTerminator(bitBuffer, dataCapacityBits);
+
+
+ addPad(bitBuffer, dataCapacityBits);
+
+
+ byte[] dataCodewords = bitBufferToCodewords(bitBuffer);
+
+ // Create the QR Code object
+ return new QrCode(version, errorCorrectionLevel, dataCodewords, mask);
+ }
+
+
+ // Pack bits into bytes in big endian
+ private static byte[] bitBufferToCodewords(BitBuffer bitBuffer) {
+ byte[] dataCodewords = new byte[bitBuffer.bitLength() / 8];
+ for (int i = 0; i < bitBuffer.bitLength(); i++)
+ dataCodewords[i >>> 3] |= bitBuffer.getBit(i) << (7 - (i & 7));
+ return dataCodewords;
+ }
+
+
+ // Pad with alternating bytes until data capacity is reached
+ private static void addPad(BitBuffer bitBuffer, int dataCapacityBits) {
+ for (int padByte = 0xEC; bitBuffer.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ bitBuffer.appendBits(padByte, 8);
+ }
+
+
+ /*---- Private helper methods for encodeSegments ----*/
+
+ // Add terminator and pad up to a byte if applicable
+ private static void addTerminator(BitBuffer bitBuffer, int dataCapacityBits) {
+ bitBuffer.appendBits(0, Math.min(4, dataCapacityBits - bitBuffer.bitLength()));
+ bitBuffer.appendBits(0, (8 - bitBuffer.bitLength() % 8) % 8);
+ assert bitBuffer.bitLength() % 8 == 0;
+ }
+
+ // Concatenate all segments to create the data bit string
+ private static BitBuffer segmentsToBitBuffer(List segments, int version) {
+ BitBuffer bitBuffer = new BitBuffer();
+ for (QrSegment segment : segments) {
+ bitBuffer.appendBits(segment.mode.modeBits, 4);
+ bitBuffer.appendBits(segment.numChars, segment.mode.numCharCountBits(version));
+ bitBuffer.appendData(segment.data);
+ }
+ return bitBuffer;
+ }
+
+
+ // Increase the error correction level while the data still fits in the current version number
+ private static Ecc findMaximalErrorCorrectionLevel(Ecc errorCorrectionLevel, boolean boostEcl, int version,
+ int dataUsedBits) {
+ for (Ecc newEcl : Ecc.values()) { // From low to high
+ final boolean canIncreaseErrorCorrectionLevel = dataUsedBits <= getNumDataCodewords(version, newEcl) * 8;
+ if (boostEcl && canIncreaseErrorCorrectionLevel)
+ errorCorrectionLevel = newEcl;
+ }
+ return errorCorrectionLevel;
+ }
+
+
+ //Returns the minimal version number to use
+ private static int findMinimalVersion(List segments, Ecc errorCorrectionLevel, int minVersion,
+ int maxVersion) {
int version, dataUsedBits;
for (version = minVersion; ; version++) {
int dataCapacityBits = getNumDataCodewords(version, errorCorrectionLevel) * 8; // Number of data bits available
@@ -170,41 +248,7 @@ public final class QrCode {
}
}
assert dataUsedBits != -1;
-
- // Increase the error correction level while the data still fits in the current version number
- for (Ecc newEcl : Ecc.values()) { // From low to high
- final boolean canIncreaseErrorCorrectionLevel = dataUsedBits <= getNumDataCodewords(version, newEcl) * 8;
- if (boostEcl && canIncreaseErrorCorrectionLevel)
- errorCorrectionLevel = newEcl;
- }
-
- // Concatenate all segments to create the data bit string
- BitBuffer bitBuffer = new BitBuffer();
- for (QrSegment segment : segments) {
- bitBuffer.appendBits(segment.mode.modeBits, 4);
- bitBuffer.appendBits(segment.numChars, segment.mode.numCharCountBits(version));
- bitBuffer.appendData(segment.data);
- }
- assert bitBuffer.bitLength() == dataUsedBits;
-
- // Add terminator and pad up to a byte if applicable
- int dataCapacityBits = getNumDataCodewords(version, errorCorrectionLevel) * 8;
- assert bitBuffer.bitLength() <= dataCapacityBits;
- bitBuffer.appendBits(0, Math.min(4, dataCapacityBits - bitBuffer.bitLength()));
- bitBuffer.appendBits(0, (8 - bitBuffer.bitLength() % 8) % 8);
- assert bitBuffer.bitLength() % 8 == 0;
-
- // Pad with alternating bytes until data capacity is reached
- for (int padByte = 0xEC; bitBuffer.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
- bitBuffer.appendBits(padByte, 8);
-
- // Pack bits into bytes in big endian
- byte[] dataCodewords = new byte[bitBuffer.bitLength() / 8];
- for (int i = 0; i < bitBuffer.bitLength(); i++)
- dataCodewords[i >>> 3] |= bitBuffer.getBit(i) << (7 - (i & 7));
-
- // Create the QR Code object
- return new QrCode(version, errorCorrectionLevel, dataCodewords, mask);
+ return version;
}
/*---- Instance fields ----*/
From 5dc8f476f782ebc712f4d0a49a081cfb88b84d5b Mon Sep 17 00:00:00 2001
From: wslbal
Date: Mon, 1 Jun 2020 10:25:18 +0900
Subject: [PATCH 14/28] 1) Command pattern 2) applyMask 3) switch statement
---
.../main/java/io/nayuki/qrcodegen/Button.java | 17 +++++++++++++++++
.../main/java/io/nayuki/qrcodegen/Command.java | 5 +++++
.../src/main/java/io/nayuki/qrcodegen/Msk0.java | 7 +++++++
.../main/java/io/nayuki/qrcodegen/QrCode.java | 9 ++++++++-
.../java/io/nayuki/qrcodegen/msk0Command.java | 13 +++++++++++++
5 files changed, 50 insertions(+), 1 deletion(-)
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Button.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Command.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Msk0.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/msk0Command.java
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Button.java b/java/src/main/java/io/nayuki/qrcodegen/Button.java
new file mode 100644
index 0000000..66fca4e
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Button.java
@@ -0,0 +1,17 @@
+package io.nayuki.qrcodegen;
+
+public class Button {
+ public Command theCommand;
+
+ public Button(Command theCommand) {
+ setCommand(theCommand);
+ }
+
+ public void setCommand(Command newCommand) {
+ this.theCommand = newCommand;
+ }
+
+ public boolean pressed(int y, int x, int msk) {
+ return theCommand.excute(y, x, msk);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Command.java b/java/src/main/java/io/nayuki/qrcodegen/Command.java
new file mode 100644
index 0000000..b12845e
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Command.java
@@ -0,0 +1,5 @@
+package io.nayuki.qrcodegen;
+
+public interface Command {
+ public abstract boolean excute(int y, int x, int msk);
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Msk0.java b/java/src/main/java/io/nayuki/qrcodegen/Msk0.java
new file mode 100644
index 0000000..a125577
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Msk0.java
@@ -0,0 +1,7 @@
+package io.nayuki.qrcodegen;
+
+public class Msk0 {
+ public boolean operation(int y, int x, int msk) {
+ return ((x + y) % 2 == 0);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index 437a16c..a2cdbc2 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -546,9 +546,15 @@ public final class QrCode {
private void applyMask(int msk) {
if (msk < 0 || msk > 7)
throw new IllegalArgumentException("Mask value out of range");
- for (int y = 0; y < size; y++) {
+ for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
boolean invert;
+ Msk0 msk0 = new Msk0();
+ Command mskCommand = new msk0Command(msk0);
+
+ Button button = new Button(mskCommand);
+ invert = button.pressed(y, x, msk);
+ /*
switch (msk) {
case 0: invert = (x + y) % 2 == 0; break;
case 1: invert = y % 2 == 0; break;
@@ -560,6 +566,7 @@ public final class QrCode {
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
default: throw new AssertionError();
}
+ */
modules[y][x] ^= invert & !isFunction[y][x];
}
}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/msk0Command.java b/java/src/main/java/io/nayuki/qrcodegen/msk0Command.java
new file mode 100644
index 0000000..357bcdc
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/msk0Command.java
@@ -0,0 +1,13 @@
+package io.nayuki.qrcodegen;
+
+public class msk0Command implements Command{
+ private Msk0 theMsk0;
+
+ public msk0Command(Msk0 theMsk0) {
+ this.theMsk0 = theMsk0;
+ }
+
+ public boolean excute(int y, int x, int msk) {
+ return theMsk0.operation(y, x, msk);
+ }
+}
From 6ca8ea40bc94e796b71fe1cbf6ce1b2da36bd384 Mon Sep 17 00:00:00 2001
From: gerzees
Date: Wed, 3 Jun 2020 09:16:27 +0900
Subject: [PATCH 15/28] 1. Rename 2. encodeSegments in QrCode 3. variable name
was wrong
---
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index 2c65b16..1951bb1 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -151,8 +151,8 @@ public final class QrCode {
Objects.requireNonNull(segments);
Objects.requireNonNull(errorCorrectionLevel);
final boolean isVersionInRange = MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION;
- final boolean isMaskValid = mask < -1 || mask > 7;
- if (!isVersionInRange || isMaskValid)
+ final boolean isMaskOutOfRange = mask < -1 || mask > 7;
+ if (!isVersionInRange || isMaskOutOfRange)
throw new IllegalArgumentException("Invalid value");
@@ -181,6 +181,7 @@ public final class QrCode {
return new QrCode(version, errorCorrectionLevel, dataCodewords, mask);
}
+ /*---- Private helper methods for encodeSegments ----*/
// Pack bits into bytes in big endian
private static byte[] bitBufferToCodewords(BitBuffer bitBuffer) {
@@ -197,9 +198,6 @@ public final class QrCode {
bitBuffer.appendBits(padByte, 8);
}
-
- /*---- Private helper methods for encodeSegments ----*/
-
// Add terminator and pad up to a byte if applicable
private static void addTerminator(BitBuffer bitBuffer, int dataCapacityBits) {
bitBuffer.appendBits(0, Math.min(4, dataCapacityBits - bitBuffer.bitLength()));
From 64581afd8c78bfef4525ca2990c22d69367ae57c Mon Sep 17 00:00:00 2001
From: gerzees
Date: Wed, 3 Jun 2020 09:21:38 +0900
Subject: [PATCH 16/28] 1. Extract method 2. drawFunctionPatterns in Qrcode 3.
Method drawFunctionPatterns was long
---
.../src/main/java/io/nayuki/qrcodegen/QrCode.java | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index 1951bb1..162aaf0 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -412,7 +412,16 @@ public final class QrCode {
drawFinderPattern(size - 1 - FINDER_SIZE, FINDER_SIZE);
drawFinderPattern(FINDER_SIZE, size - 1 - FINDER_SIZE);
- // Draw numerous alignment patterns
+ drawAlignmentsPatterns();
+
+ // Draw configuration data
+ drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
+ drawVersion();
+ }
+
+
+ // Draw numerous alignment patterns
+ private void drawAlignmentsPatterns() {
int[] alignPatPos = getAlignmentPatternPositions();
int numAlign = alignPatPos.length;
for (int i = 0; i < numAlign; i++) {
@@ -425,10 +434,6 @@ public final class QrCode {
drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
}
}
-
- // Draw configuration data
- drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
- drawVersion();
}
From f8c7c8800be70f1fa6dd1e2efa0e40875d7e73fa Mon Sep 17 00:00:00 2001
From: gerzees
Date: Wed, 3 Jun 2020 09:39:43 +0900
Subject: [PATCH 17/28] 1. Extract method 2. handleConstructorMasking in QrCode
3. To improve readability
---
.../main/java/io/nayuki/qrcodegen/QrCode.java | 40 +++++++++++--------
1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index 162aaf0..f619deb 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -626,24 +626,32 @@ public final class QrCode {
// A messy helper function for the constructor. This QR Code must be in an unmasked state when this
// method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
// This method applies and returns the actual mask chosen, from 0 to 7.
- private int handleConstructorMasking(int msk) {
- if (msk == -1) { // Automatically choose best mask
- int minPenalty = Integer.MAX_VALUE;
- for (int i = 0; i < 8; i++) {
- applyMask(i);
- drawFormatBits(i);
- int penalty = getPenaltyScore();
- if (penalty < minPenalty) {
- msk = i;
- minPenalty = penalty;
- }
- applyMask(i); // Undoes the mask due to XOR
+ private int handleConstructorMasking(int mask) {
+ if (mask == -1) {
+ mask = findBestMask();
+ }
+ assert 0 <= mask && mask <= 7;
+ applyMask(mask); // Apply the final choice of mask
+ drawFormatBits(mask); // Overwrite old format bits
+ return mask; // The caller shall assign this value to the final-declared field
+ }
+
+
+ // Automatically choose best mask
+ private int findBestMask() {
+ int mask = -1;
+ int minPenalty = Integer.MAX_VALUE;
+ for (int i = 0; i < 8; i++) {
+ applyMask(i);
+ drawFormatBits(i);
+ int penalty = getPenaltyScore();
+ if (penalty < minPenalty) {
+ mask = i;
+ minPenalty = penalty;
}
+ applyMask(i); // Undoes the mask due to XOR
}
- assert 0 <= msk && msk <= 7;
- applyMask(msk); // Apply the final choice of mask
- drawFormatBits(msk); // Overwrite old format bits
- return msk; // The caller shall assign this value to the final-declared field
+ return mask;
}
From 33734a9821ebc56043e5e73789d1195a9b2997fa Mon Sep 17 00:00:00 2001
From: wslbal
Date: Wed, 3 Jun 2020 10:10:49 +0900
Subject: [PATCH 18/28] 1) Factory Method Pattern 2) applyMask 3) dynamic
object construct
---
.../main/java/io/nayuki/qrcodegen/Msk1.java | 7 +++
.../main/java/io/nayuki/qrcodegen/Msk2.java | 7 +++
.../main/java/io/nayuki/qrcodegen/Msk3.java | 7 +++
.../main/java/io/nayuki/qrcodegen/Msk4.java | 7 +++
.../main/java/io/nayuki/qrcodegen/Msk5.java | 7 +++
.../main/java/io/nayuki/qrcodegen/Msk6.java | 7 +++
.../main/java/io/nayuki/qrcodegen/Msk7.java | 7 +++
.../nayuki/qrcodegen/MskCommandFactory.java | 46 ++++++++++++++++
.../main/java/io/nayuki/qrcodegen/QrCode.java | 55 ++++++++-----------
.../java/io/nayuki/qrcodegen/msk1Command.java | 13 +++++
.../java/io/nayuki/qrcodegen/msk2Command.java | 13 +++++
.../java/io/nayuki/qrcodegen/msk3Command.java | 13 +++++
.../java/io/nayuki/qrcodegen/msk4Command.java | 13 +++++
.../java/io/nayuki/qrcodegen/msk5Command.java | 13 +++++
.../java/io/nayuki/qrcodegen/msk6Command.java | 13 +++++
.../java/io/nayuki/qrcodegen/msk7Command.java | 13 +++++
16 files changed, 208 insertions(+), 33 deletions(-)
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Msk1.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Msk2.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Msk3.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Msk4.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Msk5.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Msk6.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Msk7.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/MskCommandFactory.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/msk1Command.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/msk2Command.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/msk3Command.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/msk4Command.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/msk5Command.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/msk6Command.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/msk7Command.java
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Msk1.java b/java/src/main/java/io/nayuki/qrcodegen/Msk1.java
new file mode 100644
index 0000000..f9f92e3
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Msk1.java
@@ -0,0 +1,7 @@
+package io.nayuki.qrcodegen;
+
+public class Msk1 {
+ public boolean operation(int y, int x, int msk) {
+ return (y % 2 == 0);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Msk2.java b/java/src/main/java/io/nayuki/qrcodegen/Msk2.java
new file mode 100644
index 0000000..42c145e
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Msk2.java
@@ -0,0 +1,7 @@
+package io.nayuki.qrcodegen;
+
+public class Msk2 {
+ public boolean operation(int y, int x, int msk) {
+ return (x % 3 == 0);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Msk3.java b/java/src/main/java/io/nayuki/qrcodegen/Msk3.java
new file mode 100644
index 0000000..45064c0
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Msk3.java
@@ -0,0 +1,7 @@
+package io.nayuki.qrcodegen;
+
+public class Msk3 {
+ public boolean operation(int y, int x, int msk) {
+ return ((x + y) % 3 == 0);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Msk4.java b/java/src/main/java/io/nayuki/qrcodegen/Msk4.java
new file mode 100644
index 0000000..d0b13a1
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Msk4.java
@@ -0,0 +1,7 @@
+package io.nayuki.qrcodegen;
+
+public class Msk4 {
+ public boolean operation(int y, int x, int msk) {
+ return ((x / 3 + y / 2) % 2 == 0);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Msk5.java b/java/src/main/java/io/nayuki/qrcodegen/Msk5.java
new file mode 100644
index 0000000..decc5df
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Msk5.java
@@ -0,0 +1,7 @@
+package io.nayuki.qrcodegen;
+
+public class Msk5 {
+ public boolean operation(int y, int x, int msk) {
+ return (x * y % 2 + x * y % 3 == 0);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Msk6.java b/java/src/main/java/io/nayuki/qrcodegen/Msk6.java
new file mode 100644
index 0000000..555fb64
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Msk6.java
@@ -0,0 +1,7 @@
+package io.nayuki.qrcodegen;
+
+public class Msk6 {
+ public boolean operation(int y, int x, int msk) {
+ return ((x * y % 2 + x * y % 3) % 2 == 0);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Msk7.java b/java/src/main/java/io/nayuki/qrcodegen/Msk7.java
new file mode 100644
index 0000000..7d98190
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Msk7.java
@@ -0,0 +1,7 @@
+package io.nayuki.qrcodegen;
+
+public class Msk7 {
+ public boolean operation(int y, int x, int msk) {
+ return (((x + y) % 2 + x * y % 3) % 2 == 0);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/MskCommandFactory.java b/java/src/main/java/io/nayuki/qrcodegen/MskCommandFactory.java
new file mode 100644
index 0000000..93bc177
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/MskCommandFactory.java
@@ -0,0 +1,46 @@
+package io.nayuki.qrcodegen;
+
+public class MskCommandFactory {
+ public static Command getCommand(int msk) {
+ Command theCommand = null;
+
+ Msk0 msk0 = new Msk0();
+ Msk1 msk1 = new Msk1();
+ Msk2 msk2 = new Msk2();
+ Msk3 msk3 = new Msk3();
+ Msk4 msk4 = new Msk4();
+ Msk5 msk5 = new Msk5();
+ Msk6 msk6 = new Msk6();
+ Msk7 msk7 = new Msk7();
+
+ switch (msk) {
+ case 0:
+ theCommand = new msk0Command(msk0);
+ break;
+ case 1:
+ theCommand = new msk1Command(msk1);
+ break;
+ case 2:
+ theCommand = new msk2Command(msk2);
+ break;
+ case 3:
+ theCommand = new msk3Command(msk3);
+ break;
+ case 4:
+ theCommand = new msk4Command(msk4);
+ break;
+ case 5:
+ theCommand = new msk5Command(msk5);
+ break;
+ case 6:
+ theCommand = new msk6Command(msk6);
+ break;
+ case 7:
+ theCommand = new msk7Command(msk7);
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return theCommand;
+ }
+}
\ No newline at end of file
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index a2cdbc2..9d4002d 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -542,35 +542,24 @@ public final class QrCode {
// The function modules must be marked and the codeword bits must be drawn
// before masking. Due to the arithmetic of XOR, calling applyMask() with
// the same mask value a second time will undo the mask. A final well-formed
- // QR Code needs exactly one (not zero, two, etc.) mask applied. Command pattern
+ // QR Code needs exactly one (not zero, two, etc.) mask applied.
private void applyMask(int msk) {
+
if (msk < 0 || msk > 7)
throw new IllegalArgumentException("Mask value out of range");
- for (int y = 0; y < size; y++) {
+ for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
boolean invert;
- Msk0 msk0 = new Msk0();
- Command mskCommand = new msk0Command(msk0);
-
+
+ Command mskCommand = MskCommandFactory.getCommand(msk);
Button button = new Button(mskCommand);
invert = button.pressed(y, x, msk);
- /*
- switch (msk) {
- case 0: invert = (x + y) % 2 == 0; break;
- case 1: invert = y % 2 == 0; break;
- case 2: invert = x % 3 == 0; break;
- case 3: invert = (x + y) % 3 == 0; break;
- case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
- case 5: invert = x * y % 2 + x * y % 3 == 0; break;
- case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
- case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
- default: throw new AssertionError();
- }
- */
+
modules[y][x] ^= invert & !isFunction[y][x];
}
}
}
+
// A messy helper function for the constructor. This QR Code must be in an unmasked state when this
@@ -619,21 +608,6 @@ public final class QrCode {
return result;
}
- private int twobytwoHavingSameColor(boolean[][] modules) {
- int result = 0;
- // 2*2 blocks of modules having same color
- for (int y = 0; y < size - 1; y++) {
- for (int x = 0; x < size - 1; x++) {
- boolean color = modules[y][x];
- if ( color == modules[y][x + 1] &&
- color == modules[y + 1][x] &&
- color == modules[y + 1][x + 1])
- result += PENALTY_N2;
- }
- }
- return result;
- }
-
// Calculates and returns the penalty score based on state of this QR Code's current modules.
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
private int getPenaltyScore() {
@@ -679,6 +653,21 @@ public final class QrCode {
return result;
}
+ private int twobytwoHavingSameColor(boolean[][] modules) {
+ int result = 0;
+ // 2*2 blocks of modules having same color.
+ for (int y = 0; y < size - 1; y++) {
+ for (int x = 0; x < size - 1; x++) {
+ boolean color = modules[y][x];
+ if ( color == modules[y][x + 1] &&
+ color == modules[y + 1][x] &&
+ color == modules[y + 1][x + 1])
+ result += PENALTY_N2;
+ }
+ }
+ return result;
+ }
+
/*---- Private helper functions ----*/
// Returns an ascending list of positions of alignment patterns for this version number.
diff --git a/java/src/main/java/io/nayuki/qrcodegen/msk1Command.java b/java/src/main/java/io/nayuki/qrcodegen/msk1Command.java
new file mode 100644
index 0000000..a503249
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/msk1Command.java
@@ -0,0 +1,13 @@
+package io.nayuki.qrcodegen;
+
+public class msk1Command implements Command {
+ private Msk1 theMsk1;
+
+ public msk1Command(Msk1 theMsk1) {
+ this.theMsk1 = theMsk1;
+ }
+
+ public boolean excute(int y, int x, int msk) {
+ return theMsk1.operation(y, x, msk);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/msk2Command.java b/java/src/main/java/io/nayuki/qrcodegen/msk2Command.java
new file mode 100644
index 0000000..d62f58e
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/msk2Command.java
@@ -0,0 +1,13 @@
+package io.nayuki.qrcodegen;
+
+public class msk2Command implements Command {
+ private Msk2 theMsk2;
+
+ public msk2Command(Msk2 theMsk2) {
+ this.theMsk2 = theMsk2;
+ }
+
+ public boolean excute(int y, int x, int msk) {
+ return theMsk2.operation(y, x, msk);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/msk3Command.java b/java/src/main/java/io/nayuki/qrcodegen/msk3Command.java
new file mode 100644
index 0000000..402f2a2
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/msk3Command.java
@@ -0,0 +1,13 @@
+package io.nayuki.qrcodegen;
+
+public class msk3Command implements Command {
+ private Msk3 theMsk3;
+
+ public msk3Command(Msk3 theMsk3) {
+ this.theMsk3 = theMsk3;
+ }
+
+ public boolean excute(int y, int x, int msk) {
+ return theMsk3.operation(y, x, msk);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/msk4Command.java b/java/src/main/java/io/nayuki/qrcodegen/msk4Command.java
new file mode 100644
index 0000000..ca755fc
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/msk4Command.java
@@ -0,0 +1,13 @@
+package io.nayuki.qrcodegen;
+
+public class msk4Command implements Command {
+ private Msk4 theMsk4;
+
+ public msk4Command(Msk4 theMsk4) {
+ this.theMsk4 = theMsk4;
+ }
+
+ public boolean excute(int y, int x, int msk) {
+ return theMsk4.operation(y, x, msk);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/msk5Command.java b/java/src/main/java/io/nayuki/qrcodegen/msk5Command.java
new file mode 100644
index 0000000..7a6f4b1
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/msk5Command.java
@@ -0,0 +1,13 @@
+package io.nayuki.qrcodegen;
+
+public class msk5Command implements Command {
+ private Msk5 theMsk5;
+
+ public msk5Command(Msk5 theMsk5) {
+ this.theMsk5 = theMsk5;
+ }
+
+ public boolean excute(int y, int x, int msk) {
+ return theMsk5.operation(y, x, msk);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/msk6Command.java b/java/src/main/java/io/nayuki/qrcodegen/msk6Command.java
new file mode 100644
index 0000000..078c270
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/msk6Command.java
@@ -0,0 +1,13 @@
+package io.nayuki.qrcodegen;
+
+public class msk6Command implements Command {
+ private Msk6 theMsk6;
+
+ public msk6Command(Msk6 theMsk6) {
+ this.theMsk6 = theMsk6;
+ }
+
+ public boolean excute(int y, int x, int msk) {
+ return theMsk6.operation(y, x, msk);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/msk7Command.java b/java/src/main/java/io/nayuki/qrcodegen/msk7Command.java
new file mode 100644
index 0000000..b5c9e2c
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/msk7Command.java
@@ -0,0 +1,13 @@
+package io.nayuki.qrcodegen;
+
+public class msk7Command implements Command {
+ private Msk7 theMsk7;
+
+ public msk7Command(Msk7 theMsk7) {
+ this.theMsk7 = theMsk7;
+ }
+
+ public boolean excute(int y, int x, int msk) {
+ return theMsk7.operation(y, x, msk);
+ }
+}
From 7047caa546b31a7e6f979403d3343efa5e6342f6 Mon Sep 17 00:00:00 2001
From: gerzees
Date: Wed, 3 Jun 2020 10:23:45 +0900
Subject: [PATCH 19/28] 1. Move method 2. addPad in QrCode 3. Feature envy.
addPad call only BitBuffer methods.
---
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index f619deb..c652ab6 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -172,7 +172,7 @@ public final class QrCode {
addTerminator(bitBuffer, dataCapacityBits);
- addPad(bitBuffer, dataCapacityBits);
+ bitBuffer.addPad(dataCapacityBits);
byte[] dataCodewords = bitBufferToCodewords(bitBuffer);
@@ -192,12 +192,6 @@ public final class QrCode {
}
- // Pad with alternating bytes until data capacity is reached
- private static void addPad(BitBuffer bitBuffer, int dataCapacityBits) {
- for (int padByte = 0xEC; bitBuffer.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
- bitBuffer.appendBits(padByte, 8);
- }
-
// Add terminator and pad up to a byte if applicable
private static void addTerminator(BitBuffer bitBuffer, int dataCapacityBits) {
bitBuffer.appendBits(0, Math.min(4, dataCapacityBits - bitBuffer.bitLength()));
From 4ddf3a02c727c757bbe8fcda8680cbe768b2d093 Mon Sep 17 00:00:00 2001
From: gerzees
Date: Wed, 3 Jun 2020 10:25:59 +0900
Subject: [PATCH 20/28] 1. Move method 2. addPad to BitBuffer 3. Feature envy.
addPad calls only BitBuffer methods.
---
java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java b/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
index 624d129..807d988 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
@@ -125,5 +125,12 @@ public final class BitBuffer implements Cloneable {
throw new AssertionError(e);
}
}
+
+
+ // Pad with alternating bytes until data capacity is reached
+ void addPad(int dataCapacityBits) {
+ for (int padByte = 0xEC; bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ appendBits(padByte, 8);
+ }
}
From 889fc7d9d5ec65f7c7fe013e3e3483acb0fe2eb0 Mon Sep 17 00:00:00 2001
From: gerzees
Date: Wed, 3 Jun 2020 10:30:39 +0900
Subject: [PATCH 21/28] 1. Move method, rename 2. bitBufferToCodewords in
QrCode 3.Feature envy. It calls only BitBuffer method. Moved it to BitBuffer
and renamed it.
---
.../src/main/java/io/nayuki/qrcodegen/BitBuffer.java | 11 ++++++++++-
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 12 ++----------
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java b/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
index 807d988..ccebe37 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
@@ -128,9 +128,18 @@ public final class BitBuffer implements Cloneable {
// Pad with alternating bytes until data capacity is reached
- void addPad(int dataCapacityBits) {
+ public void addPad(int dataCapacityBits) {
for (int padByte = 0xEC; bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
appendBits(padByte, 8);
}
+
+
+ // Pack bits into bytes in big endian
+ public byte[] toCodewords() {
+ byte[] dataCodewords = new byte[bitLength() / 8];
+ for (int i = 0; i < bitLength(); i++)
+ dataCodewords[i >>> 3] |= getBit(i) << (7 - (i & 7));
+ return dataCodewords;
+ }
}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index c652ab6..7b85539 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -175,7 +175,7 @@ public final class QrCode {
bitBuffer.addPad(dataCapacityBits);
- byte[] dataCodewords = bitBufferToCodewords(bitBuffer);
+ byte[] dataCodewords = bitBuffer.toCodewords();
// Create the QR Code object
return new QrCode(version, errorCorrectionLevel, dataCodewords, mask);
@@ -183,15 +183,7 @@ public final class QrCode {
/*---- Private helper methods for encodeSegments ----*/
- // Pack bits into bytes in big endian
- private static byte[] bitBufferToCodewords(BitBuffer bitBuffer) {
- byte[] dataCodewords = new byte[bitBuffer.bitLength() / 8];
- for (int i = 0; i < bitBuffer.bitLength(); i++)
- dataCodewords[i >>> 3] |= bitBuffer.getBit(i) << (7 - (i & 7));
- return dataCodewords;
- }
-
-
+
// Add terminator and pad up to a byte if applicable
private static void addTerminator(BitBuffer bitBuffer, int dataCapacityBits) {
bitBuffer.appendBits(0, Math.min(4, dataCapacityBits - bitBuffer.bitLength()));
From 62ad71d6d72e25e0df04df268dddc68e76c7eb6a Mon Sep 17 00:00:00 2001
From: gerzees
Date: Wed, 3 Jun 2020 10:37:53 +0900
Subject: [PATCH 22/28] 1. Move method 2. addTerminator in QrCode 3. Feature
envy. It calls only BitBuffer methods.
---
java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java | 8 ++++++++
java/src/main/java/io/nayuki/qrcodegen/QrCode.java | 8 +-------
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java b/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
index ccebe37..8b4254e 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
@@ -141,5 +141,13 @@ public final class BitBuffer implements Cloneable {
dataCodewords[i >>> 3] |= getBit(i) << (7 - (i & 7));
return dataCodewords;
}
+
+
+ // Add terminator and pad up to a byte if applicable
+ public void addTerminator(int dataCapacityBits) {
+ appendBits(0, Math.min(4, dataCapacityBits - bitLength()));
+ appendBits(0, (8 - bitLength() % 8) % 8);
+ assert bitLength() % 8 == 0;
+ }
}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index 7b85539..cebfbea 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -169,7 +169,7 @@ public final class QrCode {
int dataCapacityBits = getNumDataCodewords(version, errorCorrectionLevel) * 8;
assert bitBuffer.bitLength() <= dataCapacityBits;
- addTerminator(bitBuffer, dataCapacityBits);
+ bitBuffer.addTerminator(dataCapacityBits);
bitBuffer.addPad(dataCapacityBits);
@@ -184,12 +184,6 @@ public final class QrCode {
/*---- Private helper methods for encodeSegments ----*/
- // Add terminator and pad up to a byte if applicable
- private static void addTerminator(BitBuffer bitBuffer, int dataCapacityBits) {
- bitBuffer.appendBits(0, Math.min(4, dataCapacityBits - bitBuffer.bitLength()));
- bitBuffer.appendBits(0, (8 - bitBuffer.bitLength() % 8) % 8);
- assert bitBuffer.bitLength() % 8 == 0;
- }
// Concatenate all segments to create the data bit string
private static BitBuffer segmentsToBitBuffer(List segments, int version) {
From b63fa83f32588dc046d96300b80d6552b960d060 Mon Sep 17 00:00:00 2001
From: minsu4107 <32637512+minsu4107@users.noreply.github.com>
Date: Fri, 5 Jun 2020 16:49:40 +0900
Subject: [PATCH 23/28] 1. Strategy Pattern 2. QrSegmentsAdvanced 3. If i want
to add new mode for making qrcode, I add many part of this code so, I using
strategy pattern
---
.../nayuki/qrcodegen/QrSegmentAdvanced.java | 222 ++++--------------
1 file changed, 50 insertions(+), 172 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
index 19a32c1..a4f039c 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
@@ -112,16 +112,15 @@ public final class QrSegmentAdvanced {
private static List makeSegmentsOptimally(int[] codePoints, int version) {
if (codePoints.length == 0)
return new ArrayList<>();
- Mode[] charModes = computeCharacterModes(codePoints, version);
+ QrMode[] charModes = computeCharacterModes(codePoints, version);
return splitIntoSegments(codePoints, charModes);
}
-
// Returns a new array representing the optimal mode per code point based on the given text and version.
- private static Mode[] computeCharacterModes(int[] codePoints, int version) {
+ private static QrMode[] computeCharacterModes(int[] codePoints, int version) {
if (codePoints.length == 0)
throw new IllegalArgumentException();
- final Mode[] modeTypes = {Mode.BYTE, Mode.ALPHANUMERIC, Mode.NUMERIC, Mode.KANJI}; // Do not modify
+ final QrMode[] modeTypes = {new ByteMode(), new AlphanumericMode(), new NumericMode(), new KanjiMode()}; // Do not modify
final int numModes = modeTypes.length;
// Segment header sizes, measured in 1/6 bits
@@ -132,7 +131,7 @@ public final class QrSegmentAdvanced {
// charModes[i][j] represents the mode to encode the code point at
// index i such that the final segment ends in modeTypes[j] and the
// total number of bits is minimized over all possible choices
- Mode[][] charModes = new Mode[codePoints.length][numModes];
+ QrMode[][] charModes = new QrMode[codePoints.length][numModes];
// At the beginning of each iteration of the loop below,
// prevCosts[j] is the exact minimum number of 1/6 bits needed to
@@ -143,44 +142,44 @@ public final class QrSegmentAdvanced {
prevCosts = calculate_cost(codePoints, modeTypes, numModes, headCosts, charModes, prevCosts);
// Find optimal ending mode
- Mode curMode = find_optimal(modeTypes, numModes, prevCosts);
+ QrMode curMode = null;
+ curMode = find_optimal(modeTypes, numModes, prevCosts, curMode);
// Get optimal mode for each code point by tracing backwards
- Mode[] result = new Mode[charModes.length];
+ QrMode[] result = new QrMode[codePoints.length];
get_optimal(modeTypes, numModes, charModes, curMode, result);
return result;
}
- private static int[] calculate_cost(int[] codePoints, final Mode[] modeTypes, final int numModes,
- final int[] headCosts, Mode[][] charModes, int[] prevCosts) {
+ private static int[] calculate_cost(int[] codePoints, final QrMode[] modeTypes, final int numModes,
+ final int[] headCosts, QrMode[][] charModes, int[] prevCosts) {
for (int i = 0; i < codePoints.length; i++) {
- int cPoint = codePoints[i];
+ int codePoint = codePoints[i];
int[] curCosts = new int[numModes];
{ // Always extend a byte mode segment
- curCosts[0] = prevCosts[0] + countUtf8Bytes(cPoint) * 8 * 6;
- charModes[i][0] = modeTypes[0];
+ charModes[i][0] = new ByteMode();
+ curCosts[0] = charModes[i][0].getcost(prevCosts[0], codePoint);
}
// Extend a segment if possible
- if (is_alphanumeric(cPoint)) { // Is alphanumeric
- curCosts[1] = prevCosts[1] + 33; // 5.5 bits per alphanumeric char
- charModes[i][1] = modeTypes[1];
+ if (QrSegment.ALPHANUMERIC_CHARSET.indexOf(codePoint) != -1) { // Is alphanumeric
+ charModes[i][1] = new AlphanumericMode();
+ curCosts[1] = charModes[i][1].getcost(prevCosts[1], codePoint); // 5.5 bits per alphanumeric char
}
- if (is_numeric(cPoint)) { // Is numeric
- curCosts[2] = prevCosts[2] + 20; // 3.33 bits per digit
- charModes[i][2] = modeTypes[2];
+ if ('0' <= codePoint && codePoint <= '9') { // Is numeric
+ charModes[i][2] = new NumericMode();
+ curCosts[2] = charModes[i][2].getcost(prevCosts[2], codePoint); // 3.33 bits per digit
}
- if (isKanji(cPoint)) {
- curCosts[3] = prevCosts[3] + 78; // 13 bits per Shift JIS char
- charModes[i][3] = modeTypes[3];
+ if (isKanji(codePoint)) {
+ charModes[i][3] = new KanjiMode();
+ curCosts[3] = charModes[i][3].getcost(prevCosts[3], codePoint);; // 13 bits per Shift JIS char
}
-
+
// Start new segment at the end to switch modes
for (int j = 0; j < numModes; j++) { // To mode
for (int k = 0; k < numModes; k++) { // From mode
int newCost = (curCosts[k] + 5) / 6 * 6 + headCosts[j];
- boolean is_lower = charModes[i][k] != null && (charModes[i][j] == null || newCost < curCosts[j]);
- if (is_lower) {
+ if (charModes[i][k] != null && (charModes[i][j] == null || newCost < curCosts[j])) {
curCosts[j] = newCost;
charModes[i][j] = modeTypes[k];
}
@@ -193,8 +192,8 @@ public final class QrSegmentAdvanced {
}
- private static void get_optimal(final Mode[] modeTypes, final int numModes, Mode[][] charModes, Mode curMode,
- Mode[] result) {
+ private static void get_optimal(final QrMode[] modeTypes, final int numModes, QrMode[][] charModes, QrMode curMode,
+ QrMode[] result) {
for (int i = result.length - 1; i >= 0; i--) {
for (int j = 0; j < numModes; j++) {
if (modeTypes[j] == curMode) {
@@ -207,8 +206,7 @@ public final class QrSegmentAdvanced {
}
- private static Mode find_optimal(final Mode[] modeTypes, final int numModes, int[] prevCosts) {
- Mode curMode = null;
+ private static QrMode find_optimal(final QrMode[] modeTypes, final int numModes, int[] prevCosts, QrMode curMode) {
for (int i = 0, minCost = 0; i < numModes; i++) {
if (curMode == null || prevCosts[i] < minCost) {
minCost = prevCosts[i];
@@ -219,40 +217,31 @@ public final class QrSegmentAdvanced {
}
- private static boolean is_numeric(int c) {
- return '0' <= c && c <= '9';
+ private static boolean is_numeric(int convertedPoint) {
+ return '0' <= convertedPoint && convertedPoint <= '9';
}
- private static boolean is_alphanumeric(int c) {
- return QrSegment.ALPHANUMERIC_CHARSET.indexOf(c) != -1;
+ private static boolean is_alphanumeric(int convertedPoint) {
+ return QrSegment.ALPHANUMERIC_CHARSET.indexOf(convertedPoint) != -1;
}
// Returns a new list of segments based on the given text and modes, such that
// consecutive code points in the same mode are put into the same segment.
- private static List splitIntoSegments(int[] codePoints, Mode[] charModes) {
+ private static List splitIntoSegments(int[] codePoints, QrMode[] charModes) {
if (codePoints.length == 0)
throw new IllegalArgumentException();
List result = new ArrayList<>();
// Accumulate run of modes
- Mode curMode = charModes[0];
+ QrMode curMode = charModes[0];
int start = 0;
for (int i = 1; ; i++) {
if (i < codePoints.length && charModes[i] == curMode)
continue;
String s = new String(codePoints, start, i - start);
- if (curMode == Mode.BYTE)
- result.add(QrSegment.makeBytes(s.getBytes(StandardCharsets.UTF_8)));
- else if (curMode == Mode.NUMERIC)
- result.add(QrSegment.makeNumeric(s));
- else if (curMode == Mode.ALPHANUMERIC)
- result.add(QrSegment.makeAlphanumeric(s));
- else if (curMode == Mode.KANJI)
- result.add(makeKanji(s));
- else
- throw new AssertionError();
+ result.add(curMode.making(s));
if (i >= codePoints.length)
return result;
curMode = charModes[i];
@@ -263,8 +252,8 @@ public final class QrSegmentAdvanced {
// Returns a new array of Unicode code points (effectively
// UTF-32 / UCS-4) representing the given UTF-16 string.
- private static int[] toCodePoints(String s) {
- int[] result = s.codePoints().toArray();
+ private static int[] toCodePoints(String str) {
+ int[] result = str.codePoints().toArray();
for (int c : result) {
if (Character.isSurrogate((char)c))
throw new IllegalArgumentException("Invalid UTF-16 string");
@@ -274,7 +263,7 @@ public final class QrSegmentAdvanced {
// Returns the number of UTF-8 bytes needed to encode the given Unicode code point.
- private static int countUtf8Bytes(int currentPoint) {
+ public static int countUtf8Bytes(int currentPoint) {
if (currentPoint < 0) throw new IllegalArgumentException("Invalid code point");
else if (currentPoint < 0x80) return 1;
else if (currentPoint < 0x800) return 2;
@@ -334,118 +323,7 @@ public final class QrSegmentAdvanced {
}
// Data derived from ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
-// private static final String PACKED_QR_KANJI_TO_UNICODE = readPacked_KANJI();
- private static final String PACKED_QR_KANJI_TO_UNICODE =
- "MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZA" +
- "ALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA///////////////////" +
- "//////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h" +
- "/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBN" +
- "ME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////" +
- "////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDh" +
- "MOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+" +
- "A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQm" +
- "BCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQ" +
- "JRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "/////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32t" +
- "fe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYg" +
- "ZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2" +
- "cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5" +
- "////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLs" +
- "bTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CE" +
- "lFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKg" +
- "dZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/" +
- "U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6" +
- "UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo" +
- "//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6r" +
- "XydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOn" +
- "ZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtk" +
- "mANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiV" +
- "nfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/X" +
- "YB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6luf" +
- "hQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/S" +
- "ge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZ" +
- "WXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJac" +
- "l5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066" +
- "TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bb" +
- "fL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6" +
- "ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333P" +
- "fZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7e" +
- "gM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bj" +
- "WMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0" +
- "gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oC" +
- "iuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhY" +
- "WVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLr" +
- "W8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/D" +
- "fQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGro" +
- "XmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/" +
- "l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16c" +
- "YBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7" +
- "WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851s" +
- "Tk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04H" +
- "YWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5f" +
- "UbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+K" +
- "gACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHM" +
- "W+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3v" +
- "lzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV////////////////////////////////////////////////////////////////////////////////////////" +
- "/////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/l" +
- "UBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGT" +
- "UZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQ" +
- "Uw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////" +
- "VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaP" +
- "VqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4" +
- "WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrj" +
- "Wtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yr" +
- "XLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/" +
- "XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQ" +
- "YClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FY" +
- "YVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KU" +
- "Ytdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTH" +
- "ZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2Zo" +
- "Zl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGge" +
- "aEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammy" +
- "aa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7" +
- "awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzX" +
- "bMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7J" +
- "brdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3Aw" +
- "cD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKy" +
- "csNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTy" +
- "dPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYw" +
- "djt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7" +
- "d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXog" +
- "eh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuc" +
- "e5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G" +
- "////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5a" +
- "fnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAh" +
- "gCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHC" +
- "gbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMv" +
- "gyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UY" +
- "hSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs" +
- "//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZ" +
- "iF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9" +
- "ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tf" +
- "i2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3b" +
- "jcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485" +
- "j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEy" +
- "kTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNW" +
- "k7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYu" +
- "li+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJem" +
- "l6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnY" +
- "mdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uD" +
- "m5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1k" +
- "nVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+" +
- "n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "/////////////////////////////////////////////w==";
+ private static final String PACKED_QR_KANJI_TO_UNICODE = readPacked_KANJI();
private static short[] UNICODE_TO_QR_KANJI = new short[1 << 16];
@@ -462,19 +340,19 @@ public final class QrSegmentAdvanced {
}
}
-// private static String readPacked_KANJI() {
-// String str = "";
-// try {
-// File file = new File("./packet_KanJI.txt");
-// Scanner scan = new Scanner(file);
-// str +=scan.nextLine();
-// scan.close();
-// }
-// catch(FileNotFoundException e){
-// }
-//
-// return str;
-// }
+ private static String readPacked_KANJI() {
+ String str = "";
+ try {
+ File file = new File("./packet_KanJI.txt");
+ Scanner scan = new Scanner(file);
+ str +=scan.nextLine();
+ scan.close();
+ }
+ catch(FileNotFoundException e){
+ }
+
+ return str;
+ }
/*---- Miscellaneous ----*/
From 3383e1b34fee8666bc2d05547f87748539bec82d Mon Sep 17 00:00:00 2001
From: wslbal
Date: Fri, 5 Jun 2020 23:20:32 +0900
Subject: [PATCH 24/28] =?UTF-8?q?merge=20=EC=98=A4=EB=A5=98=EC=97=90=20?=
=?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/io/nayuki/qrcodegen/BitBuffer.java | 26 +-
.../main/java/io/nayuki/qrcodegen/QrCode.java | 352 ++++++++++--------
.../nayuki/qrcodegen/QrSegmentAdvanced.java | 284 ++++++--------
3 files changed, 332 insertions(+), 330 deletions(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java b/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
index 624d129..4ff3e42 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
@@ -125,5 +125,29 @@ public final class BitBuffer implements Cloneable {
throw new AssertionError(e);
}
}
+
+
+ // Pad with alternating bytes until data capacity is reached
+ public void addPad(int dataCapacityBits) {
+ for (int padByte = 0xEC; bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ appendBits(padByte, 8);
+ }
+
+
+ // Pack bits into bytes in big endian
+ public byte[] toCodewords() {
+ byte[] dataCodewords = new byte[bitLength() / 8];
+ for (int i = 0; i < bitLength(); i++)
+ dataCodewords[i >>> 3] |= getBit(i) << (7 - (i & 7));
+ return dataCodewords;
+ }
+
+
+ // Add terminator and pad up to a byte if applicable
+ public void addTerminator(int dataCapacityBits) {
+ appendBits(0, Math.min(4, dataCapacityBits - bitLength()));
+ appendBits(0, (8 - bitLength() % 8) % 8);
+ assert bitLength() % 8 == 0;
+ }
-}
+}
\ No newline at end of file
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index 9d4002d..733f10d 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -51,9 +51,15 @@ import java.util.Objects;
* @see QrSegment
*/
public final class QrCode {
+
+ private static final int FINDER_SIZE = 3;
+
+ private static final int TIMING_COORDINATE = 6;
- /*---- Static factory functions (high level) ----*/
+
+ /*---- Static factory functions (high level) ----*/
+
/**
* Returns a QR Code representing the specified Unicode text string at the specified error correction level.
* As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
@@ -73,8 +79,8 @@ public final class QrCode {
List segs = QrSegment.makeSegments(text);
return encodeSegments(segs, ecl);
}
-
-
+
+
/**
* Returns a QR Code representing the specified binary data at the specified error correction level.
* This function always encodes using the binary segment mode, not any text mode. The maximum number of
@@ -93,10 +99,10 @@ public final class QrCode {
QrSegment seg = QrSegment.makeBytes(data);
return encodeSegments(Arrays.asList(seg), ecl);
}
-
-
+
+
/*---- Static factory functions (mid level) ----*/
-
+
/**
* Returns a QR Code representing the specified segments at the specified error correction
* level. The smallest possible QR Code version is automatically chosen for the output. The ECC level
@@ -115,8 +121,8 @@ public final class QrCode {
public static QrCode encodeSegments(List segs, Ecc ecl) {
return encodeSegments(segs, ecl, MIN_VERSION, MAX_VERSION, -1, true);
}
-
-
+
+
/**
* Returns a QR Code representing the specified segments with the specified encoding parameters.
* The smallest possible QR Code version within the specified range is automatically
@@ -128,8 +134,8 @@ public final class QrCode {
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)}
* and {@link #encodeBinary(byte[],Ecc)}.
- * @param segs the segments to encode
- * @param ecl the error correction level to use (not {@code null}) (boostable)
+ * @param segments the segments to encode
+ * @param errorCorrectionLevel the error correction level to use (not {@code null}) (boostable)
* @param minVersion the minimum allowed version of the QR Code (at least 1)
* @param maxVersion the maximum allowed version of the QR Code (at most 40)
* @param mask the mask number to use (between 0 and 7 (inclusive)), or −1 for automatic mask
@@ -141,136 +147,159 @@ public final class QrCode {
* @throws DataTooLongException if the segments fail to fit in
* the maxVersion QR Code at the ECL, which means they are too long
*/
- public static QrCode encodeSegments(List segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) {
- Objects.requireNonNull(segs);
- Objects.requireNonNull(ecl);
- if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
+ public static QrCode encodeSegments(List segments, Ecc errorCorrectionLevel, int minVersion, int maxVersion, int mask, boolean boostEcl) {
+ Objects.requireNonNull(segments);
+ Objects.requireNonNull(errorCorrectionLevel);
+ final boolean isVersionInRange = MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION;
+ final boolean isMaskOutOfRange = mask < -1 || mask > 7;
+ if (!isVersionInRange || isMaskOutOfRange)
throw new IllegalArgumentException("Invalid value");
+
+
+ int version = findMinimalVersion(segments, errorCorrectionLevel, minVersion, maxVersion);
+
+ int dataUsedBits = QrSegment.getTotalBits(segments, version);
+
+ errorCorrectionLevel = findMaximalErrorCorrectionLevel(errorCorrectionLevel, boostEcl, version, dataUsedBits);
+
+
+ BitBuffer bitBuffer = segmentsToBitBuffer(segments, version);
+ assert bitBuffer.bitLength() == dataUsedBits;
+
+
+ int dataCapacityBits = getNumDataCodewords(version, errorCorrectionLevel) * 8;
+ assert bitBuffer.bitLength() <= dataCapacityBits;
+ bitBuffer.addTerminator(dataCapacityBits);
+
+
+ bitBuffer.addPad(dataCapacityBits);
+
+
+ byte[] dataCodewords = bitBuffer.toCodewords();
+
+ // Create the QR Code object
+ return new QrCode(version, errorCorrectionLevel, dataCodewords, mask);
+ }
+
+ /*---- Private helper methods for encodeSegments ----*/
+
+
+
+ // Concatenate all segments to create the data bit string
+ private static BitBuffer segmentsToBitBuffer(List segments, int version) {
+ BitBuffer bitBuffer = new BitBuffer();
+ for (QrSegment segment : segments) {
+ bitBuffer.appendBits(segment.mode.modeBits, 4);
+ bitBuffer.appendBits(segment.numChars, segment.mode.numCharCountBits(version));
+ bitBuffer.appendData(segment.data);
+ }
+ return bitBuffer;
+ }
+
+
+ // Increase the error correction level while the data still fits in the current version number
+ private static Ecc findMaximalErrorCorrectionLevel(Ecc errorCorrectionLevel, boolean boostEcl, int version,
+ int dataUsedBits) {
+ for (Ecc newEcl : Ecc.values()) { // From low to high
+ final boolean canIncreaseErrorCorrectionLevel = dataUsedBits <= getNumDataCodewords(version, newEcl) * 8;
+ if (boostEcl && canIncreaseErrorCorrectionLevel)
+ errorCorrectionLevel = newEcl;
+ }
+ return errorCorrectionLevel;
+ }
+
- // Find the minimal version number to use
+ //Returns the minimal version number to use
+ private static int findMinimalVersion(List segments, Ecc errorCorrectionLevel, int minVersion,
+ int maxVersion) {
int version, dataUsedBits;
for (version = minVersion; ; version++) {
- int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
- dataUsedBits = QrSegment.getTotalBits(segs, version);
+ int dataCapacityBits = getNumDataCodewords(version, errorCorrectionLevel) * 8; // Number of data bits available
+ dataUsedBits = QrSegment.getTotalBits(segments, version);
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
break; // This version number is found to be suitable
if (version >= maxVersion) { // All versions in the range could not fit the given data
- String msg = "Segment too long";
+ String message = "Segment too long";
if (dataUsedBits != -1)
- msg = String.format("Data length = %d bits, Max capacity = %d bits", dataUsedBits, dataCapacityBits);
- throw new DataTooLongException(msg);
+ message = String.format("Data length = %d bits, Max capacity = %d bits", dataUsedBits, dataCapacityBits);
+ throw new DataTooLongException(message);
}
}
assert dataUsedBits != -1;
-
- // Increase the error correction level while the data still fits in the current version number
- for (Ecc newEcl : Ecc.values()) { // From low to high
- if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
- ecl = newEcl;
- }
-
- // Concatenate all segments to create the data bit string
- BitBuffer bb = new BitBuffer();
- for (QrSegment seg : segs) {
- bb.appendBits(seg.mode.modeBits, 4);
- bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
- bb.appendData(seg.data);
- }
- assert bb.bitLength() == dataUsedBits;
-
- // Add terminator and pad up to a byte if applicable
- int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
- assert bb.bitLength() <= dataCapacityBits;
- bb.appendBits(0, Math.min(4, dataCapacityBits - bb.bitLength()));
- bb.appendBits(0, (8 - bb.bitLength() % 8) % 8);
- assert bb.bitLength() % 8 == 0;
-
- // Pad with alternating bytes until data capacity is reached
- for (int padByte = 0xEC; bb.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
- bb.appendBits(padByte, 8);
-
- // Pack bits into bytes in big endian
- byte[] dataCodewords = new byte[bb.bitLength() / 8];
- for (int i = 0; i < bb.bitLength(); i++)
- dataCodewords[i >>> 3] |= bb.getBit(i) << (7 - (i & 7));
-
- // Create the QR Code object
- return new QrCode(version, ecl, dataCodewords, mask);
+ return version;
}
-
-
-
+
/*---- Instance fields ----*/
-
+
// Public immutable scalar parameters:
-
+
/** The version number of this QR Code, which is between 1 and 40 (inclusive).
* This determines the size of this barcode. */
public final int version;
-
+
/** The width and height of this QR Code, measured in modules, between
* 21 and 177 (inclusive). This is equal to version × 4 + 17. */
public final int size;
-
+
/** The error correction level used in this QR Code, which is not {@code null}. */
public final Ecc errorCorrectionLevel;
-
+
/** The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
*
Even if a QR Code is created with automatic masking requested (mask =
* −1), the resulting object still has a mask value between 0 and 7. */
public final int mask;
-
+
// Private grids of modules/pixels, with dimensions of size*size:
-
+
// The modules of this QR Code (false = white, true = black).
// Immutable after constructor finishes. Accessed through getModule().
private boolean[][] modules;
-
+
// Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
private boolean[][] isFunction;
-
-
-
+
+
+
/*---- Constructor (low level) ----*/
-
+
/**
* Constructs a QR Code with the specified version number,
* error correction level, data codeword bytes, and mask number.
*
This is a low-level API that most users should not use directly. A mid-level
* API is the {@link #encodeSegments(List,Ecc,int,int,int,boolean)} function.
- * @param ver the version number to use, which must be in the range 1 to 40 (inclusive)
- * @param ecl the error correction level to use
+ * @param version the version number to use, which must be in the range 1 to 40 (inclusive)
+ * @param errorCorrectionLevel the error correction level to use
* @param dataCodewords the bytes representing segments to encode (without ECC)
- * @param msk the mask pattern to use, which is either −1 for automatic choice or from 0 to 7 for fixed choice
+ * @param mask the mask pattern to use, which is either −1 for automatic choice or from 0 to 7 for fixed choice
* @throws NullPointerException if the byte array or error correction level is {@code null}
* @throws IllegalArgumentException if the version or mask value is out of range,
* or if the data is the wrong length for the specified version and error correction level
*/
- public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int msk) {
+ public QrCode(int version, Ecc errorCorrectionLevel, byte[] dataCodewords, int mask) {
// Check arguments and initialize fields
- if (ver < MIN_VERSION || ver > MAX_VERSION)
+ if (version < MIN_VERSION || version > MAX_VERSION)
throw new IllegalArgumentException("Version value out of range");
- if (msk < -1 || msk > 7)
+ if (mask < -1 || mask > 7)
throw new IllegalArgumentException("Mask value out of range");
- version = ver;
- size = ver * 4 + 17;
- errorCorrectionLevel = Objects.requireNonNull(ecl);
+ this.version = version;
+ this.size = version * 4 + 17;
+ this.errorCorrectionLevel = Objects.requireNonNull(errorCorrectionLevel);
Objects.requireNonNull(dataCodewords);
- modules = new boolean[size][size]; // Initially all white
- isFunction = new boolean[size][size];
-
+ this.modules = new boolean[size][size]; // Initially all white
+ this.isFunction = new boolean[size][size];
+
// Compute ECC, draw modules, do masking
drawFunctionPatterns();
byte[] allCodewords = addEccAndInterleave(dataCodewords);
drawCodewords(allCodewords);
- this.mask = handleConstructorMasking(msk);
+ this.mask = handleConstructorMasking(mask);
isFunction = null;
}
-
-
-
+
+
+
/*---- Public instance methods ----*/
-
+
/**
* Returns the color of the module (pixel) at the specified coordinates, which is {@code false}
* for white or {@code true} for black. The top left corner has the coordinates (x=0, y=0).
@@ -283,8 +312,8 @@ public final class QrCode {
public boolean getModule(int x, int y) {
return 0 <= x && x < size && 0 <= y && y < size && modules[y][x];
}
-
-
+
+
/**
* Returns a raster image depicting this QR Code, with the specified module scale and border modules.
*
For example, toImage(scale=10, border=4) means to pad the QR Code with 4 white
@@ -301,7 +330,7 @@ public final class QrCode {
throw new IllegalArgumentException("Value out of range");
if (border > Integer.MAX_VALUE / 2 || size + border * 2L > Integer.MAX_VALUE / scale)
throw new IllegalArgumentException("Scale or border too large");
-
+
BufferedImage result = new BufferedImage((size + border * 2) * scale, (size + border * 2) * scale, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < result.getHeight(); y++) {
for (int x = 0; x < result.getWidth(); x++) {
@@ -311,8 +340,8 @@ public final class QrCode {
}
return result;
}
-
-
+
+
/**
* Returns a string of SVG code for an image depicting this QR Code, with the specified number
* of border modules. The string always uses Unix newlines (\n), regardless of the platform.
@@ -325,12 +354,12 @@ public final class QrCode {
throw new IllegalArgumentException("Border must be non-negative");
long brd = border;
StringBuilder sb = new StringBuilder()
- .append("\n")
- .append("\n")
- .append(String.format("\n",
- size + brd * 2))
- .append("\t\n")
- .append("\t\n")
+ .append("\n")
+ .append(String.format("\n",
+ size + brd * 2))
+ .append("\t\n")
+ .append("\t\n")
- .append("\n")
- .toString();
+ .append("\" fill=\"#000000\"/>\n")
+ .append("\n")
+ .toString();
}
-
-
-
+
+
+
/*---- Private helper methods for constructor: Drawing function modules ----*/
-
+
// Reads this object's version field, and draws and marks all function modules.
private void drawFunctionPatterns() {
// Draw horizontal and vertical timing patterns
for (int i = 0; i < size; i++) {
- setFunctionModule(6, i, i % 2 == 0);
- setFunctionModule(i, 6, i % 2 == 0);
+ setFunctionModule(TIMING_COORDINATE, i, i % 2 == 0);
+ setFunctionModule(i, TIMING_COORDINATE, i % 2 == 0);
}
-
+
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
- drawFinderPattern(3, 3);
- drawFinderPattern(size - 4, 3);
- drawFinderPattern(3, size - 4);
+ drawFinderPattern(FINDER_SIZE, FINDER_SIZE);
+ drawFinderPattern(size - 1 - FINDER_SIZE, FINDER_SIZE);
+ drawFinderPattern(FINDER_SIZE, size - 1 - FINDER_SIZE);
+
+ drawAlignmentsPatterns();
+
+ // Draw configuration data
+ drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
+ drawVersion();
+ }
+
- // Draw numerous alignment patterns
+ // Draw numerous alignment patterns
+ private void drawAlignmentsPatterns() {
int[] alignPatPos = getAlignmentPatternPositions();
int numAlign = alignPatPos.length;
for (int i = 0; i < numAlign; i++) {
for (int j = 0; j < numAlign; j++) {
- // Don't draw on the three finder corners
- if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0))
+ final boolean isLeftTop = i == 0 && j == 0;
+ final boolean isLeftBottom = i == 0 && j == numAlign - 1;
+ final boolean isRightTop = i == numAlign - 1 && j == 0;
+ final boolean onThreeFinderCorners = isLeftTop || isLeftBottom || isRightTop;
+ if (!onThreeFinderCorners)
drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
}
}
-
- // Draw configuration data
- drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
- drawVersion();
}
-
-
+
+
// Draws two copies of the format bits (with its own error correction code)
// based on the given mask and this object's error correction level field.
private void drawFormatBits(int msk) {
@@ -390,7 +427,7 @@ public final class QrCode {
rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
int bits = (data << 10 | rem) ^ 0x5412; // uint15
assert bits >>> 15 == 0;
-
+
// Draw first copy
for (int i = 0; i <= 5; i++)
setFunctionModule(8, i, getBit(bits, i));
@@ -399,7 +436,7 @@ public final class QrCode {
setFunctionModule(7, 8, getBit(bits, 8));
for (int i = 9; i < 15; i++)
setFunctionModule(14 - i, 8, getBit(bits, i));
-
+
// Draw second copy
for (int i = 0; i < 8; i++)
setFunctionModule(size - 1 - i, 8, getBit(bits, i));
@@ -407,21 +444,21 @@ public final class QrCode {
setFunctionModule(8, size - 15 + i, getBit(bits, i));
setFunctionModule(8, size - 8, true); // Always black
}
-
-
+
+
// Draws two copies of the version bits (with its own error correction code),
// based on this object's version field, iff 7 <= version <= 40.
private void drawVersion() {
if (version < 7)
return;
-
+
// Calculate error correction code and pack bits
int rem = version; // version is uint6, in the range [7, 40]
for (int i = 0; i < 12; i++)
rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);
int bits = version << 12 | rem; // uint18
assert bits >>> 18 == 0;
-
+
// Draw two copies
for (int i = 0; i < 18; i++) {
boolean bit = getBit(bits, i);
@@ -431,8 +468,8 @@ public final class QrCode {
setFunctionModule(b, a, bit);
}
}
-
-
+
+
// Draws a 9*9 finder pattern including the border separator,
// with the center module at (x, y). Modules can be out of bounds.
private void drawFinderPattern(int x, int y) {
@@ -445,8 +482,8 @@ public final class QrCode {
}
}
}
-
-
+
+
// Draws a 5*5 alignment pattern, with the center module
// at (x, y). All modules must be in bounds.
private void drawAlignmentPattern(int x, int y) {
@@ -455,32 +492,32 @@ public final class QrCode {
setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) != 1);
}
}
-
-
+
+
// Sets the color of a module and marks it as a function module.
// Only used by the constructor. Coordinates must be in bounds.
private void setFunctionModule(int x, int y, boolean isBlack) {
modules[y][x] = isBlack;
isFunction[y][x] = true;
}
-
-
+
+
/*---- Private helper methods for constructor: Codewords and masking ----*/
-
+
// Returns a new byte string representing the given data with the appropriate error correction
// codewords appended to it, based on this object's version and error correction level.
private byte[] addEccAndInterleave(byte[] data) {
Objects.requireNonNull(data);
if (data.length != getNumDataCodewords(version, errorCorrectionLevel))
throw new IllegalArgumentException();
-
+
// Calculate parameter numbers
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal()][version];
int blockEccLen = ECC_CODEWORDS_PER_BLOCK [errorCorrectionLevel.ordinal()][version];
int rawCodewords = getNumRawDataModules(version) / 8;
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
int shortBlockLen = rawCodewords / numBlocks;
-
+
// Split data into blocks and append ECC to each block
byte[][] blocks = new byte[numBlocks][];
byte[] rsDiv = reedSolomonComputeDivisor(blockEccLen);
@@ -492,7 +529,7 @@ public final class QrCode {
System.arraycopy(ecc, 0, block, block.length - blockEccLen, ecc.length);
blocks[i] = block;
}
-
+
// Interleave (not concatenate) the bytes from every block into a single sequence
byte[] result = new byte[rawCodewords];
for (int i = 0, k = 0; i < blocks[0].length; i++) {
@@ -506,15 +543,15 @@ public final class QrCode {
}
return result;
}
-
-
+
+
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
// data area of this QR Code. Function modules need to be marked off before this is called.
private void drawCodewords(byte[] data) {
Objects.requireNonNull(data);
if (data.length != getNumRawDataModules(version) / 8)
throw new IllegalArgumentException();
-
+
int i = 0; // Bit index into the data
// Do the funny zigzag scan
for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
@@ -536,8 +573,8 @@ public final class QrCode {
}
assert i == data.length * 8;
}
-
-
+
+
// XORs the codeword modules in this QR Code with the given mask pattern.
// The function modules must be marked and the codeword bits must be drawn
// before masking. Due to the arithmetic of XOR, calling applyMask() with
@@ -560,36 +597,39 @@ public final class QrCode {
}
}
-
-
+
// A messy helper function for the constructor. This QR Code must be in an unmasked state when this
// method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
// This method applies and returns the actual mask chosen, from 0 to 7.
- private int handleConstructorMasking(int msk) {
- if (msk == -1) { // Automatically choose best mask
- msk = chooseBestMask(msk);
+ private int handleConstructorMasking(int mask) {
+ if (mask == -1) {
+ mask = findBestMask();
}
- assert 0 <= msk && msk <= 7;
- applyMask(msk); // Apply the final choice of mask
- drawFormatBits(msk); // Overwrite old format bits
- return msk; // The caller shall assign this value to the final-declared field
+ assert 0 <= mask && mask <= 7;
+ applyMask(mask); // Apply the final choice of mask
+ drawFormatBits(mask); // Overwrite old format bits
+ return mask; // The caller shall assign this value to the final-declared field
}
-
- private int chooseBestMask(int msk) {
+
+
+ // Automatically choose best mask
+ private int findBestMask() {
+ int mask = -1;
int minPenalty = Integer.MAX_VALUE;
for (int i = 0; i < 8; i++) {
applyMask(i);
drawFormatBits(i);
int penalty = getPenaltyScore();
if (penalty < minPenalty) {
- msk = i;
+ mask = i;
minPenalty = penalty;
}
applyMask(i); // Undoes the mask due to XOR
}
- return msk;
+ return mask;
}
+
private int havingSameColor(int run, boolean runColor, int[] runHistory, int result, int y, int x) {
if (modules[y][x] == runColor) {
run++;
@@ -887,4 +927,4 @@ public final class QrCode {
}
}
-}
+}
\ No newline at end of file
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
index 1efe7b5..b125f18 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
@@ -23,12 +23,20 @@
package io.nayuki.qrcodegen;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
+import java.util.Scanner;
+
import io.nayuki.qrcodegen.QrSegment.Mode;
@@ -64,14 +72,14 @@ public final class QrSegmentAdvanced {
// Check arguments
Objects.requireNonNull(text);
Objects.requireNonNull(ecl);
- if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION))
+ if (not_Valid_Version(minVersion, maxVersion))
throw new IllegalArgumentException("Invalid value");
// Iterate through version numbers, and make tentative segments
List segs = null;
int[] codePoints = toCodePoints(text);
for (int version = minVersion; ; version++) {
- if (version == minVersion || version == 10 || version == 27)
+ if (is_valid_version(minVersion, version))
segs = makeSegmentsOptimally(codePoints, version);
assert segs != null;
@@ -88,22 +96,31 @@ public final class QrSegmentAdvanced {
}
}
}
+
+
+ private static boolean is_valid_version(int minVersion, int version) {
+ return version == minVersion || version == 10 || version == 27;
+ }
+
+
+ private static boolean not_Valid_Version(int minVersion, int maxVersion) {
+ return !(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION);
+ }
// Returns a new list of segments that is optimal for the given text at the given version number.
private static List makeSegmentsOptimally(int[] codePoints, int version) {
if (codePoints.length == 0)
return new ArrayList<>();
- Mode[] charModes = computeCharacterModes(codePoints, version);
+ QrMode[] charModes = computeCharacterModes(codePoints, version);
return splitIntoSegments(codePoints, charModes);
}
-
// Returns a new array representing the optimal mode per code point based on the given text and version.
- private static Mode[] computeCharacterModes(int[] codePoints, int version) {
+ private static QrMode[] computeCharacterModes(int[] codePoints, int version) {
if (codePoints.length == 0)
throw new IllegalArgumentException();
- final Mode[] modeTypes = {Mode.BYTE, Mode.ALPHANUMERIC, Mode.NUMERIC, Mode.KANJI}; // Do not modify
+ final QrMode[] modeTypes = {new ByteMode(), new AlphanumericMode(), new NumericMode(), new KanjiMode()}; // Do not modify
final int numModes = modeTypes.length;
// Segment header sizes, measured in 1/6 bits
@@ -114,7 +131,7 @@ public final class QrSegmentAdvanced {
// charModes[i][j] represents the mode to encode the code point at
// index i such that the final segment ends in modeTypes[j] and the
// total number of bits is minimized over all possible choices
- Mode[][] charModes = new Mode[codePoints.length][numModes];
+ QrMode[][] charModes = new QrMode[codePoints.length][numModes];
// At the beginning of each iteration of the loop below,
// prevCosts[j] is the exact minimum number of 1/6 bits needed to
@@ -122,27 +139,42 @@ public final class QrSegmentAdvanced {
int[] prevCosts = headCosts.clone();
// Calculate costs using dynamic programming
+ prevCosts = calculate_cost(codePoints, modeTypes, numModes, headCosts, charModes, prevCosts);
+
+ // Find optimal ending mode
+ QrMode curMode = null;
+ curMode = find_optimal(modeTypes, numModes, prevCosts, curMode);
+
+ // Get optimal mode for each code point by tracing backwards
+ QrMode[] result = new QrMode[codePoints.length];
+ get_optimal(modeTypes, numModes, charModes, curMode, result);
+ return result;
+ }
+
+
+ private static int[] calculate_cost(int[] codePoints, final QrMode[] modeTypes, final int numModes,
+ final int[] headCosts, QrMode[][] charModes, int[] prevCosts) {
for (int i = 0; i < codePoints.length; i++) {
- int c = codePoints[i];
+ int codePoint = codePoints[i];
int[] curCosts = new int[numModes];
{ // Always extend a byte mode segment
- curCosts[0] = prevCosts[0] + countUtf8Bytes(c) * 8 * 6;
- charModes[i][0] = modeTypes[0];
+ charModes[i][0] = new ByteMode();
+ curCosts[0] = charModes[i][0].getcost(prevCosts[0], codePoint);
}
// Extend a segment if possible
- if (QrSegment.ALPHANUMERIC_CHARSET.indexOf(c) != -1) { // Is alphanumeric
- curCosts[1] = prevCosts[1] + 33; // 5.5 bits per alphanumeric char
- charModes[i][1] = modeTypes[1];
+ if (QrSegment.ALPHANUMERIC_CHARSET.indexOf(codePoint) != -1) { // Is alphanumeric
+ charModes[i][1] = new AlphanumericMode();
+ curCosts[1] = charModes[i][1].getcost(prevCosts[1], codePoint); // 5.5 bits per alphanumeric char
}
- if ('0' <= c && c <= '9') { // Is numeric
- curCosts[2] = prevCosts[2] + 20; // 3.33 bits per digit
- charModes[i][2] = modeTypes[2];
+ if ('0' <= codePoint && codePoint <= '9') { // Is numeric
+ charModes[i][2] = new NumericMode();
+ curCosts[2] = charModes[i][2].getcost(prevCosts[2], codePoint); // 3.33 bits per digit
}
- if (isKanji(c)) {
- curCosts[3] = prevCosts[3] + 78; // 13 bits per Shift JIS char
- charModes[i][3] = modeTypes[3];
+ if (isKanji(codePoint)) {
+ charModes[i][3] = new KanjiMode();
+ curCosts[3] = charModes[i][3].getcost(prevCosts[3], codePoint);; // 13 bits per Shift JIS char
}
-
+
// Start new segment at the end to switch modes
for (int j = 0; j < numModes; j++) { // To mode
for (int k = 0; k < numModes; k++) { // From mode
@@ -156,18 +188,12 @@ public final class QrSegmentAdvanced {
prevCosts = curCosts;
}
-
- // Find optimal ending mode
- Mode curMode = null;
- for (int i = 0, minCost = 0; i < numModes; i++) {
- if (curMode == null || prevCosts[i] < minCost) {
- minCost = prevCosts[i];
- curMode = modeTypes[i];
- }
- }
-
- // Get optimal mode for each code point by tracing backwards
- Mode[] result = new Mode[charModes.length];
+ return prevCosts;
+ }
+
+
+ private static void get_optimal(final QrMode[] modeTypes, final int numModes, QrMode[][] charModes, QrMode curMode,
+ QrMode[] result) {
for (int i = result.length - 1; i >= 0; i--) {
for (int j = 0; j < numModes; j++) {
if (modeTypes[j] == curMode) {
@@ -177,34 +203,45 @@ public final class QrSegmentAdvanced {
}
}
}
- return result;
+ }
+
+
+ private static QrMode find_optimal(final QrMode[] modeTypes, final int numModes, int[] prevCosts, QrMode curMode) {
+ for (int i = 0, minCost = 0; i < numModes; i++) {
+ if (curMode == null || prevCosts[i] < minCost) {
+ minCost = prevCosts[i];
+ curMode = modeTypes[i];
+ }
+ }
+ return curMode;
+ }
+
+
+ private static boolean is_numeric(int convertedPoint) {
+ return '0' <= convertedPoint && convertedPoint <= '9';
+ }
+
+
+ private static boolean is_alphanumeric(int convertedPoint) {
+ return QrSegment.ALPHANUMERIC_CHARSET.indexOf(convertedPoint) != -1;
}
// Returns a new list of segments based on the given text and modes, such that
// consecutive code points in the same mode are put into the same segment.
- private static List splitIntoSegments(int[] codePoints, Mode[] charModes) {
+ private static List splitIntoSegments(int[] codePoints, QrMode[] charModes) {
if (codePoints.length == 0)
throw new IllegalArgumentException();
List result = new ArrayList<>();
// Accumulate run of modes
- Mode curMode = charModes[0];
+ QrMode curMode = charModes[0];
int start = 0;
for (int i = 1; ; i++) {
if (i < codePoints.length && charModes[i] == curMode)
continue;
String s = new String(codePoints, start, i - start);
- if (curMode == Mode.BYTE)
- result.add(QrSegment.makeBytes(s.getBytes(StandardCharsets.UTF_8)));
- else if (curMode == Mode.NUMERIC)
- result.add(QrSegment.makeNumeric(s));
- else if (curMode == Mode.ALPHANUMERIC)
- result.add(QrSegment.makeAlphanumeric(s));
- else if (curMode == Mode.KANJI)
- result.add(makeKanji(s));
- else
- throw new AssertionError();
+ result.add(curMode.making(s));
if (i >= codePoints.length)
return result;
curMode = charModes[i];
@@ -215,8 +252,8 @@ public final class QrSegmentAdvanced {
// Returns a new array of Unicode code points (effectively
// UTF-32 / UCS-4) representing the given UTF-16 string.
- private static int[] toCodePoints(String s) {
- int[] result = s.codePoints().toArray();
+ private static int[] toCodePoints(String str) {
+ int[] result = str.codePoints().toArray();
for (int c : result) {
if (Character.isSurrogate((char)c))
throw new IllegalArgumentException("Invalid UTF-16 string");
@@ -226,12 +263,12 @@ public final class QrSegmentAdvanced {
// Returns the number of UTF-8 bytes needed to encode the given Unicode code point.
- private static int countUtf8Bytes(int cp) {
- if (cp < 0) throw new IllegalArgumentException("Invalid code point");
- else if (cp < 0x80) return 1;
- else if (cp < 0x800) return 2;
- else if (cp < 0x10000) return 3;
- else if (cp < 0x110000) return 4;
+ public static int countUtf8Bytes(int currentPoint) {
+ if (currentPoint < 0) throw new IllegalArgumentException("Invalid code point");
+ else if (currentPoint < 0x80) return 1;
+ else if (currentPoint < 0x800) return 2;
+ else if (currentPoint < 0x10000) return 3;
+ else if (currentPoint < 0x110000) return 4;
else throw new IllegalArgumentException("Invalid code point");
}
@@ -277,8 +314,7 @@ public final class QrSegmentAdvanced {
*/
public static boolean isEncodableAsKanji(String text) {
Objects.requireNonNull(text);
- return text.chars().allMatch(
- c -> isKanji((char)c));
+ return text.chars().allMatch(c -> isKanji((char)c));
}
@@ -286,119 +322,8 @@ public final class QrSegmentAdvanced {
return c < UNICODE_TO_QR_KANJI.length && UNICODE_TO_QR_KANJI[c] != -1;
}
-
- // Data derived from ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
- private static final String PACKED_QR_KANJI_TO_UNICODE =
- "MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZA" +
- "ALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA///////////////////" +
- "//////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h" +
- "/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBN" +
- "ME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////" +
- "////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDh" +
- "MOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+" +
- "A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQm" +
- "BCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQ" +
- "JRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "/////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32t" +
- "fe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYg" +
- "ZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2" +
- "cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5" +
- "////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLs" +
- "bTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CE" +
- "lFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKg" +
- "dZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/" +
- "U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6" +
- "UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo" +
- "//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6r" +
- "XydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOn" +
- "ZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtk" +
- "mANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiV" +
- "nfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/X" +
- "YB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6luf" +
- "hQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/S" +
- "ge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZ" +
- "WXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJac" +
- "l5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066" +
- "TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bb" +
- "fL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6" +
- "ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333P" +
- "fZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7e" +
- "gM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bj" +
- "WMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0" +
- "gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oC" +
- "iuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhY" +
- "WVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLr" +
- "W8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/D" +
- "fQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGro" +
- "XmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/" +
- "l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16c" +
- "YBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7" +
- "WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851s" +
- "Tk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04H" +
- "YWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5f" +
- "UbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+K" +
- "gACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHM" +
- "W+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3v" +
- "lzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV////////////////////////////////////////////////////////////////////////////////////////" +
- "/////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/l" +
- "UBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGT" +
- "UZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQ" +
- "Uw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////" +
- "VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaP" +
- "VqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4" +
- "WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrj" +
- "Wtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yr" +
- "XLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/" +
- "XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQ" +
- "YClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FY" +
- "YVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KU" +
- "Ytdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTH" +
- "ZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2Zo" +
- "Zl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGge" +
- "aEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammy" +
- "aa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7" +
- "awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzX" +
- "bMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7J" +
- "brdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3Aw" +
- "cD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKy" +
- "csNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTy" +
- "dPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYw" +
- "djt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7" +
- "d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXog" +
- "eh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuc" +
- "e5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G" +
- "////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5a" +
- "fnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAh" +
- "gCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHC" +
- "gbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMv" +
- "gyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UY" +
- "hSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs" +
- "//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZ" +
- "iF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9" +
- "ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tf" +
- "i2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3b" +
- "jcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485" +
- "j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEy" +
- "kTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNW" +
- "k7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYu" +
- "li+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJem" +
- "l6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnY" +
- "mdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uD" +
- "m5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1k" +
- "nVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+" +
- "n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
- "/////////////////////////////////////////////w==";
+// Data derived from ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
+ private static final String PACKED_QR_KANJI_TO_UNICODE = readPacked_KANJI();
private static short[] UNICODE_TO_QR_KANJI = new short[1 << 16];
@@ -407,18 +332,31 @@ public final class QrSegmentAdvanced {
Arrays.fill(UNICODE_TO_QR_KANJI, (short)-1);
byte[] bytes = Base64.getDecoder().decode(PACKED_QR_KANJI_TO_UNICODE);
for (int i = 0; i < bytes.length; i += 2) {
- char c = (char)(((bytes[i] & 0xFF) << 8) | (bytes[i + 1] & 0xFF));
- if (c == 0xFFFF)
+ char convertChar = (char)(((bytes[i] & 0xFF) << 8) | (bytes[i + 1] & 0xFF));
+ if (convertChar == 0xFFFF)
continue;
- assert UNICODE_TO_QR_KANJI[c] == -1;
- UNICODE_TO_QR_KANJI[c] = (short)(i / 2);
+ assert UNICODE_TO_QR_KANJI[convertChar] == -1;
+ UNICODE_TO_QR_KANJI[convertChar] = (short)(i / 2);
}
}
+ private static String readPacked_KANJI() {
+ String str = "";
+ try {
+ File file = new File("./packet_KanJI.txt");
+ Scanner scan = new Scanner(file);
+ str +=scan.nextLine();
+ scan.close();
+ }
+ catch(FileNotFoundException e){
+ }
+
+ return str;
+ }
/*---- Miscellaneous ----*/
private QrSegmentAdvanced() {} // Not instantiable
-}
+}
\ No newline at end of file
From b65dad6f4179f3950ecdd5d8b6d09c5844e4e410 Mon Sep 17 00:00:00 2001
From: minsu4107 <32637512+minsu4107@users.noreply.github.com>
Date: Fri, 5 Jun 2020 23:45:52 +0900
Subject: [PATCH 25/28] 1.Strategy Pattern 2. AlphanumericMode, ByteMode,
EciMode, NumericMode, QrMode 3. Add java class for using Strategy Pattern
---
.../io/nayuki/qrcodegen/AlphanumericMode.java | 25 +++++++++++
.../java/io/nayuki/qrcodegen/ByteMode.java | 25 +++++++++++
.../java/io/nayuki/qrcodegen/EciMode.java | 23 ++++++++++
.../java/io/nayuki/qrcodegen/NumericMode.java | 23 ++++++++++
.../main/java/io/nayuki/qrcodegen/QrMode.java | 43 +++++++++++++++++++
5 files changed, 139 insertions(+)
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/AlphanumericMode.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/ByteMode.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/EciMode.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/NumericMode.java
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/QrMode.java
diff --git a/java/src/main/java/io/nayuki/qrcodegen/AlphanumericMode.java b/java/src/main/java/io/nayuki/qrcodegen/AlphanumericMode.java
new file mode 100644
index 0000000..f0d59ba
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/AlphanumericMode.java
@@ -0,0 +1,25 @@
+package io.nayuki.qrcodegen;
+
+import java.nio.charset.StandardCharsets;
+
+public class AlphanumericMode extends QrMode {
+ protected AlphanumericMode(int mode, int... ccbits) {
+ modeBits = mode;
+ numBitsCharCount = ccbits;
+ }
+
+ protected AlphanumericMode() {
+ modeBits = 0x2;
+ numBitsCharCount[0] = 9;
+ numBitsCharCount[1] = 11;
+ numBitsCharCount[2] = 13;
+ }
+
+ public int getcost(int pre, int codePoint) {
+ return pre + 33;
+ }
+
+ public QrSegment making(String str) {
+ return QrSegment.makeAlphanumeric(str);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/ByteMode.java b/java/src/main/java/io/nayuki/qrcodegen/ByteMode.java
new file mode 100644
index 0000000..1270381
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/ByteMode.java
@@ -0,0 +1,25 @@
+package io.nayuki.qrcodegen;
+
+import java.nio.charset.StandardCharsets;
+
+public class ByteMode extends QrMode {
+ protected ByteMode(int mode, int... ccbits) {
+ modeBits = mode;
+ numBitsCharCount = ccbits;
+ }
+
+ protected ByteMode() {
+ modeBits = 0x4;
+ numBitsCharCount[0] = 8;
+ numBitsCharCount[1] = 16;
+ numBitsCharCount[2] = 16;
+ }
+
+ public int getcost(int pre, int codePoint) {
+ return pre + QrSegmentAdvanced.countUtf8Bytes(codePoint) * 8 * 6;
+ }
+
+ public QrSegment making(String str) {
+ return QrSegment.makeBytes(str.getBytes(StandardCharsets.UTF_8));
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/EciMode.java b/java/src/main/java/io/nayuki/qrcodegen/EciMode.java
new file mode 100644
index 0000000..ce33fa9
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/EciMode.java
@@ -0,0 +1,23 @@
+package io.nayuki.qrcodegen;
+
+public class EciMode extends QrMode {
+ protected EciMode(int mode, int... ccbits) {
+ modeBits = mode;
+ numBitsCharCount = ccbits;
+ }
+
+ protected EciMode() {
+ modeBits = 0x7;
+ numBitsCharCount[0] = 0;
+ numBitsCharCount[1] = 0;
+ numBitsCharCount[2] = 0;
+ }
+
+ public QrSegment making(int prmt) {
+ return QrSegment.makeEci(prmt);
+ }
+
+ public int getcost(int pre, int codePoint) {
+ return pre;
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/NumericMode.java b/java/src/main/java/io/nayuki/qrcodegen/NumericMode.java
new file mode 100644
index 0000000..a8af039
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/NumericMode.java
@@ -0,0 +1,23 @@
+package io.nayuki.qrcodegen;
+
+public class NumericMode extends QrMode {
+ protected NumericMode(int mode, int... ccbits) {
+ modeBits = mode;
+ numBitsCharCount = ccbits;
+ }
+
+ protected NumericMode() {
+ modeBits = 0x1;
+ numBitsCharCount[0] = 10;
+ numBitsCharCount[1] = 12;
+ numBitsCharCount[2] = 1;
+ }
+
+ public int getcost(int pre, int codePoint) {
+ return pre + 20;
+ }
+
+ public QrSegment making(String str) {
+ return QrSegment.makeNumeric(str);
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrMode.java b/java/src/main/java/io/nayuki/qrcodegen/QrMode.java
new file mode 100644
index 0000000..3f0127f
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrMode.java
@@ -0,0 +1,43 @@
+package io.nayuki.qrcodegen;
+
+public abstract class QrMode {
+ /*-- Fields --*/
+
+ // The mode indicator bits, which is a uint4 value (range 0 to 15).
+ int modeBits;
+
+ // Number of character count bits for three different version ranges.
+ protected int[] numBitsCharCount;
+
+ int headCost;
+ /*-- Method --*/
+
+ // Returns the bit width of the character count field for a segment in this mode
+ // in a QR Code at the given version number. The result is in the range [0, 16].
+ int numCharCountBits(int ver) {
+ assert QrCode.MIN_VERSION <= ver && ver <= QrCode.MAX_VERSION;
+ return numBitsCharCount[(ver + 7) / 17];
+ }
+
+ protected QrMode() {
+ this.modeBits = 0;
+ this.numBitsCharCount = null;
+ }
+
+ public void get(QrMode md) {
+ this.modeBits = md.modeBits;
+ this.numBitsCharCount = md.numBitsCharCount;
+ }
+
+ public int whichMode() {
+ return modeBits;
+ }
+
+ protected QrSegment making(String s) {
+ return null;
+ }
+
+ public int getcost(int pre, int codePoint) {
+ return pre;
+ }
+}
\ No newline at end of file
From fe6c3980afb29637e981a6d3185709e0a0c790f9 Mon Sep 17 00:00:00 2001
From: gerzees
Date: Sat, 6 Jun 2020 18:01:16 +0900
Subject: [PATCH 26/28] 1. Extract class 2. Ecc from QrCode 3. QrCode is too
big
---
.../main/java/io/nayuki/qrcodegen/Ecc.java | 61 +++++++++++++++++++
.../main/java/io/nayuki/qrcodegen/QrCode.java | 55 ++---------------
.../nayuki/qrcodegen/QrCodeGeneratorDemo.java | 34 +++++------
.../qrcodegen/QrCodeGeneratorWorker.java | 2 +-
4 files changed, 85 insertions(+), 67 deletions(-)
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/Ecc.java
diff --git a/java/src/main/java/io/nayuki/qrcodegen/Ecc.java b/java/src/main/java/io/nayuki/qrcodegen/Ecc.java
new file mode 100644
index 0000000..1ce9752
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/Ecc.java
@@ -0,0 +1,61 @@
+package io.nayuki.qrcodegen;
+
+/**
+ * The error correction level in a QR Code symbol.
+ */
+public class Ecc {
+ /** The QR Code can tolerate about 7% erroneous codewords. */
+ public static final Ecc LOW = new Ecc(1,
+ new byte[] { -1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30,
+ 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 },
+ new byte[] { -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13,
+ 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25 });
+ /** The QR Code can tolerate about 15% erroneous codewords. */
+ public static final Ecc MEDIUM = new Ecc(0,
+ new byte[] { -1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28 },
+ new byte[] { -1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23,
+ 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49 });
+ /** The QR Code can tolerate about 25% erroneous codewords. */
+ public static final Ecc QUARTILE = new Ecc(3,
+ new byte[] { -1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30,
+ 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 },
+ new byte[] { -1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29,
+ 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68 });
+ /** The QR Code can tolerate about 30% erroneous codewords. */
+ public static final Ecc HIGH = new Ecc(2,
+ new byte[] { -1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 },
+ new byte[] { -1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35,
+ 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81 });
+
+ private final int formatBits;
+ private final byte[] blockLength;
+ private final byte[] numberOfBlocks;
+
+ // For formatBits and blockLength, array index is Version: (note that index 0 is
+ // for padding, and is set to an illegal value)
+ private Ecc(int formatBits, byte[] blockLength, byte[] numberOfBlocks) {
+ this.formatBits = formatBits;
+ this.blockLength = blockLength;
+ this.numberOfBlocks = numberOfBlocks;
+ }
+
+ public int getFormatBits() {
+ return formatBits;
+ }
+
+ public byte getBlockLength(int version) {
+ return blockLength[version];
+ }
+
+ public byte getNumberOfBlock(int version) {
+ return numberOfBlocks[version];
+ }
+
+ // Must in ascending order of error protection
+ // so that values() work properly
+ public static Ecc[] values() {
+ return new Ecc[] { LOW, MEDIUM, QUARTILE, HIGH };
+ }
+}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
index dcb8b6b..5ade16c 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCode.java
@@ -421,7 +421,7 @@ public final class QrCode {
// based on the given mask and this object's error correction level field.
private void drawFormatBits(int msk) {
// Calculate error correction code and pack bits
- int data = errorCorrectionLevel.formatBits << 3 | msk; // errCorrLvl is uint2, mask is uint3
+ int data = errorCorrectionLevel.getFormatBits() << 3 | msk; // errCorrLvl is uint2, mask is uint3
int rem = data;
for (int i = 0; i < 10; i++)
rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
@@ -512,8 +512,8 @@ public final class QrCode {
throw new IllegalArgumentException();
// Calculate parameter numbers
- int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal()][version];
- int blockEccLen = ECC_CODEWORDS_PER_BLOCK [errorCorrectionLevel.ordinal()][version];
+ int numBlocks = errorCorrectionLevel.getNumberOfBlock(version);
+ int blockEccLen = errorCorrectionLevel.getBlockLength(version);
int rawCodewords = getNumRawDataModules(version) / 8;
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
int shortBlockLen = rawCodewords / numBlocks;
@@ -830,9 +830,9 @@ public final class QrCode {
// QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
static int getNumDataCodewords(int ver, Ecc ecl) {
- return getNumRawDataModules(ver) / 8
- - ECC_CODEWORDS_PER_BLOCK [ecl.ordinal()][ver]
- * NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal()][ver];
+ return getNumRawDataModules(ver) / 8
+ - ecl.getBlockLength(ver)
+ * ecl.getNumberOfBlock(ver);
}
@@ -889,47 +889,4 @@ public final class QrCode {
private static final int PENALTY_N3 = 40;
private static final int PENALTY_N4 = 10;
-
- private static final byte[][] ECC_CODEWORDS_PER_BLOCK = {
- // Version: (note that index 0 is for padding, and is set to an illegal value)
- //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
- {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
- {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
- {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
- {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
- };
-
- private static final byte[][] NUM_ERROR_CORRECTION_BLOCKS = {
- // Version: (note that index 0 is for padding, and is set to an illegal value)
- //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
- {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
- {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
- {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
- {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
- };
-
-
-
- /*---- Public helper enumeration ----*/
-
- /**
- * The error correction level in a QR Code symbol.
- */
- public enum Ecc {
- // Must be declared in ascending order of error protection
- // so that the implicit ordinal() and values() work properly
- /** The QR Code can tolerate about 7% erroneous codewords. */ LOW(1),
- /** The QR Code can tolerate about 15% erroneous codewords. */ MEDIUM(0),
- /** The QR Code can tolerate about 25% erroneous codewords. */ QUARTILE(3),
- /** The QR Code can tolerate about 30% erroneous codewords. */ HIGH(2);
-
- // In the range 0 to 3 (unsigned 2-bit integer).
- final int formatBits;
-
- // Constructor.
- private Ecc(int fb) {
- formatBits = fb;
- }
- }
-
}
\ No newline at end of file
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java b/java/src/main/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java
index 3c50bda..f9316d7 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java
@@ -53,7 +53,7 @@ public final class QrCodeGeneratorDemo {
// Creates a single QR Code, then writes it to a PNG file and an SVG file.
private static void doBasicDemo() throws IOException {
String text = "Hello, world!"; // User-supplied Unicode text
- QrCode.Ecc errCorLvl = QrCode.Ecc.LOW; // Error correction level
+ Ecc errCorLvl = Ecc.LOW; // Error correction level
QrCode qr = QrCode.encodeText(text, errCorLvl); // Make the QR Code symbol
@@ -73,15 +73,15 @@ public final class QrCodeGeneratorDemo {
QrCode qr;
// Numeric mode encoding (3.33 bits per digit)
- qr = QrCode.encodeText("314159265358979323846264338327950288419716939937510", QrCode.Ecc.MEDIUM);
+ qr = QrCode.encodeText("314159265358979323846264338327950288419716939937510", Ecc.MEDIUM);
writePng(qr.toImage(13, 1), "pi-digits-QR.png");
// Alphanumeric mode encoding (5.5 bits per character)
- qr = QrCode.encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode.Ecc.HIGH);
+ qr = QrCode.encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", Ecc.HIGH);
writePng(qr.toImage(10, 2), "alphanumeric-QR.png");
// Unicode text as UTF-8
- qr = QrCode.encodeText("こんにちwa、世界! αβγδ", QrCode.Ecc.QUARTILE);
+ qr = QrCode.encodeText("こんにちwa、世界! αβγδ", Ecc.QUARTILE);
writePng(qr.toImage(10, 3), "unicode-QR.png");
// Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
@@ -92,7 +92,7 @@ public final class QrCodeGeneratorDemo {
+ "'without pictures or conversations?' So she was considering in her own mind (as well as she could, "
+ "for the hot day made her feel very sleepy and stupid), whether the pleasure of making a "
+ "daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly "
- + "a White Rabbit with pink eyes ran close by her.", QrCode.Ecc.HIGH);
+ + "a White Rabbit with pink eyes ran close by her.", Ecc.HIGH);
writePng(qr.toImage(6, 10), "alice-wonderland-QR.png");
}
@@ -105,36 +105,36 @@ public final class QrCodeGeneratorDemo {
// Illustration "silver"
String silver0 = "THE SQUARE ROOT OF 2 IS 1.";
String silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
- qr = QrCode.encodeText(silver0 + silver1, QrCode.Ecc.LOW);
+ qr = QrCode.encodeText(silver0 + silver1, Ecc.LOW);
writePng(qr.toImage(10, 3), "sqrt2-monolithic-QR.png");
segs = Arrays.asList(
QrSegment.makeAlphanumeric(silver0),
QrSegment.makeNumeric(silver1));
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
+ qr = QrCode.encodeSegments(segs, Ecc.LOW);
writePng(qr.toImage(10, 3), "sqrt2-segmented-QR.png");
// Illustration "golden"
String golden0 = "Golden ratio φ = 1.";
String golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
String golden2 = "......";
- qr = QrCode.encodeText(golden0 + golden1 + golden2, QrCode.Ecc.LOW);
+ qr = QrCode.encodeText(golden0 + golden1 + golden2, Ecc.LOW);
writePng(qr.toImage(8, 5), "phi-monolithic-QR.png");
segs = Arrays.asList(
QrSegment.makeBytes(golden0.getBytes(StandardCharsets.UTF_8)),
QrSegment.makeNumeric(golden1),
QrSegment.makeAlphanumeric(golden2));
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
+ qr = QrCode.encodeSegments(segs, Ecc.LOW);
writePng(qr.toImage(8, 5), "phi-segmented-QR.png");
// Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
String madoka = "「魔法少女まどか☆マギカ」って、 ИАИ desu κα?";
- qr = QrCode.encodeText(madoka, QrCode.Ecc.LOW);
+ qr = QrCode.encodeText(madoka, Ecc.LOW);
writePng(qr.toImage(9, 4), "madoka-utf8-QR.png");
segs = Arrays.asList(QrSegmentAdvanced.makeKanji(madoka));
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
+ qr = QrCode.encodeSegments(segs, Ecc.LOW);
writePng(qr.toImage(9, 4), "madoka-kanji-QR.png");
}
@@ -146,20 +146,20 @@ public final class QrCodeGeneratorDemo {
// Project Nayuki URL
segs = QrSegment.makeSegments("https://www.nayuki.io/");
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, -1, true); // Automatic mask
+ qr = QrCode.encodeSegments(segs, Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, -1, true); // Automatic mask
writePng(qr.toImage(8, 6), "project-nayuki-automask-QR.png");
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 3, true); // Force mask 3
+ qr = QrCode.encodeSegments(segs, Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 3, true); // Force mask 3
writePng(qr.toImage(8, 6), "project-nayuki-mask3-QR.png");
// Chinese text as UTF-8
segs = QrSegment.makeSegments("維基百科(Wikipedia,聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫");
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 0, true); // Force mask 0
+ qr = QrCode.encodeSegments(segs, Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 0, true); // Force mask 0
writePng(qr.toImage(10, 3), "unicode-mask0-QR.png");
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 1, true); // Force mask 1
+ qr = QrCode.encodeSegments(segs, Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 1, true); // Force mask 1
writePng(qr.toImage(10, 3), "unicode-mask1-QR.png");
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 5, true); // Force mask 5
+ qr = QrCode.encodeSegments(segs, Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 5, true); // Force mask 5
writePng(qr.toImage(10, 3), "unicode-mask5-QR.png");
- qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 7, true); // Force mask 7
+ qr = QrCode.encodeSegments(segs, Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 7, true); // Force mask 7
writePng(qr.toImage(10, 3), "unicode-mask7-QR.png");
}
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrCodeGeneratorWorker.java b/java/src/main/java/io/nayuki/qrcodegen/QrCodeGeneratorWorker.java
index 4cf9de3..54f3dbf 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrCodeGeneratorWorker.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrCodeGeneratorWorker.java
@@ -82,7 +82,7 @@ public final class QrCodeGeneratorWorker {
segs = Arrays.asList(QrSegment.makeBytes(data));
try { // Try to make QR Code symbol
- QrCode qr = QrCode.encodeSegments(segs, QrCode.Ecc.values()[errCorLvl], minVersion, maxVersion, mask, boostEcl != 0);
+ QrCode qr = QrCode.encodeSegments(segs, Ecc.values()[errCorLvl], minVersion, maxVersion, mask, boostEcl != 0);
// Print grid of modules
System.out.println(qr.version);
for (int y = 0; y < qr.size; y++) {
From 1980ace59524357baa69bb4f89362945774aa856 Mon Sep 17 00:00:00 2001
From: minsu4107 <32637512+minsu4107@users.noreply.github.com>
Date: Sat, 6 Jun 2020 18:18:11 +0900
Subject: [PATCH 27/28] 1. Strategy Pattern 2. QrSemgmentAdvanced.java 3.
Remain Concrete Strategy upload
---
.../java/io/nayuki/qrcodegen/KanjiMode.java | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 java/src/main/java/io/nayuki/qrcodegen/KanjiMode.java
diff --git a/java/src/main/java/io/nayuki/qrcodegen/KanjiMode.java b/java/src/main/java/io/nayuki/qrcodegen/KanjiMode.java
new file mode 100644
index 0000000..9729f93
--- /dev/null
+++ b/java/src/main/java/io/nayuki/qrcodegen/KanjiMode.java
@@ -0,0 +1,23 @@
+package io.nayuki.qrcodegen;
+
+public class KanjiMode extends QrMode {
+ protected KanjiMode(int mode, int... ccbits) {
+ modeBits = mode;
+ numBitsCharCount = ccbits;
+ }
+
+ protected KanjiMode() {
+ modeBits = 0x8;
+ numBitsCharCount[0] = 8;
+ numBitsCharCount[1] = 10;
+ numBitsCharCount[2] = 12;
+ }
+
+ public int getcost(int pre, int codePoint) {
+ return pre + 78;
+ }
+
+ public QrSegment making(String str) {
+ return QrSegmentAdvanced.makeKanji(str);
+ }
+}
From 419466168efdc50c02e9ea979b1739739be17925 Mon Sep 17 00:00:00 2001
From: gerzees
Date: Sat, 6 Jun 2020 18:23:26 +0900
Subject: [PATCH 28/28] 1. Extract method 2. Ecc from QrCode 3. I did not
changed QrCode.Ecc to Ecc in signature of makeSegmentsOptimally()
---
java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
index b125f18..50066e8 100644
--- a/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
+++ b/java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
@@ -68,7 +68,7 @@ public final class QrSegmentAdvanced {
* @throws IllegalArgumentException if 1 ≤ minVersion ≤ maxVersion ≤ 40 is violated
* @throws DataTooLongException if the text fails to fit in the maxVersion QR Code at the ECL
*/
- public static List makeSegmentsOptimally(String text, QrCode.Ecc ecl, int minVersion, int maxVersion) {
+ public static List makeSegmentsOptimally(String text, Ecc ecl, int minVersion, int maxVersion) {
// Check arguments
Objects.requireNonNull(text);
Objects.requireNonNull(ecl);