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 1/4] 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 2/4] 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 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 3/4] 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 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 4/4] 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 ----*/