├── .gitignore ├── README.md ├── style.css ├── halftoneQR.html ├── halftoneqr.js └── qrcode.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | 5 | # Icon must end with two \r 6 | Icon 7 | 8 | # Thumbnails 9 | ._* 10 | 11 | # Files that might appear on external disk 12 | .Spotlight-V100 13 | .Trashes 14 | 15 | # Directories potentially created on remote AFP share 16 | .AppleDB 17 | .AppleDesktop 18 | Network Trash Folder 19 | Temporary Items 20 | .apdisk 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Halftone-QRCode-Generator 2 | Halftone QR Code Generator by Lachlan Arthur 3 | 4 | from http://jsfiddle.net/lachlan/r8qWV/ 5 | 6 | More about halftone QRCode: 7 | 8 | http://vecg.cs.ucl.ac.uk/Projects/SmartGeometry/halftone_QR/halftoneQR_sigga13.html 9 | http://www.jianshu.com/p/46a4e210a542 10 | http://spacekid.me/halftone-qr-code-generator/ 11 | https://zhuanlan.zhihu.com/p/20728355 12 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | 2 | html, body { 3 | height: 100%; 4 | margin: 0; 5 | } 6 | 7 | body { 8 | position: relative; 9 | } 10 | 11 | h1, h2 { 12 | margin: 0; 13 | } 14 | 15 | #overlay { 16 | display: none; 17 | position: fixed; 18 | top: 0; 19 | left: 0; 20 | width: 100%; 21 | height: 100%; 22 | background-color: rgba(0,0,0,0.5); 23 | z-index: 10; 24 | font-size: 100px; 25 | color: white; 26 | text-align: center; 27 | } 28 | 29 | body.hover #overlay { 30 | display: block; 31 | } 32 | 33 | canvas { 34 | margin: 5px; 35 | box-shadow: 0 0 5px black; 36 | } 37 | 38 | /* Hidden for now */ 39 | #imagePixel { 40 | display: none; 41 | } 42 | 43 | #output { 44 | background-color: grey; 45 | } 46 | -------------------------------------------------------------------------------- /halftoneQR.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Halftone QR Code Generator 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Halftone QR Code Generator

13 |

Drop an image into your browser, then click generate.

14 | QR content:
15 |
16 | Redundancy (error correction level): 17 |
23 | QR size: 24 | (6 gives the largest blank square area)
37 | Background Type: 38 |
43 |
44 | 45 | 46 | 47 | 48 |
49 | By Lachlan 50 |

51 | Cat photo by Cayambe [CC-BY-SA-3.0 or GFDL], via Wikimedia Commons 52 | 53 |
Drop image
54 | 55 | -------------------------------------------------------------------------------- /halftoneqr.js: -------------------------------------------------------------------------------- 1 | var pixelSize = 2; 2 | var blockSize = (3*pixelSize); 3 | var image; 4 | var has_image = false; 5 | 6 | function halftoneQR(QRBytes, controlBytes, image) { 7 | 8 | var canvas = $('#output').get(0); 9 | canvas.width = canvas.height = QRBytes.length * (3*pixelSize); 10 | var ctx = canvas.getContext('2d'); 11 | var background = $('#background').val(); 12 | 13 | $('#imageColour, #imageThreshold, #imagePixel').attr({ 14 | width: canvas.width, 15 | height: canvas.height 16 | }); 17 | if (has_image) { 18 | // Re-draw image (incase size changed) 19 | drawImage(); 20 | } 21 | 22 | ctx.clearRect(0, 0, canvas.width, canvas.height); 23 | 24 | var canvasThreshold = $('#imageThreshold').get(0); 25 | var ctxThreshold = canvasThreshold.getContext('2d'); 26 | 27 | if (has_image && background === 'image') { 28 | ctx.drawImage(canvasThreshold, 0, 0, canvas.width, canvas.height); 29 | } 30 | 31 | for (var byteRow = 0; byteRow < QRBytes.length; byteRow++) { 32 | for (var byteCell = 0; byteCell < QRBytes[byteRow].length; byteCell++) { 33 | 34 | if ((background === 'image' && !has_image) || background === 'noise') { 35 | // Draw random bytes 36 | ctx.fillStyle = 'black'; 37 | for (var subRow = 0; subRow < 3; subRow++) { 38 | for (var subCell = 0; subCell < 3; subCell++) { 39 | ctx.fillStyle = 'black'; 40 | if (Math.random() < 0.5) { 41 | ctx.fillStyle = 'white'; 42 | } 43 | ctx.fillRect(byteRow * blockSize + (subRow * pixelSize), byteCell * blockSize + (subCell * pixelSize), pixelSize, pixelSize); 44 | } 45 | } 46 | } 47 | 48 | // Middle Cell 49 | ctx.fillStyle = QRBytes[byteRow][byteCell] ? 'black' : 'white'; 50 | ctx.fillRect(byteRow * blockSize + pixelSize, byteCell * blockSize + pixelSize, pixelSize, pixelSize); 51 | } 52 | } 53 | 54 | // Re-draw control bytes 55 | for (var byteRow = 0; byteRow < controlBytes.length; byteRow++) { 56 | for (var byteCell = 0; byteCell < controlBytes[byteRow].length; byteCell++) { 57 | if (controlBytes[byteRow][byteCell] !== null) { 58 | if (controlBytes[byteRow][byteCell] === true) { 59 | ctx.fillStyle = 'black'; 60 | } else { 61 | ctx.fillStyle = 'white'; 62 | } 63 | ctx.fillRect(byteRow * blockSize, byteCell * blockSize, blockSize, blockSize); 64 | } 65 | }; 66 | }; 67 | 68 | $('#download').attr('href', $('#output').get(0).toDataURL()); 69 | 70 | } 71 | 72 | function drawImage() { 73 | var canvasColour = $('#imageColour').get(0); 74 | var ctxColour = canvasColour.getContext('2d'); 75 | 76 | ctxColour.clearRect(0,0,canvasColour.width, canvasColour.height); 77 | ctxColour.drawImage(image, 0, 0, canvasColour.width, canvasColour.height); 78 | 79 | drawPixel(); 80 | } 81 | 82 | function drawPixel() { 83 | var canvasColour = $('#imageColour').get(0); 84 | var canvasPixel = $('#imagePixel').get(0); 85 | var ctxPixel = canvasPixel.getContext('2d'); 86 | var canvasTemp = document.createElement('canvas'); 87 | canvasTemp.width = canvasTemp.height = (canvasPixel.width / pixelSize); 88 | var ctxTemp = canvasTemp.getContext('2d'); 89 | 90 | ctxPixel.imageSmoothingEnabled = 91 | ctxPixel.mozImageSmoothingEnabled = 92 | ctxPixel.msImageSmoothingEnabled = 93 | ctxPixel.webkitImageSmoothingEnabled = 94 | ctxTemp.imageSmoothingEnabled = 95 | ctxTemp.mozImageSmoothingEnabled = 96 | ctxTemp.msImageSmoothingEnabled = 97 | ctxTemp.webkitImageSmoothingEnabled = false; 98 | 99 | ctxTemp.drawImage(canvasColour, 0, 0, canvasTemp.width, canvasTemp.height); 100 | ctxPixel.drawImage(canvasTemp, 0, 0, canvasPixel.width, canvasPixel.height); 101 | 102 | drawThreshold(); 103 | } 104 | 105 | function drawThreshold() { 106 | var canvasPixel = $('#imagePixel').get(0); 107 | var ctxPixel = canvasPixel.getContext('2d'); 108 | var canvasThreshold = $('#imageThreshold').get(0); 109 | var ctxThreshold = canvasThreshold.getContext('2d'); 110 | 111 | var pixels = ctxPixel.getImageData(0,0,canvasPixel.width,canvasPixel.height); 112 | var d = pixels.data; 113 | var width = Math.sqrt(d.length / 4) / pixelSize; 114 | for (var i=0; i= 127) ? 255 : 0; 120 | //d[i] = d[i+1] = d[i+2] = v; 121 | d[i] = d[i+1] = d[i+2] = grey; 122 | } 123 | 124 | for (var i=0; i= 127) ? 255 : 0; 127 | 128 | // Dithering 129 | var error = (grey - v) / 8; 130 | var i2 = i / 4; 131 | var row = Math.floor(i2 / width); 132 | var cell = i2 % width; 133 | 134 | d[i] = d[i+1] = d[i+2] = v; 135 | 136 | d[(((row + 0) * width) + (cell + 1)) * 4] = d[(((row + 0) * width) + (cell + 1)) * 4 + 1] = d[(((row + 0) * width) + (cell + 1)) * 4 + 2] = d[(((row + 0) * width) + (cell + 1)) * 4] + error; 137 | d[(((row + 0) * width) + (cell + 2)) * 4] = d[(((row + 0) * width) + (cell + 2)) * 4 + 1] = d[(((row + 0) * width) + (cell + 2)) * 4 + 2] = d[(((row + 0) * width) + (cell + 2)) * 4] + error; 138 | d[(((row + 1) * width) + (cell - 1)) * 4] = d[(((row + 1) * width) + (cell - 1)) * 4 + 1] = d[(((row + 1) * width) + (cell - 1)) * 4 + 2] = d[(((row + 1) * width) + (cell - 1)) * 4] + error; 139 | d[(((row + 1) * width) + (cell + 0)) * 4] = d[(((row + 1) * width) + (cell + 0)) * 4 + 1] = d[(((row + 1) * width) + (cell + 0)) * 4 + 2] = d[(((row + 1) * width) + (cell + 0)) * 4] + error; 140 | d[(((row + 1) * width) + (cell + 1)) * 4] = d[(((row + 1) * width) + (cell + 1)) * 4 + 1] = d[(((row + 1) * width) + (cell + 1)) * 4 + 2] = d[(((row + 1) * width) + (cell + 1)) * 4] + error; 141 | d[(((row + 2) * width) + (cell + 0)) * 4] = d[(((row + 2) * width) + (cell + 0)) * 4 + 1] = d[(((row + 2) * width) + (cell + 0)) * 4 + 2] = d[(((row + 2) * width) + (cell + 0)) * 4] + error; 142 | } 143 | ctxThreshold.putImageData(pixels, 0, 0); 144 | } 145 | $(function(){ 146 | $('body').on('dragover', function(e) { 147 | e.preventDefault(); 148 | $('body').addClass('hover'); 149 | }); 150 | $('#overlay').on('dragend dragleave', function(e) { 151 | e.preventDefault(); 152 | $('body').removeClass('hover'); 153 | }); 154 | $('#overlay').on('drop', function(e) { 155 | e.preventDefault(); 156 | $('body').removeClass('hover'); 157 | 158 | var file = e.originalEvent.dataTransfer.files[0], 159 | reader = new FileReader(); 160 | reader.onload = function(event) { 161 | //event.target.result; 162 | var imageColour = new Image(); 163 | imageColour.onload = function() { 164 | has_image = true; 165 | image = this; 166 | drawImage(); 167 | } 168 | imageColour.src = event.target.result; 169 | }; 170 | reader.readAsDataURL(file); 171 | 172 | return false; 173 | }); 174 | 175 | $(function() { 176 | 177 | $('#go').on('click', function() { 178 | var text = $('#input').val(); 179 | 180 | var errorLevel = $('#error_level').val(); 181 | 182 | var sizes = { 183 | L: [152, 272, 440, 640, 864, 1088, 1248, 1552, 1856, 1240], 184 | M: [128, 224, 352, 512, 688, 864, 992, 700, 700, 524], 185 | Q: [104, 176, 272, 384, 286, 608, 508, 376, 608, 434], 186 | H: [72, 128, 208, 288, 214, 480, 164, 296, 464, 346] 187 | }; 188 | 189 | var userSize = parseInt($('#size').val()); 190 | var QRsize = -1; 191 | if (userSize === 0) { 192 | for (var i = 0; i < sizes[errorLevel].length; i++) { 193 | if (text.length < sizes[errorLevel][i]) { 194 | QRsize = i + 1; 195 | break; 196 | } 197 | }; 198 | } else { 199 | if (text.length < sizes[errorLevel][userSize - 1]) { 200 | QRsize = userSize; 201 | } 202 | } 203 | if (QRsize == -1) { 204 | if (userSize === 0) { 205 | if (errorLevel === 'H') { 206 | alert('Too much text.'); 207 | } else { 208 | alert('Too much text. Try decreasing the error level.'); 209 | } 210 | } else { 211 | alert('Too much text. Try decreasing the error level or increasing the size.'); 212 | } 213 | return; 214 | } 215 | 216 | var qr = qrcode(QRsize, errorLevel); 217 | qr.addData(text); 218 | qr.make(); 219 | 220 | var controls = qrcode(QRsize, errorLevel); 221 | controls.addData(text); 222 | controls.make(true); 223 | 224 | halftoneQR(qr.returnByteArray(), controls.returnByteArray()); 225 | 226 | }); 227 | 228 | // First load (cat) 229 | var imageColour = new Image(); 230 | imageColour.onload = function() { 231 | has_image = true; 232 | image = this; 233 | $('#go').triggerHandler('click'); 234 | } 235 | imageColour.src = 'data:image/jpeg;base64,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'; 236 | 237 | }); 238 | }) 239 | 240 | -------------------------------------------------------------------------------- /qrcode.js: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // 3 | // QR Code Generator for JavaScript 4 | // 5 | // Copyright (c) 2009 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 | var qrcode = function() { 19 | 20 | //--------------------------------------------------------------------- 21 | // qrcode 22 | //--------------------------------------------------------------------- 23 | 24 | /** 25 | * qrcode 26 | * @param typeNumber 1 to 10 27 | * @param errorCorrectLevel 'L','M','Q','H' 28 | */ 29 | var qrcode = function(typeNumber, errorCorrectLevel) { 30 | 31 | var PAD0 = 0xEC; 32 | var PAD1 = 0x11; 33 | 34 | var _typeNumber = typeNumber; 35 | var _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel]; 36 | var _modules = null; 37 | var _moduleCount = 0; 38 | var _dataCache = null; 39 | var _dataList = new Array(); 40 | 41 | var _this = {}; 42 | 43 | var makeImpl = function(test, maskPattern, onlyControl) { 44 | 45 | onlyControl = onlyControl || false; 46 | _moduleCount = _typeNumber * 4 + 17; 47 | _modules = function(moduleCount) { 48 | var modules = new Array(moduleCount); 49 | for (var row = 0; row < moduleCount; row += 1) { 50 | modules[row] = new Array(moduleCount); 51 | for (var col = 0; col < moduleCount; col += 1) { 52 | modules[row][col] = null; 53 | } 54 | } 55 | return modules; 56 | }(_moduleCount); 57 | 58 | setupPositionProbePattern(0, 0); 59 | setupPositionProbePattern(_moduleCount - 7, 0); 60 | setupPositionProbePattern(0, _moduleCount - 7); 61 | setupPositionAdjustPattern(); 62 | setupTimingPattern(); 63 | setupTypeInfo(test, maskPattern); 64 | 65 | if (_typeNumber >= 7) { 66 | setupTypeNumber(test); 67 | } 68 | 69 | if (!onlyControl) { 70 | if (_dataCache == null) { 71 | _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList); 72 | } 73 | 74 | mapData(_dataCache, maskPattern); 75 | } 76 | }; 77 | 78 | var setupPositionProbePattern = function(row, col) { 79 | 80 | for (var r = -1; r <= 7; r += 1) { 81 | 82 | if (row + r <= -1 || _moduleCount <= row + r) continue; 83 | 84 | for (var c = -1; c <= 7; c += 1) { 85 | 86 | if (col + c <= -1 || _moduleCount <= col + c) continue; 87 | 88 | if ( (0 <= r && r <= 6 && (c == 0 || c == 6) ) 89 | || (0 <= c && c <= 6 && (r == 0 || r == 6) ) 90 | || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) { 91 | _modules[row + r][col + c] = true; 92 | } else { 93 | _modules[row + r][col + c] = false; 94 | } 95 | } 96 | } 97 | }; 98 | 99 | var getBestMaskPattern = function() { 100 | 101 | var minLostPoint = 0; 102 | var pattern = 0; 103 | 104 | for (var i = 0; i < 8; i += 1) { 105 | 106 | makeImpl(true, i); 107 | 108 | var lostPoint = QRUtil.getLostPoint(_this); 109 | 110 | if (i == 0 || minLostPoint > lostPoint) { 111 | minLostPoint = lostPoint; 112 | pattern = i; 113 | } 114 | } 115 | 116 | return pattern; 117 | }; 118 | 119 | var setupTimingPattern = function() { 120 | 121 | for (var r = 8; r < _moduleCount - 8; r += 1) { 122 | if (_modules[r][6] != null) { 123 | continue; 124 | } 125 | _modules[r][6] = (r % 2 == 0); 126 | } 127 | 128 | for (var c = 8; c < _moduleCount - 8; c += 1) { 129 | if (_modules[6][c] != null) { 130 | continue; 131 | } 132 | _modules[6][c] = (c % 2 == 0); 133 | } 134 | }; 135 | 136 | var setupPositionAdjustPattern = function() { 137 | 138 | var pos = QRUtil.getPatternPosition(_typeNumber); 139 | 140 | for (var i = 0; i < pos.length; i += 1) { 141 | 142 | for (var j = 0; j < pos.length; j += 1) { 143 | 144 | var row = pos[i]; 145 | var col = pos[j]; 146 | 147 | if (_modules[row][col] != null) { 148 | continue; 149 | } 150 | 151 | for (var r = -2; r <= 2; r += 1) { 152 | 153 | for (var c = -2; c <= 2; c += 1) { 154 | 155 | if (r == -2 || r == 2 || c == -2 || c == 2 156 | || (r == 0 && c == 0) ) { 157 | _modules[row + r][col + c] = true; 158 | } else { 159 | _modules[row + r][col + c] = false; 160 | } 161 | } 162 | } 163 | } 164 | } 165 | }; 166 | 167 | var setupTypeNumber = function(test) { 168 | 169 | var bits = QRUtil.getBCHTypeNumber(_typeNumber); 170 | 171 | for (var i = 0; i < 18; i += 1) { 172 | var mod = (!test && ( (bits >> i) & 1) == 1); 173 | _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod; 174 | } 175 | 176 | for (var i = 0; i < 18; i += 1) { 177 | var mod = (!test && ( (bits >> i) & 1) == 1); 178 | _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod; 179 | } 180 | }; 181 | 182 | var setupTypeInfo = function(test, maskPattern) { 183 | 184 | var data = (_errorCorrectLevel << 3) | maskPattern; 185 | var bits = QRUtil.getBCHTypeInfo(data); 186 | 187 | // vertical 188 | for (var i = 0; i < 15; i += 1) { 189 | 190 | var mod = (!test && ( (bits >> i) & 1) == 1); 191 | 192 | if (i < 6) { 193 | _modules[i][8] = mod; 194 | } else if (i < 8) { 195 | _modules[i + 1][8] = mod; 196 | } else { 197 | _modules[_moduleCount - 15 + i][8] = mod; 198 | } 199 | } 200 | 201 | // horizontal 202 | for (var i = 0; i < 15; i += 1) { 203 | 204 | var mod = (!test && ( (bits >> i) & 1) == 1); 205 | 206 | if (i < 8) { 207 | _modules[8][_moduleCount - i - 1] = mod; 208 | } else if (i < 9) { 209 | _modules[8][15 - i - 1 + 1] = mod; 210 | } else { 211 | _modules[8][15 - i - 1] = mod; 212 | } 213 | } 214 | 215 | // fixed module 216 | _modules[_moduleCount - 8][8] = (!test); 217 | }; 218 | 219 | var mapData = function(data, maskPattern) { 220 | 221 | var inc = -1; 222 | var row = _moduleCount - 1; 223 | var bitIndex = 7; 224 | var byteIndex = 0; 225 | var maskFunc = QRUtil.getMaskFunction(maskPattern); 226 | 227 | for (var col = _moduleCount - 1; col > 0; col -= 2) { 228 | 229 | if (col == 6) col -= 1; 230 | 231 | while (true) { 232 | 233 | for (var c = 0; c < 2; c += 1) { 234 | 235 | if (_modules[row][col - c] == null) { 236 | 237 | var dark = false; 238 | 239 | if (byteIndex < data.length) { 240 | dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1); 241 | } 242 | 243 | var mask = maskFunc(row, col - c); 244 | 245 | if (mask) { 246 | dark = !dark; 247 | } 248 | 249 | _modules[row][col - c] = dark; 250 | bitIndex -= 1; 251 | 252 | if (bitIndex == -1) { 253 | byteIndex += 1; 254 | bitIndex = 7; 255 | } 256 | } 257 | } 258 | 259 | row += inc; 260 | 261 | if (row < 0 || _moduleCount <= row) { 262 | row -= inc; 263 | inc = -inc; 264 | break; 265 | } 266 | } 267 | } 268 | }; 269 | 270 | var createBytes = function(buffer, rsBlocks) { 271 | 272 | var offset = 0; 273 | 274 | var maxDcCount = 0; 275 | var maxEcCount = 0; 276 | 277 | var dcdata = new Array(rsBlocks.length); 278 | var ecdata = new Array(rsBlocks.length); 279 | 280 | for (var r = 0; r < rsBlocks.length; r += 1) { 281 | 282 | var dcCount = rsBlocks[r].dataCount; 283 | var ecCount = rsBlocks[r].totalCount - dcCount; 284 | 285 | maxDcCount = Math.max(maxDcCount, dcCount); 286 | maxEcCount = Math.max(maxEcCount, ecCount); 287 | 288 | dcdata[r] = new Array(dcCount); 289 | 290 | for (var i = 0; i < dcdata[r].length; i += 1) { 291 | dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]; 292 | } 293 | offset += dcCount; 294 | 295 | var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); 296 | var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1); 297 | 298 | var modPoly = rawPoly.mod(rsPoly); 299 | ecdata[r] = new Array(rsPoly.getLength() - 1); 300 | for (var i = 0; i < ecdata[r].length; i += 1) { 301 | var modIndex = i + modPoly.getLength() - ecdata[r].length; 302 | ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0; 303 | } 304 | } 305 | 306 | var totalCodeCount = 0; 307 | for (var i = 0; i < rsBlocks.length; i += 1) { 308 | totalCodeCount += rsBlocks[i].totalCount; 309 | } 310 | 311 | var data = new Array(totalCodeCount); 312 | var index = 0; 313 | 314 | for (var i = 0; i < maxDcCount; i += 1) { 315 | for (var r = 0; r < rsBlocks.length; r += 1) { 316 | if (i < dcdata[r].length) { 317 | data[index] = dcdata[r][i]; 318 | index += 1; 319 | } 320 | } 321 | } 322 | 323 | for (var i = 0; i < maxEcCount; i += 1) { 324 | for (var r = 0; r < rsBlocks.length; r += 1) { 325 | if (i < ecdata[r].length) { 326 | data[index] = ecdata[r][i]; 327 | index += 1; 328 | } 329 | } 330 | } 331 | 332 | return data; 333 | }; 334 | 335 | var createData = function(typeNumber, errorCorrectLevel, dataList) { 336 | 337 | var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel); 338 | 339 | var buffer = qrBitBuffer(); 340 | 341 | for (var i = 0; i < dataList.length; i += 1) { 342 | var data = dataList[i]; 343 | buffer.put(data.getMode(), 4); 344 | buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) ); 345 | data.write(buffer); 346 | } 347 | 348 | // calc num max data. 349 | var totalDataCount = 0; 350 | for (var i = 0; i < rsBlocks.length; i += 1) { 351 | totalDataCount += rsBlocks[i].dataCount; 352 | } 353 | 354 | if (buffer.getLengthInBits() > totalDataCount * 8) { 355 | throw new Error('code length overflow. (' 356 | + buffer.getLengthInBits() 357 | + '>' 358 | + totalDataCount * 8 359 | + ')'); 360 | } 361 | 362 | // end code 363 | if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { 364 | buffer.put(0, 4); 365 | } 366 | 367 | // padding 368 | while (buffer.getLengthInBits() % 8 != 0) { 369 | buffer.putBit(false); 370 | } 371 | 372 | // padding 373 | while (true) { 374 | 375 | if (buffer.getLengthInBits() >= totalDataCount * 8) { 376 | break; 377 | } 378 | buffer.put(PAD0, 8); 379 | 380 | if (buffer.getLengthInBits() >= totalDataCount * 8) { 381 | break; 382 | } 383 | buffer.put(PAD1, 8); 384 | } 385 | 386 | return createBytes(buffer, rsBlocks); 387 | }; 388 | 389 | _this.addData = function(data) { 390 | var newData = qr8BitByte(data); 391 | _dataList.push(newData); 392 | _dataCache = null; 393 | }; 394 | 395 | _this.isDark = function(row, col) { 396 | if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) { 397 | throw new Error(row + ',' + col); 398 | } 399 | return _modules[row][col]; 400 | }; 401 | 402 | _this.getModuleCount = function() { 403 | return _moduleCount; 404 | }; 405 | 406 | _this.make = function(onlyControl) { 407 | makeImpl(false, getBestMaskPattern(), onlyControl); 408 | }; 409 | 410 | _this.createTableTag = function(cellSize, margin) { 411 | 412 | cellSize = cellSize || 2; 413 | margin = (typeof margin == 'undefined')? cellSize * 4 : margin; 414 | 415 | var qrHtml = ''; 416 | 417 | qrHtml += ''; 422 | qrHtml += ''; 423 | 424 | for (var r = 0; r < _this.getModuleCount(); r += 1) { 425 | 426 | qrHtml += ''; 427 | 428 | for (var c = 0; c < _this.getModuleCount(); c += 1) { 429 | qrHtml += ''; 442 | } 443 | 444 | qrHtml += ''; 445 | qrHtml += '
'; 439 | } 440 | 441 | qrHtml += '
'; 446 | 447 | return qrHtml; 448 | }; 449 | 450 | _this.returnByteArray = function() { 451 | 452 | return _modules; 453 | } 454 | 455 | _this.createImgTag = function(cellSize, margin) { 456 | 457 | cellSize = cellSize || 2; 458 | margin = (typeof margin == 'undefined')? cellSize * 4 : margin; 459 | 460 | var size = _this.getModuleCount() * cellSize + margin * 2; 461 | var min = margin; 462 | var max = size - margin; 463 | 464 | return createImgTag(size, size, function(x, y) { 465 | if (min <= x && x < max && min <= y && y < max) { 466 | var c = Math.floor( (x - min) / cellSize); 467 | var r = Math.floor( (y - min) / cellSize); 468 | return _this.isDark(r, c)? 0 : 1; 469 | } else { 470 | return 1; 471 | } 472 | } ); 473 | }; 474 | 475 | return _this; 476 | }; 477 | 478 | //--------------------------------------------------------------------- 479 | // qrcode.stringToBytes 480 | //--------------------------------------------------------------------- 481 | 482 | qrcode.stringToBytes = function(s) { 483 | var bytes = new Array(); 484 | for (var i = 0; i < s.length; i += 1) { 485 | var c = s.charCodeAt(i); 486 | bytes.push(c & 0xff); 487 | } 488 | return bytes; 489 | }; 490 | 491 | //--------------------------------------------------------------------- 492 | // qrcode.createStringToBytes 493 | //--------------------------------------------------------------------- 494 | 495 | /** 496 | * @param unicodeData base64 string of byte array. 497 | * [16bit Unicode],[16bit Bytes], ... 498 | * @param numChars 499 | */ 500 | qrcode.createStringToBytes = function(unicodeData, numChars) { 501 | 502 | // create conversion map. 503 | 504 | var unicodeMap = function() { 505 | 506 | var bin = base64DecodeInputStream(unicodeData); 507 | var read = function() { 508 | var b = bin.read(); 509 | if (b == -1) throw new Error(); 510 | return b; 511 | }; 512 | 513 | var count = 0; 514 | var unicodeMap = {}; 515 | while (true) { 516 | var b0 = bin.read(); 517 | if (b0 == -1) break; 518 | var b1 = read(); 519 | var b2 = read(); 520 | var b3 = read(); 521 | var k = String.fromCharCode( (b0 << 8) | b1); 522 | var v = (b2 << 8) | b3; 523 | unicodeMap[k] = v; 524 | count += 1; 525 | } 526 | if (count != numChars) { 527 | throw new Error(count + ' != ' + numChars); 528 | } 529 | 530 | return unicodeMap; 531 | }(); 532 | 533 | var unknownChar = '?'.charCodeAt(0); 534 | 535 | return function(s) { 536 | var bytes = new Array(); 537 | for (var i = 0; i < s.length; i += 1) { 538 | var c = s.charCodeAt(i); 539 | if (c < 128) { 540 | bytes.push(c); 541 | } else { 542 | var b = unicodeMap[s.charAt(i)]; 543 | if (typeof b == 'number') { 544 | if ( (b & 0xff) == b) { 545 | // 1byte 546 | bytes.push(b); 547 | } else { 548 | // 2bytes 549 | bytes.push(b >>> 8); 550 | bytes.push(b & 0xff); 551 | } 552 | } else { 553 | bytes.push(unknownChar); 554 | } 555 | } 556 | } 557 | return bytes; 558 | }; 559 | }; 560 | 561 | //--------------------------------------------------------------------- 562 | // QRMode 563 | //--------------------------------------------------------------------- 564 | 565 | var QRMode = { 566 | MODE_NUMBER : 1 << 0, 567 | MODE_ALPHA_NUM : 1 << 1, 568 | MODE_8BIT_BYTE : 1 << 2, 569 | MODE_KANJI : 1 << 3 570 | }; 571 | qrcode.QRMode = QRMode; 572 | 573 | //--------------------------------------------------------------------- 574 | // QRErrorCorrectLevel 575 | //--------------------------------------------------------------------- 576 | 577 | var QRErrorCorrectLevel = { 578 | L : 1, 579 | M : 0, 580 | Q : 3, 581 | H : 2 582 | }; 583 | qrcode.QRErrorCorrectLevel = QRErrorCorrectLevel; 584 | 585 | //--------------------------------------------------------------------- 586 | // QRMaskPattern 587 | //--------------------------------------------------------------------- 588 | 589 | var QRMaskPattern = { 590 | PATTERN000 : 0, 591 | PATTERN001 : 1, 592 | PATTERN010 : 2, 593 | PATTERN011 : 3, 594 | PATTERN100 : 4, 595 | PATTERN101 : 5, 596 | PATTERN110 : 6, 597 | PATTERN111 : 7 598 | }; 599 | qrcode.QRMaskPattern = QRMaskPattern; 600 | 601 | //--------------------------------------------------------------------- 602 | // QRUtil 603 | //--------------------------------------------------------------------- 604 | 605 | var QRUtil = function() { 606 | 607 | var PATTERN_POSITION_TABLE = [ 608 | [], 609 | [6, 18], 610 | [6, 22], 611 | [6, 26], 612 | [6, 30], 613 | [6, 34], 614 | [6, 22, 38], 615 | [6, 24, 42], 616 | [6, 26, 46], 617 | [6, 28, 50], 618 | [6, 30, 54], 619 | [6, 32, 58], 620 | [6, 34, 62], 621 | [6, 26, 46, 66], 622 | [6, 26, 48, 70], 623 | [6, 26, 50, 74], 624 | [6, 30, 54, 78], 625 | [6, 30, 56, 82], 626 | [6, 30, 58, 86], 627 | [6, 34, 62, 90], 628 | [6, 28, 50, 72, 94], 629 | [6, 26, 50, 74, 98], 630 | [6, 30, 54, 78, 102], 631 | [6, 28, 54, 80, 106], 632 | [6, 32, 58, 84, 110], 633 | [6, 30, 58, 86, 114], 634 | [6, 34, 62, 90, 118], 635 | [6, 26, 50, 74, 98, 122], 636 | [6, 30, 54, 78, 102, 126], 637 | [6, 26, 52, 78, 104, 130], 638 | [6, 30, 56, 82, 108, 134], 639 | [6, 34, 60, 86, 112, 138], 640 | [6, 30, 58, 86, 114, 142], 641 | [6, 34, 62, 90, 118, 146], 642 | [6, 30, 54, 78, 102, 126, 150], 643 | [6, 24, 50, 76, 102, 128, 154], 644 | [6, 28, 54, 80, 106, 132, 158], 645 | [6, 32, 58, 84, 110, 136, 162], 646 | [6, 26, 54, 82, 110, 138, 166], 647 | [6, 30, 58, 86, 114, 142, 170] 648 | ]; 649 | var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); 650 | var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); 651 | var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); 652 | 653 | var _this = {}; 654 | 655 | var getBCHDigit = function(data) { 656 | var digit = 0; 657 | while (data != 0) { 658 | digit += 1; 659 | data >>>= 1; 660 | } 661 | return digit; 662 | }; 663 | 664 | _this.getBCHTypeInfo = function(data) { 665 | var d = data << 10; 666 | while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { 667 | d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); 668 | } 669 | return ( (data << 10) | d) ^ G15_MASK; 670 | }; 671 | 672 | _this.getBCHTypeNumber = function(data) { 673 | var d = data << 12; 674 | while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { 675 | d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); 676 | } 677 | return (data << 12) | d; 678 | }; 679 | 680 | _this.getPatternPosition = function(typeNumber) { 681 | return PATTERN_POSITION_TABLE[typeNumber - 1]; 682 | }; 683 | 684 | _this.getMaskFunction = function(maskPattern) { 685 | 686 | switch (maskPattern) { 687 | 688 | case QRMaskPattern.PATTERN000 : 689 | return function(i, j) { return (i + j) % 2 == 0; }; 690 | case QRMaskPattern.PATTERN001 : 691 | return function(i, j) { return i % 2 == 0; }; 692 | case QRMaskPattern.PATTERN010 : 693 | return function(i, j) { return j % 3 == 0; }; 694 | case QRMaskPattern.PATTERN011 : 695 | return function(i, j) { return (i + j) % 3 == 0; }; 696 | case QRMaskPattern.PATTERN100 : 697 | return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; }; 698 | case QRMaskPattern.PATTERN101 : 699 | return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; }; 700 | case QRMaskPattern.PATTERN110 : 701 | return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; }; 702 | case QRMaskPattern.PATTERN111 : 703 | return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; }; 704 | 705 | default : 706 | throw new Error('bad maskPattern:' + maskPattern); 707 | } 708 | }; 709 | 710 | _this.getErrorCorrectPolynomial = function(errorCorrectLength) { 711 | var a = qrPolynomial([1], 0); 712 | for (var i = 0; i < errorCorrectLength; i += 1) { 713 | a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) ); 714 | } 715 | return a; 716 | }; 717 | 718 | _this.getLengthInBits = function(mode, type) { 719 | 720 | if (1 <= type && type < 10) { 721 | 722 | // 1 - 9 723 | 724 | switch(mode) { 725 | case QRMode.MODE_NUMBER : return 10; 726 | case QRMode.MODE_ALPHA_NUM : return 9; 727 | case QRMode.MODE_8BIT_BYTE : return 8; 728 | case QRMode.MODE_KANJI : return 8; 729 | default : 730 | throw new Error('mode:' + mode); 731 | } 732 | 733 | } else if (type < 27) { 734 | 735 | // 10 - 26 736 | 737 | switch(mode) { 738 | case QRMode.MODE_NUMBER : return 12; 739 | case QRMode.MODE_ALPHA_NUM : return 11; 740 | case QRMode.MODE_8BIT_BYTE : return 16; 741 | case QRMode.MODE_KANJI : return 10; 742 | default : 743 | throw new Error('mode:' + mode); 744 | } 745 | 746 | } else if (type < 41) { 747 | 748 | // 27 - 40 749 | 750 | switch(mode) { 751 | case QRMode.MODE_NUMBER : return 14; 752 | case QRMode.MODE_ALPHA_NUM : return 13; 753 | case QRMode.MODE_8BIT_BYTE : return 16; 754 | case QRMode.MODE_KANJI : return 12; 755 | default : 756 | throw new Error('mode:' + mode); 757 | } 758 | 759 | } else { 760 | throw new Error('type:' + type); 761 | } 762 | }; 763 | 764 | _this.getLostPoint = function(qrcode) { 765 | 766 | var moduleCount = qrcode.getModuleCount(); 767 | 768 | var lostPoint = 0; 769 | 770 | // LEVEL1 771 | 772 | for (var row = 0; row < moduleCount; row += 1) { 773 | for (var col = 0; col < moduleCount; col += 1) { 774 | 775 | var sameCount = 0; 776 | var dark = qrcode.isDark(row, col); 777 | 778 | for (var r = -1; r <= 1; r += 1) { 779 | 780 | if (row + r < 0 || moduleCount <= row + r) { 781 | continue; 782 | } 783 | 784 | for (var c = -1; c <= 1; c += 1) { 785 | 786 | if (col + c < 0 || moduleCount <= col + c) { 787 | continue; 788 | } 789 | 790 | if (r == 0 && c == 0) { 791 | continue; 792 | } 793 | 794 | if (dark == qrcode.isDark(row + r, col + c) ) { 795 | sameCount += 1; 796 | } 797 | } 798 | } 799 | 800 | if (sameCount > 5) { 801 | lostPoint += (3 + sameCount - 5); 802 | } 803 | } 804 | }; 805 | 806 | // LEVEL2 807 | 808 | for (var row = 0; row < moduleCount - 1; row += 1) { 809 | for (var col = 0; col < moduleCount - 1; col += 1) { 810 | var count = 0; 811 | if (qrcode.isDark(row, col) ) count += 1; 812 | if (qrcode.isDark(row + 1, col) ) count += 1; 813 | if (qrcode.isDark(row, col + 1) ) count += 1; 814 | if (qrcode.isDark(row + 1, col + 1) ) count += 1; 815 | if (count == 0 || count == 4) { 816 | lostPoint += 3; 817 | } 818 | } 819 | } 820 | 821 | // LEVEL3 822 | 823 | for (var row = 0; row < moduleCount; row += 1) { 824 | for (var col = 0; col < moduleCount - 6; col += 1) { 825 | if (qrcode.isDark(row, col) 826 | && !qrcode.isDark(row, col + 1) 827 | && qrcode.isDark(row, col + 2) 828 | && qrcode.isDark(row, col + 3) 829 | && qrcode.isDark(row, col + 4) 830 | && !qrcode.isDark(row, col + 5) 831 | && qrcode.isDark(row, col + 6) ) { 832 | lostPoint += 40; 833 | } 834 | } 835 | } 836 | 837 | for (var col = 0; col < moduleCount; col += 1) { 838 | for (var row = 0; row < moduleCount - 6; row += 1) { 839 | if (qrcode.isDark(row, col) 840 | && !qrcode.isDark(row + 1, col) 841 | && qrcode.isDark(row + 2, col) 842 | && qrcode.isDark(row + 3, col) 843 | && qrcode.isDark(row + 4, col) 844 | && !qrcode.isDark(row + 5, col) 845 | && qrcode.isDark(row + 6, col) ) { 846 | lostPoint += 40; 847 | } 848 | } 849 | } 850 | 851 | // LEVEL4 852 | 853 | var darkCount = 0; 854 | 855 | for (var col = 0; col < moduleCount; col += 1) { 856 | for (var row = 0; row < moduleCount; row += 1) { 857 | if (qrcode.isDark(row, col) ) { 858 | darkCount += 1; 859 | } 860 | } 861 | } 862 | 863 | var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; 864 | lostPoint += ratio * 10; 865 | 866 | return lostPoint; 867 | }; 868 | 869 | return _this; 870 | }(); 871 | qrcode.QRUtil = QRUtil; 872 | 873 | //--------------------------------------------------------------------- 874 | // QRMath 875 | //--------------------------------------------------------------------- 876 | 877 | var QRMath = function() { 878 | 879 | var EXP_TABLE = new Array(256); 880 | var LOG_TABLE = new Array(256); 881 | 882 | // initialize tables 883 | for (var i = 0; i < 8; i += 1) { 884 | EXP_TABLE[i] = 1 << i; 885 | } 886 | for (var i = 8; i < 256; i += 1) { 887 | EXP_TABLE[i] = EXP_TABLE[i - 4] 888 | ^ EXP_TABLE[i - 5] 889 | ^ EXP_TABLE[i - 6] 890 | ^ EXP_TABLE[i - 8]; 891 | } 892 | for (var i = 0; i < 255; i += 1) { 893 | LOG_TABLE[EXP_TABLE[i] ] = i; 894 | } 895 | 896 | var _this = {}; 897 | 898 | _this.glog = function(n) { 899 | 900 | if (n < 1) { 901 | throw new Error('glog(' + n + ')'); 902 | } 903 | 904 | return LOG_TABLE[n]; 905 | }; 906 | 907 | _this.gexp = function(n) { 908 | 909 | while (n < 0) { 910 | n += 255; 911 | } 912 | 913 | while (n >= 256) { 914 | n -= 255; 915 | } 916 | 917 | return EXP_TABLE[n]; 918 | }; 919 | 920 | return _this; 921 | }(); 922 | 923 | //--------------------------------------------------------------------- 924 | // qrPolynomial 925 | //--------------------------------------------------------------------- 926 | 927 | function qrPolynomial(num, shift) { 928 | 929 | if (typeof num.length == 'undefined') { 930 | throw new Error(num.length + '/' + shift); 931 | } 932 | 933 | var _num = function() { 934 | var offset = 0; 935 | while (offset < num.length && num[offset] == 0) { 936 | offset += 1; 937 | } 938 | var _num = new Array(num.length - offset + shift); 939 | for (var i = 0; i < num.length - offset; i += 1) { 940 | _num[i] = num[i + offset]; 941 | } 942 | return _num; 943 | }(); 944 | 945 | var _this = {}; 946 | 947 | _this.getAt = function(index) { 948 | return _num[index]; 949 | }; 950 | 951 | _this.getLength = function() { 952 | return _num.length; 953 | }; 954 | 955 | _this.multiply = function(e) { 956 | 957 | var num = new Array(_this.getLength() + e.getLength() - 1); 958 | 959 | for (var i = 0; i < _this.getLength(); i += 1) { 960 | for (var j = 0; j < e.getLength(); j += 1) { 961 | num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) ); 962 | } 963 | } 964 | 965 | return qrPolynomial(num, 0); 966 | }; 967 | 968 | _this.mod = function(e) { 969 | 970 | if (_this.getLength() - e.getLength() < 0) { 971 | return _this; 972 | } 973 | 974 | var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) ); 975 | 976 | var num = new Array(_this.getLength() ); 977 | for (var i = 0; i < _this.getLength(); i += 1) { 978 | num[i] = _this.getAt(i); 979 | } 980 | 981 | for (var i = 0; i < e.getLength(); i += 1) { 982 | num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio); 983 | } 984 | 985 | // recursive call 986 | return qrPolynomial(num, 0).mod(e); 987 | }; 988 | 989 | return _this; 990 | }; 991 | 992 | //--------------------------------------------------------------------- 993 | // QRRSBlock 994 | //--------------------------------------------------------------------- 995 | 996 | var QRRSBlock = function() { 997 | 998 | var _this = {}; 999 | 1000 | var RS_BLOCK_TABLE = [ 1001 | 1002 | // L 1003 | // M 1004 | // Q 1005 | // H 1006 | 1007 | // 1 1008 | [1, 26, 19], 1009 | [1, 26, 16], 1010 | [1, 26, 13], 1011 | [1, 26, 9], 1012 | 1013 | // 2 1014 | [1, 44, 34], 1015 | [1, 44, 28], 1016 | [1, 44, 22], 1017 | [1, 44, 16], 1018 | 1019 | // 3 1020 | [1, 70, 55], 1021 | [1, 70, 44], 1022 | [2, 35, 17], 1023 | [2, 35, 13], 1024 | 1025 | // 4 1026 | [1, 100, 80], 1027 | [2, 50, 32], 1028 | [2, 50, 24], 1029 | [4, 25, 9], 1030 | 1031 | // 5 1032 | [1, 134, 108], 1033 | [2, 67, 43], 1034 | [2, 33, 15, 2, 34, 16], 1035 | [2, 33, 11, 2, 34, 12], 1036 | 1037 | // 6 1038 | [2, 86, 68], 1039 | [4, 43, 27], 1040 | [4, 43, 19], 1041 | [4, 43, 15], 1042 | 1043 | // 7 1044 | [2, 98, 78], 1045 | [4, 49, 31], 1046 | [2, 32, 14, 4, 33, 15], 1047 | [4, 39, 13, 1, 40, 14], 1048 | 1049 | // 8 1050 | [2, 121, 97], 1051 | [2, 60, 38, 2, 61, 39], 1052 | [4, 40, 18, 2, 41, 19], 1053 | [4, 40, 14, 2, 41, 15], 1054 | 1055 | // 9 1056 | [2, 146, 116], 1057 | [3, 58, 36, 2, 59, 37], 1058 | [4, 36, 16, 4, 37, 17], 1059 | [4, 36, 12, 4, 37, 13], 1060 | 1061 | // 10 1062 | [2, 86, 68, 2, 87, 69], 1063 | [4, 69, 43, 1, 70, 44], 1064 | [6, 43, 19, 2, 44, 20], 1065 | [6, 43, 15, 2, 44, 16] 1066 | ]; 1067 | _this.RS_BLOCK_TABLE = RS_BLOCK_TABLE; 1068 | 1069 | var qrRSBlock = function(totalCount, dataCount) { 1070 | var _this = {}; 1071 | _this.totalCount = totalCount; 1072 | _this.dataCount = dataCount; 1073 | return _this; 1074 | }; 1075 | 1076 | var getRsBlockTable = function(typeNumber, errorCorrectLevel) { 1077 | 1078 | switch(errorCorrectLevel) { 1079 | case QRErrorCorrectLevel.L : 1080 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; 1081 | case QRErrorCorrectLevel.M : 1082 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; 1083 | case QRErrorCorrectLevel.Q : 1084 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; 1085 | case QRErrorCorrectLevel.H : 1086 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; 1087 | default : 1088 | return undefined; 1089 | } 1090 | }; 1091 | 1092 | _this.getRSBlocks = function(typeNumber, errorCorrectLevel) { 1093 | 1094 | var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel); 1095 | 1096 | if (typeof rsBlock == 'undefined') { 1097 | throw new Error('bad rs block @ typeNumber:' + typeNumber + 1098 | '/errorCorrectLevel:' + errorCorrectLevel); 1099 | } 1100 | 1101 | var length = rsBlock.length / 3; 1102 | 1103 | var list = new Array(); 1104 | 1105 | for (var i = 0; i < length; i += 1) { 1106 | 1107 | var count = rsBlock[i * 3 + 0]; 1108 | var totalCount = rsBlock[i * 3 + 1]; 1109 | var dataCount = rsBlock[i * 3 + 2]; 1110 | 1111 | for (var j = 0; j < count; j += 1) { 1112 | list.push(qrRSBlock(totalCount, dataCount) ); 1113 | } 1114 | } 1115 | 1116 | return list; 1117 | }; 1118 | 1119 | return _this; 1120 | }(); 1121 | qrcode.QRRSBlock = QRRSBlock; 1122 | 1123 | //--------------------------------------------------------------------- 1124 | // qrBitBuffer 1125 | //--------------------------------------------------------------------- 1126 | 1127 | var qrBitBuffer = function() { 1128 | 1129 | var _buffer = new Array(); 1130 | var _length = 0; 1131 | 1132 | var _this = {}; 1133 | 1134 | _this.getBuffer = function() { 1135 | return _buffer; 1136 | }; 1137 | 1138 | _this.getAt = function(index) { 1139 | var bufIndex = Math.floor(index / 8); 1140 | return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1; 1141 | }; 1142 | 1143 | _this.put = function(num, length) { 1144 | for (var i = 0; i < length; i += 1) { 1145 | _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1); 1146 | } 1147 | }; 1148 | 1149 | _this.getLengthInBits = function() { 1150 | return _length; 1151 | }; 1152 | 1153 | _this.putBit = function(bit) { 1154 | 1155 | var bufIndex = Math.floor(_length / 8); 1156 | if (_buffer.length <= bufIndex) { 1157 | _buffer.push(0); 1158 | } 1159 | 1160 | if (bit) { 1161 | _buffer[bufIndex] |= (0x80 >>> (_length % 8) ); 1162 | } 1163 | 1164 | _length += 1; 1165 | }; 1166 | 1167 | return _this; 1168 | }; 1169 | 1170 | //--------------------------------------------------------------------- 1171 | // qr8BitByte 1172 | //--------------------------------------------------------------------- 1173 | 1174 | var qr8BitByte = function(data) { 1175 | 1176 | var _mode = QRMode.MODE_8BIT_BYTE; 1177 | var _data = data; 1178 | var _bytes = qrcode.stringToBytes(data); 1179 | 1180 | var _this = {}; 1181 | 1182 | _this.getMode = function() { 1183 | return _mode; 1184 | }; 1185 | 1186 | _this.getLength = function(buffer) { 1187 | return _bytes.length; 1188 | }; 1189 | 1190 | _this.write = function(buffer) { 1191 | for (var i = 0; i < _bytes.length; i += 1) { 1192 | buffer.put(_bytes[i], 8); 1193 | } 1194 | }; 1195 | 1196 | return _this; 1197 | }; 1198 | 1199 | //===================================================================== 1200 | // GIF Support etc. 1201 | // 1202 | 1203 | //--------------------------------------------------------------------- 1204 | // byteArrayOutputStream 1205 | //--------------------------------------------------------------------- 1206 | 1207 | var byteArrayOutputStream = function() { 1208 | 1209 | var _bytes = new Array(); 1210 | 1211 | var _this = {}; 1212 | 1213 | _this.writeByte = function(b) { 1214 | _bytes.push(b & 0xff); 1215 | }; 1216 | 1217 | _this.writeShort = function(i) { 1218 | _this.writeByte(i); 1219 | _this.writeByte(i >>> 8); 1220 | }; 1221 | 1222 | _this.writeBytes = function(b, off, len) { 1223 | off = off || 0; 1224 | len = len || b.length; 1225 | for (var i = 0; i < len; i += 1) { 1226 | _this.writeByte(b[i + off]); 1227 | } 1228 | }; 1229 | 1230 | _this.writeString = function(s) { 1231 | for (var i = 0; i < s.length; i += 1) { 1232 | _this.writeByte(s.charCodeAt(i) ); 1233 | } 1234 | }; 1235 | 1236 | _this.toByteArray = function() { 1237 | return _bytes; 1238 | }; 1239 | 1240 | _this.toString = function() { 1241 | var s = ''; 1242 | s += '['; 1243 | for (var i = 0; i < _bytes.length; i += 1) { 1244 | if (i > 0) { 1245 | s += ','; 1246 | } 1247 | s += _bytes[i]; 1248 | } 1249 | s += ']'; 1250 | return s; 1251 | }; 1252 | 1253 | return _this; 1254 | }; 1255 | 1256 | //--------------------------------------------------------------------- 1257 | // base64EncodeOutputStream 1258 | //--------------------------------------------------------------------- 1259 | 1260 | var base64EncodeOutputStream = function() { 1261 | 1262 | var _buffer = 0; 1263 | var _buflen = 0; 1264 | var _length = 0; 1265 | var _base64 = ''; 1266 | 1267 | var _this = {}; 1268 | 1269 | var writeEncoded = function(b) { 1270 | _base64 += String.fromCharCode(encode(b & 0x3f) ); 1271 | }; 1272 | 1273 | var encode = function(n) { 1274 | if (n < 0) { 1275 | // error. 1276 | } else if (n < 26) { 1277 | return 0x41 + n; 1278 | } else if (n < 52) { 1279 | return 0x61 + (n - 26); 1280 | } else if (n < 62) { 1281 | return 0x30 + (n - 52); 1282 | } else if (n == 62) { 1283 | return 0x2b; 1284 | } else if (n == 63) { 1285 | return 0x2f; 1286 | } 1287 | throw new Error('n:' + n); 1288 | }; 1289 | 1290 | _this.writeByte = function(n) { 1291 | 1292 | _buffer = (_buffer << 8) | (n & 0xff); 1293 | _buflen += 8; 1294 | _length += 1; 1295 | 1296 | while (_buflen >= 6) { 1297 | writeEncoded(_buffer >>> (_buflen - 6) ); 1298 | _buflen -= 6; 1299 | } 1300 | }; 1301 | 1302 | _this.flush = function() { 1303 | 1304 | if (_buflen > 0) { 1305 | writeEncoded(_buffer << (6 - _buflen) ); 1306 | _buffer = 0; 1307 | _buflen = 0; 1308 | } 1309 | 1310 | if (_length % 3 != 0) { 1311 | // padding 1312 | var padlen = 3 - _length % 3; 1313 | for (var i = 0; i < padlen; i += 1) { 1314 | _base64 += '='; 1315 | } 1316 | } 1317 | }; 1318 | 1319 | _this.toString = function() { 1320 | return _base64; 1321 | }; 1322 | 1323 | return _this; 1324 | }; 1325 | 1326 | //--------------------------------------------------------------------- 1327 | // base64DecodeInputStream 1328 | //--------------------------------------------------------------------- 1329 | 1330 | var base64DecodeInputStream = function(str) { 1331 | 1332 | var _str = str; 1333 | var _pos = 0; 1334 | var _buffer = 0; 1335 | var _buflen = 0; 1336 | 1337 | var _this = {}; 1338 | 1339 | _this.read = function() { 1340 | 1341 | while (_buflen < 8) { 1342 | 1343 | if (_pos >= _str.length) { 1344 | if (_buflen == 0) { 1345 | return -1; 1346 | } 1347 | throw new Error('unexpected end of file./' + _buflen); 1348 | } 1349 | 1350 | var c = _str.charAt(_pos); 1351 | _pos += 1; 1352 | 1353 | if (c == '=') { 1354 | _buflen = 0; 1355 | return -1; 1356 | } else if (c.match(/^\s$/) ) { 1357 | // ignore if whitespace. 1358 | continue; 1359 | } 1360 | 1361 | _buffer = (_buffer << 6) | decode(c.charCodeAt(0) ); 1362 | _buflen += 6; 1363 | } 1364 | 1365 | var n = (_buffer >>> (_buflen - 8) ) & 0xff; 1366 | _buflen -= 8; 1367 | return n; 1368 | }; 1369 | 1370 | var decode = function(c) { 1371 | if (0x41 <= c && c <= 0x5a) { 1372 | return c - 0x41; 1373 | } else if (0x61 <= c && c <= 0x7a) { 1374 | return c - 0x61 + 26; 1375 | } else if (0x30 <= c && c <= 0x39) { 1376 | return c - 0x30 + 52; 1377 | } else if (c == 0x2b) { 1378 | return 62; 1379 | } else if (c == 0x2f) { 1380 | return 63; 1381 | } else { 1382 | throw new Error('c:' + c); 1383 | } 1384 | }; 1385 | 1386 | return _this; 1387 | }; 1388 | 1389 | //--------------------------------------------------------------------- 1390 | // gifImage (B/W) 1391 | //--------------------------------------------------------------------- 1392 | 1393 | var gifImage = function(width, height) { 1394 | 1395 | var _width = width; 1396 | var _height = height; 1397 | var _data = new Array(width * height); 1398 | 1399 | var _this = {}; 1400 | 1401 | _this.setPixel = function(x, y, pixel) { 1402 | _data[y * _width + x] = pixel; 1403 | }; 1404 | 1405 | _this.write = function(out) { 1406 | 1407 | //--------------------------------- 1408 | // GIF Signature 1409 | 1410 | out.writeString('GIF87a'); 1411 | 1412 | //--------------------------------- 1413 | // Screen Descriptor 1414 | 1415 | out.writeShort(_width); 1416 | out.writeShort(_height); 1417 | 1418 | out.writeByte(0x80); // 2bit 1419 | out.writeByte(0); 1420 | out.writeByte(0); 1421 | 1422 | //--------------------------------- 1423 | // Global Color Map 1424 | 1425 | // black 1426 | out.writeByte(0x00); 1427 | out.writeByte(0x00); 1428 | out.writeByte(0x00); 1429 | 1430 | // white 1431 | out.writeByte(0xff); 1432 | out.writeByte(0xff); 1433 | out.writeByte(0xff); 1434 | 1435 | //--------------------------------- 1436 | // Image Descriptor 1437 | 1438 | out.writeString(','); 1439 | out.writeShort(0); 1440 | out.writeShort(0); 1441 | out.writeShort(_width); 1442 | out.writeShort(_height); 1443 | out.writeByte(0); 1444 | 1445 | //--------------------------------- 1446 | // Local Color Map 1447 | 1448 | //--------------------------------- 1449 | // Raster Data 1450 | 1451 | var lzwMinCodeSize = 2; 1452 | var raster = getLZWRaster(lzwMinCodeSize); 1453 | 1454 | out.writeByte(lzwMinCodeSize); 1455 | 1456 | var offset = 0; 1457 | 1458 | while (raster.length - offset > 255) { 1459 | out.writeByte(255); 1460 | out.writeBytes(raster, offset, 255); 1461 | offset += 255; 1462 | } 1463 | 1464 | out.writeByte(raster.length - offset); 1465 | out.writeBytes(raster, offset, raster.length - offset); 1466 | out.writeByte(0x00); 1467 | 1468 | //--------------------------------- 1469 | // GIF Terminator 1470 | out.writeString(';'); 1471 | }; 1472 | 1473 | var bitOutputStream = function(out) { 1474 | 1475 | var _out = out; 1476 | var _bitLength = 0; 1477 | var _bitBuffer = 0; 1478 | 1479 | var _this = {}; 1480 | 1481 | _this.write = function(data, length) { 1482 | 1483 | if ( (data >>> length) != 0) { 1484 | throw new Error('length over'); 1485 | } 1486 | 1487 | while (_bitLength + length >= 8) { 1488 | _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) ); 1489 | length -= (8 - _bitLength); 1490 | data >>>= (8 - _bitLength); 1491 | _bitBuffer = 0; 1492 | _bitLength = 0; 1493 | } 1494 | 1495 | _bitBuffer = (data << _bitLength) | _bitBuffer; 1496 | _bitLength = _bitLength + length; 1497 | }; 1498 | 1499 | _this.flush = function() { 1500 | if (_bitLength > 0) { 1501 | _out.writeByte(_bitBuffer); 1502 | } 1503 | }; 1504 | 1505 | return _this; 1506 | }; 1507 | 1508 | var getLZWRaster = function(lzwMinCodeSize) { 1509 | 1510 | var clearCode = 1 << lzwMinCodeSize; 1511 | var endCode = (1 << lzwMinCodeSize) + 1; 1512 | var bitLength = lzwMinCodeSize + 1; 1513 | 1514 | // Setup LZWTable 1515 | var table = lzwTable(); 1516 | 1517 | for (var i = 0; i < clearCode; i += 1) { 1518 | table.add(String.fromCharCode(i) ); 1519 | } 1520 | table.add(String.fromCharCode(clearCode) ); 1521 | table.add(String.fromCharCode(endCode) ); 1522 | 1523 | var byteOut = byteArrayOutputStream(); 1524 | var bitOut = bitOutputStream(byteOut); 1525 | 1526 | // clear code 1527 | bitOut.write(clearCode, bitLength); 1528 | 1529 | var dataIndex = 0; 1530 | 1531 | var s = String.fromCharCode(_data[dataIndex]); 1532 | dataIndex += 1; 1533 | 1534 | while (dataIndex < _data.length) { 1535 | 1536 | var c = String.fromCharCode(_data[dataIndex]); 1537 | dataIndex += 1; 1538 | 1539 | if (table.contains(s + c) ) { 1540 | 1541 | s = s + c; 1542 | 1543 | } else { 1544 | 1545 | bitOut.write(table.indexOf(s), bitLength); 1546 | 1547 | if (table.size() < 0xfff) { 1548 | 1549 | if (table.size() == (1 << bitLength) ) { 1550 | bitLength += 1; 1551 | } 1552 | 1553 | table.add(s + c); 1554 | } 1555 | 1556 | s = c; 1557 | } 1558 | } 1559 | 1560 | bitOut.write(table.indexOf(s), bitLength); 1561 | 1562 | // end code 1563 | bitOut.write(endCode, bitLength); 1564 | 1565 | bitOut.flush(); 1566 | 1567 | return byteOut.toByteArray(); 1568 | }; 1569 | 1570 | var lzwTable = function() { 1571 | 1572 | var _map = {}; 1573 | var _size = 0; 1574 | 1575 | var _this = {}; 1576 | 1577 | _this.add = function(key) { 1578 | if (_this.contains(key) ) { 1579 | throw new Error('dup key:' + key); 1580 | } 1581 | _map[key] = _size; 1582 | _size += 1; 1583 | }; 1584 | 1585 | _this.size = function() { 1586 | return _size; 1587 | }; 1588 | 1589 | _this.indexOf = function(key) { 1590 | return _map[key]; 1591 | }; 1592 | 1593 | _this.contains = function(key) { 1594 | return typeof _map[key] != 'undefined'; 1595 | }; 1596 | 1597 | return _this; 1598 | }; 1599 | 1600 | return _this; 1601 | }; 1602 | 1603 | var createImgTag = function(width, height, getPixel, alt) { 1604 | 1605 | var gif = gifImage(width, height); 1606 | for (var y = 0; y < height; y += 1) { 1607 | for (var x = 0; x < width; x += 1) { 1608 | gif.setPixel(x, y, getPixel(x, y) ); 1609 | } 1610 | } 1611 | 1612 | var b = byteArrayOutputStream(); 1613 | gif.write(b); 1614 | 1615 | var base64 = base64EncodeOutputStream(); 1616 | var bytes = b.toByteArray(); 1617 | for (var i = 0; i < bytes.length; i += 1) { 1618 | base64.writeByte(bytes[i]); 1619 | } 1620 | base64.flush(); 1621 | 1622 | var img = ''; 1623 | img += '