1/* 2 * QR Code generator output demo (TypeScript) 3 * 4 * Copyright (c) Project Nayuki. (MIT License) 5 * https://www.nayuki.io/page/qr-code-generator-library 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 * this software and associated documentation files (the "Software"), to deal in 9 * the Software without restriction, including without limitation the rights to 10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 * the Software, and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * - The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * - The Software is provided "as is", without warranty of any kind, express or 16 * implied, including but not limited to the warranties of merchantability, 17 * fitness for a particular purpose and noninfringement. In no event shall the 18 * authors or copyright holders be liable for any claim, damages or other 19 * liability, whether in an action of contract, tort or otherwise, arising from, 20 * out of or in connection with the Software or the use or other dealings in the 21 * Software. 22 */ 23 24"use strict"; 25 26 27namespace app { 28 29 let outputElem = document.getElementById("output") as HTMLElement; 30 31 32 // The main application program. 33 function main(): void { 34 while (outputElem.firstChild !== null) 35 outputElem.removeChild(outputElem.firstChild); 36 doBasicDemo(); 37 doVarietyDemo(); 38 doSegmentDemo(); 39 doMaskDemo(); 40 } 41 42 43 // Creates a single QR Code, then appends it to the document. 44 function doBasicDemo(): void { 45 appendHeading("Basic"); 46 const text: string = "Hello, world!"; // User-supplied Unicode text 47 const errCorLvl: qrcodegen.QrCode.Ecc = qrcodegen.QrCode.Ecc.LOW; // Error correction level 48 const qr: qrcodegen.QrCode = qrcodegen.QrCode.encodeText(text, errCorLvl); // Make the QR Code symbol 49 drawCanvas(qr, 10, 4, "#FFFFFF", "#000000", appendCanvas("hello-world-QR")); // Draw it on screen 50 } 51 52 53 // Creates a variety of QR Codes that exercise different features of the library, and appends each one to the document. 54 function doVarietyDemo(): void { 55 appendHeading("Variety"); 56 let qr: qrcodegen.QrCode; 57 const QrCode = qrcodegen.QrCode; // Abbreviation 58 59 // Numeric mode encoding (3.33 bits per digit) 60 qr = QrCode.encodeText("314159265358979323846264338327950288419716939937510", QrCode.Ecc.MEDIUM); 61 drawCanvas(qr, 13, 1, "#FFFFFF", "#000000", appendCanvas("pi-digits-QR")); 62 63 // Alphanumeric mode encoding (5.5 bits per character) 64 qr = QrCode.encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode.Ecc.HIGH); 65 drawCanvas(qr, 10, 2, "#FFFFFF", "#000000", appendCanvas("alphanumeric-QR")); 66 67 // Unicode text as UTF-8 68 qr = QrCode.encodeText("\u3053\u3093\u306B\u3061wa\u3001\u4E16\u754C\uFF01 \u03B1\u03B2\u03B3\u03B4", QrCode.Ecc.QUARTILE); 69 drawCanvas(qr, 10, 3, "#FFFFFF", "#000000", appendCanvas("unicode-QR")); 70 71 // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland) 72 qr = QrCode.encodeText( 73 "Alice was beginning to get very tired of sitting by her sister on the bank, " 74 + "and of having nothing to do: once or twice she had peeped into the book her sister was reading, " 75 + "but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice " 76 + "'without pictures or conversations?' So she was considering in her own mind (as well as she could, " 77 + "for the hot day made her feel very sleepy and stupid), whether the pleasure of making a " 78 + "daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly " 79 + "a White Rabbit with pink eyes ran close by her.", QrCode.Ecc.HIGH); 80 drawCanvas(qr, 6, 10, "#FFFFFF", "#000000", appendCanvas("alice-wonderland-QR")); 81 } 82 83 84 // Creates QR Codes with manually specified segments for better compactness. 85 function doSegmentDemo(): void { 86 appendHeading("Segment"); 87 let qr: qrcodegen.QrCode; 88 let segs: Array<qrcodegen.QrSegment>; 89 const QrCode = qrcodegen.QrCode; // Abbreviation 90 const QrSegment = qrcodegen.QrSegment; // Abbreviation 91 92 // Illustration "silver" 93 const silver0: string = "THE SQUARE ROOT OF 2 IS 1."; 94 const silver1: string = "41421356237309504880168872420969807856967187537694807317667973799"; 95 qr = QrCode.encodeText(silver0 + silver1, QrCode.Ecc.LOW); 96 drawCanvas(qr, 10, 3, "#FFFFFF", "#000000", appendCanvas("sqrt2-monolithic-QR")); 97 98 segs = [ 99 QrSegment.makeAlphanumeric(silver0), 100 QrSegment.makeNumeric(silver1)]; 101 qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW); 102 drawCanvas(qr, 10, 3, "#FFFFFF", "#000000", appendCanvas("sqrt2-segmented-QR")); 103 104 // Illustration "golden" 105 const golden0: string = "Golden ratio \u03C6 = 1."; 106 const golden1: string = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374"; 107 const golden2: string = "......"; 108 qr = QrCode.encodeText(golden0 + golden1 + golden2, QrCode.Ecc.LOW); 109 drawCanvas(qr, 8, 5, "#FFFFFF", "#000000", appendCanvas("phi-monolithic-QR")); 110 111 segs = [ 112 QrSegment.makeBytes(toUtf8ByteArray(golden0)), 113 QrSegment.makeNumeric(golden1), 114 QrSegment.makeAlphanumeric(golden2)]; 115 qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW); 116 drawCanvas(qr, 8, 5, "#FFFFFF", "#000000", appendCanvas("phi-segmented-QR")); 117 118 // Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters 119 const madoka: string = "\u300C\u9B54\u6CD5\u5C11\u5973\u307E\u3069\u304B\u2606\u30DE\u30AE\u30AB\u300D\u3063\u3066\u3001\u3000\u0418\u0410\u0418\u3000\uFF44\uFF45\uFF53\uFF55\u3000\u03BA\u03B1\uFF1F"; 120 qr = QrCode.encodeText(madoka, QrCode.Ecc.LOW); 121 drawCanvas(qr, 9, 4, "#FFFFE0", "#303080", appendCanvas("madoka-utf8-QR")); 122 123 const kanjiCharBits: Array<number> = [ // Kanji mode encoding (13 bits per character) 124 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 125 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 126 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 127 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 128 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 129 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 130 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 131 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 132 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 133 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 134 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 135 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 136 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 137 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 138 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 142 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 143 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 146 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 147 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 148 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 151 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 152 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 153 ]; 154 segs = [new QrSegment(QrSegment.Mode.KANJI, kanjiCharBits.length / 13, kanjiCharBits)]; 155 qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW); 156 drawCanvas(qr, 9, 4, "#E0F0FF", "#404040", appendCanvas("madoka-kanji-QR")); 157 } 158 159 160 // Creates QR Codes with the same size and contents but different mask patterns. 161 function doMaskDemo(): void { 162 appendHeading("Mask"); 163 let qr: qrcodegen.QrCode; 164 let segs: Array<qrcodegen.QrSegment>; 165 const QrCode = qrcodegen.QrCode; // Abbreviation 166 167 // Project Nayuki URL 168 segs = qrcodegen.QrSegment.makeSegments("https://www.nayuki.io/"); 169 qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, -1, true); // Automatic mask 170 drawCanvas(qr, 8, 6, "#E0FFE0", "#206020", appendCanvas("project-nayuki-automask-QR")); 171 qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 3, true); // Force mask 3 172 drawCanvas(qr, 8, 6, "#FFE0E0", "#602020", appendCanvas("project-nayuki-mask3-QR")); 173 174 // Chinese text as UTF-8 175 segs = qrcodegen.QrSegment.makeSegments("\u7DAD\u57FA\u767E\u79D1\uFF08Wikipedia\uFF0C\u8046\u807Di/\u02CCw\u026Ak\u1D7B\u02C8pi\u02D0di.\u0259/\uFF09\u662F\u4E00" 176 + "\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"); 177 qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 0, true); // Force mask 0 178 drawCanvas(qr, 10, 3, "#FFFFFF", "#000000", appendCanvas("unicode-mask0-QR")); 179 qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 1, true); // Force mask 1 180 drawCanvas(qr, 10, 3, "#FFFFFF", "#000000", appendCanvas("unicode-mask1-QR")); 181 qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 5, true); // Force mask 5 182 drawCanvas(qr, 10, 3, "#FFFFFF", "#000000", appendCanvas("unicode-mask5-QR")); 183 qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 7, true); // Force mask 7 184 drawCanvas(qr, 10, 3, "#FFFFFF", "#000000", appendCanvas("unicode-mask7-QR")); 185 } 186 187 188 function appendHeading(text: string): void { 189 let h2 = outputElem.appendChild(document.createElement("h2")); 190 h2.textContent = text; 191 } 192 193 194 function appendCanvas(caption: string): HTMLCanvasElement { 195 let p = outputElem.appendChild(document.createElement("p")); 196 p.textContent = caption + ":"; 197 let result = document.createElement("canvas"); 198 outputElem.appendChild(result); 199 return result; 200 } 201 202 203 // Draws the given QR Code, with the given module scale and border modules, onto the given HTML 204 // canvas element. The canvas's width and height is resized to (qr.size + border * 2) * scale. 205 // The drawn image is purely dark and light, and fully opaque. 206 // The scale must be a positive integer and the border must be a non-negative integer. 207 function drawCanvas(qr: qrcodegen.QrCode, scale: number, border: number, lightColor: string, darkColor: string, canvas: HTMLCanvasElement): void { 208 if (scale <= 0 || border < 0) 209 throw new RangeError("Value out of range"); 210 const width: number = (qr.size + border * 2) * scale; 211 canvas.width = width; 212 canvas.height = width; 213 let ctx = canvas.getContext("2d") as CanvasRenderingContext2D; 214 for (let y = -border; y < qr.size + border; y++) { 215 for (let x = -border; x < qr.size + border; x++) { 216 ctx.fillStyle = qr.getModule(x, y) ? darkColor : lightColor; 217 ctx.fillRect((x + border) * scale, (y + border) * scale, scale, scale); 218 } 219 } 220 } 221 222 223 function toUtf8ByteArray(str: string): Array<number> { 224 str = encodeURI(str); 225 let result: Array<number> = []; 226 for (let i = 0; i < str.length; i++) { 227 if (str.charAt(i) != "%") 228 result.push(str.charCodeAt(i)); 229 else { 230 result.push(parseInt(str.substr(i + 1, 2), 16)); 231 i += 2; 232 } 233 } 234 return result; 235 } 236 237 238 main(); 239 240} 241