From b86466ecd5b0817d81d664be3c8a5fa62bdba6a3 Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Mon, 23 Oct 2017 03:45:24 +0000 Subject: [PATCH] - Deleted constructors/functions/code for remasking existing QrCode object (due to doubtful real-world usefulness): C++, Java, JavaScript, Python, Rust. - Tweaked code and comments due to feature removal: JavaScript, Python. - Updated demo programs to reflect new API usage and add new example: C, C++, Java, Python, Rust. --- c/qrcodegen-demo.c | 88 +++++++++++++------ cpp/QrCode.cpp | 19 ---- cpp/QrCode.hpp | 8 -- cpp/QrCodeGeneratorDemo.cpp | 36 ++++++-- java/io/nayuki/qrcodegen/QrCode.java | 32 ------- .../nayuki/qrcodegen/QrCodeGeneratorDemo.java | 38 +++++--- javascript/qrcodegen.js | 49 +++-------- python/qrcodegen-demo.py | 34 ++++--- python/qrcodegen.py | 57 ++++-------- rust/examples/qrcodegen-demo.rs | 35 +++++--- rust/src/lib.rs | 24 ----- 11 files changed, 191 insertions(+), 229 deletions(-) diff --git a/c/qrcodegen-demo.c b/c/qrcodegen-demo.c index aee3064..36cdec3 100644 --- a/c/qrcodegen-demo.c +++ b/c/qrcodegen-demo.c @@ -36,6 +36,7 @@ static void doBasicDemo(void); static void doVarietyDemo(void); static void doSegmentDemo(void); +static void doMaskDemo(void); static void printQr(const uint8_t qrcode[]); @@ -45,6 +46,7 @@ int main(void) { doBasicDemo(); doVarietyDemo(); doSegmentDemo(); + doMaskDemo(); return EXIT_SUCCESS; } @@ -66,15 +68,6 @@ static void doBasicDemo(void) { // Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console. static void doVarietyDemo(void) { - { // Project Nayuki URL - uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX]; - uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX]; - bool ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode, - qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_3, true); - if (ok) - printQr(qrcode); - } - { // Numeric mode encoding (3.33 bits per digit) uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX]; uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX]; @@ -93,29 +86,12 @@ static void doVarietyDemo(void) { printQr(qrcode); } - { // Unicode text as UTF-8, and different masks + { // Unicode text as UTF-8 const char *text = "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4"; uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX]; uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX]; - bool ok; - - ok = qrcodegen_encodeText(text, tempBuffer, qrcode, - qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_0, true); - if (ok) - printQr(qrcode); - - ok = qrcodegen_encodeText(text, tempBuffer, qrcode, - qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_1, true); - if (ok) - printQr(qrcode); - - ok = qrcodegen_encodeText(text, tempBuffer, qrcode, - qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_5, true); - if (ok) - printQr(qrcode); - - ok = qrcodegen_encodeText(text, tempBuffer, qrcode, - qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_7, true); + bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode, + qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true); if (ok) printQr(qrcode); } @@ -260,6 +236,60 @@ static void doSegmentDemo(void) { } +// Creates QR Codes with the same size and contents but different mask patterns. +static void doMaskDemo(void) { + { // Project Nayuki URL + uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX]; + uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX]; + bool ok; + + ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode, + qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true); + if (ok) + printQr(qrcode); + + ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode, + qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_3, true); + if (ok) + printQr(qrcode); + } + + { // Chinese text as UTF-8 + const char *text = + "\xE7\xB6\xAD\xE5\x9F\xBA\xE7\x99\xBE\xE7\xA7\x91\xEF\xBC\x88\x57\x69\x6B\x69\x70" + "\x65\x64\x69\x61\xEF\xBC\x8C\xE8\x81\x86\xE8\x81\xBD\x69\x2F\xCB\x8C\x77\xC9\xAA" + "\x6B\xE1\xB5\xBB\xCB\x88\x70\x69\xCB\x90\x64\x69\x2E\xC9\x99\x2F\xEF\xBC\x89\xE6" + "\x98\xAF\xE4\xB8\x80\xE5\x80\x8B\xE8\x87\xAA\xE7\x94\xB1\xE5\x85\xA7\xE5\xAE\xB9" + "\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4" + "\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7" + "\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB"; + uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX]; + uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX]; + bool ok; + + ok = qrcodegen_encodeText(text, tempBuffer, qrcode, + qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_0, true); + if (ok) + printQr(qrcode); + + ok = qrcodegen_encodeText(text, tempBuffer, qrcode, + qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_1, true); + if (ok) + printQr(qrcode); + + ok = qrcodegen_encodeText(text, tempBuffer, qrcode, + qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_5, true); + if (ok) + printQr(qrcode); + + ok = qrcodegen_encodeText(text, tempBuffer, qrcode, + qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_7, true); + if (ok) + printQr(qrcode); + } +} + + // Prints the given QR Code to the console. static void printQr(const uint8_t qrcode[]) { int size = qrcodegen_getSize(qrcode); diff --git a/cpp/QrCode.cpp b/cpp/QrCode.cpp index bad055a..ef73d54 100644 --- a/cpp/QrCode.cpp +++ b/cpp/QrCode.cpp @@ -139,25 +139,6 @@ QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int mask) } -QrCode::QrCode(const QrCode &qr, int mask) : - // Copy scalar fields - version(qr.version), - size(qr.size), - errorCorrectionLevel(qr.errorCorrectionLevel), - // Handle grid fields - modules(qr.modules), - isFunction(qr.isFunction) { - - // Check arguments - if (mask < -1 || mask > 7) - throw "Mask value out of range"; - - // Handle masking - applyMask(qr.mask); // Undo old mask - this->mask = handleConstructorMasking(mask); -} - - int QrCode::getVersion() const { return version; } diff --git a/cpp/QrCode.hpp b/cpp/QrCode.hpp index d7d050d..688e70a 100644 --- a/cpp/QrCode.hpp +++ b/cpp/QrCode.hpp @@ -132,14 +132,6 @@ class QrCode final { public: QrCode(int ver, Ecc ecl, const std::vector &dataCodewords, int mask); - /* - * Creates a new QR Code symbol based on the given existing object, but with a potentially - * different mask pattern. The version, error correction level, codewords, etc. of the newly - * created object are all identical to the argument object; only the mask may differ. - */ - public: QrCode(const QrCode &qr, int mask); - - /*---- Public instance methods ----*/ diff --git a/cpp/QrCodeGeneratorDemo.cpp b/cpp/QrCodeGeneratorDemo.cpp index fc124f5..63951e4 100644 --- a/cpp/QrCodeGeneratorDemo.cpp +++ b/cpp/QrCodeGeneratorDemo.cpp @@ -42,6 +42,7 @@ using qrcodegen::QrSegment; static void doBasicDemo(); static void doVarietyDemo(); static void doSegmentDemo(); +static void doMaskDemo(); static void printQr(const QrCode &qr); @@ -51,6 +52,7 @@ int main() { doBasicDemo(); doVarietyDemo(); doSegmentDemo(); + doMaskDemo(); return EXIT_SUCCESS; } @@ -69,10 +71,6 @@ static void doBasicDemo() { // Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console. static void doVarietyDemo() { - // Project Nayuki URL - const QrCode qr0 = QrCode::encodeText("https://www.nayuki.io/", QrCode::Ecc::HIGH); - printQr(QrCode(qr0, 3)); // Change mask, forcing to mask #3 - // Numeric mode encoding (3.33 bits per digit) const QrCode qr1 = QrCode::encodeText("314159265358979323846264338327950288419716939937510", QrCode::Ecc::MEDIUM); printQr(qr1); @@ -81,12 +79,9 @@ static void doVarietyDemo() { const QrCode qr2 = QrCode::encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode::Ecc::HIGH); printQr(qr2); - // Unicode text as UTF-8, and different masks + // Unicode text as UTF-8 const QrCode qr3 = QrCode::encodeText("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4", QrCode::Ecc::QUARTILE); - printQr(QrCode(qr3, 0)); - printQr(QrCode(qr3, 1)); - printQr(QrCode(qr3, 5)); - printQr(QrCode(qr3, 7)); + printQr(qr3); // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland) const QrCode qr4 = QrCode::encodeText( @@ -163,6 +158,29 @@ static void doSegmentDemo() { } +// Creates QR Codes with the same size and contents but different mask patterns. +static void doMaskDemo() { + // Project Nayuki URL + std::vector segs0 = QrSegment::makeSegments("https://www.nayuki.io/"); + printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, 1, 40, -1, true)); // Automatic mask + printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, 1, 40, 3, true)); // Force mask 3 + + // Chinese text as UTF-8 + std::vector segs1 = QrSegment::makeSegments( + "\xE7\xB6\xAD\xE5\x9F\xBA\xE7\x99\xBE\xE7\xA7\x91\xEF\xBC\x88\x57\x69\x6B\x69\x70" + "\x65\x64\x69\x61\xEF\xBC\x8C\xE8\x81\x86\xE8\x81\xBD\x69\x2F\xCB\x8C\x77\xC9\xAA" + "\x6B\xE1\xB5\xBB\xCB\x88\x70\x69\xCB\x90\x64\x69\x2E\xC9\x99\x2F\xEF\xBC\x89\xE6" + "\x98\xAF\xE4\xB8\x80\xE5\x80\x8B\xE8\x87\xAA\xE7\x94\xB1\xE5\x85\xA7\xE5\xAE\xB9" + "\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4" + "\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7" + "\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB"); + printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, 1, 40, 0, true)); // Force mask 0 + printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, 1, 40, 1, true)); // Force mask 1 + printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, 1, 40, 5, true)); // Force mask 5 + printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, 1, 40, 7, true)); // Force mask 7 +} + + // Prints the given QR Code to the console. static void printQr(const QrCode &qr) { int border = 4; diff --git a/java/io/nayuki/qrcodegen/QrCode.java b/java/io/nayuki/qrcodegen/QrCode.java index 76bfa81..7495d44 100644 --- a/java/io/nayuki/qrcodegen/QrCode.java +++ b/java/io/nayuki/qrcodegen/QrCode.java @@ -222,38 +222,6 @@ public final class QrCode { } - /** - * Creates a new QR Code symbol based on the specified existing object, but with a potentially - * different mask pattern. The version, error correction level, codewords, etc. of the newly - * created object are all identical to the argument object; only the mask may differ. - * @param qr the existing QR Code to copy and modify - * @param mask the new mask pattern, 0 to 7 to force a fixed choice or -1 for an automatic choice - * @throws NullPointerException if the QR Code is {@code null} - * @throws IllegalArgumentException if the mask value is out of range - */ - public QrCode(QrCode qr, int mask) { - // Check arguments - Objects.requireNonNull(qr); - if (mask < -1 || mask > 7) - throw new IllegalArgumentException("Mask value out of range"); - - // Copy scalar fields - version = qr.version; - size = qr.size; - errorCorrectionLevel = qr.errorCorrectionLevel; - - // Handle grid fields - isFunction = qr.isFunction; // Shallow copy because the data is read-only - modules = qr.modules.clone(); // Deep copy - for (int i = 0; i < modules.length; i++) - modules[i] = modules[i].clone(); - - // Handle masking - applyMask(qr.mask); // Undo old mask - this.mask = handleConstructorMasking(mask); - } - - /*---- Public instance methods ----*/ diff --git a/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java b/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java index c9d5dfd..ba54148 100644 --- a/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java +++ b/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java @@ -45,6 +45,7 @@ public final class QrCodeGeneratorDemo { doBasicDemo(); doVarietyDemo(); doSegmentDemo(); + doMaskDemo(); } @@ -72,11 +73,6 @@ public final class QrCodeGeneratorDemo { private static void doVarietyDemo() throws IOException { QrCode qr; - // Project Nayuki URL - qr = QrCode.encodeText("https://www.nayuki.io/", QrCode.Ecc.HIGH); - qr = new QrCode(qr, 3); // Change mask, forcing to mask #3 - writePng(qr.toImage(8, 6), "project-nayuki-QR.png"); - // Numeric mode encoding (3.33 bits per digit) qr = QrCode.encodeText("314159265358979323846264338327950288419716939937510", QrCode.Ecc.MEDIUM); writePng(qr.toImage(13, 1), "pi-digits-QR.png"); @@ -85,12 +81,9 @@ public final class QrCodeGeneratorDemo { qr = QrCode.encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode.Ecc.HIGH); writePng(qr.toImage(10, 2), "alphanumeric-QR.png"); - // Unicode text as UTF-8, and different masks + // Unicode text as UTF-8 qr = QrCode.encodeText("こんにちwa、世界! αβγδ", QrCode.Ecc.QUARTILE); - writePng(new QrCode(qr, 0).toImage(10, 3), "unicode-mask0-QR.png"); - writePng(new QrCode(qr, 1).toImage(10, 3), "unicode-mask1-QR.png"); - writePng(new QrCode(qr, 5).toImage(10, 3), "unicode-mask5-QR.png"); - writePng(new QrCode(qr, 7).toImage(10, 3), "unicode-mask7-QR.png"); + writePng(qr.toImage(10, 3), "unicode-QR.png"); // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland) qr = QrCode.encodeText( @@ -158,6 +151,31 @@ public final class QrCodeGeneratorDemo { } + // Creates QR Codes with the same size and contents but different mask patterns. + private static void doMaskDemo() throws IOException { + QrCode qr; + List segs; + + // Project Nayuki URL + segs = QrSegment.makeSegments("https://www.nayuki.io/"); + qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 1, 40, -1, true); // Automatic mask + writePng(qr.toImage(8, 6), "project-nayuki-automask-QR.png"); + qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 1, 40, 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, 1, 40, 0, true); // Force mask 0 + writePng(qr.toImage(10, 3), "unicode-mask0-QR.png"); + qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, 1, 40, 1, true); // Force mask 1 + writePng(qr.toImage(10, 3), "unicode-mask1-QR.png"); + qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, 1, 40, 5, true); // Force mask 5 + writePng(qr.toImage(10, 3), "unicode-mask5-QR.png"); + qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, 1, 40, 7, true); // Force mask 7 + writePng(qr.toImage(10, 3), "unicode-mask7-QR.png"); + } + + // Helper function to reduce code duplication. private static void writePng(BufferedImage img, String filepath) throws IOException { ImageIO.write(img, "png", new File(filepath)); diff --git a/javascript/qrcodegen.js b/javascript/qrcodegen.js index 3115097..e2fc53e 100644 --- a/javascript/qrcodegen.js +++ b/javascript/qrcodegen.js @@ -31,7 +31,6 @@ * - Function encodeBinary(list data, QrCode.Ecc ecl) -> QrCode * - Function encodeSegments(list segs, QrCode.Ecc ecl, * int minVersion=1, int maxVersion=40, mask=-1, boostEcl=true) -> QrCode - * - Constructor QrCode(QrCode qr, int mask) * - Constructor QrCode(list datacodewords, int mask, int version, QrCode.Ecc ecl) * - Fields int version, size, mask * - Field QrCode.Ecc errorCorrectionLevel @@ -64,35 +63,19 @@ var qrcodegen = new function() { * with associated static functions to create a QR Code from user-supplied textual or binary data. * This class covers the QR Code model 2 specification, supporting all versions (sizes) * from 1 to 40, all 4 error correction levels. - * - * This constructor can be called in one of two ways: - * - new QrCode(datacodewords, mask, version, errCorLvl): - * Creates a new QR Code symbol with the given version number, error correction level, binary data array, - * and mask number. This is a cumbersome low-level constructor that should not be invoked directly by the user. - * To go one level up, see the QrCode.encodeSegments() function. - * - new QrCode(qr, mask): - * Creates a new QR Code symbol based on the given existing object, but with a potentially different - * mask pattern. The version, error correction level, codewords, etc. of the newly created object are - * all identical to the argument object; only the mask may differ. - * In both cases, mask = -1 is for automatic choice or 0 to 7 for fixed choice. + * This constructor creates a new QR Code symbol with the given version number, error correction level, binary data array, + * and mask number. mask = -1 is for automatic choice, or 0 to 7 for fixed choice. This is a cumbersome low-level constructor + * that should not be invoked directly by the user. To go one level up, see the QrCode.encodeSegments() function. */ - this.QrCode = function(initData, mask, version, errCorLvl) { + this.QrCode = function(datacodewords, mask, version, errCorLvl) { /*---- Constructor ----*/ // Check arguments and handle simple scalar fields if (mask < -1 || mask > 7) throw "Mask value out of range"; - if (initData instanceof Array) { - if (version < 1 || version > 40) - throw "Version value out of range"; - } else if (initData instanceof qrcodegen.QrCode) { - if (version != undefined || errCorLvl != undefined) - throw "Values must be undefined"; - version = initData.version; - errCorLvl = initData.errorCorrectionLevel; - } else - throw "Invalid initial data"; + if (version < 1 || version > 40) + throw "Version value out of range"; var size = version * 4 + 17; // Initialize both grids to be size*size arrays of Boolean false @@ -106,22 +89,10 @@ var qrcodegen = new function() { isFunction.push(row.slice()); } - // Handle grid fields - if (initData instanceof Array) { - // Draw function patterns, draw all codewords - drawFunctionPatterns(); - var allCodewords = appendErrorCorrection(initData); - drawCodewords(allCodewords); - } else if (initData instanceof qrcodegen.QrCode) { - for (var y = 0; y < size; y++) { - for (var x = 0; x < size; x++) { - modules[y][x] = initData.getModule(x, y); - isFunction[y][x] = initData.isFunctionModule(x, y); - } - } - applyMask(initData.mask); // Undo old mask - } else - throw "Invalid initial data"; + // Handle grid fields, draw function patterns, draw all codewords + drawFunctionPatterns(); + var allCodewords = appendErrorCorrection(datacodewords); + drawCodewords(allCodewords); // Handle masking if (mask == -1) { // Automatically choose best mask diff --git a/python/qrcodegen-demo.py b/python/qrcodegen-demo.py index 035820d..9db5c1f 100644 --- a/python/qrcodegen-demo.py +++ b/python/qrcodegen-demo.py @@ -35,6 +35,7 @@ def main(): do_basic_demo() do_variety_demo() do_segment_demo() + do_mask_demo() def do_basic_demo(): @@ -51,11 +52,6 @@ def do_basic_demo(): def do_variety_demo(): """Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.""" - # Project Nayuki URL - qr = qrcodegen.QrCode.encode_text("https://www.nayuki.io/", qrcodegen.QrCode.Ecc.HIGH) - qr = qrcodegen.QrCode(qrcode=qr, mask=3) # Change mask, forcing to mask #3 - print_qr(qr) - # Numeric mode encoding (3.33 bits per digit) qr = qrcodegen.QrCode.encode_text("314159265358979323846264338327950288419716939937510", qrcodegen.QrCode.Ecc.MEDIUM) print_qr(qr) @@ -64,12 +60,9 @@ def do_variety_demo(): qr = qrcodegen.QrCode.encode_text("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", qrcodegen.QrCode.Ecc.HIGH) print_qr(qr) - # Unicode text as UTF-8, and different masks + # Unicode text as UTF-8 qr = qrcodegen.QrCode.encode_text(u"\u3053\u3093\u306B\u3061\u0077\u0061\u3001\u4E16\u754C\uFF01\u0020\u03B1\u03B2\u03B3\u03B4", qrcodegen.QrCode.Ecc.QUARTILE) - print_qr(qrcodegen.QrCode(qrcode=qr, mask=0)) - print_qr(qrcodegen.QrCode(qrcode=qr, mask=1)) - print_qr(qrcodegen.QrCode(qrcode=qr, mask=5)) - print_qr(qrcodegen.QrCode(qrcode=qr, mask=7)) + print_qr(qr) # Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland) qr = qrcodegen.QrCode.encode_text( @@ -153,6 +146,27 @@ def do_segment_demo(): print_qr(qr) +def do_mask_demo(): + """Creates QR Codes with the same size and contents but different mask patterns.""" + + # Project Nayuki URL + segs = qrcodegen.QrSegment.make_segments("https://www.nayuki.io/") + print_qr(qrcodegen.QrCode.encode_segments(segs, qrcodegen.QrCode.Ecc.HIGH, mask=-1)) # Automatic mask + print_qr(qrcodegen.QrCode.encode_segments(segs, qrcodegen.QrCode.Ecc.HIGH, mask=3)) # Force mask 3 + + # Chinese text as UTF-8 + segs = qrcodegen.QrSegment.make_segments( + u"\u7DAD\u57FA\u767E\u79D1\uFF08\u0057\u0069\u006B\u0069\u0070\u0065\u0064\u0069\u0061\uFF0C" + "\u8046\u807D\u0069\u002F\u02CC\u0077\u026A\u006B\u1D7B\u02C8\u0070\u0069\u02D0\u0064\u0069" + "\u002E\u0259\u002F\uFF09\u662F\u4E00\u500B\u81EA\u7531\u5167\u5BB9\u3001\u516C\u958B\u7DE8" + "\u8F2F\u4E14\u591A\u8A9E\u8A00\u7684\u7DB2\u8DEF\u767E\u79D1\u5168\u66F8\u5354\u4F5C\u8A08" + "\u756B") + print_qr(qrcodegen.QrCode.encode_segments(segs, qrcodegen.QrCode.Ecc.MEDIUM, mask=0)) # Force mask 0 + print_qr(qrcodegen.QrCode.encode_segments(segs, qrcodegen.QrCode.Ecc.MEDIUM, mask=1)) # Force mask 1 + print_qr(qrcodegen.QrCode.encode_segments(segs, qrcodegen.QrCode.Ecc.MEDIUM, mask=5)) # Force mask 5 + print_qr(qrcodegen.QrCode.encode_segments(segs, qrcodegen.QrCode.Ecc.MEDIUM, mask=7)) # Force mask 7 + + # ---- Utilities ---- diff --git a/python/qrcodegen.py b/python/qrcodegen.py index b175ce8..1d90bdc 100644 --- a/python/qrcodegen.py +++ b/python/qrcodegen.py @@ -31,7 +31,6 @@ This module "qrcodegen", public members: - Function encode_binary(bytes data, QrCode.Ecc ecl) -> QrCode - Function encode_segments(list segs, QrCode.Ecc ecl, int minversion=1, int maxversion=40, mask=-1, boostecl=true) -> QrCode - - Constructor QrCode(QrCode qr, int mask) - Constructor QrCode(bytes datacodewords, int mask, int version, QrCode.Ecc ecl) - Method get_version() -> int - Method get_size() -> int @@ -135,56 +134,36 @@ class QrCode(object): assert len(bb) % 8 == 0 # Create the QR Code symbol - return QrCode(None, bb.get_bytes(), mask, version, ecl) + return QrCode(bb.get_bytes(), mask, version, ecl) # ---- Constructor ---- - def __init__(self, qrcode=None, datacodewords=None, mask=None, version=None, errcorlvl=None): - """This constructor can be called in one of two ways: - - QrCode(datacodewords=list, mask=int, version=int, errcorlvl=QrCode.Ecc): - Creates a new QR Code symbol with the given version number, error correction level, binary data array, - and mask number. This is a cumbersome low-level constructor that should not be invoked directly by the user. - To go one level up, see the QrCode.encode_segments() function. - - QrCode(qrcode=QrCode, mask=int): - Creates a new QR Code symbol based on the given existing object, but with a potentially different - mask pattern. The version, error correction level, codewords, etc. of the newly created object are - all identical to the argument object; only the mask may differ. - In both cases, mask = -1 is for automatic choice or 0 to 7 for fixed choice.""" + def __init__(self, datacodewords, mask, version, errcorlvl): + """Creates a new QR Code symbol with the given version number, error correction level, binary data array, + and mask number. mask = -1 is for automatic choice, or 0 to 7 for fixed choice. This is a cumbersome low-level constructor + that should not be invoked directly by the user. To go one level up, see the QrCode.encode_segments() function.""" # Check arguments and handle simple scalar fields if not (-1 <= mask <= 7): raise ValueError("Mask value out of range") - if datacodewords is not None and qrcode is None: - if not (1 <= version <= 40): - raise ValueError("Version value out of range") - if not isinstance(errcorlvl, QrCode.Ecc): - raise TypeError("QrCode.Ecc expected") - elif qrcode is not None and datacodewords is None: - if version is not None or errcorlvl is not None: - raise ValueError("Values must be None") - version = qrcode._version - errcorlvl = qrcode._errcorlvl - else: - raise ValueError("Exactly one of datacodewords or qrcode must be not None") + if not (1 <= version <= 40): + raise ValueError("Version value out of range") + if not isinstance(errcorlvl, QrCode.Ecc): + raise TypeError("QrCode.Ecc expected") self._version = version self._errcorlvl = errcorlvl self._size = version * 4 + 17 - if datacodewords is not None: # Render from scratch a QR Code based on data codewords - if len(datacodewords) != QrCode._get_num_data_codewords(version, errcorlvl): - raise ValueError("Invalid array length") - # Initialize grids of modules - self._modules = [[False] * self._size for _ in range(self._size)] # The modules of the QR symbol; start with entirely white grid - self._isfunction = [[False] * self._size for _ in range(self._size)] # Indicates function modules that are not subjected to masking - # Draw function patterns, draw all codewords - self._draw_function_patterns() - allcodewords = self._append_error_correction(datacodewords) - self._draw_codewords(allcodewords) - elif qrcode is not None: # Modify the mask of an existing QR Code - self._modules = [list(row) for row in qrcode._modules] # Deep copy - self._isfunction = qrcode._isfunction # Shallow copy because the data is read-only - self._apply_mask(qrcode._mask) # Undo existing mask + if len(datacodewords) != QrCode._get_num_data_codewords(version, errcorlvl): + raise ValueError("Invalid array length") + # Initialize grids of modules + self._modules = [[False] * self._size for _ in range(self._size)] # The modules of the QR symbol; start with entirely white grid + self._isfunction = [[False] * self._size for _ in range(self._size)] # Indicates function modules that are not subjected to masking + # Draw function patterns, draw all codewords + self._draw_function_patterns() + allcodewords = self._append_error_correction(datacodewords) + self._draw_codewords(allcodewords) # Handle masking if mask == -1: # Automatically choose best mask diff --git a/rust/examples/qrcodegen-demo.rs b/rust/examples/qrcodegen-demo.rs index 069d491..ec1f535 100644 --- a/rust/examples/qrcodegen-demo.rs +++ b/rust/examples/qrcodegen-demo.rs @@ -35,6 +35,7 @@ fn main() { do_basic_demo(); do_variety_demo(); do_segment_demo(); + do_mask_demo(); } @@ -52,11 +53,6 @@ fn do_basic_demo() { // Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console. fn do_variety_demo() { - // Project Nayuki URL - let qr = QrCode::encode_text("https://www.nayuki.io/", QrCodeEcc::High).unwrap(); - let qr = QrCode::remask(&qr, Some(3)); // Change mask, forcing to mask #3 - print_qr(&qr); - // Numeric mode encoding (3.33 bits per digit) let qr = QrCode::encode_text("314159265358979323846264338327950288419716939937510", QrCodeEcc::Medium).unwrap(); print_qr(&qr); @@ -65,12 +61,9 @@ fn do_variety_demo() { let qr = QrCode::encode_text("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCodeEcc::High).unwrap(); print_qr(&qr); - // Unicode text as UTF-8, and different masks + // Unicode text as UTF-8 let qr = QrCode::encode_text("こんにちwa、世界! αβγδ", QrCodeEcc::Quartile).unwrap(); - print_qr(&QrCode::remask(&qr, Some(0))); - print_qr(&QrCode::remask(&qr, Some(1))); - print_qr(&QrCode::remask(&qr, Some(5))); - print_qr(&QrCode::remask(&qr, Some(7))); + print_qr(&qr); // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland) let qr = QrCode::encode_text(concat!( @@ -140,6 +133,28 @@ fn do_segment_demo() { } +// Creates QR Codes with the same size and contents but different mask patterns. +fn do_mask_demo() { + // Project Nayuki URL + let segs = QrSegment::make_segments(&to_chars("https://www.nayuki.io/")); + let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, 1, 40, None, true).unwrap(); // Automatic mask + print_qr(&qr); + let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, 1, 40, Some(3), true).unwrap(); // Force mask 3 + print_qr(&qr); + + // Chinese text as UTF-8 + let segs = QrSegment::make_segments(&to_chars("維基百科(Wikipedia,聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫")); + let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, 1, 40, Some(0), true).unwrap(); // Force mask 0 + print_qr(&qr); + let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, 1, 40, Some(1), true).unwrap(); // Force mask 1 + print_qr(&qr); + let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, 1, 40, Some(5), true).unwrap(); // Force mask 5 + print_qr(&qr); + let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, 1, 40, Some(7), true).unwrap(); // Force mask 7 + print_qr(&qr); +} + + /*---- Utilities ----*/ // Prints the given QrCode object to the console. diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 1a6696d..c33945d 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -193,30 +193,6 @@ impl QrCode { } - // Creates a new QR Code symbol based on the given existing object, but with a potentially - // different mask pattern. The version, error correction level, codewords, etc. of the newly - // created object are all identical to the argument object; only the mask may differ. - pub fn remask(qr: &QrCode, mask: Option) -> QrCode { - // Check arguments - assert!(mask == None || mask.unwrap() <= 7, "Mask out of range"); - - // Copy fields - let mut result = QrCode { - version: qr.version, - size: qr.size, - mask: 0, // Dummy value - errorcorrectionlevel: qr.errorcorrectionlevel, - modules: qr.modules.clone(), - isfunction: qr.isfunction.clone(), - }; - - // Handle masking - result.apply_mask(qr.mask); // Undo old mask - result.handle_constructor_masking(mask); - result - } - - // Returns this QR Code's version, in the range [1, 40]. pub fn version(&self) -> u8 { self.version