├── .gitignore ├── .project ├── .settings ├── .jsdtscope ├── com.palantir.typescript.prefs ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.core.prefs ├── org.eclipse.wst.jsdt.ui.superType.container └── org.eclipse.wst.jsdt.ui.superType.name ├── LICENSE ├── README.md ├── as3 ├── .gitignore └── src │ ├── as3 │ └── com │ │ └── d_project │ │ └── qrcode │ │ ├── BitBuffer.as │ │ ├── ErrorCorrectLevel.as │ │ ├── MaskPattern.as │ │ ├── Mode.as │ │ ├── Polynomial.as │ │ ├── QR8BitByte.as │ │ ├── QRAlphaNum.as │ │ ├── QRCode.as │ │ ├── QRData.as │ │ ├── QRKanji.as │ │ ├── QRMath.as │ │ ├── QRNumber.as │ │ ├── QRUtil.as │ │ ├── RSBlock.as │ │ ├── StringUtil.as │ │ └── mx │ │ └── QRCode.as │ ├── assets │ ├── README.txt │ └── manifest.xml │ ├── build.xml │ └── sample │ ├── QRCodeSample1.as │ └── QRCodeSample2.mxml ├── hack ├── .gitignore ├── .hhconfig ├── composer.json ├── composer.lock ├── hh_autoload.json ├── hhast-lint.json ├── hhast_lint.json ├── samples │ ├── hhvm_generated.html │ ├── sample.html │ ├── sample_custom.php │ ├── sample_html.php │ └── sample_image.php ├── src │ └── qrcode.hack └── unit_test.diffme.gif ├── java ├── .gitignore ├── README.txt ├── build.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── d_project │ │ │ └── qrcode │ │ │ ├── BitBuffer.java │ │ │ ├── ErrorCorrectionLevel.java │ │ │ ├── MaskPattern.java │ │ │ ├── Mode.java │ │ │ ├── Polynomial.java │ │ │ ├── QR8BitByte.java │ │ │ ├── QRAlphaNum.java │ │ │ ├── QRCode.java │ │ │ ├── QRData.java │ │ │ ├── QRKanji.java │ │ │ ├── QRMath.java │ │ │ ├── QRNumber.java │ │ │ ├── QRUtil.java │ │ │ ├── RSBlock.java │ │ │ └── web │ │ │ ├── GIFImage.java │ │ │ └── QRCodeServlet.java │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── form.jsp │ │ └── index.jsp │ └── test │ └── java │ └── com │ └── d_project │ └── qrcode │ ├── BitBufferTest.java │ ├── PolynomialTest.java │ ├── QRCodeTest.java │ └── web │ └── GIFImageTest.java ├── js ├── .gitignore ├── .npmignore ├── README.md ├── demo │ ├── assets │ │ ├── qrcode.png │ │ ├── sample.js │ │ └── style.css │ └── index.html ├── misc │ ├── .gitignore │ ├── build.xml │ └── src │ │ ├── GenSJISSupport.java │ │ ├── SJIS.txt │ │ └── qrcode_SJIS.js.tmpl ├── package.json ├── qrcode.d.ts ├── qrcode.js ├── qrcode_SJIS.js ├── qrcode_UTF8.js ├── sample.html ├── sample.js ├── test │ └── qrcode.js └── ts-test │ ├── .gitignore │ ├── Gruntfile.js │ ├── package.json │ └── src │ ├── .gitignore │ └── import_test.ts ├── php ├── qrcode.php ├── sample.html ├── sample_custom.php ├── sample_html.php └── sample_image.php ├── python └── qrcode.py ├── ruby └── qrcode.rb └── ts ├── .gitignore └── src └── ts ├── com └── d_project │ ├── image │ └── GIFImage.ts │ ├── io │ ├── Base64.ts │ ├── Base64DecodeInputStream.ts │ ├── Base64EncodeOutputStream.ts │ ├── ByteArrayInputStream.ts │ ├── ByteArrayOutputStream.ts │ ├── InputStream.ts │ └── OutputStream.ts │ ├── qrcode │ ├── BitBuffer.ts │ ├── ErrorCorrectLevel.ts │ ├── MaskPattern.ts │ ├── Mode.ts │ ├── Polynomial.ts │ ├── QR8BitByte.ts │ ├── QRAlphaNum.ts │ ├── QRCode.ts │ ├── QRData.ts │ ├── QRKanji.ts │ ├── QRMath.ts │ ├── QRNumber.ts │ ├── QRUtil.ts │ └── RSBlock.ts │ └── text │ ├── createStringToBytes.ts │ ├── stringToBytes_SJIS.ts │ └── stringToBytes_UTF8.ts ├── test.html └── test.ts /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | qrcode-generator 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | com.palantir.typescript.typeScriptBuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.wst.jsdt.core.jsNature 21 | com.palantir.typescript.typeScriptNature 22 | 23 | 24 | 25 | 1476438204826 26 | 27 | 26 28 | 29 | org.eclipse.ui.ide.multiFilter 30 | 1.0-name-matches-true-false-node_modules 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.settings/com.palantir.typescript.prefs: -------------------------------------------------------------------------------- 1 | build.path.exportedFolder= 2 | build.path.sourceFolder= 3 | compiler.codeGenTarget=ECMASCRIPT5 4 | compiler.compileOnSave=false 5 | compiler.generateDeclarationFiles=false 6 | compiler.inlineSourceMap=false 7 | compiler.inlineSources=false 8 | compiler.jsx=NONE 9 | compiler.mapSourceFiles=false 10 | compiler.moduleGenTarget=NONE 11 | compiler.moduleResolution=CLASSIC 12 | compiler.noFallthroughCasesInSwitch=false 13 | compiler.noImplicitAny=false 14 | compiler.noImplicitReturns=false 15 | compiler.noLib=false 16 | compiler.outputDirOption= 17 | compiler.outputFileOption= 18 | compiler.removeComments=false 19 | compiler.suppressExcessPropertyErrors=false 20 | compiler.suppressImplicitAnyIndexErrors=false 21 | eclipse.preferences.version=1 22 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//php/sample_custom.php=MS932 3 | encoding//php/sample_html.php=MS932 4 | encoding//php/sample_image.php=MS932 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.5 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.5 12 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.JRE_CONTAINER -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Global -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2009 Kazuhiko Arase 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qrcode-generator 2 | QR Code Generator implementation in JavaScript, Java and more 3 | 4 | [online demo(js)](https://kazuhikoarase.github.io/qrcode-generator/js/demo/) 5 | 6 | All the implementations are based on JIS X 0510:1999. 7 | 8 | The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED 9 |
http://www.denso-wave.com/qrcode/faqpatent-e.html 10 | -------------------------------------------------------------------------------- /as3/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /dist 3 | -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/BitBuffer.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * BitBuffer 5 | * @author Kazuhiko Arase 6 | */ 7 | internal class BitBuffer { 8 | 9 | private var buffer : Array; 10 | 11 | private var length : int; 12 | 13 | public function BitBuffer() { 14 | buffer = new Array(); 15 | length = 0; 16 | } 17 | 18 | public function getBuffer() : Array { 19 | return buffer; 20 | } 21 | 22 | public function getLengthInBits() : int { 23 | return length; 24 | } 25 | 26 | private function getBitAt(index : int) : Boolean { 27 | return ( (buffer[Math.floor(index / 8)] >>> (7 - index % 8) ) & 1) == 1; 28 | } 29 | 30 | public function put(num : int, length : int) : void { 31 | for (var i : int = 0; i < length; i++) { 32 | putBit( ( (num >>> (length - i - 1) ) & 1) == 1); 33 | } 34 | } 35 | 36 | public function putBit(bit : Boolean) : void { 37 | 38 | if (length == buffer.length * 8) { 39 | buffer.push(0); 40 | } 41 | 42 | if (bit) { 43 | buffer[Math.floor(length / 8)] |= (0x80 >>> (length % 8) ); 44 | } 45 | 46 | length++; 47 | } 48 | 49 | public function toString() : String { 50 | var buffer : String = ""; 51 | for (var i : int = 0; i < getLengthInBits(); i++) { 52 | buffer += (getBitAt(i)? '1' : '0'); 53 | } 54 | return buffer; 55 | } 56 | 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/ErrorCorrectLevel.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * 誤り訂正レベル. 5 | * @author Kazuhiko Arase 6 | */ 7 | public class ErrorCorrectLevel { 8 | 9 | /** 10 | * 復元能力 7%. 11 | *
vodafoneで使用不可? 12 | */ 13 | public static const L : int = 1; 14 | 15 | /** 16 | * 復元能力 15%. 17 | */ 18 | public static const M : int = 0; 19 | 20 | /** 21 | * 復元能力 25%. 22 | */ 23 | public static const Q : int = 3; 24 | 25 | /** 26 | * 復元能力 30%. 27 | */ 28 | public static const H : int = 2; 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/MaskPattern.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * マスクパターン. 5 | * @author Kazuhiko Arase 6 | */ 7 | internal class MaskPattern { 8 | 9 | /** 10 | * マスクパターン000 11 | */ 12 | public static const PATTERN000 : int = 0; 13 | 14 | /** 15 | * マスクパターン001 16 | */ 17 | public static const PATTERN001 : int = 1; 18 | 19 | /** 20 | * マスクパターン010 21 | */ 22 | public static const PATTERN010 : int = 2; 23 | 24 | /** 25 | * マスクパターン011 26 | */ 27 | public static const PATTERN011 : int = 3; 28 | 29 | /** 30 | * マスクパターン100 31 | */ 32 | public static const PATTERN100 : int = 4; 33 | 34 | /** 35 | * マスクパターン101 36 | */ 37 | public static const PATTERN101 : int = 5; 38 | 39 | /** 40 | * マスクパターン110 41 | */ 42 | public static const PATTERN110 : int = 6; 43 | 44 | /** 45 | * マスクパターン111 46 | */ 47 | public static const PATTERN111 : int = 7; 48 | 49 | } 50 | 51 | 52 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/Mode.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * モード. 5 | * @author Kazuhiko Arase 6 | */ 7 | public class Mode { 8 | 9 | /** 10 | * 自動モード 11 | */ 12 | public static const MODE_AUTO : int = 0; 13 | 14 | /** 15 | * 数値モード 16 | */ 17 | public static const MODE_NUMBER : int = 1 << 0; 18 | 19 | /** 20 | * 英数字モード 21 | */ 22 | public static const MODE_ALPHA_NUM : int = 1 << 1; 23 | 24 | /** 25 | * 8ビットバイトモード 26 | */ 27 | public static const MODE_8BIT_BYTE : int = 1 << 2; 28 | 29 | /** 30 | * 漢字モード 31 | */ 32 | public static const MODE_KANJI : int = 1 << 3; 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/Polynomial.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * Polynomial 5 | * @author Kazuhiko Arase 6 | */ 7 | internal class Polynomial { 8 | 9 | private var num : Array; 10 | 11 | public function Polynomial(num : Array, shift : int = 0) { 12 | 13 | var offset : int = 0; 14 | 15 | while (offset < num.length && num[offset] == 0) { 16 | offset++; 17 | } 18 | 19 | this.num = new Array(num.length - offset + shift); 20 | for (var i : int = 0; i < num.length - offset; i++) { 21 | this.num[i] = num[offset + i]; 22 | } 23 | } 24 | 25 | public function getAt(index : int) : int { 26 | return num[index]; 27 | } 28 | 29 | public function getLength() : int { 30 | return num.length; 31 | } 32 | 33 | public function toString() : String { 34 | 35 | var buffer : String = ""; 36 | 37 | for (var i : int = 0; i < getLength(); i++) { 38 | if (i > 0) { 39 | buffer += ","; 40 | } 41 | buffer += getAt(i); 42 | } 43 | 44 | return buffer; 45 | } 46 | 47 | public function toLogString() : String { 48 | 49 | var buffer : String = ""; 50 | 51 | for (var i : int = 0; i < getLength(); i++) { 52 | if (i > 0) { 53 | buffer += ","; 54 | } 55 | buffer += QRMath.glog(getAt(i) ); 56 | 57 | } 58 | 59 | return buffer.toString(); 60 | } 61 | 62 | public function multiply(e : Polynomial) : Polynomial { 63 | 64 | var num : Array = new Array(getLength() + e.getLength() - 1); 65 | 66 | for (var i : int = 0; i < getLength(); i++) { 67 | for (var j : int = 0; j < e.getLength(); j++) { 68 | num[i + j] ^= QRMath.gexp(QRMath.glog(getAt(i) ) + QRMath.glog(e.getAt(j) ) ); 69 | } 70 | } 71 | 72 | return new Polynomial(num); 73 | } 74 | 75 | public function mod(e : Polynomial) : Polynomial { 76 | 77 | if (getLength() - e.getLength() < 0) { 78 | return this; 79 | } 80 | 81 | // 最上位桁の比率 82 | var ratio : int = QRMath.glog(getAt(0) ) - QRMath.glog(e.getAt(0) ); 83 | 84 | var i : int; 85 | 86 | // コピー作成 87 | var num : Array = new Array(getLength() ); 88 | for (i = 0; i < getLength(); i++) { 89 | num[i] = getAt(i); 90 | } 91 | 92 | // 引き算して余りを計算 93 | for (i = 0; i < e.getLength(); i++) { 94 | num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio); 95 | } 96 | 97 | // 再帰計算 98 | return new Polynomial(num).mod(e); 99 | } 100 | 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/QR8BitByte.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | import flash.utils.ByteArray; 4 | 5 | /** 6 | * QR8BitByte 7 | * @author Kazuhiko Arase 8 | */ 9 | internal class QR8BitByte extends QRData { 10 | 11 | public function QR8BitByte(data : String) { 12 | super(Mode.MODE_8BIT_BYTE, data); 13 | } 14 | 15 | public override function write(buffer : BitBuffer) : void { 16 | var data : ByteArray = StringUtil.getBytes(getData(), QRUtil.getJISEncoding() ); 17 | for (var i : int = 0; i < data.length; i++) { 18 | buffer.put(data[i], 8); 19 | } 20 | } 21 | 22 | public override function getLength() : int { 23 | return StringUtil.getBytes(getData(), QRUtil.getJISEncoding() ).length; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/QRAlphaNum.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * QRAlphaNum 5 | * @author Kazuhiko Arase 6 | */ 7 | internal class QRAlphaNum extends QRData { 8 | 9 | public function QRAlphaNum(data : String) { 10 | super(Mode.MODE_ALPHA_NUM, data); 11 | } 12 | 13 | public override function write(buffer : BitBuffer) : void { 14 | 15 | var i : int = 0; 16 | var s : String = getData(); 17 | 18 | while (i + 1 < s.length) { 19 | buffer.put(getCode(s.charAt(i) ) * 45 + getCode(s.charAt(i + 1) ), 11); 20 | i += 2; 21 | } 22 | 23 | if (i < s.length) { 24 | buffer.put(getCode(s.charAt(i) ), 6); 25 | } 26 | } 27 | 28 | public override function getLength() : int { 29 | return getData().length; 30 | } 31 | 32 | private static function getCode(c : String) : int { 33 | var code : int = c.charCodeAt(0); 34 | if (getCharCode('0') <= code && code <= getCharCode('9') ) { 35 | return code - getCharCode('0'); 36 | } else if (getCharCode('A') <= code && code <= getCharCode('Z') ) { 37 | return code - getCharCode('A') + 10; 38 | } else { 39 | switch (c) { 40 | case ' ' : return 36; 41 | case '$' : return 37; 42 | case '%' : return 38; 43 | case '*' : return 39; 44 | case '+' : return 40; 45 | case '-' : return 41; 46 | case '.' : return 42; 47 | case '/' : return 43; 48 | case ':' : return 44; 49 | default : 50 | throw new Error("illegal char :" + c); 51 | } 52 | } 53 | throw new Error(); 54 | } 55 | 56 | private static function getCharCode(c : String) : int { 57 | return c.charCodeAt(0); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/QRData.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * QRData 5 | * @author Kazuhiko Arase 6 | */ 7 | internal class QRData { 8 | 9 | private var mode : int; 10 | 11 | private var data : String; 12 | 13 | public function QRData(mode : int, data : String) { 14 | this.mode = mode; 15 | this.data = data; 16 | } 17 | 18 | public function getMode() : int { 19 | return mode; 20 | } 21 | 22 | public function getData() : String { 23 | return data; 24 | } 25 | 26 | public function getLength() : int { 27 | throw new Error("not implemented."); 28 | } 29 | 30 | public function write(buffer : BitBuffer) : void { 31 | throw new Error("not implemented."); 32 | } 33 | 34 | /** 35 | * 型番及びモードに対するビット長を取得する。 36 | */ 37 | public function getLengthInBits(type : int) : int { 38 | 39 | if (1 <= type && type < 10) { 40 | 41 | // 1 - 9 42 | 43 | switch(mode) { 44 | case Mode.MODE_NUMBER : return 10; 45 | case Mode.MODE_ALPHA_NUM : return 9; 46 | case Mode.MODE_8BIT_BYTE : return 8; 47 | case Mode.MODE_KANJI : return 8; 48 | default : 49 | throw new Error("mode:" + mode); 50 | } 51 | 52 | } else if (type < 27) { 53 | 54 | // 10 - 26 55 | 56 | switch(mode) { 57 | case Mode.MODE_NUMBER : return 12; 58 | case Mode.MODE_ALPHA_NUM : return 11; 59 | case Mode.MODE_8BIT_BYTE : return 16; 60 | case Mode.MODE_KANJI : return 10; 61 | default : 62 | throw new Error("mode:" + mode); 63 | } 64 | 65 | } else if (type < 41) { 66 | 67 | // 27 - 40 68 | 69 | switch(mode) { 70 | case Mode.MODE_NUMBER : return 14; 71 | case Mode.MODE_ALPHA_NUM : return 13; 72 | case Mode.MODE_8BIT_BYTE : return 16; 73 | case Mode.MODE_KANJI : return 12; 74 | default : 75 | throw new Error("mode:" + mode); 76 | } 77 | 78 | } else { 79 | throw new Error("type:" + type); 80 | } 81 | } 82 | 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/QRKanji.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | import flash.utils.ByteArray; 4 | 5 | /** 6 | * QRKanji 7 | * @author Kazuhiko Arase 8 | */ 9 | internal class QRKanji extends QRData { 10 | 11 | public function QRKanji(data : String) { 12 | super(Mode.MODE_KANJI, data); 13 | } 14 | 15 | public override function write(buffer : BitBuffer) : void { 16 | 17 | var data : ByteArray = StringUtil.getBytes(getData(), QRUtil.getJISEncoding() ); 18 | 19 | var i : int = 0; 20 | 21 | while (i + 1 < data.length) { 22 | 23 | var c : int = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]); 24 | 25 | if (0x8140 <= c && c <= 0x9FFC) { 26 | c -= 0x8140; 27 | } else if (0xE040 <= c && c <= 0xEBBF) { 28 | c -= 0xC140; 29 | } else { 30 | throw new Error("illegal char at " + (i + 1) + "/" + c); 31 | } 32 | 33 | c = ( (c >>> 8) & 0xff) * 0xC0 + (c & 0xff); 34 | 35 | buffer.put(c, 13); 36 | 37 | i += 2; 38 | } 39 | 40 | if (i < data.length) { 41 | throw new Error("illegal char at " + (i + 1) ); 42 | } 43 | } 44 | 45 | public override function getLength() : int { 46 | return Math.floor(StringUtil.getBytes(getData(), QRUtil.getJISEncoding() ).length / 2); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/QRMath.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * QRMath 5 | * @author Kazuhiko Arase 6 | */ 7 | internal class QRMath { 8 | 9 | function QRMath() { 10 | throw new Error(""); 11 | } 12 | 13 | private static var EXP_TABLE : Array; 14 | private static var LOG_TABLE : Array; 15 | 16 | private static var classInitialized : Boolean = initializeClass(); 17 | 18 | private static function initializeClass() : Boolean { 19 | 20 | var i : int; 21 | 22 | EXP_TABLE = new Array(256); 23 | 24 | for (i = 0; i < 8; i++) { 25 | EXP_TABLE[i] = 1 << i; 26 | } 27 | 28 | for (i = 8; i < 256; i++) { 29 | EXP_TABLE[i] = EXP_TABLE[i - 4] 30 | ^ EXP_TABLE[i - 5] 31 | ^ EXP_TABLE[i - 6] 32 | ^ EXP_TABLE[i - 8]; 33 | } 34 | 35 | LOG_TABLE = new Array(256); 36 | for (i = 0; i < 255; i++) { 37 | LOG_TABLE[EXP_TABLE[i] ] = i; 38 | } 39 | 40 | return true; 41 | } 42 | 43 | public static function glog(n : int) : int { 44 | 45 | if (n < 1) { 46 | throw new Error("log(" + n + ")"); 47 | } 48 | 49 | return LOG_TABLE[n]; 50 | } 51 | 52 | public static function gexp(n : int) : int { 53 | 54 | while (n < 0) { 55 | n += 255; 56 | } 57 | 58 | while (n >= 256) { 59 | n -= 255; 60 | } 61 | 62 | return EXP_TABLE[n]; 63 | } 64 | 65 | 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/QRNumber.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * QRNumber 5 | * @author Kazuhiko Arase 6 | */ 7 | internal class QRNumber extends QRData { 8 | 9 | public function QRNumber(data : String) { 10 | super(Mode.MODE_NUMBER, data); 11 | } 12 | 13 | public override function write(buffer : BitBuffer) : void { 14 | 15 | var data : String = getData(); 16 | 17 | var i : int = 0; 18 | var num : int; 19 | 20 | while (i + 2 < data.length) { 21 | num = parseInt(data.substring(i, i + 3) ); 22 | buffer.put(num, 10); 23 | i += 3; 24 | } 25 | 26 | if (i < data.length) { 27 | 28 | if (data.length - i == 1) { 29 | num = parseInt(data.substring(i, i + 1) ); 30 | buffer.put(num, 4); 31 | } else if (data.length - i == 2) { 32 | num = parseInt(data.substring(i, i + 2) ); 33 | buffer.put(num, 7); 34 | } 35 | 36 | } 37 | } 38 | 39 | public override function getLength() : int { 40 | return getData().length; 41 | } 42 | 43 | private static function parseInt(s : String) : int { 44 | var num : int = 0; 45 | for (var i : int = 0; i < s.length; i++) { 46 | num = num * 10 + parseCharCode(s.charCodeAt(i) ); 47 | } 48 | return num; 49 | } 50 | 51 | private static function parseCharCode(c : int) : int { 52 | 53 | if (getCharCode('0') <= c && c <= getCharCode('9') ) { 54 | return c - getCharCode('0') ; 55 | } 56 | 57 | throw new Error("illegal char :" + c); 58 | } 59 | 60 | private static function getCharCode(c : String) : int { 61 | return c.charCodeAt(0); 62 | } 63 | 64 | } 65 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/QRUtil.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | import flash.utils.ByteArray; 4 | 5 | /** 6 | * QRUtil 7 | * @author Kazuhiko Arase 8 | */ 9 | internal class QRUtil { 10 | 11 | public static function getJISEncoding() : String { 12 | return "shift_jis"; 13 | } 14 | 15 | public static function getPatternPosition(typeNumber : int) : Array { 16 | return PATTERN_POSITION_TABLE[typeNumber - 1]; 17 | } 18 | 19 | private static var PATTERN_POSITION_TABLE : Array =[ 20 | [], 21 | [6, 18], 22 | [6, 22], 23 | [6, 26], 24 | [6, 30], 25 | [6, 34], 26 | [6, 22, 38], 27 | [6, 24, 42], 28 | [6, 26, 46], 29 | [6, 28, 50], 30 | [6, 30, 54], 31 | [6, 32, 58], 32 | [6, 34, 62], 33 | [6, 26, 46, 66], 34 | [6, 26, 48, 70], 35 | [6, 26, 50, 74], 36 | [6, 30, 54, 78], 37 | [6, 30, 56, 82], 38 | [6, 30, 58, 86], 39 | [6, 34, 62, 90], 40 | [6, 28, 50, 72, 94], 41 | [6, 26, 50, 74, 98], 42 | [6, 30, 54, 78, 102], 43 | [6, 28, 54, 80, 106], 44 | [6, 32, 58, 84, 110], 45 | [6, 30, 58, 86, 114], 46 | [6, 34, 62, 90, 118], 47 | [6, 26, 50, 74, 98, 122], 48 | [6, 30, 54, 78, 102, 126], 49 | [6, 26, 52, 78, 104, 130], 50 | [6, 30, 56, 82, 108, 134], 51 | [6, 34, 60, 86, 112, 138], 52 | [6, 30, 58, 86, 114, 142], 53 | [6, 34, 62, 90, 118, 146], 54 | [6, 30, 54, 78, 102, 126, 150], 55 | [6, 24, 50, 76, 102, 128, 154], 56 | [6, 28, 54, 80, 106, 132, 158], 57 | [6, 32, 58, 84, 110, 136, 162], 58 | [6, 26, 54, 82, 110, 138, 166], 59 | [6, 30, 58, 86, 114, 142, 170] 60 | ]; 61 | 62 | private static var MAX_LENGTH : Array = [ 63 | [ [41, 25, 17, 10], [34, 20, 14, 8], [27, 16, 11, 7], [17, 10, 7, 4] ], 64 | [ [77, 47, 32, 20], [63, 38, 26, 16], [48, 29, 20, 12], [34, 20, 14, 8] ], 65 | [ [127, 77, 53, 32], [101, 61, 42, 26], [77, 47, 32, 20], [58, 35, 24, 15] ], 66 | [ [187, 114, 78, 48], [149, 90, 62, 38], [111, 67, 46, 28], [82, 50, 34, 21] ], 67 | [ [255, 154, 106, 65], [202, 122, 84, 52], [144, 87, 60, 37], [106, 64, 44, 27] ], 68 | [ [322, 195, 134, 82], [255, 154, 106, 65], [178, 108, 74, 45], [139, 84, 58, 36] ], 69 | [ [370, 224, 154, 95], [293, 178, 122, 75], [207, 125, 86, 53], [154, 93, 64, 39] ], 70 | [ [461, 279, 192, 118], [365, 221, 152, 93], [259, 157, 108, 66], [202, 122, 84, 52] ], 71 | [ [552, 335, 230, 141], [432, 262, 180, 111], [312, 189, 130, 80], [235, 143, 98, 60] ], 72 | [ [652, 395, 271, 167], [513, 311, 213, 131], [364, 221, 151, 93], [288, 174, 119, 74] ] 73 | ]; 74 | 75 | public static function getMaxLength(typeNumber : int, mode : int, errorCorrectLevel : int) : int { 76 | 77 | var t : int = typeNumber - 1; 78 | var e : int = 0; 79 | var m : int = 0; 80 | 81 | switch(errorCorrectLevel) { 82 | case ErrorCorrectLevel.L : e = 0; break; 83 | case ErrorCorrectLevel.M : e = 1; break; 84 | case ErrorCorrectLevel.Q : e = 2; break; 85 | case ErrorCorrectLevel.H : e = 3; break; 86 | default : 87 | throw new Error("e:" + errorCorrectLevel); 88 | } 89 | 90 | switch(mode) { 91 | case Mode.MODE_NUMBER : m = 0; break; 92 | case Mode.MODE_ALPHA_NUM : m = 1; break; 93 | case Mode.MODE_8BIT_BYTE : m = 2; break; 94 | case Mode.MODE_KANJI : m = 3; break; 95 | default : 96 | throw new Error("m:" + mode); 97 | } 98 | 99 | return MAX_LENGTH[t][e][m]; 100 | } 101 | 102 | 103 | /** 104 | * エラー訂正多項式を取得する。 105 | */ 106 | public static function getErrorCorrectPolynomial(errorCorrectLength : int) : Polynomial{ 107 | 108 | var a : Polynomial = new Polynomial([1]); 109 | 110 | for (var i : int = 0; i < errorCorrectLength; i++) { 111 | a = a.multiply(new Polynomial([1, QRMath.gexp(i)]) ); 112 | } 113 | 114 | return a; 115 | } 116 | 117 | /** 118 | * 指定されたパターンのマスクを取得する。 119 | */ 120 | public static function getMask(maskPattern : int, i : int, j : int) : Boolean { 121 | 122 | switch (maskPattern) { 123 | 124 | case MaskPattern.PATTERN000 : return (i + j) % 2 == 0; 125 | case MaskPattern.PATTERN001 : return i % 2 == 0; 126 | case MaskPattern.PATTERN010 : return j % 3 == 0; 127 | case MaskPattern.PATTERN011 : return (i + j) % 3 == 0; 128 | case MaskPattern.PATTERN100 : return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; 129 | case MaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0; 130 | case MaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; 131 | case MaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; 132 | 133 | default : 134 | throw new Error("mask:" + maskPattern); 135 | } 136 | } 137 | 138 | /** 139 | * 失点を取得する 140 | */ 141 | public static function getLostPoint(qrCode : QRCode) : int { 142 | 143 | var moduleCount : int = qrCode.getModuleCount(); 144 | 145 | var lostPoint : int = 0; 146 | 147 | var row : int; 148 | var col : int; 149 | 150 | // LEVEL1 151 | 152 | for (row = 0; row < moduleCount; row++) { 153 | 154 | for (col = 0; col < moduleCount; col++) { 155 | 156 | var sameCount : int = 0; 157 | var dark : Boolean = qrCode.isDark(row, col); 158 | 159 | for (var r : int = -1; r <= 1; r++) { 160 | 161 | if (row + r < 0 || moduleCount <= row + r) { 162 | continue; 163 | } 164 | 165 | for (var c : int = -1; c <= 1; c++) { 166 | 167 | if (col + c < 0 || moduleCount <= col + c) { 168 | continue; 169 | } 170 | 171 | if (r == 0 && c == 0) { 172 | continue; 173 | } 174 | 175 | if (dark == qrCode.isDark(row + r, col + c) ) { 176 | sameCount++; 177 | } 178 | } 179 | } 180 | 181 | if (sameCount > 5) { 182 | lostPoint += (3 + sameCount - 5); 183 | } 184 | } 185 | } 186 | 187 | // LEVEL2 188 | 189 | for (row = 0; row < moduleCount - 1; row++) { 190 | for (col = 0; col < moduleCount - 1; col++) { 191 | var count : int = 0; 192 | if (qrCode.isDark(row, col ) ) count++; 193 | if (qrCode.isDark(row + 1, col ) ) count++; 194 | if (qrCode.isDark(row, col + 1) ) count++; 195 | if (qrCode.isDark(row + 1, col + 1) ) count++; 196 | if (count == 0 || count == 4) { 197 | lostPoint += 3; 198 | } 199 | } 200 | } 201 | 202 | // LEVEL3 203 | 204 | for (row = 0; row < moduleCount; row++) { 205 | for (col = 0; col < moduleCount - 6; col++) { 206 | if (qrCode.isDark(row, col) 207 | && !qrCode.isDark(row, col + 1) 208 | && qrCode.isDark(row, col + 2) 209 | && qrCode.isDark(row, col + 3) 210 | && qrCode.isDark(row, col + 4) 211 | && !qrCode.isDark(row, col + 5) 212 | && qrCode.isDark(row, col + 6) ) { 213 | lostPoint += 40; 214 | } 215 | } 216 | } 217 | 218 | for (col = 0; col < moduleCount; col++) { 219 | for (row = 0; row < moduleCount - 6; row++) { 220 | if (qrCode.isDark(row, col) 221 | && !qrCode.isDark(row + 1, col) 222 | && qrCode.isDark(row + 2, col) 223 | && qrCode.isDark(row + 3, col) 224 | && qrCode.isDark(row + 4, col) 225 | && !qrCode.isDark(row + 5, col) 226 | && qrCode.isDark(row + 6, col) ) { 227 | lostPoint += 40; 228 | } 229 | } 230 | } 231 | 232 | // LEVEL4 233 | 234 | var darkCount : int = 0; 235 | 236 | for (col = 0; col < moduleCount; col++) { 237 | for (row = 0; row < moduleCount; row++) { 238 | if (qrCode.isDark(row, col) ) { 239 | darkCount++; 240 | } 241 | } 242 | } 243 | 244 | var ratio : int = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; 245 | lostPoint += ratio * 10; 246 | 247 | return lostPoint; 248 | } 249 | 250 | public static function getMode(s : String) : int { 251 | if (isAlphaNum(s) ) { 252 | if (isNumber(s) ) { 253 | return Mode.MODE_NUMBER; 254 | } 255 | return Mode.MODE_ALPHA_NUM; 256 | } else if (isKanji(s) ) { 257 | return Mode.MODE_KANJI; 258 | } else { 259 | return Mode.MODE_8BIT_BYTE; 260 | } 261 | } 262 | 263 | private static function isNumber(s : String) : Boolean { 264 | for (var i : int = 0; i < s.length; i++) { 265 | var c : String = s.charAt(i); 266 | if (!('0' <= c && c <= '9') ) { 267 | return false; 268 | } 269 | } 270 | return true; 271 | } 272 | 273 | private static function isAlphaNum(s : String) : Boolean { 274 | for (var i : int = 0; i < s.length; i++) { 275 | var c : String = s.charAt(i); 276 | if (!('0' <= c && c <= '9') && !('A' <= c && c <= 'Z') && " $%*+-./:".indexOf(c) == -1) { 277 | return false; 278 | } 279 | } 280 | return true; 281 | } 282 | 283 | private static function isKanji(s : String) : Boolean { 284 | 285 | var data : ByteArray = StringUtil.getBytes(s, QRUtil.getJISEncoding() ); 286 | 287 | var i : int = 0; 288 | 289 | while (i + 1 < data.length) { 290 | 291 | var c : int = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]); 292 | 293 | if (!(0x8140 <= c && c <= 0x9FFC) && !(0xE040 <= c && c <= 0xEBBF) ) { 294 | return false; 295 | } 296 | 297 | i += 2; 298 | } 299 | 300 | if (i < data.length) { 301 | return false; 302 | } 303 | 304 | return true; 305 | } 306 | 307 | private static const G15 : int = (1 << 10) | (1 << 8) | (1 << 5) 308 | | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); 309 | 310 | private static const G18 : int = (1 << 12) | (1 << 11) | (1 << 10) 311 | | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); 312 | 313 | private static const G15_MASK : int = (1 << 14) | (1 << 12) | (1 << 10) 314 | | (1 << 4) | (1 << 1); 315 | 316 | public static function getBCHTypeInfo(data : int) : int { 317 | var d : int = data << 10; 318 | while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { 319 | d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); 320 | } 321 | return ( (data << 10) | d) ^ G15_MASK; 322 | } 323 | 324 | public static function getBCHTypeNumber(data : int) : int { 325 | var d : int = data << 12; 326 | while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { 327 | d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); 328 | } 329 | return (data << 12) | d; 330 | } 331 | 332 | private static function getBCHDigit(data : int) : int { 333 | 334 | var digit : int = 0; 335 | 336 | while (data != 0) { 337 | digit++; 338 | data >>>= 1; 339 | } 340 | 341 | return digit; 342 | 343 | } 344 | } 345 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/RSBlock.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | /** 4 | * RSBlock 5 | * @author Kazuhiko Arase 6 | */ 7 | internal class RSBlock { 8 | 9 | private static var RS_BLOCK_TABLE : Array = [ 10 | 11 | // L 12 | // M 13 | // Q 14 | // H 15 | 16 | // 1 17 | [1, 26, 19], 18 | [1, 26, 16], 19 | [1, 26, 13], 20 | [1, 26, 9], 21 | 22 | // 2 23 | [1, 44, 34], 24 | [1, 44, 28], 25 | [1, 44, 22], 26 | [1, 44, 16], 27 | 28 | // 3 29 | [1, 70, 55], 30 | [1, 70, 44], 31 | [2, 35, 17], 32 | [2, 35, 13], 33 | 34 | // 4 35 | [1, 100, 80], 36 | [2, 50, 32], 37 | [2, 50, 24], 38 | [4, 25, 9], 39 | 40 | // 5 41 | [1, 134, 108], 42 | [2, 67, 43], 43 | [2, 33, 15, 2, 34, 16], 44 | [2, 33, 11, 2, 34, 12], 45 | 46 | // 6 47 | [2, 86, 68], 48 | [4, 43, 27], 49 | [4, 43, 19], 50 | [4, 43, 15], 51 | 52 | // 7 53 | [2, 98, 78], 54 | [4, 49, 31], 55 | [2, 32, 14, 4, 33, 15], 56 | [4, 39, 13, 1, 40, 14], 57 | 58 | // 8 59 | [2, 121, 97], 60 | [2, 60, 38, 2, 61, 39], 61 | [4, 40, 18, 2, 41, 19], 62 | [4, 40, 14, 2, 41, 15], 63 | 64 | // 9 65 | [2, 146, 116], 66 | [3, 58, 36, 2, 59, 37], 67 | [4, 36, 16, 4, 37, 17], 68 | [4, 36, 12, 4, 37, 13], 69 | 70 | // 10 71 | [2, 86, 68, 2, 87, 69], 72 | [4, 69, 43, 1, 70, 44], 73 | [6, 43, 19, 2, 44, 20], 74 | [6, 43, 15, 2, 44, 16] 75 | 76 | ]; 77 | 78 | private var totalCount : int; 79 | private var dataCount : int; 80 | 81 | public function RSBlock(totalCount : int, dataCount : int) { 82 | this.totalCount = totalCount; 83 | this.dataCount = dataCount; 84 | } 85 | 86 | public function getDataCount() : int { 87 | return dataCount; 88 | } 89 | 90 | public function getTotalCount() : int { 91 | return totalCount; 92 | } 93 | 94 | public static function getRSBlocks(typeNumber : int, errorCorrectLevel : int) : Array { 95 | 96 | var rsBlock : Array = getRsBlockTable(typeNumber, errorCorrectLevel); 97 | var length : int = Math.floor(rsBlock.length / 3); 98 | var list : Array = new Array(); 99 | 100 | for (var i : int = 0; i < length; i++) { 101 | 102 | var count : int = rsBlock[i * 3 + 0]; 103 | var totalCount : int = rsBlock[i * 3 + 1]; 104 | var dataCount : int = rsBlock[i * 3 + 2]; 105 | 106 | for (var j : int = 0; j < count; j++) { 107 | list.push(new RSBlock(totalCount, dataCount) ); 108 | } 109 | } 110 | 111 | return list; 112 | } 113 | 114 | private static function getRsBlockTable(typeNumber : int, errorCorrectLevel : int) : Array { 115 | 116 | try { 117 | 118 | switch(errorCorrectLevel) { 119 | case ErrorCorrectLevel.L : 120 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; 121 | case ErrorCorrectLevel.M : 122 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; 123 | case ErrorCorrectLevel.Q : 124 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; 125 | case ErrorCorrectLevel.H : 126 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; 127 | default : 128 | break; 129 | } 130 | 131 | } catch(e : Error) { 132 | } 133 | 134 | throw new Error("tn:" + typeNumber + "/ecl:" + errorCorrectLevel); 135 | } 136 | 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/StringUtil.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode { 2 | 3 | import flash.utils.ByteArray; 4 | 5 | /** 6 | * StringUtil 7 | * @author Kazuhiko Arase 8 | */ 9 | internal class StringUtil { 10 | 11 | public static function getBytes(s : String, encoding : String) : ByteArray { 12 | var b : ByteArray = new ByteArray(); 13 | b.writeMultiByte(s, encoding); 14 | return b; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /as3/src/as3/com/d_project/qrcode/mx/QRCode.as: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode.mx { 2 | 3 | import mx.core.UIComponent; 4 | import flash.display.Graphics; 5 | 6 | import com.d_project.qrcode.ErrorCorrectLevel; 7 | 8 | 9 | /** 10 | * QRコード. 11 | * @author Kazuhiko Arase 12 | */ 13 | public class QRCode extends UIComponent { 14 | 15 | private var qr : com.d_project.qrcode.QRCode; 16 | 17 | private var _text : String; 18 | 19 | [Inspectable(enumeration="L,M,Q,H", defaultValue="H")] 20 | public var errorCorrectLevel : String = "H"; 21 | 22 | public function QRCode() { 23 | _text = "QRCode"; 24 | qr = null; 25 | } 26 | 27 | public function get text() : String { 28 | return _text; 29 | } 30 | 31 | public function set text(value : String) : void { 32 | _text = value; 33 | qr = null; 34 | invalidateDisplayList(); 35 | } 36 | 37 | protected override function updateDisplayList(unscaledWidth : Number, unscaledHeight : Number) : void { 38 | 39 | var padding : Number = 10; 40 | 41 | var size : Number = Math.min(unscaledWidth, unscaledHeight) - padding * 2; 42 | var xOffset : Number = (unscaledWidth - size) / 2; 43 | var yOffset : Number = (unscaledHeight - size) / 2; 44 | 45 | if (qr == null) { 46 | qr = com.d_project.qrcode.QRCode.getMinimumQRCode(text, ErrorCorrectLevel[errorCorrectLevel]); 47 | } 48 | 49 | var cs : Number = size / qr.getModuleCount(); 50 | 51 | var g : Graphics = graphics; 52 | 53 | g.beginFill(0xffffff); 54 | g.drawRect(0, 0, unscaledWidth, unscaledHeight); 55 | g.endFill(); 56 | 57 | for (var row : int = 0; row < qr.getModuleCount(); row++) { 58 | for (var col : int = 0; col < qr.getModuleCount(); col++) { 59 | g.beginFill( (qr.isDark(row, col)? 0 : 0xffffff) ); 60 | g.drawRect(cs * col + xOffset, cs * row + yOffset, cs, cs); 61 | g.endFill(); 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /as3/src/assets/README.txt: -------------------------------------------------------------------------------- 1 | QRCode for ActionScript3 2 | 3 | Copyright (c) 2009 Kazuhiko Arase 4 | 5 | URL: http://www.d-project.com/ 6 | 7 | Licensed under the MIT license: 8 | http://www.opensource.org/licenses/mit-license.php 9 | 10 | The word "QR Code" is registered trademark of 11 | DENSO WAVE INCORPORATED 12 | http://www.denso-wave.com/qrcode/faqpatent-e.html 13 | 14 | 15 | -- REQUIREMENTS 16 | 17 | FlashPlayer 9.0.28 or above 18 | 19 | -- CONTENTS 20 | 21 | README.txt - this file 22 | qrcode.swc - library 23 | sample - sample 24 | apidocs - API document 25 | -------------------------------------------------------------------------------- /as3/src/assets/manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /as3/src/build.xml: -------------------------------------------------------------------------------- 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 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 101 | 102 | 103 | 104 | #ffffff 105 | 106 | true 107 | 108 | 109 | 114 | 115 | 116 | 117 | #ffffff 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /as3/src/sample/QRCodeSample1.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import com.d_project.qrcode.ErrorCorrectLevel; 4 | import com.d_project.qrcode.QRCode; 5 | 6 | import flash.display.Graphics; 7 | import flash.display.Sprite; 8 | 9 | public class QRCodeSample1 extends Sprite { 10 | 11 | public function QRCodeSample1() { 12 | 13 | var width : Number = 200; 14 | var height : Number = 200; 15 | var padding : Number = 10; 16 | 17 | var size : Number = Math.min(width, height) - padding * 2; 18 | var xOffset : Number = (width - size) / 2; 19 | var yOffset : Number = (height - size) / 2; 20 | 21 | var qr : QRCode = QRCode.getMinimumQRCode("AS3ならば、文字コードの扱いも簡単!", ErrorCorrectLevel.H); 22 | 23 | var cs : Number = size / qr.getModuleCount(); 24 | 25 | var g : Graphics = graphics; 26 | 27 | for (var row : int = 0; row < qr.getModuleCount(); row++) { 28 | for (var col : int = 0; col < qr.getModuleCount(); col++) { 29 | g.beginFill( (qr.isDark(row, col)? 0 : 0xffffff) ); 30 | g.drawRect(cs * col + xOffset, cs * row + yOffset, cs, cs); 31 | g.endFill(); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /as3/src/sample/QRCodeSample2.mxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /hack/.gitignore: -------------------------------------------------------------------------------- 1 | vendor/** 2 | **/*hhast.parser-cache 3 | .var/ 4 | -------------------------------------------------------------------------------- /hack/.hhconfig: -------------------------------------------------------------------------------- 1 | ignored_paths = [ "vendor/.+/tests/.+", "vendor/.+/bin/.+"] 2 | hackfmt.line_width = 80 3 | hackfmt.indent_width = 4 4 | allowed_decl_fixme_codes = 2053, 4047 5 | allowed_fixme_codes_strict = 2049, 2053, 4027, 4047, 4104, 4107, 4110, 4128, 4188, 4323 6 | -------------------------------------------------------------------------------- /hack/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kazuhikoarase/qrcode-generator", 3 | "description": "A Hack port of the PHP 5 program Kazuhikoarase\\QrcodeGenerator", 4 | "require": { 5 | "hhvm": "^4.32" 6 | }, 7 | "require-dev": { 8 | "hhvm/hhvm-autoload": "^2.0|^3.0", 9 | "hhvm/hhast": "^4.41" 10 | } 11 | } -------------------------------------------------------------------------------- /hack/hh_autoload.json: -------------------------------------------------------------------------------- 1 | { 2 | "roots": [ 3 | "src/" 4 | ], 5 | "devRoots": [ 6 | "samples/" 7 | ], 8 | "devFailureHandler": "Facebook\\AutoloadMap\\HHClientFallbackHandler" 9 | } -------------------------------------------------------------------------------- /hack/hhast-lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "roots": [ 3 | "src/" 4 | ], 5 | "builtinLinters": "all", 6 | } -------------------------------------------------------------------------------- /hack/hhast_lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "roots": ["src"], 3 | "builtinLinters": "all" 4 | } 5 | -------------------------------------------------------------------------------- /hack/samples/sample.html: -------------------------------------------------------------------------------- 1 | sample_html.php 2 |
3 | sample_image.php 4 |
5 | sample_custom.php 6 | -------------------------------------------------------------------------------- /hack/samples/sample_custom.php: -------------------------------------------------------------------------------- 1 | > 6 | function sample_custom(): noreturn { 7 | require_once __DIR__.'/../vendor/autoload.hack'; 8 | \Facebook\AutoloadMap\initialize(); 9 | $qr = QrcodeGenerator\QRCode::getMinimumQRCode( 10 | "日本語のQR 1234:! 漢字", 11 | QrcodeGenerator\ErrorCorrectionPercentage::SEVEN, 12 | ); 13 | 14 | header("Content-type: text/xml"); 15 | 16 | print(""); 17 | 18 | for ($r = 0; $r < $qr->getModuleCount(); $r++) { 19 | print(""); 20 | for ($c = 0; $c < $qr->getModuleCount(); $c++) { 21 | print($qr->isDark($r, $c) ? "1" : "0"); 22 | } 23 | print(""); 24 | } 25 | 26 | print(""); 27 | 28 | exit(0); 29 | } 30 | -------------------------------------------------------------------------------- /hack/samples/sample_html.php: -------------------------------------------------------------------------------- 1 | > 6 | function sample_html(): noreturn { 7 | require_once __DIR__.'/../vendor/autoload.hack'; 8 | \Facebook\AutoloadMap\initialize(); 9 | //--------------------------------------------------------- 10 | 11 | print(''); 12 | 13 | // QR in Japanese 1234:! Kanji 14 | print("

日本語のQR 1234:! 漢字

"); 15 | 16 | $qr = new QrcodeGenerator\QRCode(); 17 | // QR_ERROR_CORRECT_LEVEL_L : 7% 18 | // QR_ERROR_CORRECT_LEVEL_M : 15% 19 | // QR_ERROR_CORRECT_LEVEL_Q : 25% 20 | // QR_ERROR_CORRECT_LEVEL_H : 30% 21 | $qr->setErrorCorrectLevel(QrcodeGenerator\ErrorCorrectionPercentage::SEVEN); 22 | $qr->setTypeNumber(4); 23 | $qr->addData("日本語のQR 1234:! 漢字"); 24 | $qr->make(); 25 | $qr->printHTML(); 26 | 27 | //--------------------------------------------------------- 28 | 29 | // QR quick 1234:! 30 | print("

QRクイック 1234:!

"); 31 | 32 | $qr = QrcodeGenerator\QRCode::getMinimumQRCode( 33 | "QRクイック", 34 | QrcodeGenerator\ErrorCorrectionPercentage::SEVEN, 35 | ); 36 | $qr->printHTML(); 37 | 38 | exit(0); 39 | } 40 | -------------------------------------------------------------------------------- /hack/samples/sample_image.php: -------------------------------------------------------------------------------- 1 | > 7 | function sample_image(): noreturn { 8 | require_once __DIR__.'/../vendor/autoload.hack'; 9 | \Facebook\AutoloadMap\initialize(); 10 | $qr = QrcodeGenerator\QRCode::getMinimumQRCode( 11 | "日本語のQR 1234:! 漢字", 12 | QrcodeGenerator\ErrorCorrectionPercentage::SEVEN, 13 | ); 14 | 15 | $im = $qr->createImage(2, 4); 16 | 17 | header("Content-type: image/gif"); 18 | imagegif($im); 19 | 20 | imagedestroy($im); 21 | 22 | exit(0); 23 | } 24 | -------------------------------------------------------------------------------- /hack/unit_test.diffme.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kazuhikoarase/qrcode-generator/0e51e6310a34b5e4f70280533b3d43e1fc6a0b16/hack/unit_test.diffme.gif -------------------------------------------------------------------------------- /java/.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle 2 | /.settings 3 | /.classpath 4 | /.project 5 | /bin 6 | /build 7 | /gradle.properties 8 | -------------------------------------------------------------------------------- /java/README.txt: -------------------------------------------------------------------------------- 1 | QRCode for Java 2 | 3 | Copyright (c) 2009 Kazuhiko Arase 4 | 5 | URL: http://www.d-project.com/ 6 | 7 | Licensed under the MIT license: 8 | http://www.opensource.org/licenses/mit-license.php 9 | 10 | The word "QR Code" is registered trademark of 11 | DENSO WAVE INCORPORATED 12 | http://www.denso-wave.com/qrcode/faqpatent-e.html 13 | 14 | 15 | -- REQUIREMENTS 16 | 17 | Java Runtime Environment (JRE) 1.6 or above 18 | 19 | -- CONTENTS 20 | 21 | README.txt - this file 22 | qrcode.jar - library 23 | sample 24 | /QRCodeSample.war - sample web application 25 | apidocs - API document 26 | -------------------------------------------------------------------------------- /java/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'java' 3 | 4 | sourceCompatibility = 1.6 5 | 6 | compileJava.options.encoding = 'UTF-8' 7 | compileTestJava.options.encoding = 'UTF-8' 8 | 9 | jar { 10 | baseName "qrcode" 11 | } 12 | 13 | task all { 14 | dependsOn 'clean' 15 | dependsOn 'jar' 16 | } 17 | 18 | /* 19 | uploadArchives { 20 | repositories { 21 | flatDir { 22 | dirs 'repos' 23 | } 24 | } 25 | } 26 | */ 27 | 28 | repositories { 29 | mavenCentral() 30 | } 31 | 32 | dependencies { 33 | implementation 'javax.servlet:javax.servlet-api:3.0.1' 34 | testImplementation 'junit:junit:4.12' 35 | } 36 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/BitBuffer.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * BitBuffer 5 | * @author Kazuhiko Arase 6 | */ 7 | class BitBuffer { 8 | 9 | private byte[] buffer; 10 | private int length; 11 | private int inclements; 12 | 13 | public BitBuffer() { 14 | inclements = 32; 15 | buffer = new byte[inclements]; 16 | length = 0; 17 | } 18 | 19 | public byte[] getBuffer() { 20 | return buffer; 21 | } 22 | 23 | public int getLengthInBits() { 24 | return length; 25 | } 26 | 27 | public String toString() { 28 | StringBuilder buffer = new StringBuilder(); 29 | for (int i = 0; i < getLengthInBits(); i++) { 30 | buffer.append(get(i)? '1' : '0'); 31 | } 32 | return buffer.toString(); 33 | } 34 | 35 | private boolean get(int index) { 36 | return ( (buffer[index / 8] >>> (7 - index % 8) ) & 1) == 1; 37 | } 38 | 39 | public void put(int num, int length) { 40 | for (int i = 0; i < length; i++) { 41 | put( ( (num >>> (length - i - 1) ) & 1) == 1); 42 | } 43 | } 44 | 45 | public void put(boolean bit) { 46 | 47 | if (length == buffer.length * 8) { 48 | byte[] newBuffer = new byte[buffer.length + inclements]; 49 | System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); 50 | buffer = newBuffer; 51 | } 52 | 53 | if (bit) { 54 | buffer[length / 8] |= (0x80 >>> (length % 8) ); 55 | } 56 | 57 | length++; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/ErrorCorrectionLevel.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * 誤り訂正レベル. 5 | * @author Kazuhiko Arase 6 | */ 7 | public interface ErrorCorrectionLevel { 8 | 9 | /** 10 | * 復元能力 7%. 11 | */ 12 | int L = 1; 13 | 14 | /** 15 | * 復元能力 15%. 16 | */ 17 | int M = 0; 18 | 19 | /** 20 | * 復元能力 25%. 21 | */ 22 | int Q = 3; 23 | 24 | /** 25 | * 復元能力 30%. 26 | */ 27 | int H = 2; 28 | } 29 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/MaskPattern.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * マスクパターン. 5 | * @author Kazuhiko Arase 6 | */ 7 | interface MaskPattern { 8 | 9 | /** 10 | * マスクパターン000 11 | */ 12 | int PATTERN000 = 0; 13 | 14 | /** 15 | * マスクパターン001 16 | */ 17 | int PATTERN001 = 1; 18 | 19 | /** 20 | * マスクパターン010 21 | */ 22 | int PATTERN010 = 2; 23 | 24 | /** 25 | * マスクパターン011 26 | */ 27 | int PATTERN011 = 3; 28 | 29 | /** 30 | * マスクパターン100 31 | */ 32 | int PATTERN100 = 4; 33 | 34 | /** 35 | * マスクパターン101 36 | */ 37 | int PATTERN101 = 5; 38 | 39 | /** 40 | * マスクパターン110 41 | */ 42 | int PATTERN110 = 6; 43 | 44 | /** 45 | * マスクパターン111 46 | */ 47 | int PATTERN111 = 7; 48 | } 49 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/Mode.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * モード. 5 | * @author Kazuhiko Arase 6 | */ 7 | public interface Mode { 8 | 9 | /** 10 | * 数値モード 11 | */ 12 | int MODE_NUMBER = 1 << 0; 13 | 14 | /** 15 | * 英数字モード 16 | */ 17 | int MODE_ALPHA_NUM = 1 << 1; 18 | 19 | /** 20 | * 8ビットバイトモード 21 | */ 22 | int MODE_8BIT_BYTE = 1 << 2; 23 | 24 | /** 25 | * 漢字モード 26 | */ 27 | int MODE_KANJI = 1 << 3; 28 | } 29 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/Polynomial.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * Polynomial 5 | * @author Kazuhiko Arase 6 | */ 7 | class Polynomial { 8 | 9 | private final int[] num; 10 | 11 | public Polynomial(int[] num) { 12 | this(num, 0); 13 | } 14 | 15 | public Polynomial(int[] num, int shift) { 16 | 17 | int offset = 0; 18 | 19 | while (offset < num.length && num[offset] == 0) { 20 | offset++; 21 | } 22 | 23 | this.num = new int[num.length - offset + shift]; 24 | System.arraycopy(num, offset, this.num, 0, num.length - offset); 25 | } 26 | 27 | public int get(int index) { 28 | return num[index]; 29 | } 30 | 31 | public int getLength() { 32 | return num.length; 33 | } 34 | 35 | public String toString() { 36 | 37 | StringBuilder buffer = new StringBuilder(); 38 | 39 | for (int i = 0; i < getLength(); i++) { 40 | if (i > 0) { 41 | buffer.append(","); 42 | } 43 | buffer.append(get(i) ); 44 | } 45 | 46 | return buffer.toString(); 47 | } 48 | 49 | public String toLogString() { 50 | 51 | StringBuilder buffer = new StringBuilder(); 52 | 53 | for (int i = 0; i < getLength(); i++) { 54 | if (i > 0) { 55 | buffer.append(","); 56 | } 57 | buffer.append(QRMath.glog(get(i) ) ); 58 | 59 | } 60 | 61 | return buffer.toString(); 62 | } 63 | 64 | public Polynomial multiply(Polynomial e) { 65 | 66 | int[] num = new int[getLength() + e.getLength() - 1]; 67 | 68 | for (int i = 0; i < getLength(); i++) { 69 | for (int j = 0; j < e.getLength(); j++) { 70 | num[i + j] ^= QRMath.gexp(QRMath.glog(get(i) ) + QRMath.glog(e.get(j) ) ); 71 | } 72 | } 73 | 74 | return new Polynomial(num); 75 | } 76 | 77 | public Polynomial mod(Polynomial e) { 78 | 79 | if (getLength() - e.getLength() < 0) { 80 | return this; 81 | } 82 | 83 | // 最上位桁の比率 84 | int ratio = QRMath.glog(get(0) ) - QRMath.glog(e.get(0) ); 85 | 86 | // コピー作成 87 | int[] num = new int[getLength()]; 88 | for (int i = 0; i < getLength(); i++) { 89 | num[i] = get(i); 90 | } 91 | 92 | // 引き算して余りを計算 93 | for (int i = 0; i < e.getLength(); i++) { 94 | num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio); 95 | } 96 | 97 | // 再帰計算 98 | return new Polynomial(num).mod(e); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/QR8BitByte.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | /** 6 | * QR8BitByte 7 | * @author Kazuhiko Arase 8 | */ 9 | class QR8BitByte extends QRData { 10 | 11 | public QR8BitByte(String data) { 12 | super(Mode.MODE_8BIT_BYTE, data); 13 | } 14 | 15 | public void write(BitBuffer buffer) { 16 | 17 | try { 18 | 19 | byte[] data = getData().getBytes(QRCode.get8BitByteEncoding() ); 20 | 21 | for (int i = 0; i < data.length; i++) { 22 | buffer.put(data[i], 8); 23 | } 24 | 25 | } catch(UnsupportedEncodingException e) { 26 | throw new RuntimeException(e.getMessage() ); 27 | } 28 | } 29 | 30 | public int getLength() { 31 | try { 32 | return getData().getBytes(QRCode.get8BitByteEncoding() ).length; 33 | } catch(UnsupportedEncodingException e) { 34 | throw new RuntimeException(e.getMessage() ); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/QRAlphaNum.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * QRAlphaNum 5 | * @author Kazuhiko Arase 6 | */ 7 | class QRAlphaNum extends QRData { 8 | 9 | public QRAlphaNum(String data) { 10 | super(Mode.MODE_ALPHA_NUM, data); 11 | } 12 | 13 | public void write(BitBuffer buffer) { 14 | 15 | char[] c = getData().toCharArray(); 16 | 17 | int i = 0; 18 | 19 | while (i + 1 < c.length) { 20 | buffer.put(getCode(c[i]) * 45 + getCode(c[i + 1]), 11); 21 | i += 2; 22 | } 23 | 24 | if (i < c.length) { 25 | buffer.put(getCode(c[i]), 6); 26 | } 27 | } 28 | 29 | public int getLength() { 30 | return getData().length(); 31 | } 32 | 33 | private static int getCode(char c) { 34 | 35 | if ('0' <= c && c <= '9') { 36 | return c - '0'; 37 | } else if ('A' <= c && c <= 'Z') { 38 | return c - 'A' + 10; 39 | } else { 40 | switch (c) { 41 | case ' ' : return 36; 42 | case '$' : return 37; 43 | case '%' : return 38; 44 | case '*' : return 39; 45 | case '+' : return 40; 46 | case '-' : return 41; 47 | case '.' : return 42; 48 | case '/' : return 43; 49 | case ':' : return 44; 50 | default : 51 | throw new IllegalArgumentException("illegal char :" + c); 52 | } 53 | } 54 | 55 | } 56 | } -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/QRData.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * QRData 5 | * @author Kazuhiko Arase 6 | */ 7 | abstract class QRData { 8 | 9 | private final int mode; 10 | 11 | private final String data; 12 | 13 | protected QRData(int mode, String data) { 14 | this.mode = mode; 15 | this.data = data; 16 | } 17 | 18 | public int getMode() { 19 | return mode; 20 | } 21 | 22 | public String getData() { 23 | return data; 24 | } 25 | 26 | public abstract int getLength(); 27 | 28 | public abstract void write(BitBuffer buffer); 29 | 30 | /** 31 | * 型番及びモードに対するビット長を取得する。 32 | */ 33 | public int getLengthInBits(int type) { 34 | 35 | if (1 <= type && type < 10) { 36 | 37 | // 1 - 9 38 | 39 | switch(mode) { 40 | case Mode.MODE_NUMBER : return 10; 41 | case Mode.MODE_ALPHA_NUM : return 9; 42 | case Mode.MODE_8BIT_BYTE : return 8; 43 | case Mode.MODE_KANJI : return 8; 44 | default : 45 | throw new IllegalArgumentException("mode:" + mode); 46 | } 47 | 48 | } else if (type < 27) { 49 | 50 | // 10 - 26 51 | 52 | switch(mode) { 53 | case Mode.MODE_NUMBER : return 12; 54 | case Mode.MODE_ALPHA_NUM : return 11; 55 | case Mode.MODE_8BIT_BYTE : return 16; 56 | case Mode.MODE_KANJI : return 10; 57 | default : 58 | throw new IllegalArgumentException("mode:" + mode); 59 | } 60 | 61 | } else if (type < 41) { 62 | 63 | // 27 - 40 64 | 65 | switch(mode) { 66 | case Mode.MODE_NUMBER : return 14; 67 | case Mode.MODE_ALPHA_NUM : return 13; 68 | case Mode.MODE_8BIT_BYTE : return 16; 69 | case Mode.MODE_KANJI : return 12; 70 | default : 71 | throw new IllegalArgumentException("mode:" + mode); 72 | } 73 | 74 | } else { 75 | throw new IllegalArgumentException("type:" + type); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/QRKanji.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | /** 6 | * QRKanji 7 | * @author Kazuhiko Arase 8 | */ 9 | class QRKanji extends QRData { 10 | 11 | public QRKanji(String data) { 12 | super(Mode.MODE_KANJI, data); 13 | } 14 | 15 | public void write(BitBuffer buffer) { 16 | 17 | try { 18 | 19 | byte[] data = getData().getBytes(QRUtil.getJISEncoding() ); 20 | 21 | int i = 0; 22 | 23 | while (i + 1 < data.length) { 24 | 25 | int c = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]); 26 | 27 | if (0x8140 <= c && c <= 0x9FFC) { 28 | c -= 0x8140; 29 | } else if (0xE040 <= c && c <= 0xEBBF) { 30 | c -= 0xC140; 31 | } else { 32 | throw new IllegalArgumentException("illegal char at " + (i + 1) + "/" + Integer.toHexString(c) ); 33 | } 34 | 35 | c = ( (c >>> 8) & 0xff) * 0xC0 + (c & 0xff); 36 | 37 | buffer.put(c, 13); 38 | 39 | i += 2; 40 | } 41 | 42 | if (i < data.length) { 43 | throw new IllegalArgumentException("illegal char at " + (i + 1) ); 44 | } 45 | 46 | } catch(UnsupportedEncodingException e) { 47 | throw new RuntimeException(e.getMessage() ); 48 | } 49 | } 50 | 51 | public int getLength() { 52 | try { 53 | return getData().getBytes(QRUtil.getJISEncoding() ).length / 2; 54 | } catch(UnsupportedEncodingException e) { 55 | throw new RuntimeException(e.getMessage() ); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/QRMath.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * QRMath 5 | * @author Kazuhiko Arase 6 | */ 7 | class QRMath { 8 | 9 | private QRMath() { 10 | } 11 | 12 | private static final int[] EXP_TABLE; 13 | private static final int[] LOG_TABLE; 14 | 15 | static { 16 | 17 | EXP_TABLE = new int[256]; 18 | 19 | for (int i = 0; i < 8; i++) { 20 | EXP_TABLE[i] = 1 << i; 21 | } 22 | 23 | for (int i = 8; i < 256; i++) { 24 | EXP_TABLE[i] = EXP_TABLE[i - 4] 25 | ^ EXP_TABLE[i - 5] 26 | ^ EXP_TABLE[i - 6] 27 | ^ EXP_TABLE[i - 8]; 28 | } 29 | 30 | LOG_TABLE = new int[256]; 31 | for (int i = 0; i < 255; i++) { 32 | LOG_TABLE[EXP_TABLE[i] ] = i; 33 | } 34 | } 35 | 36 | public static int glog(int n) { 37 | 38 | if (n < 1) { 39 | throw new ArithmeticException("log(" + n + ")"); 40 | } 41 | 42 | return LOG_TABLE[n]; 43 | } 44 | 45 | public static int gexp(int n) { 46 | 47 | while (n < 0) { 48 | n += 255; 49 | } 50 | 51 | while (n >= 256) { 52 | n -= 255; 53 | } 54 | 55 | return EXP_TABLE[n]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/QRNumber.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | /** 4 | * QRNumber 5 | * @author Kazuhiko Arase 6 | */ 7 | class QRNumber extends QRData { 8 | 9 | public QRNumber(String data) { 10 | super(Mode.MODE_NUMBER, data); 11 | } 12 | 13 | public void write(BitBuffer buffer) { 14 | 15 | String data = getData(); 16 | 17 | int i = 0; 18 | 19 | while (i + 2 < data.length() ) { 20 | int num = parseInt(data.substring(i, i + 3) ); 21 | buffer.put(num, 10); 22 | i += 3; 23 | } 24 | 25 | if (i < data.length() ) { 26 | if (data.length() - i == 1) { 27 | int num = parseInt(data.substring(i, i + 1) ); 28 | buffer.put(num, 4); 29 | } else if (data.length() - i == 2) { 30 | int num = parseInt(data.substring(i, i + 2) ); 31 | buffer.put(num, 7); 32 | } 33 | } 34 | } 35 | 36 | public int getLength() { 37 | return getData().length(); 38 | } 39 | 40 | private static int parseInt(String s) { 41 | int num = 0; 42 | for (int i = 0; i < s.length(); i++) { 43 | num = num * 10 + parseInt(s.charAt(i) ); 44 | } 45 | return num; 46 | } 47 | 48 | private static int parseInt(char c) { 49 | if ('0' <= c && c <= '9') { 50 | return c - '0'; 51 | } 52 | throw new IllegalArgumentException("illegal char :" + c); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/QRUtil.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | /** 6 | * QRUtil 7 | * @author Kazuhiko Arase 8 | */ 9 | class QRUtil { 10 | 11 | private QRUtil() { 12 | } 13 | 14 | public static String getJISEncoding() { 15 | return "SJIS"; 16 | } 17 | 18 | public static int[] getPatternPosition(int typeNumber) { 19 | return PATTERN_POSITION_TABLE[typeNumber - 1]; 20 | } 21 | 22 | private static final int[][] PATTERN_POSITION_TABLE ={ 23 | {}, 24 | {6, 18}, 25 | {6, 22}, 26 | {6, 26}, 27 | {6, 30}, 28 | {6, 34}, 29 | {6, 22, 38}, 30 | {6, 24, 42}, 31 | {6, 26, 46}, 32 | {6, 28, 50}, 33 | {6, 30, 54}, 34 | {6, 32, 58}, 35 | {6, 34, 62}, 36 | {6, 26, 46, 66}, 37 | {6, 26, 48, 70}, 38 | {6, 26, 50, 74}, 39 | {6, 30, 54, 78}, 40 | {6, 30, 56, 82}, 41 | {6, 30, 58, 86}, 42 | {6, 34, 62, 90}, 43 | {6, 28, 50, 72, 94}, 44 | {6, 26, 50, 74, 98}, 45 | {6, 30, 54, 78, 102}, 46 | {6, 28, 54, 80, 106}, 47 | {6, 32, 58, 84, 110}, 48 | {6, 30, 58, 86, 114}, 49 | {6, 34, 62, 90, 118}, 50 | {6, 26, 50, 74, 98, 122}, 51 | {6, 30, 54, 78, 102, 126}, 52 | {6, 26, 52, 78, 104, 130}, 53 | {6, 30, 56, 82, 108, 134}, 54 | {6, 34, 60, 86, 112, 138}, 55 | {6, 30, 58, 86, 114, 142}, 56 | {6, 34, 62, 90, 118, 146}, 57 | {6, 30, 54, 78, 102, 126, 150}, 58 | {6, 24, 50, 76, 102, 128, 154}, 59 | {6, 28, 54, 80, 106, 132, 158}, 60 | {6, 32, 58, 84, 110, 136, 162}, 61 | {6, 26, 54, 82, 110, 138, 166}, 62 | {6, 30, 58, 86, 114, 142, 170} 63 | }; 64 | 65 | private static int[][][] MAX_LENGTH = { 66 | { {41, 25, 17, 10}, {34, 20, 14, 8}, {27, 16, 11, 7}, {17, 10, 7, 4} }, 67 | { {77, 47, 32, 20}, {63, 38, 26, 16}, {48, 29, 20, 12}, {34, 20, 14, 8} }, 68 | { {127, 77, 53, 32}, {101, 61, 42, 26}, {77, 47, 32, 20}, {58, 35, 24, 15} }, 69 | { {187, 114, 78, 48}, {149, 90, 62, 38}, {111, 67, 46, 28}, {82, 50, 34, 21} }, 70 | { {255, 154, 106, 65}, {202, 122, 84, 52}, {144, 87, 60, 37}, {106, 64, 44, 27} }, 71 | { {322, 195, 134, 82}, {255, 154, 106, 65}, {178, 108, 74, 45}, {139, 84, 58, 36} }, 72 | { {370, 224, 154, 95}, {293, 178, 122, 75}, {207, 125, 86, 53}, {154, 93, 64, 39} }, 73 | { {461, 279, 192, 118}, {365, 221, 152, 93}, {259, 157, 108, 66}, {202, 122, 84, 52} }, 74 | { {552, 335, 230, 141}, {432, 262, 180, 111}, {312, 189, 130, 80}, {235, 143, 98, 60} }, 75 | { {652, 395, 271, 167}, {513, 311, 213, 131}, {364, 221, 151, 93}, {288, 174, 119, 74} } 76 | }; 77 | 78 | public static int getMaxLength(int typeNumber, int mode, int errorCorrectionLevel) { 79 | 80 | int t = typeNumber - 1; 81 | int e = 0; 82 | int m = 0; 83 | 84 | switch(errorCorrectionLevel) { 85 | case ErrorCorrectionLevel.L : e = 0; break; 86 | case ErrorCorrectionLevel.M : e = 1; break; 87 | case ErrorCorrectionLevel.Q : e = 2; break; 88 | case ErrorCorrectionLevel.H : e = 3; break; 89 | default : 90 | throw new IllegalArgumentException("e:" + errorCorrectionLevel); 91 | } 92 | 93 | switch(mode) { 94 | case Mode.MODE_NUMBER : m = 0; break; 95 | case Mode.MODE_ALPHA_NUM : m = 1; break; 96 | case Mode.MODE_8BIT_BYTE : m = 2; break; 97 | case Mode.MODE_KANJI : m = 3; break; 98 | default : 99 | throw new IllegalArgumentException("m:" + mode); 100 | } 101 | 102 | return MAX_LENGTH[t][e][m]; 103 | } 104 | 105 | 106 | /** 107 | * エラー訂正多項式を取得する。 108 | */ 109 | public static Polynomial getErrorCorrectPolynomial(int errorCorrectLength) { 110 | 111 | Polynomial a = new Polynomial(new int[]{1}); 112 | 113 | for (int i = 0; i < errorCorrectLength; i++) { 114 | a = a.multiply(new Polynomial(new int[]{1, QRMath.gexp(i) }) ); 115 | } 116 | 117 | return a; 118 | } 119 | 120 | /** 121 | * 指定されたパターンのマスクを取得する。 122 | */ 123 | public static boolean getMask(int maskPattern, int i, int j) { 124 | 125 | switch (maskPattern) { 126 | 127 | case MaskPattern.PATTERN000 : return (i + j) % 2 == 0; 128 | case MaskPattern.PATTERN001 : return i % 2 == 0; 129 | case MaskPattern.PATTERN010 : return j % 3 == 0; 130 | case MaskPattern.PATTERN011 : return (i + j) % 3 == 0; 131 | case MaskPattern.PATTERN100 : return (i / 2 + j / 3) % 2 == 0; 132 | case MaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0; 133 | case MaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; 134 | case MaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; 135 | 136 | default : 137 | throw new IllegalArgumentException("mask:" + maskPattern); 138 | } 139 | } 140 | 141 | /** 142 | * 失点を取得する 143 | */ 144 | public static int getLostPoint(QRCode qrCode) { 145 | 146 | int moduleCount = qrCode.getModuleCount(); 147 | 148 | int lostPoint = 0; 149 | 150 | 151 | // LEVEL1 152 | 153 | for (int row = 0; row < moduleCount; row++) { 154 | 155 | for (int col = 0; col < moduleCount; col++) { 156 | 157 | int sameCount = 0; 158 | boolean dark = qrCode.isDark(row, col); 159 | 160 | for (int r = -1; r <= 1; r++) { 161 | 162 | if (row + r < 0 || moduleCount <= row + r) { 163 | continue; 164 | } 165 | 166 | for (int c = -1; c <= 1; c++) { 167 | 168 | if (col + c < 0 || moduleCount <= col + c) { 169 | continue; 170 | } 171 | 172 | if (r == 0 && c == 0) { 173 | continue; 174 | } 175 | 176 | if (dark == qrCode.isDark(row + r, col + c) ) { 177 | sameCount++; 178 | } 179 | } 180 | } 181 | 182 | if (sameCount > 5) { 183 | lostPoint += (3 + sameCount - 5); 184 | } 185 | } 186 | } 187 | 188 | // LEVEL2 189 | 190 | for (int row = 0; row < moduleCount - 1; row++) { 191 | for (int col = 0; col < moduleCount - 1; col++) { 192 | int count = 0; 193 | if (qrCode.isDark(row, col ) ) count++; 194 | if (qrCode.isDark(row + 1, col ) ) count++; 195 | if (qrCode.isDark(row, col + 1) ) count++; 196 | if (qrCode.isDark(row + 1, col + 1) ) count++; 197 | if (count == 0 || count == 4) { 198 | lostPoint += 3; 199 | } 200 | } 201 | } 202 | 203 | // LEVEL3 204 | 205 | for (int row = 0; row < moduleCount; row++) { 206 | for (int col = 0; col < moduleCount - 6; col++) { 207 | if (qrCode.isDark(row, col) 208 | && !qrCode.isDark(row, col + 1) 209 | && qrCode.isDark(row, col + 2) 210 | && qrCode.isDark(row, col + 3) 211 | && qrCode.isDark(row, col + 4) 212 | && !qrCode.isDark(row, col + 5) 213 | && qrCode.isDark(row, col + 6) ) { 214 | lostPoint += 40; 215 | } 216 | } 217 | } 218 | 219 | for (int col = 0; col < moduleCount; col++) { 220 | for (int row = 0; row < moduleCount - 6; row++) { 221 | if (qrCode.isDark(row, col) 222 | && !qrCode.isDark(row + 1, col) 223 | && qrCode.isDark(row + 2, col) 224 | && qrCode.isDark(row + 3, col) 225 | && qrCode.isDark(row + 4, col) 226 | && !qrCode.isDark(row + 5, col) 227 | && qrCode.isDark(row + 6, col) ) { 228 | lostPoint += 40; 229 | } 230 | } 231 | } 232 | 233 | // LEVEL4 234 | 235 | int darkCount = 0; 236 | 237 | for (int col = 0; col < moduleCount; col++) { 238 | for (int row = 0; row < moduleCount; row++) { 239 | if (qrCode.isDark(row, col) ) { 240 | darkCount++; 241 | } 242 | } 243 | } 244 | 245 | int ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; 246 | lostPoint += ratio * 10; 247 | 248 | return lostPoint; 249 | } 250 | 251 | public static int getMode(String s) { 252 | if (isAlphaNum(s) ) { 253 | if (isNumber(s) ) { 254 | return Mode.MODE_NUMBER; 255 | } 256 | return Mode.MODE_ALPHA_NUM; 257 | } else if (isKanji(s) ) { 258 | return Mode.MODE_KANJI; 259 | } else { 260 | return Mode.MODE_8BIT_BYTE; 261 | } 262 | } 263 | 264 | private static boolean isNumber(String s) { 265 | for (int i = 0; i < s.length(); i++) { 266 | char c = s.charAt(i); 267 | if (!('0' <= c && c <= '9') ) { 268 | return false; 269 | } 270 | } 271 | return true; 272 | } 273 | 274 | private static boolean isAlphaNum(String s) { 275 | for (int i = 0; i < s.length(); i++) { 276 | char c = s.charAt(i); 277 | if (!('0' <= c && c <= '9') && !('A' <= c && c <= 'Z') && " $%*+-./:".indexOf(c) == -1) { 278 | return false; 279 | } 280 | } 281 | return true; 282 | } 283 | 284 | private static boolean isKanji(String s) { 285 | 286 | try { 287 | 288 | byte[] data = s.getBytes(QRUtil.getJISEncoding() ); 289 | 290 | int i = 0; 291 | 292 | while (i + 1 < data.length) { 293 | 294 | int c = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]); 295 | 296 | if (!(0x8140 <= c && c <= 0x9FFC) && !(0xE040 <= c && c <= 0xEBBF) ) { 297 | return false; 298 | } 299 | 300 | i += 2; 301 | } 302 | 303 | if (i < data.length) { 304 | return false; 305 | } 306 | 307 | return true; 308 | 309 | } catch(UnsupportedEncodingException e) { 310 | throw new RuntimeException(e.getMessage() ); 311 | } 312 | } 313 | 314 | private static final int G15 = (1 << 10) | (1 << 8) | (1 << 5) 315 | | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); 316 | 317 | private static final int G18 = (1 << 12) | (1 << 11) | (1 << 10) 318 | | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); 319 | 320 | private static final int G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) 321 | | (1 << 4) | (1 << 1); 322 | 323 | public static int getBCHTypeInfo(int data) { 324 | int d = data << 10; 325 | while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { 326 | d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); 327 | } 328 | return ( (data << 10) | d) ^ G15_MASK; 329 | } 330 | 331 | public static int getBCHTypeNumber(int data) { 332 | int d = data << 12; 333 | while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { 334 | d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); 335 | } 336 | return (data << 12) | d; 337 | } 338 | 339 | private static int getBCHDigit(int data) { 340 | 341 | int digit = 0; 342 | 343 | while (data != 0) { 344 | digit++; 345 | data >>>= 1; 346 | } 347 | 348 | return digit; 349 | 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/RSBlock.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * RSBlock 8 | * @author Kazuhiko Arase 9 | */ 10 | class RSBlock { 11 | 12 | private static final int[][] RS_BLOCK_TABLE = { 13 | 14 | // L 15 | // M 16 | // Q 17 | // H 18 | 19 | // 1 20 | {1, 26, 19}, 21 | {1, 26, 16}, 22 | {1, 26, 13}, 23 | {1, 26, 9}, 24 | 25 | // 2 26 | {1, 44, 34}, 27 | {1, 44, 28}, 28 | {1, 44, 22}, 29 | {1, 44, 16}, 30 | 31 | // 3 32 | {1, 70, 55}, 33 | {1, 70, 44}, 34 | {2, 35, 17}, 35 | {2, 35, 13}, 36 | 37 | // 4 38 | {1, 100, 80}, 39 | {2, 50, 32}, 40 | {2, 50, 24}, 41 | {4, 25, 9}, 42 | 43 | // 5 44 | {1, 134, 108}, 45 | {2, 67, 43}, 46 | {2, 33, 15, 2, 34, 16}, 47 | {2, 33, 11, 2, 34, 12}, 48 | 49 | // 6 50 | {2, 86, 68}, 51 | {4, 43, 27}, 52 | {4, 43, 19}, 53 | {4, 43, 15}, 54 | 55 | // 7 56 | {2, 98, 78}, 57 | {4, 49, 31}, 58 | {2, 32, 14, 4, 33, 15}, 59 | {4, 39, 13, 1, 40, 14}, 60 | 61 | // 8 62 | {2, 121, 97}, 63 | {2, 60, 38, 2, 61, 39}, 64 | {4, 40, 18, 2, 41, 19}, 65 | {4, 40, 14, 2, 41, 15}, 66 | 67 | // 9 68 | {2, 146, 116}, 69 | {3, 58, 36, 2, 59, 37}, 70 | {4, 36, 16, 4, 37, 17}, 71 | {4, 36, 12, 4, 37, 13}, 72 | 73 | // 10 74 | {2, 86, 68, 2, 87, 69}, 75 | {4, 69, 43, 1, 70, 44}, 76 | {6, 43, 19, 2, 44, 20}, 77 | {6, 43, 15, 2, 44, 16}, 78 | 79 | // 11 80 | {4, 101, 81}, 81 | {1, 80, 50, 4, 81, 51}, 82 | {4, 50, 22, 4, 51, 23}, 83 | {3, 36, 12, 8, 37, 13}, 84 | 85 | // 12 86 | {2, 116, 92, 2, 117, 93}, 87 | {6, 58, 36, 2, 59, 37}, 88 | {4, 46, 20, 6, 47, 21}, 89 | {7, 42, 14, 4, 43, 15}, 90 | 91 | // 13 92 | {4, 133, 107}, 93 | {8, 59, 37, 1, 60, 38}, 94 | {8, 44, 20, 4, 45, 21}, 95 | {12, 33, 11, 4, 34, 12}, 96 | 97 | // 14 98 | {3, 145, 115, 1, 146, 116}, 99 | {4, 64, 40, 5, 65, 41}, 100 | {11, 36, 16, 5, 37, 17}, 101 | {11, 36, 12, 5, 37, 13}, 102 | 103 | // 15 104 | {5, 109, 87, 1, 110, 88}, 105 | {5, 65, 41, 5, 66, 42}, 106 | {5, 54, 24, 7, 55, 25}, 107 | {11, 36, 12, 7, 37, 13}, 108 | 109 | // 16 110 | {5, 122, 98, 1, 123, 99}, 111 | {7, 73, 45, 3, 74, 46}, 112 | {15, 43, 19, 2, 44, 20}, 113 | {3, 45, 15, 13, 46, 16}, 114 | 115 | // 17 116 | {1, 135, 107, 5, 136, 108}, 117 | {10, 74, 46, 1, 75, 47}, 118 | {1, 50, 22, 15, 51, 23}, 119 | {2, 42, 14, 17, 43, 15}, 120 | 121 | // 18 122 | {5, 150, 120, 1, 151, 121}, 123 | {9, 69, 43, 4, 70, 44}, 124 | {17, 50, 22, 1, 51, 23}, 125 | {2, 42, 14, 19, 43, 15}, 126 | 127 | // 19 128 | {3, 141, 113, 4, 142, 114}, 129 | {3, 70, 44, 11, 71, 45}, 130 | {17, 47, 21, 4, 48, 22}, 131 | {9, 39, 13, 16, 40, 14}, 132 | 133 | // 20 134 | {3, 135, 107, 5, 136, 108}, 135 | {3, 67, 41, 13, 68, 42}, 136 | {15, 54, 24, 5, 55, 25}, 137 | {15, 43, 15, 10, 44, 16}, 138 | 139 | // 21 140 | {4, 144, 116, 4, 145, 117}, 141 | {17, 68, 42}, 142 | {17, 50, 22, 6, 51, 23}, 143 | {19, 46, 16, 6, 47, 17}, 144 | 145 | // 22 146 | {2, 139, 111, 7, 140, 112}, 147 | {17, 74, 46}, 148 | {7, 54, 24, 16, 55, 25}, 149 | {34, 37, 13}, 150 | 151 | // 23 152 | {4, 151, 121, 5, 152, 122}, 153 | {4, 75, 47, 14, 76, 48}, 154 | {11, 54, 24, 14, 55, 25}, 155 | {16, 45, 15, 14, 46, 16}, 156 | 157 | // 24 158 | {6, 147, 117, 4, 148, 118}, 159 | {6, 73, 45, 14, 74, 46}, 160 | {11, 54, 24, 16, 55, 25}, 161 | {30, 46, 16, 2, 47, 17}, 162 | 163 | // 25 164 | {8, 132, 106, 4, 133, 107}, 165 | {8, 75, 47, 13, 76, 48}, 166 | {7, 54, 24, 22, 55, 25}, 167 | {22, 45, 15, 13, 46, 16}, 168 | 169 | // 26 170 | {10, 142, 114, 2, 143, 115}, 171 | {19, 74, 46, 4, 75, 47}, 172 | {28, 50, 22, 6, 51, 23}, 173 | {33, 46, 16, 4, 47, 17}, 174 | 175 | // 27 176 | {8, 152, 122, 4, 153, 123}, 177 | {22, 73, 45, 3, 74, 46}, 178 | {8, 53, 23, 26, 54, 24}, 179 | {12, 45, 15, 28, 46, 16}, 180 | 181 | // 28 182 | {3, 147, 117, 10, 148, 118}, 183 | {3, 73, 45, 23, 74, 46}, 184 | {4, 54, 24, 31, 55, 25}, 185 | {11, 45, 15, 31, 46, 16}, 186 | 187 | // 29 188 | {7, 146, 116, 7, 147, 117}, 189 | {21, 73, 45, 7, 74, 46}, 190 | {1, 53, 23, 37, 54, 24}, 191 | {19, 45, 15, 26, 46, 16}, 192 | 193 | // 30 194 | {5, 145, 115, 10, 146, 116}, 195 | {19, 75, 47, 10, 76, 48}, 196 | {15, 54, 24, 25, 55, 25}, 197 | {23, 45, 15, 25, 46, 16}, 198 | 199 | // 31 200 | {13, 145, 115, 3, 146, 116}, 201 | {2, 74, 46, 29, 75, 47}, 202 | {42, 54, 24, 1, 55, 25}, 203 | {23, 45, 15, 28, 46, 16}, 204 | 205 | // 32 206 | {17, 145, 115}, 207 | {10, 74, 46, 23, 75, 47}, 208 | {10, 54, 24, 35, 55, 25}, 209 | {19, 45, 15, 35, 46, 16}, 210 | 211 | // 33 212 | {17, 145, 115, 1, 146, 116}, 213 | {14, 74, 46, 21, 75, 47}, 214 | {29, 54, 24, 19, 55, 25}, 215 | {11, 45, 15, 46, 46, 16}, 216 | 217 | // 34 218 | {13, 145, 115, 6, 146, 116}, 219 | {14, 74, 46, 23, 75, 47}, 220 | {44, 54, 24, 7, 55, 25}, 221 | {59, 46, 16, 1, 47, 17}, 222 | 223 | // 35 224 | {12, 151, 121, 7, 152, 122}, 225 | {12, 75, 47, 26, 76, 48}, 226 | {39, 54, 24, 14, 55, 25}, 227 | {22, 45, 15, 41, 46, 16}, 228 | 229 | // 36 230 | {6, 151, 121, 14, 152, 122}, 231 | {6, 75, 47, 34, 76, 48}, 232 | {46, 54, 24, 10, 55, 25}, 233 | {2, 45, 15, 64, 46, 16}, 234 | 235 | // 37 236 | {17, 152, 122, 4, 153, 123}, 237 | {29, 74, 46, 14, 75, 47}, 238 | {49, 54, 24, 10, 55, 25}, 239 | {24, 45, 15, 46, 46, 16}, 240 | 241 | // 38 242 | {4, 152, 122, 18, 153, 123}, 243 | {13, 74, 46, 32, 75, 47}, 244 | {48, 54, 24, 14, 55, 25}, 245 | {42, 45, 15, 32, 46, 16}, 246 | 247 | // 39 248 | {20, 147, 117, 4, 148, 118}, 249 | {40, 75, 47, 7, 76, 48}, 250 | {43, 54, 24, 22, 55, 25}, 251 | {10, 45, 15, 67, 46, 16}, 252 | 253 | // 40 254 | {19, 148, 118, 6, 149, 119}, 255 | {18, 75, 47, 31, 76, 48}, 256 | {34, 54, 24, 34, 55, 25}, 257 | {20, 45, 15, 61, 46, 16} 258 | }; 259 | 260 | private int totalCount; 261 | private int dataCount; 262 | 263 | private RSBlock(int totalCount, int dataCount) { 264 | this.totalCount = totalCount; 265 | this.dataCount = dataCount; 266 | } 267 | 268 | public final int getDataCount() { 269 | return dataCount; 270 | } 271 | 272 | public final int getTotalCount() { 273 | return totalCount; 274 | } 275 | 276 | public static RSBlock[] getRSBlocks(int typeNumber, int errorCorrectionLevel) { 277 | 278 | int[] rsBlock = getRsBlockTable(typeNumber, errorCorrectionLevel); 279 | int length = rsBlock.length / 3; 280 | 281 | 282 | List list = new ArrayList(); 283 | 284 | for (int i = 0; i < length; i++) { 285 | 286 | int count = rsBlock[i * 3 + 0]; 287 | int totalCount = rsBlock[i * 3 + 1]; 288 | int dataCount = rsBlock[i * 3 + 2]; 289 | 290 | for (int j = 0; j < count; j++) { 291 | list.add(new RSBlock(totalCount, dataCount) ); 292 | } 293 | } 294 | 295 | return list.toArray(new RSBlock[list.size() ]); 296 | } 297 | 298 | private static int[] getRsBlockTable(int typeNumber, int errorCorrectionLevel) { 299 | 300 | try { 301 | 302 | switch(errorCorrectionLevel) { 303 | case ErrorCorrectionLevel.L : 304 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; 305 | case ErrorCorrectionLevel.M : 306 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; 307 | case ErrorCorrectionLevel.Q : 308 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; 309 | case ErrorCorrectionLevel.H : 310 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; 311 | default : 312 | break; 313 | } 314 | 315 | } catch(Exception e) { 316 | } 317 | 318 | throw new IllegalArgumentException("tn:" + typeNumber + "/ecl:" + errorCorrectionLevel); 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/web/GIFImage.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode.web; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.OutputStream; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * GIFイメージ(B/W) 11 | * @author Kazuhiko Arase 12 | */ 13 | class GIFImage { 14 | 15 | private int width; 16 | private int height; 17 | private int[] data; 18 | 19 | public GIFImage(int width, int height) { 20 | this.width = width; 21 | this.height = height; 22 | this.data = new int[width * height]; 23 | } 24 | 25 | public void setPixel(int x, int y, int pixel) { 26 | if (x < 0 || width <= x) throw new IllegalArgumentException(); 27 | if (y < 0 || height <= y) throw new IllegalArgumentException(); 28 | data[y * width + x] = pixel; 29 | } 30 | 31 | public int getPixel(int x, int y) { 32 | if (x < 0 || width <= x) throw new IllegalArgumentException(); 33 | if (y < 0 || height <= y) throw new IllegalArgumentException(); 34 | return data[y * width + x]; 35 | } 36 | 37 | public void write(OutputStream out) throws IOException { 38 | 39 | //--------------------------------- 40 | // GIF Signature 41 | 42 | out.write("GIF87a".getBytes("ISO-8859-1") ); 43 | 44 | //--------------------------------- 45 | // Screen Descriptor 46 | 47 | write(out, width); 48 | write(out, height); 49 | 50 | out.write(0x80); // 2bit 51 | out.write(0); 52 | out.write(0); 53 | 54 | //--------------------------------- 55 | // Global Color Map 56 | 57 | // black 58 | out.write(0x00); 59 | out.write(0x00); 60 | out.write(0x00); 61 | 62 | // white 63 | out.write(0xff); 64 | out.write(0xff); 65 | out.write(0xff); 66 | 67 | //--------------------------------- 68 | // Image Descriptor 69 | 70 | out.write(','); 71 | write(out, 0); 72 | write(out, 0); 73 | write(out, width); 74 | write(out, height); 75 | out.write(0); 76 | 77 | //--------------------------------- 78 | // Local Color Map 79 | 80 | //--------------------------------- 81 | // Raster Data 82 | 83 | int lzwMinCodeSize = 2; 84 | byte[] raster = getLZWRaster(lzwMinCodeSize); 85 | 86 | out.write(lzwMinCodeSize); 87 | 88 | int offset = 0; 89 | 90 | while (raster.length - offset > 255) { 91 | out.write(255); 92 | out.write(raster, offset, 255); 93 | offset += 255; 94 | } 95 | 96 | out.write(raster.length - offset); 97 | out.write(raster, offset, raster.length - offset); 98 | out.write(0x00); 99 | 100 | //--------------------------------- 101 | // GIF Terminator 102 | out.write(';'); 103 | 104 | } 105 | 106 | private byte[] getLZWRaster(int lzwMinCodeSize) throws IOException { 107 | 108 | int clearCode = 1 << lzwMinCodeSize; 109 | int endCode = (1 << lzwMinCodeSize) + 1; 110 | int bitLength = lzwMinCodeSize + 1; 111 | 112 | // Setup LZWTable 113 | LZWTable table = new LZWTable(); 114 | 115 | for (int i = 0; i < clearCode; i++) { 116 | table.add(String.valueOf( (char)i) ); 117 | } 118 | table.add(String.valueOf( (char)clearCode) ); 119 | table.add(String.valueOf( (char)endCode) ); 120 | 121 | 122 | ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 123 | BitOutputStream bitOut = new BitOutputStream(byteOut); 124 | 125 | try { 126 | 127 | // clear code 128 | bitOut.write(clearCode, bitLength); 129 | 130 | int dataIndex = 0; 131 | String s = String.valueOf( (char)data[dataIndex++]); 132 | 133 | while (dataIndex < data.length) { 134 | 135 | char c = (char)data[dataIndex++]; 136 | 137 | if (table.contains(s + c) ) { 138 | 139 | s = s + c; 140 | 141 | } else { 142 | 143 | bitOut.write(table.indexOf(s), bitLength); 144 | 145 | if (table.size() < 0xfff) { 146 | 147 | if (table.size() == (1 << bitLength) ) { 148 | bitLength++; 149 | } 150 | 151 | table.add(s + c); 152 | } 153 | 154 | s = String.valueOf(c); 155 | } 156 | } 157 | 158 | bitOut.write(table.indexOf(s), bitLength); 159 | 160 | // end code 161 | bitOut.write(endCode, bitLength); 162 | 163 | } finally { 164 | bitOut.close(); 165 | } 166 | 167 | return byteOut.toByteArray(); 168 | } 169 | 170 | private static void write(OutputStream out, int i) throws IOException { 171 | out.write(i & 0xff); 172 | out.write( (i >>> 8) & 0xff); 173 | } 174 | 175 | private static class LZWTable { 176 | 177 | private Map map; 178 | 179 | public LZWTable() { 180 | map = new HashMap(); 181 | } 182 | 183 | public void add(String key) { 184 | if (contains(key) ) { 185 | throw new IllegalArgumentException("dup key:" + key); 186 | } 187 | map.put(key, map.size() ); 188 | } 189 | 190 | public int size() { 191 | return map.size(); 192 | } 193 | 194 | public int indexOf(String key) { 195 | return ( (Integer)map.get(key) ).intValue(); 196 | } 197 | 198 | public boolean contains(String key) { 199 | return map.containsKey(key); 200 | } 201 | 202 | } 203 | 204 | private static class BitOutputStream { 205 | 206 | private OutputStream out; 207 | private int bitLength; 208 | private int bitBuffer; 209 | 210 | public BitOutputStream(OutputStream out) { 211 | this.out = out; 212 | this.bitLength = 0; 213 | } 214 | 215 | public void write(int data, int length) throws IOException{ 216 | 217 | if ( (data >>> length) != 0) { 218 | throw new IOException("length over"); 219 | } 220 | 221 | while (bitLength + length >= 8) { 222 | out.write(0xff & ( (data << bitLength) | bitBuffer) ); 223 | length -= (8 - bitLength); 224 | data >>>= (8 - bitLength); 225 | bitBuffer = 0; 226 | bitLength = 0; 227 | } 228 | 229 | bitBuffer = (data << bitLength) | bitBuffer; 230 | bitLength = bitLength + length; 231 | } 232 | 233 | public void flush() throws IOException { 234 | if (bitLength > 0) { 235 | out.write(bitBuffer); 236 | } 237 | out.flush(); 238 | } 239 | 240 | public void close() throws IOException { 241 | flush(); 242 | out.close(); 243 | } 244 | 245 | } 246 | 247 | } 248 | -------------------------------------------------------------------------------- /java/src/main/java/com/d_project/qrcode/web/QRCodeServlet.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode.web; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.io.BufferedOutputStream; 5 | import java.io.IOException; 6 | import java.io.OutputStream; 7 | import java.io.OutputStreamWriter; 8 | import java.io.PrintWriter; 9 | 10 | import javax.imageio.ImageIO; 11 | import javax.servlet.ServletConfig; 12 | import javax.servlet.ServletException; 13 | import javax.servlet.http.HttpServlet; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | 17 | import com.d_project.qrcode.ErrorCorrectionLevel; 18 | import com.d_project.qrcode.QRCode; 19 | 20 | /** 21 | * QRコードサーブレット. 22 | *
QRコードのモノクロGIF画像を応答するサーブレットです。 23 | *
[パラメータ] 24 | *
o : 出力形式 (text/plain, image/gif, image/jpeg, image/png のいずれか, 省略した場合は image/gif) 25 | *
t : 型番 (0:自動, 1~10, 省略した場合は 0) 26 | *
e : 誤り訂正レベル (L, Q, M, H のいずれか, 省略した場合は H) 27 | *
d : テキストデータ (文字列) 28 | *
m : マージン (0~32, 省略した場合は 0) 29 | *
s : セルサイズ (1~4, 省略した場合は 1) 30 | * @author Kazuhiko Arase 31 | * @see com.d_project.qrcode.Mode 32 | * @see com.d_project.qrcode.ErrorCorrectionLevel 33 | */ 34 | @SuppressWarnings("serial") 35 | public class QRCodeServlet extends HttpServlet { 36 | 37 | private String defaultCharacterEncoding; 38 | 39 | /** 40 | * コンストラクタ 41 | */ 42 | public QRCodeServlet() { 43 | } 44 | 45 | public void init(ServletConfig config) throws ServletException { 46 | 47 | super.init(config); 48 | 49 | defaultCharacterEncoding = getServletConfig().getInitParameter("default-character-encoding"); 50 | } 51 | 52 | public void doGet(HttpServletRequest request, HttpServletResponse response) 53 | throws ServletException, IOException { 54 | 55 | String data = getParameter(request, "d", "qrcode"); 56 | 57 | if (defaultCharacterEncoding != null) { 58 | data = new String(data.getBytes("ISO-8859-1"), defaultCharacterEncoding); 59 | } 60 | 61 | String output = getParameter(request, "o", "image/gif"); 62 | 63 | int typeNumber = getIntParameter(request, "t", 0); 64 | if (typeNumber < 0 || 10 < typeNumber) { 65 | throw new IllegalArgumentException("illegal type number : " + typeNumber); 66 | } 67 | 68 | int margin = getIntParameter(request, "m", 2); 69 | if (margin < 0 || 32 < margin) { 70 | throw new IllegalArgumentException("illegal margin : " + margin); 71 | } 72 | 73 | int cellSize = getIntParameter(request, "s", 1); 74 | if (cellSize < 1 || 4 < cellSize) { 75 | throw new IllegalArgumentException("illegal cell size : " + cellSize); 76 | } 77 | 78 | int errorCorrectionLevel = parseErrorCorrectionLevel(getParameter(request, "e", "H") ); 79 | 80 | QRCode qrcode = getQRCode(data, typeNumber, errorCorrectionLevel); 81 | 82 | if ("text/plain".equals(output) ) { 83 | 84 | response.setContentType("text/plain"); 85 | 86 | PrintWriter out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), "ISO-8859-1") ); 87 | 88 | try { 89 | for (int row = 0; row < qrcode.getModuleCount(); row++) { 90 | for (int col = 0; col < qrcode.getModuleCount(); col++) { 91 | out.print(qrcode.isDark(row, col)? "1" : "0"); 92 | } 93 | out.print("\r\n"); 94 | } 95 | } finally { 96 | out.close(); 97 | } 98 | 99 | } else if ("image/jpeg".equals(output) ) { 100 | 101 | BufferedImage image = qrcode.createImage(cellSize, margin); 102 | 103 | response.setContentType("image/jpeg"); 104 | 105 | OutputStream out = new BufferedOutputStream(response.getOutputStream() ); 106 | 107 | try { 108 | ImageIO.write(image, "jpeg", out); 109 | } finally { 110 | out.close(); 111 | } 112 | 113 | } else if ("image/png".equals(output) ) { 114 | 115 | BufferedImage image = qrcode.createImage(cellSize, margin); 116 | 117 | response.setContentType("image/png"); 118 | 119 | OutputStream out = new BufferedOutputStream(response.getOutputStream() ); 120 | 121 | try { 122 | ImageIO.write(image, "png", out); 123 | } finally { 124 | out.close(); 125 | } 126 | 127 | } else if ("image/gif".equals(output) ) { 128 | 129 | GIFImage image = createGIFImage(qrcode, cellSize, margin); 130 | 131 | response.setContentType("image/gif"); 132 | 133 | OutputStream out = new BufferedOutputStream(response.getOutputStream() ); 134 | 135 | try { 136 | image.write(out); 137 | } finally { 138 | out.close(); 139 | } 140 | 141 | } else { 142 | throw new IllegalArgumentException("illegal output type : " + output); 143 | } 144 | } 145 | 146 | private static String getParameter(HttpServletRequest request, String name, String defaultValue) { 147 | String value = request.getParameter(name); 148 | return (value != null)? value : defaultValue; 149 | } 150 | 151 | private static int getIntParameter(HttpServletRequest request, String name, int defaultValue) { 152 | String value = request.getParameter(name); 153 | return (value != null)? Integer.parseInt(value) : defaultValue; 154 | } 155 | 156 | private static QRCode getQRCode(String text, int typeNumber, int errorCorrectionLevel) { 157 | 158 | if (typeNumber == 0) { 159 | 160 | return QRCode.getMinimumQRCode(text, errorCorrectionLevel); 161 | 162 | } else { 163 | 164 | QRCode qr = new QRCode(); 165 | qr.setTypeNumber(typeNumber); 166 | qr.setErrorCorrectionLevel(errorCorrectionLevel); 167 | qr.addData(text); 168 | qr.make(); 169 | 170 | return qr; 171 | 172 | } 173 | } 174 | 175 | private static int parseErrorCorrectionLevel(String ecl) { 176 | 177 | if ("L".equals(ecl) ) { 178 | return ErrorCorrectionLevel.L; 179 | } else if ("Q".equals(ecl) ) { 180 | return ErrorCorrectionLevel.Q; 181 | } else if ("M".equals(ecl) ) { 182 | return ErrorCorrectionLevel.M; 183 | } else if ("H".equals(ecl) ) { 184 | return ErrorCorrectionLevel.H; 185 | } else { 186 | throw new IllegalArgumentException("invalid error correct level : " + ecl); 187 | } 188 | 189 | } 190 | 191 | /** 192 | * GIFイメージを取得する。 193 | * @param cellSize セルのサイズ(pixel) 194 | * @param margin 余白(pixel) 195 | */ 196 | private static GIFImage createGIFImage(QRCode qrcode, int cellSize, int margin) throws IOException { 197 | 198 | int imageSize = qrcode.getModuleCount() * cellSize + margin * 2; 199 | 200 | GIFImage image = new GIFImage(imageSize, imageSize); 201 | 202 | for (int y = 0; y < imageSize; y++) { 203 | 204 | for (int x = 0; x < imageSize; x++) { 205 | 206 | if (margin <= x && x < imageSize - margin 207 | && margin <= y && y < imageSize - margin) { 208 | 209 | int col = (x - margin) / cellSize; 210 | int row = (y - margin) / cellSize; 211 | 212 | if (qrcode.isDark(row, col) ) { 213 | image.setPixel(x, y, 0); 214 | } else { 215 | image.setPixel(x, y, 1); 216 | } 217 | 218 | } else { 219 | image.setPixel(x, y, 1); 220 | } 221 | } 222 | } 223 | 224 | return image; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /java/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | qrcode 10 | com.d_project.qrcode.web.QRCodeServlet 11 | 12 | default-character-encoding 13 | Utf-8 14 | 15 | 16 | 17 | 18 | qrcode 19 | /qrcode 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /java/src/main/webapp/form.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=Utf-8" %> 2 | 3 | 4 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 43 | 44 | 45 | 46 | 54 | 55 | 56 | 57 | 64 | 65 | 66 | 67 | 74 | 75 |
出力形式 19 | 25 |
テキスト 30 | 31 |
誤り訂正レベル 36 | 42 |
種別 47 | 53 |
余白
※出力形式が画像の場合のみ有効
58 | 63 |
セルサイズ
※出力形式が画像の場合のみ有効
68 | 73 |
76 | 77 | 78 | 79 |
80 | 81 | 82 | -------------------------------------------------------------------------------- /java/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=Utf-8" %> 2 | 3 | 4 | 5 | QRCode for Java 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /java/src/test/java/com/d_project/qrcode/BitBufferTest.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class BitBufferTest { 7 | 8 | @Test 9 | public void test1() { 10 | BitBuffer bb = new BitBuffer(); 11 | QRData qd = new QR8BitByte("534TEST!!!あ"); 12 | qd.write(bb); 13 | 14 | Assert.assertEquals(96, bb.getLengthInBits() ); 15 | } 16 | 17 | @Test 18 | public void test2() { 19 | BitBuffer bb = new BitBuffer(); 20 | QRData qd = new QRAlphaNum("534TEST $%*+-./:"); 21 | qd.write(bb); 22 | 23 | Assert.assertEquals(88, bb.getLengthInBits() ); 24 | } 25 | 26 | @Test 27 | public void test3() { 28 | BitBuffer bb = new BitBuffer(); 29 | QRData qd = new QRKanji("あいうえお"); 30 | qd.write(bb); 31 | 32 | Assert.assertEquals(65, bb.getLengthInBits() ); 33 | } 34 | 35 | @Test 36 | public void test4() { 37 | BitBuffer bb = new BitBuffer(); 38 | QRData qd = new QRNumber("0123456789"); 39 | qd.write(bb); 40 | 41 | Assert.assertEquals(34, bb.getLengthInBits() ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /java/src/test/java/com/d_project/qrcode/PolynomialTest.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class PolynomialTest { 7 | 8 | @Test 9 | public void test1() { 10 | 11 | int[] rs = new int[] {0, 43, 139, 206, 78, 43, 239, 123, 206, 214, 147, 24, 99, 150, 39, 243, 163, 136}; 12 | for (int i = 0; i < rs.length; i++) { 13 | rs[i] = QRMath.gexp(rs[i]); 14 | } 15 | int[] data = new int[]{32,65,205,69,41,220,46,128,236}; 16 | 17 | Polynomial e = new Polynomial(rs); 18 | Polynomial e2 = new Polynomial(data, e.getLength() - 1); 19 | 20 | assertEquals(new int[]{32,65,205,69,41,220,46,128,236,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, e2); 21 | assertEquals(new int[]{1,119,66,83,120,119,22,197,83,249,41,143,134,85,53,125,99,79}, e); 22 | assertEquals(new int[]{42,159,74,221,244,169,239,150,138,70,237,85,224,96,74,219,61}, e2.mod(e) ); 23 | } 24 | 25 | @Test 26 | public void test2() { 27 | 28 | Polynomial a = new Polynomial(new int[]{1}, 0); 29 | for (int i = 0; i < 7; i++) { 30 | a = a.multiply(new Polynomial(new int[]{1, QRMath.gexp(i) }, 0) ); 31 | } 32 | 33 | int[] log = {0,87,229,146,149,238,102,21}; 34 | Assert.assertEquals(log.length, a.getLength() ); 35 | for (int i = 0; i < a.getLength(); i++) { 36 | Assert.assertEquals(log[i], QRMath.glog(a.get(i) ) ); 37 | } 38 | } 39 | 40 | protected void assertEquals(int[] num, Polynomial p) { 41 | Assert.assertEquals(num.length, p.getLength() ); 42 | for (int i = 0; i < num.length; i++) { 43 | Assert.assertEquals(num[i], p.get(i) ); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /java/src/test/java/com/d_project/qrcode/QRCodeTest.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class QRCodeTest { 7 | 8 | @Test 9 | public void test1() { 10 | QRNumber data = new QRNumber("0123"); 11 | byte[] act = QRCode.createData(1, ErrorCorrectionLevel.H, new QRData[]{data} ); 12 | byte[] exp = new byte[]{16,16,12,48,-20,17,-20,17,-20,-50,-20,-24,66,-27,44,-31,-124,-111,13,-69,-37,15,-16,36,-69,104}; 13 | assertEquals(exp, act); 14 | } 15 | 16 | @Test 17 | public void test2() { 18 | QRAlphaNum data = new QRAlphaNum("AB01"); 19 | byte[] act = QRCode.createData(1, ErrorCorrectionLevel.H, new QRData[]{data} ); 20 | byte[] exp = new byte[]{32,33,-51,0,32,-20,17,-20,17,105,-125,-85,106,65,-91,54,-123,-112,-11,-73,21,-13,-106,-89,114,-25}; 21 | assertEquals(exp, act); 22 | } 23 | 24 | @Test 25 | public void test3() { 26 | QRKanji data = new QRKanji("漢字"); 27 | byte[] act = QRCode.createData(1, ErrorCorrectionLevel.H, new QRData[]{data} ); 28 | byte[] exp = new byte[]{-128,35,-97,-88,104,0,-20,17,-20,-11,-82,108,-126,119,-6,118,-128,99,-41,-105,117,-68,-107,-120,47,-5}; 29 | assertEquals(exp, act); 30 | } 31 | 32 | @Test 33 | public void test4() { 34 | QR8BitByte data = new QR8BitByte("ab01"); 35 | byte[] act = QRCode.createData(1, ErrorCorrectionLevel.H, new QRData[]{data} ); 36 | byte[] exp = new byte[]{64,70,22,35,3,16,-20,17,-20,91,-25,80,48,-87,54,40,-83,84,-117,33,87,54,-57,50,-84,49}; 37 | assertEquals(exp, act); 38 | } 39 | 40 | protected void assertEquals(byte[] expected, byte[] actual) { 41 | Assert.assertEquals(expected.length, actual.length); 42 | for (int i = 0; i < expected.length; i++) { 43 | Assert.assertEquals(expected[i], actual[i]); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /java/src/test/java/com/d_project/qrcode/web/GIFImageTest.java: -------------------------------------------------------------------------------- 1 | package com.d_project.qrcode.web; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | 5 | import org.junit.Test; 6 | 7 | public class GIFImageTest { 8 | 9 | @Test 10 | public void test() throws Exception { 11 | 12 | GIFImage g = new GIFImage(2, 2); 13 | g.setPixel(0, 0, 1); 14 | g.setPixel(0, 1, 0); 15 | g.setPixel(1, 0, 0); 16 | g.setPixel(1, 1, 1); 17 | 18 | ByteArrayOutputStream b = new ByteArrayOutputStream(); 19 | g.write(b); 20 | byte[] raw = b.toByteArray(); 21 | for (int i = 0; i < raw.length; i++) { 22 | if (i > 0) { 23 | System.out.print(","); 24 | } 25 | System.out.print(raw[i] & 0xff); 26 | } 27 | System.out.println(); 28 | } 29 | } -------------------------------------------------------------------------------- /js/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.tgz 3 | -------------------------------------------------------------------------------- /js/.npmignore: -------------------------------------------------------------------------------- 1 | ts-test 2 | misc 3 | demo 4 | sample.* 5 | *.tgz 6 | -------------------------------------------------------------------------------- /js/README.md: -------------------------------------------------------------------------------- 1 | QR Code Generator 2 | === 3 | 4 | ## Getting Started 5 | 6 | 1. Include qrcode.js in your html. 7 | 2. Prepare a place holder. 8 | 3. Generate QR and render it. 9 | 10 | ```html 11 | 12 | ``` 13 | ```html 14 |
15 | ``` 16 | ```javascript 17 | var typeNumber = 4; 18 | var errorCorrectionLevel = 'L'; 19 | var qr = qrcode(typeNumber, errorCorrectionLevel); 20 | qr.addData('Hi!'); 21 | qr.make(); 22 | document.getElementById('placeHolder').innerHTML = qr.createImgTag(); 23 | ``` 24 | ## API Documentation 25 | 26 | ### QRCodeFactory 27 | 28 | #### qrcode(typeNumber, errorCorrectionLevel) => QRCode 29 | Create a QRCode Object. 30 | 31 | | Param | Type | Description | 32 | | ---------------------| ------------------- | ---------------------------------------------- | 33 | | typeNumber | number | Type number (1 ~ 40), or 0 for auto detection. | 34 | | errorCorrectionLevel | string | Error correction level ('L', 'M', 'Q', 'H') | 35 | 36 | #### qrcode.stringToBytes(s) : number[] 37 | Encodes a string into an array of number(byte) using any charset. 38 | This function is used by internal. 39 | Overwrite this function to encode using a multibyte charset. 40 | 41 | | Param | Type | Description | 42 | | ------ | ------------------- | ---------------- | 43 | | s | string | string to encode | 44 | 45 | ### QRCode 46 | 47 | #### addData(data, mode) => void 48 | Add a data to encode. 49 | 50 | | Param | Type | Description | 51 | | ------ | ------------------- | ---------------------------------------------------------- | 52 | | data | string | string to encode | 53 | | mode | string | Mode ('Numeric', 'Alphanumeric', 'Byte'(default), 'Kanji') | 54 | 55 | #### make() => void 56 | Make a QR Code. 57 | 58 | #### getModuleCount() => number 59 | The number of modules(cells) for each orientation. 60 | _[Note] call make() before this function._ 61 | 62 | #### isDark(row, col) => boolean 63 | The module at row and col is dark or not. 64 | _[Note] call make() before this function._ 65 | 66 | | Param | Type | Description | 67 | | ----- | ------------------- | ------------------- | 68 | | row | number | 0 ~ moduleCount - 1 | 69 | | col | number | 0 ~ moduleCount - 1 | 70 | 71 | #### createDataURL(cellSize, margin) => string 72 | #### createImgTag(cellSize, margin, alt) => string 73 | #### createSvgTag(cellSize, margin) => string 74 | #### createTableTag(cellSize, margin) => string 75 | #### createASCII(cellSize, margin) => string 76 | Helper functions for HTML. 77 | _[Note] call make() before these functions._ 78 | 79 | | Param | Type | Description | 80 | | -------- | ------------------- | --------------------- | 81 | | cellSize | number | default: 2 | 82 | | margin | number | default: cellSize * 4 | 83 | | alt | string | (optional) | 84 | 85 | #### createSvgTag(opts) => string 86 | 87 | | Param | Type | Description | 88 | | ------------- | -------------------- | --------------------- | 89 | | opts | object | default: {} | 90 | | opts.cellSize | number | default: 2 | 91 | | opts.margin | number | default: cellSize * 4 | 92 | | opts.scalable | boolean | default: false | 93 | 94 | #### renderTo2dContext(context, cellSize) => void 95 | 96 | -- 97 | 98 | This implementation is based on JIS X 0510:1999. 99 | 100 | The word 'QR Code' is registered trademark of DENSO WAVE INCORPORATED 101 |
http://www.denso-wave.com/qrcode/faqpatent-e.html 102 | -------------------------------------------------------------------------------- /js/demo/assets/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kazuhikoarase/qrcode-generator/0e51e6310a34b5e4f70280533b3d43e1fc6a0b16/js/demo/assets/qrcode.png -------------------------------------------------------------------------------- /js/demo/assets/sample.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var body_loadHander = function() { 4 | 5 | var crtOpt = function(value, label) { 6 | var opt = document.createElement('option'); 7 | opt.appendChild(document.createTextNode(label) ); 8 | opt.value = value; 9 | return opt; 10 | }; 11 | 12 | var t = document.forms['qrForm'].elements['t']; 13 | t.appendChild(crtOpt('' + 0, 'Auto Detect') ); 14 | for (var i = 1; i <= 40; i += 1) { 15 | t.appendChild(crtOpt('' + i, '' + i) ); 16 | } 17 | t.value = '0'; 18 | 19 | document.getElementById('dataCaps').appendChild(createDataCapsTable() ); 20 | 21 | update_qrcode(); 22 | }; 23 | 24 | var draw_qrcode = function(text, typeNumber, errorCorrectionLevel) { 25 | document.write(create_qrcode(text, typeNumber, errorCorrectionLevel) ); 26 | }; 27 | 28 | var create_qrcode = function(text, typeNumber, 29 | errorCorrectionLevel, mode, mb) { 30 | 31 | qrcode.stringToBytes = qrcode.stringToBytesFuncs[mb]; 32 | 33 | var qr = qrcode(typeNumber || 4, errorCorrectionLevel || 'M'); 34 | qr.addData(text, mode); 35 | qr.make(); 36 | 37 | // return qr.createTableTag(); 38 | // return qr.createSvgTag(); 39 | return qr.createImgTag(); 40 | }; 41 | 42 | var update_qrcode = function() { 43 | var form = document.forms['qrForm']; 44 | var text = form.elements['msg'].value. 45 | replace(/^[\s\u3000]+|[\s\u3000]+$/g, ''); 46 | var t = form.elements['t'].value; 47 | var e = form.elements['e'].value; 48 | var m = form.elements['m'].value; 49 | var mb = form.elements['mb'].value; 50 | document.getElementById('qr').innerHTML = 51 | create_qrcode(text, t, e, m, mb); 52 | }; 53 | 54 | var createDataCapsTable = function() { 55 | 56 | var modes = [ 'Numeric', 'Alphanumeric', 'Byte', 'Kanji' ]; 57 | var ecls = [ 'L', 'M', 'Q', 'H' ]; 58 | var colors = ['255,0,0','255,159,0','0,255,0','0,0,255']; 59 | var getCellBg = function(m, e) { 60 | return 'rgba(' + colors[m] + ',' + (0.1 * (e + 0.5) ) + ')'; 61 | }; 62 | 63 | var table = document.createElement('table'); 64 | var thead = document.createElement('thead'); 65 | table.appendChild(thead); 66 | !function() { 67 | var tr = document.createElement('tr'); 68 | var th = document.createElement('th'); 69 | th.appendChild(document.createTextNode('TypeNumber') ); 70 | th.setAttribute('rowspan', '2'); 71 | tr.appendChild(th); 72 | for (var m = 0; m < 4; m += 1) { 73 | var th = document.createElement('th'); 74 | th.setAttribute('colspan', '4'); 75 | th.style.backgroundColor = getCellBg(m, 4); 76 | th.style.textAlign = 'center'; 77 | th.appendChild(document.createTextNode(modes[m]) ); 78 | tr.appendChild(th); 79 | } 80 | thead.appendChild(tr); 81 | }(); 82 | !function() { 83 | var tr = document.createElement('tr'); 84 | for (var m = 0; m < 4; m += 1) { 85 | for (var e = 0; e < 4; e += 1) { 86 | var th = document.createElement('th'); 87 | th.style.backgroundColor = getCellBg(m, e % 2); 88 | th.style.textAlign = 'center'; 89 | th.appendChild(document.createTextNode(ecls[e]) ); 90 | tr.appendChild(th); 91 | } 92 | } 93 | thead.appendChild(tr); 94 | }(); 95 | var tbody = document.createElement('tbody'); 96 | table.appendChild(tbody); 97 | for (var t = 0; t < DATA_CAPS.length; t += 1) { 98 | var tr = document.createElement('tr'); 99 | tr.style.backgroundColor = 'rgba(0,0,0,' + 100 | (t % 2 == 0? 0 : 0.1) + ')'; 101 | var td = document.createElement('td'); 102 | td.style.textAlign = 'center'; 103 | td.appendChild(document.createTextNode(''+ (t + 1) ) ); 104 | tr.appendChild(td); 105 | for (var m = 0; m < 4; m += 1) { 106 | for (var e = 0; e < 4; e += 1) { 107 | var td = document.createElement('td'); 108 | td.style.backgroundColor = getCellBg(m, e % 2); 109 | td.style.textAlign = 'right'; 110 | td.appendChild(document.createTextNode(''+ DATA_CAPS[t][e][m]) ); 111 | tr.appendChild(td); 112 | } 113 | } 114 | tbody.appendChild(tr); 115 | } 116 | return table; 117 | }; 118 | 119 | var DATA_CAPS = [ 120 | /* 1 */ [ [41, 25, 17, 10], [34, 20, 14, 8], [27, 16, 11, 7], [17, 10, 7, 4] ], 121 | /* 2 */ [ [77, 47, 32, 20], [63, 38, 26, 16], [48, 29, 20, 12], [34, 20, 14, 8] ], 122 | /* 3 */ [ [127, 77, 53, 32], [101, 61, 42, 26], [77, 47, 32, 20], [58, 35, 24, 15] ], 123 | /* 4 */ [ [187, 114, 78, 48], [149, 90, 62, 38], [111, 67, 46, 28], [82, 50, 34, 21] ], 124 | /* 5 */ [ [255, 154, 106, 65], [202, 122, 84, 52], [144, 87, 60, 37], [106, 64, 44, 27] ], 125 | /* 6 */ [ [322, 195, 134, 82], [255, 154, 106, 65], [178, 108, 74, 45], [139, 84, 58, 36] ], 126 | /* 7 */ [ [370, 224, 154, 95], [293, 178, 122, 75], [207, 125, 86, 53], [154, 93, 64, 39] ], 127 | /* 8 */ [ [461, 279, 192, 118], [365, 221, 152, 93], [259, 157, 108, 66], [202, 122, 84, 52] ], 128 | /* 9 */ [ [552, 335, 230, 141], [432, 262, 180, 111], [312, 189, 130, 80], [235, 143, 98, 60] ], 129 | /* 10 */ [ [652, 395, 271, 167], [513, 311, 213, 131], [364, 221, 151, 93], [288, 174, 119, 74] ], 130 | /* 11 */ [ [772, 468, 321, 198], [604, 366, 251, 155], [427, 259, 177, 109], [331, 200, 137, 85] ], 131 | /* 12 */ [ [883, 535, 367, 226], [691, 419, 287, 177], [489, 296, 203, 125], [374, 227, 155, 96] ], 132 | /* 13 */ [ [1022, 619, 425, 262], [796, 483, 331, 204], [580, 352, 241, 149], [427, 259, 177, 109] ], 133 | /* 14 */ [ [1101, 667, 458, 282], [871, 528, 362, 223], [621, 376, 258, 159], [468, 283, 194, 120] ], 134 | /* 15 */ [ [1250, 758, 520, 320], [991, 600, 412, 254], [703, 426, 292, 180], [530, 321, 220, 136] ], 135 | /* 16 */ [ [1408, 854, 586, 361], [1082, 656, 450, 277], [775, 470, 322, 198], [602, 365, 250, 154] ], 136 | /* 17 */ [ [1548, 938, 644, 397], [1212, 734, 504, 310], [876, 531, 364, 224], [674, 408, 280, 173] ], 137 | /* 18 */ [ [1725, 1046, 718, 442], [1346, 816, 560, 345], [948, 574, 394, 243], [746, 452, 310, 191] ], 138 | /* 19 */ [ [1903, 1153, 792, 488], [1500, 909, 624, 384], [1063, 644, 442, 272], [813, 493, 338, 208] ], 139 | /* 20 */ [ [2061, 1249, 858, 528], [1600, 970, 666, 410], [1159, 702, 482, 297], [919, 557, 382, 235] ], 140 | /* 21 */ [ [2232, 1352, 929, 572], [1708, 1035, 711, 438], [1224, 742, 509, 314], [969, 587, 403, 248] ], 141 | /* 22 */ [ [2409, 1460, 1003, 618], [1872, 1134, 779, 480], [1358, 823, 565, 348], [1056, 640, 439, 270] ], 142 | /* 23 */ [ [2620, 1588, 1091, 672], [2059, 1248, 857, 528], [1468, 890, 611, 376], [1108, 672, 461, 284] ], 143 | /* 24 */ [ [2812, 1704, 1171, 721], [2188, 1326, 911, 561], [1588, 963, 661, 407], [1228, 744, 511, 315] ], 144 | /* 25 */ [ [3057, 1853, 1273, 784], [2395, 1451, 997, 614], [1718, 1041, 715, 440], [1286, 779, 535, 330] ], 145 | /* 26 */ [ [3283, 1990, 1367, 842], [2544, 1542, 1059, 652], [1804, 1094, 751, 462], [1425, 864, 593, 365] ], 146 | /* 27 */ [ [3517, 2132, 1465, 902], [2701, 1637, 1125, 692], [1933, 1172, 805, 496], [1501, 910, 625, 385] ], 147 | /* 28 */ [ [3669, 2223, 1528, 940], [2857, 1732, 1190, 732], [2085, 1263, 868, 534], [1581, 958, 658, 405] ], 148 | /* 29 */ [ [3909, 2369, 1628, 1002], [3035, 1839, 1264, 778], [2181, 1322, 908, 559], [1677, 1016, 698, 430] ], 149 | /* 30 */ [ [4158, 2520, 1732, 1066], [3289, 1994, 1370, 843], [2358, 1429, 982, 604], [1782, 1080, 742, 457] ], 150 | /* 31 */ [ [4417, 2677, 1840, 1132], [3486, 2113, 1452, 894], [2473, 1499, 1030, 634], [1897, 1150, 790, 486] ], 151 | /* 32 */ [ [4686, 2840, 1952, 1201], [3693, 2238, 1538, 947], [2670, 1618, 1112, 684], [2022, 1226, 842, 518] ], 152 | /* 33 */ [ [4965, 3009, 2068, 1273], [3909, 2369, 1628, 1002], [2805, 1700, 1168, 719], [2157, 1307, 898, 553] ], 153 | /* 34 */ [ [5253, 3183, 2188, 1347], [4134, 2506, 1722, 1060], [2949, 1787, 1228, 756], [2301, 1394, 958, 590] ], 154 | /* 35 */ [ [5529, 3351, 2303, 1417], [4343, 2632, 1809, 1113], [3081, 1867, 1283, 790], [2361, 1431, 983, 605] ], 155 | /* 36 */ [ [5836, 3537, 2431, 1496], [4588, 2780, 1911, 1176], [3244, 1966, 1351, 832], [2524, 1530, 1051, 647] ], 156 | /* 37 */ [ [6153, 3729, 2563, 1577], [4775, 2894, 1989, 1224], [3417, 2071, 1423, 876], [2625, 1591, 1093, 673] ], 157 | /* 38 */ [ [6479, 3927, 2699, 1661], [5039, 3054, 2099, 1292], [3599, 2181, 1499, 923], [2735, 1658, 1139, 701] ], 158 | /* 39 */ [ [6743, 4087, 2809, 1729], [5313, 3220, 2213, 1362], [3791, 2298, 1579, 972], [2927, 1774, 1219, 750] ], 159 | /* 40 */ [ [7089, 4296, 2953, 1817], [5596, 3391, 2331, 1435], [3993, 2420, 1663, 1024], [3057, 1852, 1273, 784] ] 160 | ]; 161 | -------------------------------------------------------------------------------- /js/demo/assets/style.css: -------------------------------------------------------------------------------- 1 | BODY, TH, TD, INPUT, SELECT, TEXTAREA { 2 | font-size: 10pt; 3 | font-family: Verdana, Arial, sans-serif; 4 | } 5 | 6 | H1 { font-size: 18pt; } 7 | H2 { font-size: 14pt; } 8 | H3 { font-size: 12pt; } 9 | H4 { font-size: 10pt; } 10 | H5 { font-size: 9pt; } 11 | H6 { font-size: 8pt; } 12 | 13 | BODY { 14 | color: #333333; 15 | background-color: #ffffff; 16 | } 17 | 18 | DIV.page-header { 19 | margin: 16px 0px 16px 0px; 20 | } 21 | 22 | DIV.page-footer { 23 | margin: 16px 0px 16px 0px; 24 | text-align: right; 25 | } 26 | 27 | DIV.section { 28 | margin: 16px 0px 16px 0px; 29 | } 30 | 31 | #dataCaps TABLE { 32 | border-collapse: collapse; 33 | } 34 | 35 | #dataCaps TABLE, 36 | #dataCaps TABLE TH, 37 | #dataCaps TABLE TD { 38 | margin: 0px; 39 | padding: 0px 4px 0px 4px; 40 | border: 1px solid #000000; 41 | } 42 | -------------------------------------------------------------------------------- /js/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | QR Code Generator 11 | 12 | 13 | 14 | 15 | home 16 | 17 | Fork me on GitHub 18 | 19 | 20 |

QR Code Generator

21 | 22 |
QR Code Generator implementation in JavaScript, Java and more.
23 | 24 |
25 | 26 |
27 | TypeNumber: 28 | 29 | ErrorCorrectionLevel: 30 | 36 | Mode: 37 | 43 | Multibyte: 44 | 49 |
50 | 51 |
52 | 53 |
54 |
55 |

Appendix (data capacity in bytes)

56 |
57 |
58 | 59 |
60 | 67 |
68 | 69 |
70 | 71 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /js/misc/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | qrcode_SJIS.js -------------------------------------------------------------------------------- /js/misc/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /js/misc/src/GenSJISSupport.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.ByteArrayOutputStream; 3 | import java.io.FilterOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.OutputStream; 7 | import java.io.PrintWriter; 8 | import java.util.ArrayList; 9 | import java.util.Collections; 10 | import java.util.Comparator; 11 | import java.util.List; 12 | 13 | /** 14 | * GenSJISSupport 15 | * @author Kazuhiko Arase 16 | */ 17 | public class GenSJISSupport { 18 | 19 | private static final String US_ASCII = "ISO-8859-1"; 20 | 21 | public static void main(String[] args) throws Exception { 22 | new GenSJISSupport().start(); 23 | } 24 | 25 | public void start() throws Exception { 26 | 27 | String templateFile = "qrcode_SJIS.js.tmpl"; 28 | String dstFile = "qrcode_SJIS.js"; 29 | 30 | List codeTable = new ArrayList(); 31 | BufferedReader in = new BufferedReader(new InputStreamReader( 32 | getClass().getResourceAsStream("SJIS.txt"), US_ASCII) ); 33 | try { 34 | String line; 35 | while ( (line = in.readLine() ) != null) { 36 | line = line.trim(); 37 | if (line.length() == 0 || line.startsWith("#") ) { 38 | continue; 39 | } 40 | String[] code = line.split("\\s+"); 41 | if (code.length != 2) { 42 | throw new RuntimeException(line); 43 | } 44 | codeTable.add(new int[]{ 45 | Integer.parseInt(code[0], 16), 46 | Integer.parseInt(code[1], 16) }); 47 | } 48 | } finally { 49 | in.close(); 50 | } 51 | 52 | // JIS X 0201 (191 chars) + JIS X 0208 (6879 chars) 53 | if (codeTable.size() != 7070) { 54 | throw new Exception("!"); 55 | } 56 | 57 | // sort by UTF-16 58 | Collections.sort(codeTable, new Comparator() { 59 | @Override 60 | public int compare(int[] c1, int[] c2) { 61 | return c1[1] < c2[1]? -1 : 1; 62 | } 63 | }); 64 | 65 | ByteArrayOutputStream bout = new ByteArrayOutputStream(); 66 | OutputStream out = new Base64EncodeOutputStream(bout); 67 | try { 68 | for (int[] code : codeTable) { 69 | out.write( (code[1] >>> 8) & 0xff); 70 | out.write(code[1] & 0xff); 71 | out.write( (code[0] >>> 8) & 0xff); 72 | out.write(code[0] & 0xff); 73 | } 74 | } finally { 75 | out.close(); 76 | } 77 | 78 | String sjisEncoded = new String(bout.toByteArray(), US_ASCII). 79 | replace("/", "\\/"); // escape slash 80 | 81 | PrintWriter srcOut = new PrintWriter(dstFile, US_ASCII); 82 | try { 83 | BufferedReader tmplIn = new BufferedReader(new InputStreamReader( 84 | getClass().getResourceAsStream(templateFile), US_ASCII) ); 85 | try { 86 | String line; 87 | while ( (line = tmplIn.readLine() ) != null) { 88 | srcOut.write(line.replace("@DATA@", sjisEncoded). 89 | replace("@NUM_CHARS@", String.valueOf(codeTable.size() ) ) ); 90 | srcOut.write('\n'); 91 | } 92 | } finally { 93 | tmplIn.close(); 94 | } 95 | } finally { 96 | srcOut.close(); 97 | } 98 | } 99 | 100 | protected static class Base64EncodeOutputStream 101 | extends FilterOutputStream { 102 | 103 | private int buffer; 104 | private int buflen; 105 | private int length; 106 | 107 | public Base64EncodeOutputStream(OutputStream out) { 108 | super(out); 109 | this.buffer = 0; 110 | this.buflen = 0; 111 | this.length = 0; 112 | } 113 | 114 | public void write(int n) throws IOException { 115 | 116 | buffer = (buffer << 8) | (n & 0xff); 117 | buflen += 8; 118 | length++; 119 | 120 | while (buflen >= 6) { 121 | writeEncoded(buffer >>> (buflen - 6) ); 122 | buflen -= 6; 123 | } 124 | } 125 | 126 | public void flush() throws IOException { 127 | 128 | if (buflen > 0) { 129 | writeEncoded(buffer << (6 - buflen) ); 130 | buffer = 0; 131 | buflen = 0; 132 | } 133 | 134 | if (length % 3 != 0) { 135 | // padding 136 | int padlen = 3 - length % 3; 137 | for (int i = 0; i < padlen; i++) { 138 | super.write('='); 139 | } 140 | } 141 | 142 | super.flush(); 143 | } 144 | 145 | private void writeEncoded(int b) throws IOException { 146 | super.write(encode(b & 0x3f) ); 147 | } 148 | 149 | private static int encode(int n) { 150 | if (n < 0) { 151 | // error. 152 | } else if (n < 26) { 153 | return 'A' + n; 154 | } else if (n < 52) { 155 | return 'a' + (n - 26); 156 | } else if (n < 62) { 157 | return '0' + (n - 52); 158 | } else if (n == 62) { 159 | return '+'; 160 | } else if (n == 63) { 161 | return '/'; 162 | } 163 | throw new IllegalArgumentException("n:" + n); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /js/misc/src/qrcode_SJIS.js.tmpl: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // 3 | // QR Code Generator for JavaScript SJIS Support (optional) 4 | // 5 | // Copyright (c) 2011 Kazuhiko Arase 6 | // 7 | // URL: http://www.d-project.com/ 8 | // 9 | // Licensed under the MIT license: 10 | // http://www.opensource.org/licenses/mit-license.php 11 | // 12 | // The word 'QR Code' is registered trademark of 13 | // DENSO WAVE INCORPORATED 14 | // http://www.denso-wave.com/qrcode/faqpatent-e.html 15 | // 16 | //--------------------------------------------------------------------- 17 | 18 | !function(qrcode) { 19 | 20 | //--------------------------------------------------------------------- 21 | // overwrite qrcode.stringToBytes 22 | //--------------------------------------------------------------------- 23 | 24 | qrcode.stringToBytesFuncs['SJIS'] = qrcode.createStringToBytes( 25 | '@DATA@', 26 | @NUM_CHARS@ 27 | ); 28 | qrcode.stringToBytes = qrcode.stringToBytesFuncs['SJIS']; 29 | 30 | }(qrcode); 31 | -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qrcode-generator", 3 | "version": "1.4.4", 4 | "description": "QR Code Generator implementation in JavaScript.", 5 | "author": "Kazuhiko Arase", 6 | "main": "qrcode.js", 7 | "types": "qrcode.d.ts", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/kazuhikoarase/qrcode-generator.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/kazuhikoarase/qrcode-generator/issues" 14 | }, 15 | "keywords": [ 16 | "qr", 17 | "qrcode", 18 | "generator" 19 | ], 20 | "license": "MIT", 21 | "directories": { 22 | "test": "test" 23 | }, 24 | "scripts": { 25 | "test": "mocha" 26 | }, 27 | "devDependencies": { 28 | "mocha": "^5.2.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /js/qrcode.d.ts: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // 3 | // QR Code Generator for JavaScript - TypeScript Declaration File 4 | // 5 | // Copyright (c) 2016 Kazuhiko Arase 6 | // 7 | // URL: http://www.d-project.com/ 8 | // 9 | // Licensed under the MIT license: 10 | // http://www.opensource.org/licenses/mit-license.php 11 | // 12 | // The word 'QR Code' is registered trademark of 13 | // DENSO WAVE INCORPORATED 14 | // http://www.denso-wave.com/qrcode/faqpatent-e.html 15 | // 16 | //--------------------------------------------------------------------- 17 | 18 | type TypeNumber = 19 | | 0 // Automatic type number 20 | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 21 | | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 22 | | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 23 | | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 24 | ; 25 | 26 | type ErrorCorrectionLevel = 'L' | 'M' | 'Q' | 'H'; 27 | 28 | type Mode = 'Numeric' | 'Alphanumeric' | 'Byte' /* Default */ | 'Kanji'; 29 | 30 | interface QRCodeFactory { 31 | (typeNumber: TypeNumber, errorCorrectionLevel: ErrorCorrectionLevel) : QRCode; 32 | stringToBytes(s: string) : number[]; 33 | stringToBytesFuncs : { [encoding : string] : (s: string) => number[] }; 34 | createStringToBytes(unicodeData: string, numChars: number) : 35 | (s : string) => number[]; 36 | } 37 | 38 | interface QRCode { 39 | addData(data: string, mode?: Mode) : void; 40 | make() : void; 41 | getModuleCount() : number; 42 | isDark(row: number, col: number) : boolean; 43 | createImgTag(cellSize?: number, margin?: number) : string; 44 | createSvgTag(cellSize?: number, margin?: number) : string; 45 | createSvgTag(opts? : { cellSize?: number, margin?: number, 46 | scalable?: boolean }) : string; 47 | createDataURL(cellSize?: number, margin?: number) : string; 48 | createTableTag(cellSize?: number, margin?: number) : string; 49 | createASCII(cellSize?: number, margin?: number) : string; 50 | renderTo2dContext(context: CanvasRenderingContext2D, cellSize?: number): void; 51 | } 52 | 53 | declare var qrcode : QRCodeFactory; 54 | 55 | declare module 'qrcode-generator' { 56 | export = qrcode; 57 | } 58 | -------------------------------------------------------------------------------- /js/qrcode_UTF8.js: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // 3 | // QR Code Generator for JavaScript UTF8 Support (optional) 4 | // 5 | // Copyright (c) 2011 Kazuhiko Arase 6 | // 7 | // URL: http://www.d-project.com/ 8 | // 9 | // Licensed under the MIT license: 10 | // http://www.opensource.org/licenses/mit-license.php 11 | // 12 | // The word 'QR Code' is registered trademark of 13 | // DENSO WAVE INCORPORATED 14 | // http://www.denso-wave.com/qrcode/faqpatent-e.html 15 | // 16 | //--------------------------------------------------------------------- 17 | 18 | !function(qrcode) { 19 | 20 | //--------------------------------------------------------------------- 21 | // overwrite qrcode.stringToBytes 22 | //--------------------------------------------------------------------- 23 | 24 | qrcode.stringToBytes = qrcode.stringToBytesFuncs['UTF-8']; 25 | 26 | }(qrcode); 27 | -------------------------------------------------------------------------------- /js/sample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 15 | 16 | QR Code Generator for JavaScript 17 | 18 | 19 |
20 | TypeNumber: 21 | 22 | ErrorCorrectionLevel: 23 | 29 | Mode: 30 | 36 | Multibyte: 37 | 42 |
43 | 44 |
45 | 46 |
47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /js/sample.js: -------------------------------------------------------------------------------- 1 | 2 | var body_loadHander = function() { 3 | 4 | var crtOpt = function(value, label) { 5 | var opt = document.createElement('option'); 6 | opt.appendChild(document.createTextNode(label) ); 7 | opt.value = value; 8 | return opt; 9 | }; 10 | 11 | var t = document.forms['qrForm'].elements['t']; 12 | t.appendChild(crtOpt('' + 0, 'Auto Detect') ); 13 | for (var i = 1; i <= 40; i += 1) { 14 | t.appendChild(crtOpt('' + i, '' + i) ); 15 | } 16 | t.value = '0'; 17 | 18 | update_qrcode(); 19 | }; 20 | 21 | var draw_qrcode = function(text, typeNumber, errorCorrectionLevel) { 22 | document.write(create_qrcode(text, typeNumber, errorCorrectionLevel) ); 23 | }; 24 | 25 | var create_qrcode = function(text, typeNumber, 26 | errorCorrectionLevel, mode, mb) { 27 | 28 | qrcode.stringToBytes = qrcode.stringToBytesFuncs[mb]; 29 | 30 | var qr = qrcode(typeNumber || 4, errorCorrectionLevel || 'M'); 31 | qr.addData(text, mode); 32 | qr.make(); 33 | 34 | // return qr.createTableTag(); 35 | // return qr.createSvgTag(); 36 | return qr.createImgTag(); 37 | }; 38 | 39 | var update_qrcode = function() { 40 | var form = document.forms['qrForm']; 41 | var text = form.elements['msg'].value. 42 | replace(/^[\s\u3000]+|[\s\u3000]+$/g, ''); 43 | var t = form.elements['t'].value; 44 | var e = form.elements['e'].value; 45 | var m = form.elements['m'].value; 46 | var mb = form.elements['mb'].value; 47 | document.getElementById('qr').innerHTML = 48 | create_qrcode(text, t, e, m, mb); 49 | }; 50 | -------------------------------------------------------------------------------- /js/test/qrcode.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var qrcode = require('../qrcode.js'); 3 | 4 | describe('QRCode', function(){ 5 | it('should exist', function(){ 6 | assert.ok(qrcode); 7 | }); 8 | 9 | it('should be a callable function', function(){ 10 | assert.ok(qrcode instanceof Function); 11 | }); 12 | 13 | it('should generate correct GIF image tag', function(){ 14 | var sourceText = 'http://www.example.com/ążśźęćńół'; 15 | var correctImgTag = ''; 16 | 17 | var qr = qrcode(-1, 'M'); 18 | qr.addData(unescape(encodeURI(sourceText))); 19 | qr.make(); 20 | 21 | assert.strictEqual(qr.createImgTag(), correctImgTag); 22 | }); 23 | 24 | it('should generate correct GIF image data', function(){ 25 | var sourceText = 'http://www.example.com/ążśźęćńół'; 26 | var correctImgData = 'R0lGODdhSgBKAIAAAAAAAP///ywAAAAASgBKAAAC/4yPqcvtD6OctNqLs968+w+G4kiWZgKk6roa7ZEiccACco1TeE6r9997uXYsna0xmw0VLyXsyHBCpKijk9qEPh1UrrXYAy4Xu3FtLEmCr9pucP3NGofyN9peBZ7DE3W9Tqd15+fDlxZXiPVlltiGqDb3BpnHRzj4uNgnSHkjZCiZGbXpRVrlyQZINopE9Jc5CdtaeCj7asvIWEvimet4oqkYKDZiCSrMWtobmcW8esfki2exN4XY2cj7aZQtehxIGHwR+41dDg3tdogLCm7N+ZTOOom+irqZGk//DF/vqDiv7cEpTMW4CZxVYSC5gghpOTt46dg4PGxE5aNUkeItje3Drm3zh9DewIytPl7LuBCkHiImpbEjaAvlloTm+DVzJXNftZM89lAz5vLiOZs94YysqZNmtZ8/vQiFeJApmKUPu30qU6mhKola1V0t6g2ZxqcaAK4biraE2axW004LyeNs1loGHfIkGY3uVLV7Ge4rSayvu7WAHQIGGMvn4KqqdLGd2S5xKE2lit2dfIlswJVhU/5VSRmoyEbr9NbdKhqkq156l8GJCFQZ0aRWFcOWGtZ2aN2IN3LlvPv149Kg8UZqi5ElP+JvkyXH+ns4MFnR/+0F/vEw6YDQk//6Dj68+PHky5s/jz69+vULCgAAOw=='; 27 | 28 | var qr = qrcode(-1, 'M'); 29 | qr.addData(unescape(encodeURI(sourceText))); 30 | qr.make(); 31 | 32 | var data = Buffer.from(qr.createDataURL().replace('data:image/gif;base64,', ''), 'base64'); 33 | 34 | assert.strictEqual(data.toString('base64'), correctImgData); 35 | }); 36 | 37 | it('should generate correct UTF8 text data', function(){ 38 | var sourceText = 'http://www.example.com/ążśźęćńół'; 39 | var correctTextData1 = [ 40 | '█████████████████████████████████', 41 | '██ ▄▄▄▄▄ █ ▄█▀▄██ ▀▄ ▄██ ▄▄▄▄▄ ██', 42 | '██ █ █ █▀ █▀▄█▀▀█▄▄ ▄█ █ █ ██', 43 | '██ █▄▄▄█ ███ ▀ █▄▀▄▄▀ ▀█ █▄▄▄█ ██', 44 | '██▄▄▄▄▄▄▄█ ▀▄█▄▀▄▀ █▄▀▄█▄▄▄▄▄▄▄██', 45 | '██▄█ ▀▄▄▄█▄▄█▀█▀▀▄█▀▀▀█ ▀▀▄█▄ ██', 46 | '██▀▀▄▀▄█▄█ ▄▄█▄ ▄█ ███ ▀█▀▄▄▀██', 47 | '██ ▄▀█▄▀▄ ▄▀▄ █ ▄▀▀█▀██▀██▄▄▀▀██', 48 | '██ █▀ ▄▄▀▀ ▀█ █▀▄ ▀█▄▀▄▄▄ ▄██', 49 | '██▄██ ▄▄▄▄▄█ ▀▄▄ ▀▀▄▄▄█▄▄█▀ ███', 50 | '██▄█▄██▄▄▄ █ █▄▄▀█▀███▄▀▄▄█▄ ████', 51 | '███▄▄██▄▄▄ ▀▀▄█ █▀ █ ▄ ▄▄▄ ▀▀██', 52 | '██ ▄▄▄▄▄ █ █ ▀█▄█ ▀ ▄ █▄█ ▄█ ▀██', 53 | '██ █ █ █▀▄▄ ▄▀ ▀▄█ █ ▄▄ ▄ ██', 54 | '██ █▄▄▄█ █▄█▄▀█ ▀ ▀ ██ █ █▀▄▀▄██', 55 | '██▄▄▄▄▄▄▄█▄▄█▄█▄███▄▄▄▄████▄█▄███', 56 | '▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀'].join('\n'); 57 | 58 | var correctTextData2 = [ 59 | ' ▄▄▄▄▄ █ ▄█▀▄██ ▀▄ ▄██ ▄▄▄▄▄ ', 60 | ' █ █ █▀ █▀▄█▀▀█▄▄ ▄█ █ █ ', 61 | ' █▄▄▄█ ███ ▀ █▄▀▄▄▀ ▀█ █▄▄▄█ ', 62 | '▄▄▄▄▄▄▄█ ▀▄█▄▀▄▀ █▄▀▄█▄▄▄▄▄▄▄', 63 | '▄█ ▀▄▄▄█▄▄█▀█▀▀▄█▀▀▀█ ▀▀▄█▄ ', 64 | '▀▀▄▀▄█▄█ ▄▄█▄ ▄█ ███ ▀█▀▄▄▀', 65 | ' ▄▀█▄▀▄ ▄▀▄ █ ▄▀▀█▀██▀██▄▄▀▀', 66 | ' █▀ ▄▄▀▀ ▀█ █▀▄ ▀█▄▀▄▄▄ ▄', 67 | '▄██ ▄▄▄▄▄█ ▀▄▄ ▀▀▄▄▄█▄▄█▀ █', 68 | '▄█▄██▄▄▄ █ █▄▄▀█▀███▄▀▄▄█▄ ██', 69 | '█▄▄██▄▄▄ ▀▀▄█ █▀ █ ▄ ▄▄▄ ▀▀', 70 | ' ▄▄▄▄▄ █ █ ▀█▄█ ▀ ▄ █▄█ ▄█ ▀', 71 | ' █ █ █▀▄▄ ▄▀ ▀▄█ █ ▄▄ ▄ ', 72 | ' █▄▄▄█ █▄█▄▀█ ▀ ▀ ██ █ █▀▄▀▄', 73 | ' ▀ ▀ ▀ ▀▀▀ ▀▀▀▀ ▀ ▀'].join('\n'); 74 | 75 | var correctTextData3 = [ 76 | '██████████████████████████████████████████████████████████████████', 77 | '██████████████████████████████████████████████████████████████████', 78 | '████ ██ ████ ████ ██ ████ ████', 79 | '████ ██████████ ██ ████ ██████ ██ ██████ ██████████ ████', 80 | '████ ██ ██ ████ ████ ████████ ██ ██ ██ ████', 81 | '████ ██ ██ ██ ██ ████ ██████ ████ ██ ██ ████', 82 | '████ ██ ██ ██████ ██ ██ ██ ██ ████ ██ ██ ████', 83 | '████ ██████████ ██████ ████ ████ ██ ██████████ ████', 84 | '████ ██ ██ ██ ██ ██ ██ ██ ██ ████', 85 | '████████████████████ ██████ ██ ████ ██████████████████████', 86 | '████ ██ ██ ██ ██████████ ██████████ ████ ██ ████', 87 | '████████ ██████████████ ██ ████ ██ ██████ ████', 88 | '████████ ██ ██ ██ ██ ██ ██████ ██████ ██████', 89 | '████ ██ ████████ ████████ ████ ██████ ██ ████ ████', 90 | '████ ████ ██ ██ ██ ██████████████████ ████████', 91 | '████ ██ ████ ██ ██ ██ ██ ██ ██ ████ ████████ ████', 92 | '████ ████ ████ ████ ████ ████ ██ ████', 93 | '████ ██ ████ ██ ██ ██ ████ ██████ ██████', 94 | '████ ████ ██ ██ ████ ██ ████ ██████', 95 | '██████████ ████████████ ████ ██████████████ ██████', 96 | '████ ██ ████ ██ ██ ████████████ ██ ██ ████████', 97 | '████████████████████ ██ ██████ ██ ████████ ████████ ████████', 98 | '██████ ████ ████ ██ ████ ██ ████████', 99 | '████████████████████ ████ ██ ██ ██ ██████ ████', 100 | '████ ██ ██ ████ ██ ██ ██ ██ ██ ██████', 101 | '████ ██████████ ██ ██ ██████ ██ ██████ ████ ████', 102 | '████ ██ ██ ████ ██ ██ ██ ██ ████', 103 | '████ ██ ██ ██ ████ ██ ████ ██ ████ ██ ████', 104 | '████ ██ ██ ██ ██ ████ ██ ██ ████ ██ ████ ██ ████', 105 | '████ ██████████ ████████ ██ ████ ██ ██ ██ ██████', 106 | '████ ██ ██ ██ ██████ ████████ ██ ██████', 107 | '██████████████████████████████████████████████████████████████████', 108 | '██████████████████████████████████████████████████████████████████',].join('\n'); 109 | 110 | var qr = qrcode(-1, 'M'); 111 | qr.addData(unescape(encodeURI(sourceText))); 112 | qr.make(); 113 | 114 | assert.strictEqual(qr.createASCII(), correctTextData1, 'ASCII QRCode of size 1 is incorrect'); 115 | assert.strictEqual(qr.createASCII(1, 0), correctTextData2, 'ASCII QRCode of size 1 without margin is incorrect'); 116 | assert.strictEqual(qr.createASCII(2), correctTextData3, 'ASCII QRCode of size 2 is incorrect'); 117 | }); 118 | }); -------------------------------------------------------------------------------- /js/ts-test/.gitignore: -------------------------------------------------------------------------------- 1 | /.tscache 2 | /build 3 | /dist 4 | /node_modules 5 | -------------------------------------------------------------------------------- /js/ts-test/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | src: 'src', 6 | build: 'build', 7 | dist: 'dist', 8 | ts: { 9 | main: { 10 | options : { sourceMap: false }, 11 | src: ['<%= src %>/**/*.ts'], 12 | outDir: '<%= build %>' 13 | } 14 | }, 15 | nodeunit: { 16 | all: [ '<%= build %>/*_test.js' ], 17 | options: { 18 | reporter: 'default', 19 | reporterOptions: { 20 | output: 'dist' 21 | } 22 | } 23 | }, 24 | clean: { 25 | build : { src: ['<%= build %>', '.tscache'] }, 26 | dist : { src: ['<%= dist %>'] } 27 | } 28 | }); 29 | 30 | grunt.loadNpmTasks('grunt-contrib-clean'); 31 | grunt.loadNpmTasks('grunt-contrib-nodeunit'); 32 | grunt.loadNpmTasks("grunt-ts"); 33 | 34 | grunt.registerTask('default', ['ts']); 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /js/ts-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-test", 3 | "version": "0.1.0", 4 | "devDependencies": { 5 | "grunt": "^1.0.0", 6 | "grunt-contrib-clean": "^1.0.0", 7 | "grunt-contrib-nodeunit": "^1.0.0", 8 | "grunt-ts": "^6.0.0-beta.3", 9 | "typescript": "^2.0.0", 10 | "uglify": "^0.1.5", 11 | "qrcode-generator": "file:../" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /js/ts-test/src/.gitignore: -------------------------------------------------------------------------------- 1 | /.baseDir.ts 2 | -------------------------------------------------------------------------------- /js/ts-test/src/import_test.ts: -------------------------------------------------------------------------------- 1 | declare var require: any; 2 | declare var exports : any; 3 | 4 | import * as imported from 'qrcode-generator'; 5 | 6 | exports.requireAndImport = function(test : any) { 7 | 8 | var testQR = function(qrcode : any) { 9 | test.equal(typeof qrcode, 'function'); 10 | test.equal(typeof qrcode.stringToBytes, 'function'); 11 | }; 12 | 13 | var required = require('qrcode-generator'); 14 | testQR(required); 15 | testQR(imported); 16 | test.done(); 17 | }; 18 | -------------------------------------------------------------------------------- /php/sample.html: -------------------------------------------------------------------------------- 1 | sample_html.php 2 |
3 | sample_image.php 4 |
5 | sample_custom.php 6 | -------------------------------------------------------------------------------- /php/sample_custom.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kazuhikoarase/qrcode-generator/0e51e6310a34b5e4f70280533b3d43e1fc6a0b16/php/sample_custom.php -------------------------------------------------------------------------------- /php/sample_html.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kazuhikoarase/qrcode-generator/0e51e6310a34b5e4f70280533b3d43e1fc6a0b16/php/sample_html.php -------------------------------------------------------------------------------- /php/sample_image.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kazuhikoarase/qrcode-generator/0e51e6310a34b5e4f70280533b3d43e1fc6a0b16/php/sample_image.php -------------------------------------------------------------------------------- /ts/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/image/GIFImage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 'use strict'; 5 | namespace com.d_project.image { 6 | 7 | import OutputStream = com.d_project.io.OutputStream; 8 | import ByteArrayOutputStream = com.d_project.io.ByteArrayOutputStream; 9 | import Base64 = com.d_project.io.Base64; 10 | 11 | /** 12 | * GIF Image (B/W) 13 | * @author Kazuhiko Arase 14 | */ 15 | export class GIFImage { 16 | 17 | private width : number; 18 | private height : number; 19 | private data : number[]; 20 | 21 | constructor(width : number, height : number) { 22 | this.width = width; 23 | this.height = height; 24 | var size = width * height; 25 | this.data = []; 26 | for (var i = 0; i < size; i += 1) { 27 | this.data.push(0); 28 | } 29 | } 30 | 31 | public setPixel(x : number, y : number, pixel : number) : void { 32 | if (x < 0 || this.width <= x) throw '!' + x; 33 | if (y < 0 || this.height <= y) throw '!' + y; 34 | this.data[y * this.width + x] = pixel; 35 | } 36 | 37 | public getPixel(x : number, y : number) : number { 38 | if (x < 0 || this.width <= x) throw '!' + x; 39 | if (y < 0 || this.height <= y) throw '!' + y; 40 | return this.data[y * this.width + x]; 41 | } 42 | 43 | public write(out : OutputStream) : void { 44 | 45 | //--------------------------------- 46 | // GIF Signature 47 | 48 | out.writeByte('G'.charCodeAt(0) ); 49 | out.writeByte('I'.charCodeAt(0) ); 50 | out.writeByte('F'.charCodeAt(0) ); 51 | out.writeByte('8'.charCodeAt(0) ); 52 | out.writeByte('7'.charCodeAt(0) ); 53 | out.writeByte('a'.charCodeAt(0) ); 54 | 55 | //--------------------------------- 56 | // Screen Descriptor 57 | 58 | this.writeWord(out, this.width); 59 | this.writeWord(out, this.height); 60 | 61 | out.writeByte(0x80); // 2bit 62 | out.writeByte(0); 63 | out.writeByte(0); 64 | 65 | //--------------------------------- 66 | // Global Color Map 67 | 68 | // black 69 | out.writeByte(0x00); 70 | out.writeByte(0x00); 71 | out.writeByte(0x00); 72 | 73 | // white 74 | out.writeByte(0xff); 75 | out.writeByte(0xff); 76 | out.writeByte(0xff); 77 | 78 | //--------------------------------- 79 | // Image Descriptor 80 | 81 | out.writeByte(','.charCodeAt(0) ); 82 | this.writeWord(out, 0); 83 | this.writeWord(out, 0); 84 | this.writeWord(out, this.width); 85 | this.writeWord(out, this.height); 86 | out.writeByte(0); 87 | 88 | //--------------------------------- 89 | // Local Color Map 90 | 91 | //--------------------------------- 92 | // Raster Data 93 | 94 | var lzwMinCodeSize = 2; 95 | var raster = this.getLZWRaster(lzwMinCodeSize); 96 | 97 | out.writeByte(lzwMinCodeSize); 98 | 99 | var offset : number = 0; 100 | 101 | while (raster.length - offset > 255) { 102 | out.writeByte(255); 103 | this.writeBytes(out, raster, offset, 255); 104 | offset += 255; 105 | } 106 | 107 | out.writeByte(raster.length - offset); 108 | this.writeBytes(out, raster, offset, raster.length - offset); 109 | out.writeByte(0x00); 110 | 111 | //--------------------------------- 112 | // GIF Terminator 113 | out.writeByte(';'.charCodeAt(0) ); 114 | } 115 | 116 | private getLZWRaster(lzwMinCodeSize : number) : number[] { 117 | 118 | var clearCode = 1 << lzwMinCodeSize; 119 | var endCode = (1 << lzwMinCodeSize) + 1; 120 | var bitLength = lzwMinCodeSize + 1; 121 | 122 | // Setup LZWTable 123 | var table = new LZWTable(); 124 | 125 | for (var i = 0; i < clearCode; i += 1) { 126 | table.add(String.fromCharCode(i) ); 127 | } 128 | table.add(String.fromCharCode(clearCode) ); 129 | table.add(String.fromCharCode(endCode) ); 130 | 131 | var byteOut = new ByteArrayOutputStream(); 132 | var bitOut = new BitOutputStream(byteOut); 133 | 134 | try { 135 | 136 | // clear code 137 | bitOut.write(clearCode, bitLength); 138 | 139 | var dataIndex = 0; 140 | var s = String.fromCharCode(this.data[dataIndex]); 141 | dataIndex += 1; 142 | 143 | while (dataIndex < this.data.length) { 144 | var c = String.fromCharCode(this.data[dataIndex]); 145 | dataIndex += 1; 146 | if (table.contains(s + c) ) { 147 | s = s + c; 148 | } else { 149 | bitOut.write(table.indexOf(s), bitLength); 150 | if (table.getSize() < 0xfff) { 151 | if (table.getSize() == (1 << bitLength) ) { 152 | bitLength += 1; 153 | } 154 | table.add(s + c); 155 | } 156 | s = c; 157 | } 158 | } 159 | 160 | bitOut.write(table.indexOf(s), bitLength); 161 | 162 | // end code 163 | bitOut.write(endCode, bitLength); 164 | 165 | } finally { 166 | bitOut.close(); 167 | } 168 | 169 | return byteOut.toByteArray(); 170 | } 171 | 172 | private writeWord(out : OutputStream, i : number) { 173 | out.writeByte(i & 0xff); 174 | out.writeByte( (i >>> 8) & 0xff); 175 | } 176 | 177 | private writeBytes( 178 | out : OutputStream, 179 | bytes : number[], off : number, len : number 180 | ) { 181 | for (var i = 0; i < len; i += 1) { 182 | out.writeByte(bytes[i + off]); 183 | } 184 | } 185 | 186 | public toDataURL() : string { 187 | var bout = new ByteArrayOutputStream(); 188 | this.write(bout); 189 | bout.close(); 190 | var s = ''; 191 | var bytes = Base64.encode(bout.toByteArray() ); 192 | for (var i = 0; i < bytes.length; i += 1) { 193 | s += String.fromCharCode(bytes[i]); 194 | } 195 | return 'data:image/gif;base64,' + s; 196 | } 197 | } 198 | 199 | class LZWTable { 200 | 201 | private map : { [key : string] : number; } = {}; 202 | private size : number = 0; 203 | 204 | constructor() { 205 | } 206 | 207 | public add(key : string) : void { 208 | if (this.contains(key) ) { 209 | throw 'dup key:' + key; 210 | } 211 | this.map[key] = this.size; 212 | this.size += 1; 213 | } 214 | 215 | public getSize() : number { 216 | return this.size; 217 | } 218 | 219 | public indexOf(key : string) : number { 220 | return this.map[key]; 221 | } 222 | 223 | public contains(key : string) : boolean { 224 | return typeof this.map[key] != 'undefined'; 225 | } 226 | } 227 | 228 | class BitOutputStream { 229 | 230 | private out : OutputStream; 231 | private bitLength : number; 232 | private bitBuffer : number; 233 | 234 | constructor(out : OutputStream) { 235 | this.out = out; 236 | this.bitLength = 0; 237 | } 238 | 239 | public write(data : number, length : number) : void { 240 | 241 | if ( (data >>> length) != 0) { 242 | throw 'length over'; 243 | } 244 | 245 | while (this.bitLength + length >= 8) { 246 | this.out.writeByte(0xff & 247 | ( (data << this.bitLength) | this.bitBuffer) ); 248 | length -= (8 - this.bitLength); 249 | data >>>= (8 - this.bitLength); 250 | this.bitBuffer = 0; 251 | this.bitLength = 0; 252 | } 253 | 254 | this.bitBuffer = (data << this.bitLength) | this.bitBuffer; 255 | this.bitLength = this.bitLength + length; 256 | } 257 | 258 | public flush() : void { 259 | if (this.bitLength > 0) { 260 | this.out.writeByte(this.bitBuffer); 261 | } 262 | this.out.flush(); 263 | } 264 | 265 | public close() : void { 266 | this.flush(); 267 | this.out.close(); 268 | } 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/io/Base64.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.io { 3 | 4 | /** 5 | * Base64 6 | * @author Kazuhiko Arase 7 | */ 8 | export class Base64 { 9 | 10 | constructor() { 11 | throw 'error'; 12 | } 13 | 14 | public static encode(data : number[]) : number[] { 15 | var bout = new ByteArrayOutputStream(); 16 | try { 17 | var ostream = new Base64EncodeOutputStream(bout); 18 | try { 19 | ostream.writeBytes(data); 20 | } finally { 21 | ostream.close(); 22 | } 23 | } finally { 24 | bout.close(); 25 | } 26 | return bout.toByteArray(); 27 | } 28 | 29 | public static decode(data : number[]) : number[] { 30 | var bout = new ByteArrayOutputStream(); 31 | try { 32 | var istream = new Base64DecodeInputStream( 33 | new ByteArrayInputStream(data) ); 34 | try { 35 | var b : number; 36 | while ( (b = istream.readByte() ) != -1) { 37 | bout.writeByte(b); 38 | } 39 | } finally { 40 | istream.close(); 41 | } 42 | } finally { 43 | bout.close(); 44 | } 45 | return bout.toByteArray(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/io/Base64DecodeInputStream.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace com.d_project.io { 4 | 5 | /** 6 | * Base64DecodeInputStream 7 | * @author Kazuhiko Arase 8 | */ 9 | export class Base64DecodeInputStream extends InputStream { 10 | 11 | private buffer = 0; 12 | private buflen = 0; 13 | 14 | constructor(private istream : InputStream) { 15 | super(); 16 | } 17 | 18 | public readByte() : number { 19 | 20 | while (this.buflen < 8) { 21 | 22 | var c = this.istream.readByte(); 23 | 24 | if (c == -1) { 25 | 26 | if (this.buflen == 0) { 27 | return -1; 28 | } 29 | 30 | throw 'unexpected end of file./' + this.buflen; 31 | 32 | } else if (c == '='.charCodeAt(0) ) { 33 | 34 | this.buflen = 0; 35 | return -1; 36 | 37 | } else if (Base64DecodeInputStream.isWhitespace(c) ) { 38 | // ignore if whitespace. 39 | continue; 40 | } 41 | 42 | this.buffer = (this.buffer << 6) | 43 | Base64DecodeInputStream.decode(c); 44 | this.buflen += 6; 45 | } 46 | 47 | var n = (this.buffer >>> (this.buflen - 8) ) & 0xff; 48 | this.buflen -= 8; 49 | return n; 50 | } 51 | 52 | private static isWhitespace(c : number) : boolean { 53 | return c == '\v'.charCodeAt(0) || 54 | c == '\t'.charCodeAt(0) || 55 | c == '\r'.charCodeAt(0) || 56 | c == '\n'.charCodeAt(0); 57 | } 58 | 59 | private static decode(c : number) : number { 60 | if ('A'.charCodeAt(0) <= c && c <= 'Z'.charCodeAt(0) ) { 61 | return c - 'A'.charCodeAt(0); 62 | } else if ('a'.charCodeAt(0) <= c && c <= 'z'.charCodeAt(0) ) { 63 | return c - 'a'.charCodeAt(0) + 26; 64 | } else if ('0'.charCodeAt(0) <= c && c <= '9'.charCodeAt(0) ) { 65 | return c - '0'.charCodeAt(0) + 52; 66 | } else if (c == '+'.charCodeAt(0) ) { 67 | return 62; 68 | } else if (c == '/'.charCodeAt(0) ) { 69 | return 63; 70 | } else { 71 | throw 'c:' + c; 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/io/Base64EncodeOutputStream.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace com.d_project.io { 4 | 5 | /** 6 | * Base64EncodeOutputStream 7 | * @author Kazuhiko Arase 8 | */ 9 | export class Base64EncodeOutputStream extends OutputStream { 10 | 11 | private buffer = 0; 12 | private buflen = 0; 13 | private length = 0; 14 | 15 | constructor(private ostream : OutputStream) { 16 | super(); 17 | } 18 | 19 | public writeByte(n : number) : void { 20 | 21 | this.buffer = (this.buffer << 8) | (n & 0xff); 22 | this.buflen += 8; 23 | this.length += 1; 24 | 25 | while (this.buflen >= 6) { 26 | this.writeEncoded(this.buffer >>> (this.buflen - 6) ); 27 | this.buflen -= 6; 28 | } 29 | } 30 | 31 | public flush() : void { 32 | if (this.buflen > 0) { 33 | this.writeEncoded(this.buffer << (6 - this.buflen) ); 34 | this.buffer = 0; 35 | this.buflen = 0; 36 | } 37 | 38 | if (this.length % 3 != 0) { 39 | // padding 40 | var padlen = 3 - this.length % 3; 41 | for (var i = 0; i < padlen; i += 1) { 42 | this.ostream.writeByte('='.charCodeAt(0) ); 43 | } 44 | } 45 | } 46 | 47 | private writeEncoded(b : number) : void { 48 | this.ostream.writeByte(Base64EncodeOutputStream.encode(b & 0x3f) ); 49 | } 50 | 51 | private static encode(n : number) : number { 52 | if (n < 0) { 53 | // error. 54 | } else if (n < 26) { 55 | return 'A'.charCodeAt(0) + n; 56 | } else if (n < 52) { 57 | return 'a'.charCodeAt(0) + (n - 26); 58 | } else if (n < 62) { 59 | return '0'.charCodeAt(0) + (n - 52); 60 | } else if (n == 62) { 61 | return '+'.charCodeAt(0); 62 | } else if (n == 63) { 63 | return '/'.charCodeAt(0); 64 | } 65 | throw 'n:' + n; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/io/ByteArrayInputStream.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace com.d_project.io { 4 | 5 | /** 6 | * ByteArrayInputStream 7 | * @author Kazuhiko Arase 8 | */ 9 | export class ByteArrayInputStream extends InputStream { 10 | 11 | private pos = 0; 12 | 13 | constructor(private bytes : number[]) { 14 | super(); 15 | } 16 | 17 | public readByte() : number { 18 | if (this.pos < this.bytes.length) { 19 | var b = this.bytes[this.pos]; 20 | this.pos += 1; 21 | return b; 22 | } 23 | return -1; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/io/ByteArrayOutputStream.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace com.d_project.io { 4 | 5 | /** 6 | * ByteArrayOutputStream 7 | * @author Kazuhiko Arase 8 | */ 9 | export class ByteArrayOutputStream extends OutputStream { 10 | 11 | private bytes : number[] = []; 12 | 13 | constructor() { 14 | super(); 15 | } 16 | 17 | public writeByte(b : number) : void { 18 | this.bytes.push(b); 19 | } 20 | 21 | public toByteArray() : number[] { 22 | return this.bytes; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/io/InputStream.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.io { 3 | 4 | /** 5 | * InputStream 6 | * @author Kazuhiko Arase 7 | */ 8 | export abstract class InputStream { 9 | constructor() {} 10 | public abstract readByte() : number; 11 | public close() : void { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/io/OutputStream.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.io { 3 | 4 | /** 5 | * OutputStream 6 | * @author Kazuhiko Arase 7 | */ 8 | export abstract class OutputStream { 9 | constructor() {} 10 | public abstract writeByte(b : number) : void; 11 | public writeBytes(bytes : number[]) : void { 12 | for (var i = 0; i < bytes.length; i += 1) { 13 | this.writeByte(bytes[i]); 14 | } 15 | } 16 | public flush() : void { 17 | } 18 | public close() : void { 19 | this.flush(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/BitBuffer.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * BitBuffer 6 | * @author Kazuhiko Arase 7 | */ 8 | export class BitBuffer { 9 | 10 | private buffer : number[]; 11 | private length : number; 12 | 13 | public constructor() { 14 | this.buffer = []; 15 | this.length = 0; 16 | } 17 | 18 | public getBuffer() : number[] { 19 | return this.buffer; 20 | } 21 | 22 | public getLengthInBits() : number { 23 | return this.length; 24 | } 25 | 26 | public toString() : string { 27 | var buffer = ''; 28 | for (var i = 0; i < this.getLengthInBits(); i += 1) { 29 | buffer += this.getBit(i)? '1' : '0'; 30 | } 31 | return buffer; 32 | } 33 | 34 | private getBit(index : number) : boolean { 35 | return ( (this.buffer[~~(index / 8)] >>> (7 - index % 8) ) & 1) == 1; 36 | } 37 | 38 | public put(num : number, length : number) : void { 39 | for (var i = 0; i < length; i += 1) { 40 | this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1); 41 | } 42 | } 43 | 44 | public putBit(bit : boolean) : void { 45 | if (this.length == this.buffer.length * 8) { 46 | this.buffer.push(0); 47 | } 48 | if (bit) { 49 | this.buffer[~~(this.length / 8)] |= (0x80 >>> (this.length % 8) ); 50 | } 51 | this.length += 1; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/ErrorCorrectLevel.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * ErrorCorrectLevel 6 | * @author Kazuhiko Arase 7 | */ 8 | export enum ErrorCorrectLevel { 9 | 10 | /** 11 | * 7% 12 | */ 13 | L = 1, 14 | 15 | /** 16 | * 15% 17 | */ 18 | M = 0, 19 | 20 | /** 21 | * 25% 22 | */ 23 | Q = 3, 24 | 25 | /** 26 | * 30% 27 | */ 28 | H = 2 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/MaskPattern.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * MaskPattern 6 | * @author Kazuhiko Arase 7 | */ 8 | export enum MaskPattern { 9 | 10 | /** 11 | * mask pattern 000 12 | */ 13 | PATTERN000 = 0b000, 14 | 15 | /** 16 | * mask pattern 001 17 | */ 18 | PATTERN001 = 0b001, 19 | 20 | /** 21 | * mask pattern 010 22 | */ 23 | PATTERN010 = 0b010, 24 | 25 | /** 26 | * mask pattern 011 27 | */ 28 | PATTERN011 = 0b011, 29 | 30 | /** 31 | * mask pattern 100 32 | */ 33 | PATTERN100 = 0b100, 34 | 35 | /** 36 | * mask pattern 101 37 | */ 38 | PATTERN101 = 0b101, 39 | 40 | /** 41 | * mask pattern 110 42 | */ 43 | PATTERN110 = 0b110, 44 | 45 | /** 46 | * mask pattern 111 47 | */ 48 | PATTERN111 = 0b111 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/Mode.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * Mode 6 | * @author Kazuhiko Arase 7 | */ 8 | export enum Mode { 9 | 10 | /** 11 | * number 12 | */ 13 | MODE_NUMBER = 1 << 0, 14 | 15 | /** 16 | * alphabet and number 17 | */ 18 | MODE_ALPHA_NUM = 1 << 1, 19 | 20 | /** 21 | * 8bit byte 22 | */ 23 | MODE_8BIT_BYTE = 1 << 2, 24 | 25 | /** 26 | * KANJI 27 | */ 28 | MODE_KANJI = 1 << 3 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/Polynomial.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * Polynomial 6 | * @author Kazuhiko Arase 7 | */ 8 | export class Polynomial { 9 | 10 | private num : number[]; 11 | 12 | public constructor(num : number[], shift = 0) { 13 | 14 | var offset = 0; 15 | 16 | while (offset < num.length && num[offset] == 0) { 17 | offset += 1; 18 | } 19 | 20 | this.num = []; 21 | var len = num.length - offset; 22 | for (var i = 0; i < len; i += 1) { 23 | this.num.push(num[offset + i]); 24 | } 25 | for (var i = 0; i < shift; i += 1) { 26 | this.num.push(0); 27 | } 28 | } 29 | 30 | public getAt(index : number) : number{ 31 | return this.num[index]; 32 | } 33 | 34 | public getLength() : number { 35 | return this.num.length; 36 | } 37 | 38 | public toString() : string { 39 | var buffer = ''; 40 | for (var i = 0; i < this.getLength(); i += 1) { 41 | if (i > 0) { 42 | buffer += ','; 43 | } 44 | buffer += this.getAt(i); 45 | } 46 | return buffer.toString(); 47 | } 48 | 49 | public toLogString() : string { 50 | var buffer = ''; 51 | for (var i = 0; i < this.getLength(); i += 1) { 52 | if (i > 0) { 53 | buffer += ','; 54 | } 55 | buffer += QRMath.glog(this.getAt(i) ); 56 | } 57 | return buffer.toString(); 58 | } 59 | 60 | public multiply(e : Polynomial) : Polynomial { 61 | var num : number[] = []; 62 | var len = this.getLength() + e.getLength() - 1; 63 | for (var i = 0; i < len; i += 1) { 64 | num.push(0); 65 | } 66 | for (var i = 0; i < this.getLength(); i += 1) { 67 | for (var j = 0; j < e.getLength(); j += 1) { 68 | num[i + j] ^= QRMath.gexp(QRMath.glog(this.getAt(i) ) + 69 | QRMath.glog(e.getAt(j) ) ); 70 | } 71 | } 72 | return new Polynomial(num); 73 | } 74 | 75 | public mod(e : Polynomial) : Polynomial { 76 | 77 | if (this.getLength() - e.getLength() < 0) { 78 | return this; 79 | } 80 | 81 | var ratio = QRMath.glog(this.getAt(0) ) - QRMath.glog(e.getAt(0) ); 82 | 83 | // create copy 84 | var num : number[] = []; 85 | for (var i = 0; i < this.getLength(); i += 1) { 86 | num.push(this.getAt(i) ); 87 | } 88 | 89 | // subtract and calc rest. 90 | for (var i = 0; i < e.getLength(); i += 1) { 91 | num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio); 92 | } 93 | 94 | // call recursively 95 | return new Polynomial(num).mod(e); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/QR8BitByte.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace com.d_project.qrcode { 4 | 5 | /** 6 | * QR8BitByte 7 | * @author Kazuhiko Arase 8 | */ 9 | export class QR8BitByte extends QRData { 10 | 11 | constructor(data : string) { 12 | super(Mode.MODE_8BIT_BYTE, data); 13 | } 14 | 15 | public write(buffer : BitBuffer) : void { 16 | var data = QRCode.stringToBytes(this.getData() ); 17 | for (var i = 0; i < data.length; i += 1) { 18 | buffer.put(data[i], 8); 19 | } 20 | } 21 | 22 | public getLength() : number { 23 | return QRCode.stringToBytes(this.getData() ).length; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/QRAlphaNum.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace com.d_project.qrcode { 4 | 5 | /** 6 | * QRAlphaNum 7 | * @author Kazuhiko Arase 8 | */ 9 | export class QRAlphaNum extends QRData { 10 | 11 | constructor(data : string) { 12 | super(Mode.MODE_ALPHA_NUM, data); 13 | } 14 | 15 | public write(buffer : BitBuffer) : void { 16 | 17 | var s = this.getData(); 18 | 19 | var i = 0; 20 | 21 | while (i + 1 < s.length) { 22 | buffer.put( 23 | QRAlphaNum.getCode(s.charAt(i) ) * 45 + 24 | QRAlphaNum.getCode(s.charAt(i + 1) ), 11); 25 | i += 2; 26 | } 27 | 28 | if (i < s.length) { 29 | buffer.put(QRAlphaNum.getCode(s.charAt(i) ), 6); 30 | } 31 | } 32 | 33 | public getLength() : number { 34 | return this.getData().length; 35 | } 36 | 37 | private static getCode(c : string) : number { 38 | 39 | if ('0' <= c && c <= '9') { 40 | return c.charCodeAt(0) - '0'.charCodeAt(0); 41 | } else if ('A' <= c && c <= 'Z') { 42 | return c.charCodeAt(0) - 'A'.charCodeAt(0) + 10; 43 | } else { 44 | switch (c) { 45 | case ' ' : return 36; 46 | case '$' : return 37; 47 | case '%' : return 38; 48 | case '*' : return 39; 49 | case '+' : return 40; 50 | case '-' : return 41; 51 | case '.' : return 42; 52 | case '/' : return 43; 53 | case ':' : return 44; 54 | default : 55 | throw 'illegal char :' + c; 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/QRData.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * QRData 6 | * @author Kazuhiko Arase 7 | */ 8 | export abstract class QRData { 9 | 10 | constructor(private mode : Mode, private data : string) { 11 | } 12 | 13 | public getMode() : Mode { 14 | return this.mode; 15 | } 16 | 17 | public getData() : string { 18 | return this.data; 19 | } 20 | 21 | public abstract getLength() : number; 22 | 23 | public abstract write(buffer : BitBuffer) : void; 24 | 25 | public getLengthInBits(typeNumber : number) : number { 26 | 27 | if (1 <= typeNumber && typeNumber < 10) { 28 | 29 | // 1 - 9 30 | 31 | switch(this.mode) { 32 | case Mode.MODE_NUMBER : return 10; 33 | case Mode.MODE_ALPHA_NUM : return 9; 34 | case Mode.MODE_8BIT_BYTE : return 8; 35 | case Mode.MODE_KANJI : return 8; 36 | default : 37 | throw 'mode:' + this.mode; 38 | } 39 | 40 | } else if (typeNumber < 27) { 41 | 42 | // 10 - 26 43 | 44 | switch(this.mode) { 45 | case Mode.MODE_NUMBER : return 12; 46 | case Mode.MODE_ALPHA_NUM : return 11; 47 | case Mode.MODE_8BIT_BYTE : return 16; 48 | case Mode.MODE_KANJI : return 10; 49 | default : 50 | throw 'mode:' + this.mode; 51 | } 52 | 53 | } else if (typeNumber < 41) { 54 | 55 | // 27 - 40 56 | 57 | switch(this.mode) { 58 | case Mode.MODE_NUMBER : return 14; 59 | case Mode.MODE_ALPHA_NUM : return 13; 60 | case Mode.MODE_8BIT_BYTE : return 16; 61 | case Mode.MODE_KANJI : return 12; 62 | default : 63 | throw 'mode:' + this.mode; 64 | } 65 | 66 | } else { 67 | throw 'typeNumber:' + typeNumber; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/QRKanji.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace com.d_project.qrcode { 4 | 5 | /** 6 | * QRKanji(SJIS only) 7 | * @author Kazuhiko Arase 8 | */ 9 | export class QRKanji extends QRData { 10 | 11 | constructor(data : string) { 12 | super(Mode.MODE_KANJI, data); 13 | } 14 | 15 | public write(buffer : BitBuffer) : void { 16 | 17 | var data = QRCode.stringToBytes(this.getData() ); 18 | 19 | var i = 0; 20 | 21 | while (i + 1 < data.length) { 22 | 23 | var c = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]); 24 | 25 | if (0x8140 <= c && c <= 0x9FFC) { 26 | c -= 0x8140; 27 | } else if (0xE040 <= c && c <= 0xEBBF) { 28 | c -= 0xC140; 29 | } else { 30 | throw 'illegal char at ' + (i + 1) + '/' + c; 31 | } 32 | 33 | c = ( (c >>> 8) & 0xff) * 0xC0 + (c & 0xff); 34 | 35 | buffer.put(c, 13); 36 | 37 | i += 2; 38 | } 39 | 40 | if (i < data.length) { 41 | throw 'illegal char at ' + (i + 1); 42 | } 43 | } 44 | 45 | public getLength() : number { 46 | return QRCode.stringToBytes(this.getData() ).length / 2; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/QRMath.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * QRMath 6 | * @author Kazuhiko Arase 7 | */ 8 | export class QRMath { 9 | 10 | constructor() { 11 | throw 'error'; 12 | } 13 | 14 | private static EXP_TABLE : number[]; 15 | private static LOG_TABLE : number[]; 16 | 17 | private static initialize = function() { 18 | QRMath.EXP_TABLE = []; 19 | QRMath.LOG_TABLE = []; 20 | for (var i = 0; i < 256; i += 1) { 21 | QRMath.EXP_TABLE.push(i < 8? 1 << i : 22 | QRMath.EXP_TABLE[i - 4] ^ 23 | QRMath.EXP_TABLE[i - 5] ^ 24 | QRMath.EXP_TABLE[i - 6] ^ 25 | QRMath.EXP_TABLE[i - 8]); 26 | QRMath.LOG_TABLE.push(0); 27 | } 28 | for (var i = 0; i < 255; i += 1) { 29 | QRMath.LOG_TABLE[QRMath.EXP_TABLE[i] ] = i; 30 | } 31 | }(); 32 | 33 | public static glog(n : number) : number { 34 | if (n < 1) { 35 | throw 'log(' + n + ')'; 36 | } 37 | return QRMath.LOG_TABLE[n]; 38 | } 39 | 40 | public static gexp(n : number) : number { 41 | while (n < 0) { 42 | n += 255; 43 | } 44 | while (n >= 256) { 45 | n -= 255; 46 | } 47 | return QRMath.EXP_TABLE[n]; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/QRNumber.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace com.d_project.qrcode { 4 | 5 | /** 6 | * QRNumber 7 | * @author Kazuhiko Arase 8 | */ 9 | export class QRNumber extends QRData { 10 | 11 | constructor(data : string) { 12 | super(Mode.MODE_NUMBER, data); 13 | } 14 | 15 | public write(buffer : BitBuffer) : void { 16 | 17 | var data = this.getData(); 18 | 19 | var i = 0; 20 | 21 | while (i + 2 < data.length) { 22 | buffer.put(QRNumber.strToNum(data.substring(i, i + 3) ), 10); 23 | i += 3; 24 | } 25 | 26 | if (i < data.length) { 27 | if (data.length - i == 1) { 28 | buffer.put(QRNumber.strToNum(data.substring(i, i + 1) ), 4); 29 | } else if (data.length - i == 2) { 30 | buffer.put(QRNumber.strToNum(data.substring(i, i + 2) ), 7); 31 | } 32 | } 33 | } 34 | 35 | public getLength() : number { 36 | return this.getData().length; 37 | } 38 | 39 | private static strToNum(s : string) : number { 40 | var num = 0; 41 | for (var i = 0; i < s.length; i += 1) { 42 | num = num * 10 + QRNumber.chatToNum(s.charAt(i) ); 43 | } 44 | return num; 45 | } 46 | 47 | private static chatToNum(c : string) : number { 48 | if ('0' <= c && c <= '9') { 49 | return c.charCodeAt(0) - '0'.charCodeAt(0); 50 | } 51 | throw 'illegal char :' + c; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/QRUtil.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * QRUtil 6 | * @author Kazuhiko Arase 7 | */ 8 | export class QRUtil { 9 | 10 | constructor() { 11 | throw 'error'; 12 | } 13 | 14 | public static getPatternPosition(typeNumber: number) : number[] { 15 | return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]; 16 | } 17 | 18 | private static PATTERN_POSITION_TABLE = [ 19 | [], 20 | [6, 18], 21 | [6, 22], 22 | [6, 26], 23 | [6, 30], 24 | [6, 34], 25 | [6, 22, 38], 26 | [6, 24, 42], 27 | [6, 26, 46], 28 | [6, 28, 50], 29 | [6, 30, 54], 30 | [6, 32, 58], 31 | [6, 34, 62], 32 | [6, 26, 46, 66], 33 | [6, 26, 48, 70], 34 | [6, 26, 50, 74], 35 | [6, 30, 54, 78], 36 | [6, 30, 56, 82], 37 | [6, 30, 58, 86], 38 | [6, 34, 62, 90], 39 | [6, 28, 50, 72, 94], 40 | [6, 26, 50, 74, 98], 41 | [6, 30, 54, 78, 102], 42 | [6, 28, 54, 80, 106], 43 | [6, 32, 58, 84, 110], 44 | [6, 30, 58, 86, 114], 45 | [6, 34, 62, 90, 118], 46 | [6, 26, 50, 74, 98, 122], 47 | [6, 30, 54, 78, 102, 126], 48 | [6, 26, 52, 78, 104, 130], 49 | [6, 30, 56, 82, 108, 134], 50 | [6, 34, 60, 86, 112, 138], 51 | [6, 30, 58, 86, 114, 142], 52 | [6, 34, 62, 90, 118, 146], 53 | [6, 30, 54, 78, 102, 126, 150], 54 | [6, 24, 50, 76, 102, 128, 154], 55 | [6, 28, 54, 80, 106, 132, 158], 56 | [6, 32, 58, 84, 110, 136, 162], 57 | [6, 26, 54, 82, 110, 138, 166], 58 | [6, 30, 58, 86, 114, 142, 170] 59 | ]; 60 | 61 | private static MAX_LENGTH = [ 62 | [ [41, 25, 17, 10], [34, 20, 14, 8], [27, 16, 11, 7], [17, 10, 7, 4] ], 63 | [ [77, 47, 32, 20], [63, 38, 26, 16], [48, 29, 20, 12], [34, 20, 14, 8] ], 64 | [ [127, 77, 53, 32], [101, 61, 42, 26], [77, 47, 32, 20], [58, 35, 24, 15] ], 65 | [ [187, 114, 78, 48], [149, 90, 62, 38], [111, 67, 46, 28], [82, 50, 34, 21] ], 66 | [ [255, 154, 106, 65], [202, 122, 84, 52], [144, 87, 60, 37], [106, 64, 44, 27] ], 67 | [ [322, 195, 134, 82], [255, 154, 106, 65], [178, 108, 74, 45], [139, 84, 58, 36] ], 68 | [ [370, 224, 154, 95], [293, 178, 122, 75], [207, 125, 86, 53], [154, 93, 64, 39] ], 69 | [ [461, 279, 192, 118], [365, 221, 152, 93], [259, 157, 108, 66], [202, 122, 84, 52] ], 70 | [ [552, 335, 230, 141], [432, 262, 180, 111], [312, 189, 130, 80], [235, 143, 98, 60] ], 71 | [ [652, 395, 271, 167], [513, 311, 213, 131], [364, 221, 151, 93], [288, 174, 119, 74] ] 72 | ]; 73 | 74 | public static getMaxLength( 75 | typeNumber : number, 76 | mode : Mode, 77 | errorCorrectLevel : ErrorCorrectLevel 78 | ) : number { 79 | 80 | var t = typeNumber - 1; 81 | var e = 0; 82 | var m = 0; 83 | 84 | switch(errorCorrectLevel) { 85 | case ErrorCorrectLevel.L : e = 0; break; 86 | case ErrorCorrectLevel.M : e = 1; break; 87 | case ErrorCorrectLevel.Q : e = 2; break; 88 | case ErrorCorrectLevel.H : e = 3; break; 89 | default : 90 | throw 'e:' + errorCorrectLevel; 91 | } 92 | 93 | switch(mode) { 94 | case Mode.MODE_NUMBER : m = 0; break; 95 | case Mode.MODE_ALPHA_NUM : m = 1; break; 96 | case Mode.MODE_8BIT_BYTE : m = 2; break; 97 | case Mode.MODE_KANJI : m = 3; break; 98 | default : 99 | throw 'm:' + mode; 100 | } 101 | 102 | return QRUtil.MAX_LENGTH[t][e][m]; 103 | } 104 | 105 | public static getErrorCorrectPolynomial( 106 | errorCorrectLength : number) : Polynomial { 107 | 108 | var a = new Polynomial([1]); 109 | 110 | for (var i = 0; i < errorCorrectLength; i += 1) { 111 | a = a.multiply(new Polynomial([1, QRMath.gexp(i)]) ); 112 | } 113 | 114 | return a; 115 | } 116 | 117 | public static getMaskFunc( 118 | maskPattern : number 119 | ) : (i : number, j : number) => boolean { 120 | 121 | switch (maskPattern) { 122 | 123 | case MaskPattern.PATTERN000 : 124 | return (i : number, j : number) => (i + j) % 2 == 0; 125 | case MaskPattern.PATTERN001 : 126 | return (i : number, j : number) => i % 2 == 0; 127 | case MaskPattern.PATTERN010 : 128 | return (i : number, j : number) => j % 3 == 0; 129 | case MaskPattern.PATTERN011 : 130 | return (i : number, j : number) => (i + j) % 3 == 0; 131 | case MaskPattern.PATTERN100 : 132 | return (i : number, j : number) => (~~(i / 2) + ~~(j / 3) ) % 2 == 0; 133 | case MaskPattern.PATTERN101 : 134 | return (i : number, j : number) => (i * j) % 2 + (i * j) % 3 == 0; 135 | case MaskPattern.PATTERN110 : 136 | return (i : number, j : number) => ( (i * j) % 2 + (i * j) % 3) % 2 == 0; 137 | case MaskPattern.PATTERN111 : 138 | return (i : number, j : number) => ( (i * j) % 3 + (i + j) % 2) % 2 == 0; 139 | 140 | default : 141 | throw 'mask:' + maskPattern; 142 | } 143 | } 144 | 145 | public static getLostPoint(qrCode : QRCode) : number { 146 | 147 | var moduleCount = qrCode.getModuleCount(); 148 | 149 | var lostPoint = 0; 150 | 151 | // LEVEL1 152 | 153 | for (var row = 0; row < moduleCount; row += 1) { 154 | 155 | for (var col = 0; col < moduleCount; col += 1) { 156 | 157 | var sameCount = 0; 158 | var dark = qrCode.isDark(row, col); 159 | 160 | for (var r = -1; r <= 1; r += 1) { 161 | 162 | if (row + r < 0 || moduleCount <= row + r) { 163 | continue; 164 | } 165 | 166 | for (var c = -1; c <= 1; c += 1) { 167 | 168 | if (col + c < 0 || moduleCount <= col + c) { 169 | continue; 170 | } 171 | 172 | if (r == 0 && c == 0) { 173 | continue; 174 | } 175 | 176 | if (dark == qrCode.isDark(row + r, col + c) ) { 177 | sameCount += 1; 178 | } 179 | } 180 | } 181 | 182 | if (sameCount > 5) { 183 | lostPoint += (3 + sameCount - 5); 184 | } 185 | } 186 | } 187 | 188 | // LEVEL2 189 | 190 | for (var row = 0; row < moduleCount - 1; row += 1) { 191 | for (var col = 0; col < moduleCount - 1; col += 1) { 192 | var count = 0; 193 | if (qrCode.isDark(row, col ) ) count += 1; 194 | if (qrCode.isDark(row + 1, col ) ) count += 1; 195 | if (qrCode.isDark(row, col + 1) ) count += 1; 196 | if (qrCode.isDark(row + 1, col + 1) ) count += 1; 197 | if (count == 0 || count == 4) { 198 | lostPoint += 3; 199 | } 200 | } 201 | } 202 | 203 | // LEVEL3 204 | 205 | for (var row = 0; row < moduleCount; row += 1) { 206 | for (var col = 0; col < moduleCount - 6; col += 1) { 207 | if (qrCode.isDark(row, col) 208 | && !qrCode.isDark(row, col + 1) 209 | && qrCode.isDark(row, col + 2) 210 | && qrCode.isDark(row, col + 3) 211 | && qrCode.isDark(row, col + 4) 212 | && !qrCode.isDark(row, col + 5) 213 | && qrCode.isDark(row, col + 6) ) { 214 | lostPoint += 40; 215 | } 216 | } 217 | } 218 | 219 | for (var col = 0; col < moduleCount; col += 1) { 220 | for (var row = 0; row < moduleCount - 6; row += 1) { 221 | if (qrCode.isDark(row, col) 222 | && !qrCode.isDark(row + 1, col) 223 | && qrCode.isDark(row + 2, col) 224 | && qrCode.isDark(row + 3, col) 225 | && qrCode.isDark(row + 4, col) 226 | && !qrCode.isDark(row + 5, col) 227 | && qrCode.isDark(row + 6, col) ) { 228 | lostPoint += 40; 229 | } 230 | } 231 | } 232 | 233 | // LEVEL4 234 | 235 | var darkCount = 0; 236 | 237 | for (var col = 0; col < moduleCount; col += 1) { 238 | for (var row = 0; row < moduleCount; row += 1) { 239 | if (qrCode.isDark(row, col) ) { 240 | darkCount += 1; 241 | } 242 | } 243 | } 244 | 245 | var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; 246 | lostPoint += ratio * 10; 247 | 248 | return lostPoint; 249 | } 250 | 251 | public static getBCHTypeInfo(data : number) : number { 252 | var d = data << 10; 253 | while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { 254 | d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - 255 | QRUtil.getBCHDigit(QRUtil.G15) ) ); 256 | } 257 | return ( (data << 10) | d) ^ QRUtil.G15_MASK; 258 | } 259 | 260 | public static getBCHTypeNumber(data : number) : number { 261 | var d = data << 12; 262 | while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { 263 | d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - 264 | QRUtil.getBCHDigit(QRUtil.G18) ) ); 265 | } 266 | return (data << 12) | d; 267 | } 268 | 269 | private static G15 = (1 << 10) | (1 << 8) | (1 << 5) 270 | | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); 271 | 272 | private static G18 = (1 << 12) | (1 << 11) | (1 << 10) 273 | | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); 274 | 275 | private static G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) 276 | | (1 << 4) | (1 << 1); 277 | 278 | private static getBCHDigit(data : number) : number { 279 | var digit = 0; 280 | while (data != 0) { 281 | digit += 1; 282 | data >>>= 1; 283 | } 284 | return digit; 285 | } 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/qrcode/RSBlock.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.qrcode { 3 | 4 | /** 5 | * RSBlock 6 | * @author Kazuhiko Arase 7 | */ 8 | export class RSBlock { 9 | 10 | private static RS_BLOCK_TABLE = [ 11 | 12 | // L 13 | // M 14 | // Q 15 | // H 16 | 17 | // 1 18 | [1, 26, 19], 19 | [1, 26, 16], 20 | [1, 26, 13], 21 | [1, 26, 9], 22 | 23 | // 2 24 | [1, 44, 34], 25 | [1, 44, 28], 26 | [1, 44, 22], 27 | [1, 44, 16], 28 | 29 | // 3 30 | [1, 70, 55], 31 | [1, 70, 44], 32 | [2, 35, 17], 33 | [2, 35, 13], 34 | 35 | // 4 36 | [1, 100, 80], 37 | [2, 50, 32], 38 | [2, 50, 24], 39 | [4, 25, 9], 40 | 41 | // 5 42 | [1, 134, 108], 43 | [2, 67, 43], 44 | [2, 33, 15, 2, 34, 16], 45 | [2, 33, 11, 2, 34, 12], 46 | 47 | // 6 48 | [2, 86, 68], 49 | [4, 43, 27], 50 | [4, 43, 19], 51 | [4, 43, 15], 52 | 53 | // 7 54 | [2, 98, 78], 55 | [4, 49, 31], 56 | [2, 32, 14, 4, 33, 15], 57 | [4, 39, 13, 1, 40, 14], 58 | 59 | // 8 60 | [2, 121, 97], 61 | [2, 60, 38, 2, 61, 39], 62 | [4, 40, 18, 2, 41, 19], 63 | [4, 40, 14, 2, 41, 15], 64 | 65 | // 9 66 | [2, 146, 116], 67 | [3, 58, 36, 2, 59, 37], 68 | [4, 36, 16, 4, 37, 17], 69 | [4, 36, 12, 4, 37, 13], 70 | 71 | // 10 72 | [2, 86, 68, 2, 87, 69], 73 | [4, 69, 43, 1, 70, 44], 74 | [6, 43, 19, 2, 44, 20], 75 | [6, 43, 15, 2, 44, 16], 76 | 77 | // 11 78 | [4, 101, 81], 79 | [1, 80, 50, 4, 81, 51], 80 | [4, 50, 22, 4, 51, 23], 81 | [3, 36, 12, 8, 37, 13], 82 | 83 | // 12 84 | [2, 116, 92, 2, 117, 93], 85 | [6, 58, 36, 2, 59, 37], 86 | [4, 46, 20, 6, 47, 21], 87 | [7, 42, 14, 4, 43, 15], 88 | 89 | // 13 90 | [4, 133, 107], 91 | [8, 59, 37, 1, 60, 38], 92 | [8, 44, 20, 4, 45, 21], 93 | [12, 33, 11, 4, 34, 12], 94 | 95 | // 14 96 | [3, 145, 115, 1, 146, 116], 97 | [4, 64, 40, 5, 65, 41], 98 | [11, 36, 16, 5, 37, 17], 99 | [11, 36, 12, 5, 37, 13], 100 | 101 | // 15 102 | [5, 109, 87, 1, 110, 88], 103 | [5, 65, 41, 5, 66, 42], 104 | [5, 54, 24, 7, 55, 25], 105 | [11, 36, 12, 7, 37, 13], 106 | 107 | // 16 108 | [5, 122, 98, 1, 123, 99], 109 | [7, 73, 45, 3, 74, 46], 110 | [15, 43, 19, 2, 44, 20], 111 | [3, 45, 15, 13, 46, 16], 112 | 113 | // 17 114 | [1, 135, 107, 5, 136, 108], 115 | [10, 74, 46, 1, 75, 47], 116 | [1, 50, 22, 15, 51, 23], 117 | [2, 42, 14, 17, 43, 15], 118 | 119 | // 18 120 | [5, 150, 120, 1, 151, 121], 121 | [9, 69, 43, 4, 70, 44], 122 | [17, 50, 22, 1, 51, 23], 123 | [2, 42, 14, 19, 43, 15], 124 | 125 | // 19 126 | [3, 141, 113, 4, 142, 114], 127 | [3, 70, 44, 11, 71, 45], 128 | [17, 47, 21, 4, 48, 22], 129 | [9, 39, 13, 16, 40, 14], 130 | 131 | // 20 132 | [3, 135, 107, 5, 136, 108], 133 | [3, 67, 41, 13, 68, 42], 134 | [15, 54, 24, 5, 55, 25], 135 | [15, 43, 15, 10, 44, 16], 136 | 137 | // 21 138 | [4, 144, 116, 4, 145, 117], 139 | [17, 68, 42], 140 | [17, 50, 22, 6, 51, 23], 141 | [19, 46, 16, 6, 47, 17], 142 | 143 | // 22 144 | [2, 139, 111, 7, 140, 112], 145 | [17, 74, 46], 146 | [7, 54, 24, 16, 55, 25], 147 | [34, 37, 13], 148 | 149 | // 23 150 | [4, 151, 121, 5, 152, 122], 151 | [4, 75, 47, 14, 76, 48], 152 | [11, 54, 24, 14, 55, 25], 153 | [16, 45, 15, 14, 46, 16], 154 | 155 | // 24 156 | [6, 147, 117, 4, 148, 118], 157 | [6, 73, 45, 14, 74, 46], 158 | [11, 54, 24, 16, 55, 25], 159 | [30, 46, 16, 2, 47, 17], 160 | 161 | // 25 162 | [8, 132, 106, 4, 133, 107], 163 | [8, 75, 47, 13, 76, 48], 164 | [7, 54, 24, 22, 55, 25], 165 | [22, 45, 15, 13, 46, 16], 166 | 167 | // 26 168 | [10, 142, 114, 2, 143, 115], 169 | [19, 74, 46, 4, 75, 47], 170 | [28, 50, 22, 6, 51, 23], 171 | [33, 46, 16, 4, 47, 17], 172 | 173 | // 27 174 | [8, 152, 122, 4, 153, 123], 175 | [22, 73, 45, 3, 74, 46], 176 | [8, 53, 23, 26, 54, 24], 177 | [12, 45, 15, 28, 46, 16], 178 | 179 | // 28 180 | [3, 147, 117, 10, 148, 118], 181 | [3, 73, 45, 23, 74, 46], 182 | [4, 54, 24, 31, 55, 25], 183 | [11, 45, 15, 31, 46, 16], 184 | 185 | // 29 186 | [7, 146, 116, 7, 147, 117], 187 | [21, 73, 45, 7, 74, 46], 188 | [1, 53, 23, 37, 54, 24], 189 | [19, 45, 15, 26, 46, 16], 190 | 191 | // 30 192 | [5, 145, 115, 10, 146, 116], 193 | [19, 75, 47, 10, 76, 48], 194 | [15, 54, 24, 25, 55, 25], 195 | [23, 45, 15, 25, 46, 16], 196 | 197 | // 31 198 | [13, 145, 115, 3, 146, 116], 199 | [2, 74, 46, 29, 75, 47], 200 | [42, 54, 24, 1, 55, 25], 201 | [23, 45, 15, 28, 46, 16], 202 | 203 | // 32 204 | [17, 145, 115], 205 | [10, 74, 46, 23, 75, 47], 206 | [10, 54, 24, 35, 55, 25], 207 | [19, 45, 15, 35, 46, 16], 208 | 209 | // 33 210 | [17, 145, 115, 1, 146, 116], 211 | [14, 74, 46, 21, 75, 47], 212 | [29, 54, 24, 19, 55, 25], 213 | [11, 45, 15, 46, 46, 16], 214 | 215 | // 34 216 | [13, 145, 115, 6, 146, 116], 217 | [14, 74, 46, 23, 75, 47], 218 | [44, 54, 24, 7, 55, 25], 219 | [59, 46, 16, 1, 47, 17], 220 | 221 | // 35 222 | [12, 151, 121, 7, 152, 122], 223 | [12, 75, 47, 26, 76, 48], 224 | [39, 54, 24, 14, 55, 25], 225 | [22, 45, 15, 41, 46, 16], 226 | 227 | // 36 228 | [6, 151, 121, 14, 152, 122], 229 | [6, 75, 47, 34, 76, 48], 230 | [46, 54, 24, 10, 55, 25], 231 | [2, 45, 15, 64, 46, 16], 232 | 233 | // 37 234 | [17, 152, 122, 4, 153, 123], 235 | [29, 74, 46, 14, 75, 47], 236 | [49, 54, 24, 10, 55, 25], 237 | [24, 45, 15, 46, 46, 16], 238 | 239 | // 38 240 | [4, 152, 122, 18, 153, 123], 241 | [13, 74, 46, 32, 75, 47], 242 | [48, 54, 24, 14, 55, 25], 243 | [42, 45, 15, 32, 46, 16], 244 | 245 | // 39 246 | [20, 147, 117, 4, 148, 118], 247 | [40, 75, 47, 7, 76, 48], 248 | [43, 54, 24, 22, 55, 25], 249 | [10, 45, 15, 67, 46, 16], 250 | 251 | // 40 252 | [19, 148, 118, 6, 149, 119], 253 | [18, 75, 47, 31, 76, 48], 254 | [34, 54, 24, 34, 55, 25], 255 | [20, 45, 15, 61, 46, 16] 256 | ]; 257 | 258 | constructor( 259 | private totalCount : number, 260 | private dataCount : number 261 | ) { 262 | } 263 | 264 | public getDataCount() : number { 265 | return this.dataCount; 266 | } 267 | 268 | public getTotalCount() : number { 269 | return this.totalCount; 270 | } 271 | 272 | public static getRSBlocks( 273 | typeNumber : number, 274 | errorCorrectLevel : ErrorCorrectLevel 275 | ) : RSBlock[] { 276 | 277 | var rsBlock = RSBlock.getRsBlockTable(typeNumber, errorCorrectLevel); 278 | var length = rsBlock.length / 3; 279 | 280 | var list : RSBlock[] = []; 281 | 282 | for (var i = 0; i < length; i += 1) { 283 | 284 | var count = rsBlock[i * 3 + 0]; 285 | var totalCount = rsBlock[i * 3 + 1]; 286 | var dataCount = rsBlock[i * 3 + 2]; 287 | 288 | for (var j = 0; j < count; j += 1) { 289 | list.push(new RSBlock(totalCount, dataCount) ); 290 | } 291 | } 292 | 293 | return list; 294 | } 295 | 296 | private static getRsBlockTable( 297 | typeNumber : number, 298 | errorCorrectLevel : ErrorCorrectLevel 299 | ) : number[] { 300 | 301 | switch(errorCorrectLevel) { 302 | case ErrorCorrectLevel.L : 303 | return RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; 304 | case ErrorCorrectLevel.M : 305 | return RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; 306 | case ErrorCorrectLevel.Q : 307 | return RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; 308 | case ErrorCorrectLevel.H : 309 | return RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; 310 | default : 311 | break; 312 | } 313 | 314 | throw 'tn:' + typeNumber + '/ecl:' + errorCorrectLevel; 315 | } 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/text/createStringToBytes.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 'use strict'; 4 | namespace com.d_project.text { 5 | 6 | import ByteArrayInputStream = com.d_project.io.ByteArrayInputStream; 7 | import Base64DecodeInputStream = com.d_project.io.Base64DecodeInputStream; 8 | 9 | /** 10 | * createStringToBytes 11 | * @author Kazuhiko Arase 12 | * @param unicodeData base64 string of byte array. 13 | * [16bit Unicode],[16bit Bytes], ... 14 | * @param numChars 15 | */ 16 | export function createStringToBytes( 17 | unicodeData : string, 18 | numChars : number 19 | ) : (s : string) => number[] { 20 | function toBytes(s : string) : number[] { 21 | var bytes : number[] = []; 22 | for (var i = 0; i < s.length; i += 1) { 23 | bytes.push(s.charCodeAt(i) ); 24 | } 25 | return bytes; 26 | } 27 | // create conversion map. 28 | var unicodeMap = function() { 29 | var bin = new Base64DecodeInputStream( 30 | new ByteArrayInputStream(toBytes(unicodeData) ) ); 31 | var read = function() { 32 | var b = bin.readByte(); 33 | if (b == -1) throw 'eof'; 34 | return b; 35 | }; 36 | var count = 0; 37 | var unicodeMap : { [ch : string] : number; } = {}; 38 | while (true) { 39 | var b0 = bin.readByte(); 40 | if (b0 == -1) break; 41 | var b1 = read(); 42 | var b2 = read(); 43 | var b3 = read(); 44 | var k = String.fromCharCode( (b0 << 8) | b1); 45 | var v = (b2 << 8) | b3; 46 | unicodeMap[k] = v; 47 | count += 1; 48 | } 49 | if (count != numChars) { 50 | throw count + '!=' + numChars; 51 | } 52 | return unicodeMap; 53 | }(); 54 | 55 | var unknownChar = '?'.charCodeAt(0); 56 | 57 | return function(s : string) : number[] { 58 | var bytes : number[] = []; 59 | for (var i = 0; i < s.length; i += 1) { 60 | var c = s.charCodeAt(i); 61 | if (c < 128) { 62 | bytes.push(c); 63 | } else { 64 | var b = unicodeMap[s.charAt(i)]; 65 | if (typeof b == 'number') { 66 | if ( (b & 0xff) == b) { 67 | // 1byte 68 | bytes.push(b); 69 | } else { 70 | // 2bytes 71 | bytes.push(b >>> 8); 72 | bytes.push(b & 0xff); 73 | } 74 | } else { 75 | bytes.push(unknownChar); 76 | } 77 | } 78 | } 79 | return bytes; 80 | }; 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /ts/src/ts/com/d_project/text/stringToBytes_UTF8.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace com.d_project.text { 3 | 4 | /** 5 | * stringToBytes_UTF8 6 | * contributed by elhigu 7 | */ 8 | export function stringToBytes_UTF8(s : string) : number[] { 9 | // http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array 10 | function toUTF8Array(str : string) : number[] { 11 | var utf8 : number[] = []; 12 | for (var i=0; i < str.length; i++) { 13 | var charcode = str.charCodeAt(i); 14 | if (charcode < 0x80) utf8.push(charcode); 15 | else if (charcode < 0x800) { 16 | utf8.push(0xc0 | (charcode >> 6), 17 | 0x80 | (charcode & 0x3f)); 18 | } 19 | else if (charcode < 0xd800 || charcode >= 0xe000) { 20 | utf8.push(0xe0 | (charcode >> 12), 21 | 0x80 | ((charcode>>6) & 0x3f), 22 | 0x80 | (charcode & 0x3f)); 23 | } 24 | // surrogate pair 25 | else { 26 | i++; 27 | // UTF-16 encodes 0x10000-0x10FFFF by 28 | // subtracting 0x10000 and splitting the 29 | // 20 bits of 0x0-0xFFFFF into two halves 30 | charcode = 0x10000 + (((charcode & 0x3ff)<<10) 31 | | (str.charCodeAt(i) & 0x3ff)); 32 | utf8.push(0xf0 | (charcode >>18), 33 | 0x80 | ((charcode>>12) & 0x3f), 34 | 0x80 | ((charcode>>6) & 0x3f), 35 | 0x80 | (charcode & 0x3f)); 36 | } 37 | } 38 | return utf8; 39 | } 40 | return toUTF8Array(s); 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /ts/src/ts/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ts/src/ts/test.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | 8 | 'use strict' 9 | namespace test { 10 | 11 | import QRCode = com.d_project.qrcode.QRCode; 12 | import ErrorCorrectLevel = com.d_project.qrcode.ErrorCorrectLevel; 13 | import QRNumber = com.d_project.qrcode.QRNumber; 14 | import QRAlphaNum = com.d_project.qrcode.QRAlphaNum; 15 | import QR8BitByte = com.d_project.qrcode.QR8BitByte; 16 | import QRKanji = com.d_project.qrcode.QRKanji; 17 | 18 | export function run() : void { 19 | 20 | // uncomment if UTF-8 support is required. 21 | //QRCode.stringToBytes = com.d_project.text.stringToBytes_UTF8; 22 | 23 | var qr = new QRCode(); 24 | qr.setTypeNumber(5); 25 | qr.setErrorCorrectLevel(ErrorCorrectLevel.L); 26 | qr.addData(new QRNumber('0123') ); // Number only 27 | qr.addData(new QRAlphaNum('AB5678CD') ); // Alphabet and Number 28 | qr.addData(new QR8BitByte('[8BitByte :)]') ); // most useful for usual purpose. 29 | qr.addData('[here is 8BitByte too]'); 30 | qr.addData(new QRKanji('漢字') ); // Kanji(SJIS) only 31 | qr.make(); 32 | 33 | // img 34 | var img = document.createElement('img'); 35 | img.setAttribute('src', qr.toDataURL() ); 36 | document.body.appendChild(img); 37 | 38 | // canvas 39 | document.body.appendChild(createCanvas(qr, 2) ); 40 | } 41 | 42 | function createCanvas(qr : QRCode, cellSize = 2, margin = cellSize * 4) { 43 | 44 | var canvas = document.createElement('canvas'); 45 | var size = qr.getModuleCount() * cellSize + margin * 2; 46 | canvas.width = size; 47 | canvas.height = size; 48 | var ctx = canvas.getContext('2d'); 49 | 50 | // fill background 51 | ctx.fillStyle = '#ffffff'; 52 | ctx.fillRect(0, 0, size, size); 53 | 54 | // draw cells 55 | ctx.fillStyle = '#000000'; 56 | for (var row = 0; row < qr.getModuleCount(); row += 1) { 57 | for (var col = 0; col < qr.getModuleCount(); col += 1) { 58 | if (qr.isDark(row, col) ) { 59 | ctx.fillRect( 60 | col * cellSize + margin, 61 | row * cellSize + margin, 62 | cellSize, cellSize); 63 | } 64 | } 65 | } 66 | return canvas; 67 | } 68 | } 69 | 70 | window.onload = function() { 71 | test.run(); 72 | }; 73 | --------------------------------------------------------------------------------