├── src └── NodeServicesExample.WebApi │ ├── Scripts │ ├── qr-image │ │ ├── tests │ │ │ ├── .gitignore │ │ │ └── test.js │ │ ├── .gitignore │ │ ├── examples │ │ │ ├── qr-svg.js │ │ │ └── qr-server.js │ │ ├── package.json │ │ ├── LICENSE │ │ ├── lib │ │ │ ├── crc32.js │ │ │ ├── crc32buffer.js │ │ │ ├── png.js │ │ │ ├── errorcode.js │ │ │ ├── qr.js │ │ │ ├── encode.js │ │ │ ├── qr-base.js │ │ │ ├── vector.js │ │ │ └── matrix.js │ │ └── README.md │ ├── Add.js │ ├── Eval.js │ └── QR.js │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── Program.cs │ ├── Startup.cs │ ├── NodeServicesExample.WebApi.csproj │ ├── Properties │ └── launchSettings.json │ └── Controllers │ └── ValuesController.cs ├── README.md ├── .gitattributes ├── NodeServicesExample.sln └── .gitignore /src/NodeServicesExample.WebApi/Scripts/qr-image/tests/.gitignore: -------------------------------------------------------------------------------- 1 | /qr.* 2 | /qr_* 3 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/.gitignore: -------------------------------------------------------------------------------- 1 | /qr-image-*.tgz 2 | .*.swp 3 | /node_modules 4 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/Add.js: -------------------------------------------------------------------------------- 1 | module.exports = function (callback, x, y) { 2 | let result = x + y; 3 | callback(null, result); 4 | }; -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/Eval.js: -------------------------------------------------------------------------------- 1 | module.exports = function (callback, x) { 2 | let result = eval(x); 3 | callback(null, result); 4 | }; 5 | 6 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/QR.js: -------------------------------------------------------------------------------- 1 | let qr = require('./qr-image'); 2 | module.exports = function (callback, text) { 3 | var result = qr.imageSync(text, { type: 'png' }); 4 | 5 | var data = []; 6 | result.forEach(i => { 7 | data.push(i); 8 | }); 9 | 10 | callback(null, data); 11 | }; -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "Debug": { 5 | "LogLevel": { 6 | "Default": "Warning" 7 | } 8 | }, 9 | "Console": { 10 | "LogLevel": { 11 | "Default": "Warning" 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NodeServicesExample 2 | Basic Web API Examples of NodeServices 3 | 4 | ## Related Blog Post 5 | 6 | You can read more about the contents of this repo in [this blog post entitled "NodeServices: Where Javascript and .NET Meet Back on the Other Side"](http://rion.io/nodeservices-where-javascript-and-net-meet-back-on-the-other-side). 7 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/examples/qr-svg.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var qr = require('../'); 4 | var text = process.argv.slice(2).join(' '); 5 | 6 | if (!text) { 7 | console.error('Usage: node qr-svg.js "text to encode" > qr.svg'); 8 | process.exit(1); 9 | } 10 | 11 | qr.image(text, { type: 'svg' }).pipe(process.stdout); 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | 4 | namespace NodeServicesExample.WebApi 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | BuildWebHost(args).Run(); 11 | } 12 | 13 | public static IWebHost BuildWebHost(string[] args) => 14 | WebHost.CreateDefaultBuilder(args) 15 | .UseStartup() 16 | .Build(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/examples/qr-server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var url = require('url'); 3 | var qr = require('../'); 4 | 5 | http.createServer(function (req, res) { 6 | var text = url.parse(req.url, true).query.text; 7 | try { 8 | var img = qr.image(text); 9 | res.writeHead(200, {'Content-Type': 'image/png'}); 10 | img.pipe(res); 11 | } catch (e) { 12 | res.writeHead(414, {'Content-Type': 'text/html'}); 13 | res.end('

414 Request-URI Too Large

'); 14 | } 15 | }).listen(5152); 16 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace NodeServicesExample.WebApi 6 | { 7 | public class Startup 8 | { 9 | public void ConfigureServices(IServiceCollection services) 10 | { 11 | services.AddMvc(); 12 | services.AddNodeServices(); 13 | } 14 | 15 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 16 | { 17 | app.UseMvc(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qr-image", 3 | "version": "3.2.0", 4 | "description": "QR Code generator (png, svg, pdf, eps)", 5 | "homepage": "https://github.com/alexeyten/qr-image", 6 | "keywords": [ "qrcode", "qr code", "qr", "png", "svg", "image" ], 7 | "author": { 8 | "name": "Alexey Ten", 9 | "url": "http://git.io/alexeyten" 10 | }, 11 | "license": "MIT", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/alexeyten/qr-image.git" 15 | }, 16 | "bugs": "https://github.com/alexeyten/qr-image/issues", 17 | "main": "./lib/qr.js", 18 | "scripts": { 19 | "test": "./tests/test.js" 20 | }, 21 | "files": [ 22 | "lib", 23 | "LICENSE" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/NodeServicesExample.WebApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | aspnet-NodeServicesExample-A7055113-C611-482E-86E8-BCEA5BE9CB3E 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/tests/test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | function file(name) { 5 | return fs.createWriteStream(__dirname + '/' + name); 6 | } 7 | 8 | var qr = require('./../'); 9 | var text = 'I \u2764\uFE0F QR code!'; 10 | var text = 'https://yadi.sk/d/FuzPeEg-QyaZN?qr'; 11 | var ec_level = 'Q'; 12 | 13 | qr.image(text, { type: 'png', ec_level: ec_level, parse_url: false, margin: 1}).pipe(file('qr_f.png')); 14 | qr.image(text, { type: 'png', ec_level: ec_level, parse_url: true, margin: 1}).pipe(file('qr_t.png')); 15 | qr.image(text, { type: 'svg', ec_level: ec_level}).pipe(file('qr.svg')); 16 | qr.image(text, { type: 'eps', ec_level: ec_level}).pipe(file('qr.eps')); 17 | qr.image(text, { type: 'pdf', ec_level: ec_level}).pipe(file('qr.pdf')); 18 | 19 | fs.writeFileSync('qr_sync.png', qr.imageSync(text)); 20 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:50441/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "api/values", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "NodeServicesExample": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "launchUrl": "api/values", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | }, 26 | "applicationUrl": "http://localhost:50442/" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Yandex LLC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /NodeServicesExample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NodeServicesExample.WebApi", "src\NodeServicesExample.WebApi\NodeServicesExample.WebApi.csproj", "{74AF62B6-B274-4E78-9EF4-5574FC8A4CA4}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {74AF62B6-B274-4E78-9EF4-5574FC8A4CA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {74AF62B6-B274-4E78-9EF4-5574FC8A4CA4}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {74AF62B6-B274-4E78-9EF4-5574FC8A4CA4}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {74AF62B6-B274-4E78-9EF4-5574FC8A4CA4}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {7AE102C3-8D6D-4A88-A836-F44AD8ADCC55} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Controllers/ValuesController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.NodeServices; 3 | using System.Threading.Tasks; 4 | 5 | namespace NodeServicesExample.Controllers 6 | { 7 | [Route("api/[controller]")] 8 | public class ValuesController : Controller 9 | { 10 | private readonly INodeServices _nodeServices; 11 | 12 | public ValuesController(INodeServices nodeServices) 13 | { 14 | _nodeServices = nodeServices; 15 | } 16 | 17 | [HttpGet("add")] 18 | public async Task Add(int x = 11, int y = 31) 19 | { 20 | return await _nodeServices.InvokeAsync("Scripts/Add.js", x, y); 21 | } 22 | 23 | [HttpGet("eval")] 24 | public async Task Multiply(string expression = "6 * 7") 25 | { 26 | return await _nodeServices.InvokeAsync("Scripts/Eval.js", expression); 27 | } 28 | 29 | [HttpGet("qr")] 30 | public async Task QR(string text = "42") 31 | { 32 | var data = await _nodeServices.InvokeAsync("Scripts/QR.js", text); 33 | return File(data, "image/png"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/crc32.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | (function() { 4 | 5 | // ARMv6 (Raspberry Pi) has bug in bitwise operations 6 | // https://code.google.com/p/v8/issues/detail?id=3757 7 | // https://github.com/alexeyten/qr-image/issues/13 8 | if (process.arch === 'arm') { 9 | module.exports = require('./crc32buffer'); 10 | return; 11 | } 12 | 13 | var crc_table = []; 14 | 15 | (function() { 16 | for (var n = 0; n < 256; n++) { 17 | var c = n; 18 | for (var k = 0; k < 8; k++) { 19 | if (c & 1) { 20 | c = 0xedb88320 ^ (c >>> 1); 21 | } else { 22 | c = c >>> 1; 23 | } 24 | } 25 | crc_table[n] = c >>> 0; 26 | } 27 | })(); 28 | 29 | function update(c, buf) { 30 | var l = buf.length; 31 | for (var n = 0; n < l; n++) { 32 | c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >>> 8); 33 | } 34 | return c; 35 | } 36 | 37 | function crc32(/* arguments */) { 38 | var l = arguments.length; 39 | var c = -1; 40 | for (var i = 0; i < l; i++) { 41 | c = update(c, new Buffer(arguments[i])); 42 | } 43 | c = (c ^ -1) >>> 0; 44 | return c; 45 | } 46 | 47 | module.exports = crc32; 48 | 49 | })(); 50 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/crc32buffer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var crc_table = []; 4 | 5 | for (var n = 0; n < 256; n++) { 6 | var c = crc_table[n] = new Buffer(4); 7 | c.writeUInt32BE(n, 0); 8 | 9 | for (var k = 0; k < 8; k++) { 10 | var b0 = c[0] & 1; 11 | var b1 = c[1] & 1; 12 | var b2 = c[2] & 1; 13 | var b3 = c[3] & 1; 14 | 15 | c[0] = (c[0] >> 1) ^ (b3 ? 0xed : 0); 16 | c[1] = (c[1] >> 1) ^ (b3 ? 0xb8 : 0) ^ (b0 ? 0x80 : 0); 17 | c[2] = (c[2] >> 1) ^ (b3 ? 0x83 : 0) ^ (b1 ? 0x80 : 0); 18 | c[3] = (c[3] >> 1) ^ (b3 ? 0x20 : 0) ^ (b2 ? 0x80 : 0); 19 | } 20 | } 21 | 22 | function update(c, buf) { 23 | var l = buf.length; 24 | for (var n = 0; n < l; n++) { 25 | var e = crc_table[c[3] ^ buf[n]]; 26 | c[3] = e[3] ^ c[2]; 27 | c[2] = e[2] ^ c[1]; 28 | c[1] = e[1] ^ c[0]; 29 | c[0] = e[0]; 30 | } 31 | } 32 | 33 | function crc32(/* arguments */) { 34 | var l = arguments.length; 35 | var c = new Buffer(4); 36 | c.fill(0xff); 37 | 38 | for (var i = 0; i < l; i++) { 39 | update(c, new Buffer(arguments[i])); 40 | } 41 | 42 | c[0] = c[0] ^ 0xff; 43 | c[1] = c[1] ^ 0xff; 44 | c[2] = c[2] ^ 0xff; 45 | c[3] = c[3] ^ 0xff; 46 | 47 | return c.readUInt32BE(0); 48 | } 49 | 50 | module.exports = crc32; 51 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/png.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var zlib = require('zlib'); 4 | 5 | var crc32 = require('./crc32'); 6 | 7 | var PNG_HEAD = new Buffer([137,80,78,71,13,10,26,10]); 8 | var PNG_IHDR = new Buffer([0,0,0,13,73,72,68,82,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0]); 9 | var PNG_IDAT = new Buffer([0,0,0,0,73,68,65,84]); 10 | var PNG_IEND = new Buffer([0,0,0,0,73,69,78,68,174,66,96,130]); 11 | 12 | function png(bitmap, stream) { 13 | stream.push(PNG_HEAD); 14 | 15 | var IHDR = Buffer.concat([PNG_IHDR]); 16 | IHDR.writeUInt32BE(bitmap.size, 8); 17 | IHDR.writeUInt32BE(bitmap.size, 12); 18 | IHDR.writeUInt32BE(crc32(IHDR.slice(4, -4)), 21); 19 | stream.push(IHDR); 20 | 21 | var IDAT = Buffer.concat([ 22 | PNG_IDAT, 23 | zlib.deflateSync(bitmap.data, { level: 9 }), 24 | new Buffer(4) 25 | ]); 26 | IDAT.writeUInt32BE(IDAT.length - 12, 0); 27 | IDAT.writeUInt32BE(crc32(IDAT.slice(4, -4)), IDAT.length - 4); 28 | stream.push(IDAT); 29 | 30 | stream.push(PNG_IEND); 31 | stream.push(null); 32 | } 33 | 34 | function bitmap(matrix, size, margin) { 35 | var N = matrix.length; 36 | var X = (N + 2 * margin) * size; 37 | var data = new Buffer((X + 1) * X); 38 | data.fill(255); 39 | for (var i = 0; i < X; i++) { 40 | data[i * (X + 1)] = 0; 41 | } 42 | 43 | for (var i = 0; i < N; i++) { 44 | for (var j = 0; j < N; j++) { 45 | if (matrix[i][j]) { 46 | var offset = ((margin + i) * (X + 1) + (margin + j)) * size + 1; 47 | data.fill(0, offset, offset + size); 48 | for (var c = 1; c < size; c++) { 49 | data.copy(data, offset + c * (X + 1), offset, offset + size); 50 | } 51 | } 52 | } 53 | } 54 | 55 | return { 56 | data: data, 57 | size: X 58 | } 59 | } 60 | 61 | module.exports = { 62 | bitmap: bitmap, 63 | png: png 64 | } 65 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/errorcode.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // {{{1 Galois Field Math 4 | var GF256_BASE = 285; 5 | 6 | var EXP_TABLE = [1]; 7 | var LOG_TABLE = []; 8 | 9 | for (var i = 1; i < 256; i++) { 10 | var n = EXP_TABLE[i - 1] << 1; 11 | if (n > 255) n = n ^ GF256_BASE; 12 | EXP_TABLE[i] = n; 13 | } 14 | 15 | for (var i = 0; i < 255; i++) { 16 | LOG_TABLE[EXP_TABLE[i]] = i; 17 | } 18 | 19 | function exp(k) { 20 | while (k < 0) k += 255; 21 | while (k > 255) k -= 255; 22 | return EXP_TABLE[k]; 23 | } 24 | 25 | function log(k) { 26 | if (k < 1 || k > 255) { 27 | throw Error('Bad log(' + k + ')'); 28 | } 29 | return LOG_TABLE[k]; 30 | } 31 | 32 | // {{{1 Generator Polynomials 33 | var POLYNOMIALS = [ 34 | [0], // a^0 x^0 35 | [0, 0], // a^0 x^1 + a^0 x^0 36 | [0, 25, 1], // a^0 x^2 + a^25 x^1 + a^1 x^0 37 | // and so on... 38 | ]; 39 | 40 | function generatorPolynomial(num) { 41 | if (POLYNOMIALS[num]) { 42 | return POLYNOMIALS[num]; 43 | } 44 | var prev = generatorPolynomial(num - 1); 45 | var res = []; 46 | 47 | res[0] = prev[0]; 48 | for (var i = 1; i <= num; i++) { 49 | res[i] = log(exp(prev[i]) ^ exp(prev[i - 1] + num - 1)); 50 | } 51 | POLYNOMIALS[num] = res; 52 | return res; 53 | } 54 | 55 | // {{{1 export functions 56 | module.exports = function calculate_ec(msg, ec_len) { 57 | // `msg` could be array or buffer 58 | // convert `msg` to array 59 | msg = [].slice.call(msg); 60 | 61 | // Generator Polynomial 62 | var poly = generatorPolynomial(ec_len); 63 | 64 | for (var i = 0; i < ec_len; i++) msg.push(0); 65 | while (msg.length > ec_len) { 66 | if (!msg[0]) { 67 | msg.shift(); 68 | continue; 69 | } 70 | var log_k = log(msg[0]); 71 | for (var i = 0; i <= ec_len; i++) { 72 | msg[i] = msg[i] ^ exp(poly[i] + log_k); 73 | } 74 | msg.shift(); 75 | } 76 | return new Buffer(msg); 77 | } 78 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/README.md: -------------------------------------------------------------------------------- 1 | qr-image 2 | ======== 3 | 4 | [![npm version](https://badge.fury.io/js/qr-image.svg)](https://badge.fury.io/js/qr-image) 5 | 6 | This is yet another QR Code generator. 7 | 8 | Overview 9 | -------- 10 | 11 | * No dependecies; 12 | * generate image in `png`, `svg`, `eps` and `pdf` formats; 13 | * numeric and alphanumeric modes; 14 | * support UTF-8. 15 | 16 | [Releases](https://github.com/alexeyten/qr-image/releases/) 17 | 18 | 19 | Installing 20 | ----- 21 | 22 | ```shell 23 | npm install qr-image 24 | ``` 25 | 26 | Usage 27 | ----- 28 | 29 | Example: 30 | ```javascript 31 | var qr = require('qr-image'); 32 | 33 | var qr_svg = qr.image('I love QR!', { type: 'svg' }); 34 | qr_svg.pipe(require('fs').createWriteStream('i_love_qr.svg')); 35 | 36 | var svg_string = qr.imageSync('I love QR!', { type: 'svg' }); 37 | ``` 38 | 39 | [More examples](./examples) 40 | 41 | `qr = require('qr-image')` 42 | 43 | ### Methods 44 | 45 | * `qr.image(text, [ec_level | options])` — Readable stream with image data; 46 | * `qr.imageSync(text, [ec_level | options])` — string with image data. (Buffer for `png`); 47 | * `qr.svgObject(text, [ec_level | options])` — object with SVG path and size; 48 | * `qr.matrix(text, [ec_level])` — 2D array. 49 | 50 | 51 | ### Options 52 | 53 | * `text` — text to encode; 54 | * `ec_level` — error correction level. One of `L`, `M`, `Q`, `H`. Default `M`. 55 | * `options` — image options object: 56 | * `ec_level` — default `M`. 57 | * `type` — image type. Possible values `png` (default), `svg`, `pdf` and `eps`. 58 | * `size` (png and svg only) — size of one module in pixels. Default `5` for png and `undefined` for svg. 59 | * `margin` — white space around QR image in modules. Default `4` for `png` and `1` for others. 60 | * `customize` (only png) — function to customize qr bitmap before encoding to PNG. 61 | * `parse_url` (experimental, default `false`) — try to optimize QR-code for URLs. 62 | 63 | Changes 64 | ------- 65 | 66 | * Use `zlib.deflateSync` instead of `pako`. 67 | * Fix deprecation warning for NodeJS 7. 68 | 69 | 70 | TODO 71 | ---- 72 | 73 | * Tests; 74 | * mixing modes; 75 | * Kanji (???). 76 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/qr.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Readable = require('stream').Readable; 4 | 5 | var QR = require('./qr-base').QR; 6 | var png = require('./png'); 7 | var vector = require('./vector'); 8 | 9 | var fn_noop = function() {}; 10 | 11 | var BITMAP_OPTIONS = { 12 | parse_url: false, 13 | ec_level: 'M', 14 | size: 5, 15 | margin: 4, 16 | customize: null 17 | }; 18 | 19 | var VECTOR_OPTIONS = { 20 | parse_url: false, 21 | ec_level: 'M', 22 | margin: 1, 23 | size: 0 24 | }; 25 | 26 | function get_options(options, force_type) { 27 | if (typeof options === 'string') { 28 | options = { 'ec_level': options } 29 | } else { 30 | options = options || {}; 31 | } 32 | var _options = { 33 | type: String(force_type || options.type || 'png').toLowerCase() 34 | }; 35 | 36 | var defaults = _options.type == 'png' ? BITMAP_OPTIONS : VECTOR_OPTIONS; 37 | 38 | for (var k in defaults) { 39 | _options[k] = k in options ? options[k] : defaults[k]; 40 | } 41 | 42 | return _options; 43 | } 44 | 45 | function qr_image(text, options) { 46 | options = get_options(options); 47 | 48 | var matrix = QR(text, options.ec_level, options.parse_url); 49 | var stream = new Readable(); 50 | stream._read = fn_noop; 51 | 52 | switch (options.type) { 53 | case 'svg': 54 | case 'pdf': 55 | case 'eps': 56 | process.nextTick(function() { 57 | vector[options.type](matrix, stream, options.margin, options.size); 58 | }); 59 | break; 60 | case 'svgpath': 61 | // deprecated, use svg_object method 62 | process.nextTick(function() { 63 | var obj = vector.svg_object(matrix, options.margin, options.size); 64 | stream.push(obj.path); 65 | stream.push(null); 66 | }); 67 | break; 68 | case 'png': 69 | default: 70 | process.nextTick(function() { 71 | var bitmap = png.bitmap(matrix, options.size, options.margin); 72 | if (options.customize) { 73 | options.customize(bitmap); 74 | } 75 | png.png(bitmap, stream); 76 | }); 77 | } 78 | 79 | return stream; 80 | } 81 | 82 | function qr_image_sync(text, options) { 83 | options = get_options(options); 84 | 85 | var matrix = QR(text, options.ec_level, options.parse_url); 86 | var stream = []; 87 | var result; 88 | 89 | switch (options.type) { 90 | case 'svg': 91 | case 'pdf': 92 | case 'eps': 93 | vector[options.type](matrix, stream, options.margin, options.size); 94 | result = stream.filter(Boolean).join(''); 95 | break; 96 | case 'png': 97 | default: 98 | var bitmap = png.bitmap(matrix, options.size, options.margin); 99 | if (options.customize) { 100 | options.customize(bitmap); 101 | } 102 | png.png(bitmap, stream); 103 | result = Buffer.concat(stream.filter(Boolean)); 104 | } 105 | 106 | return result; 107 | } 108 | 109 | function svg_object(text, options) { 110 | options = get_options(options, 'svg'); 111 | 112 | var matrix = QR(text, options.ec_level); 113 | return vector.svg_object(matrix, options.margin); 114 | } 115 | 116 | module.exports = { 117 | matrix: QR, 118 | image: qr_image, 119 | imageSync: qr_image_sync, 120 | svgObject: svg_object 121 | }; 122 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/encode.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function pushBits(arr, n, value) { 4 | for (var bit = 1 << (n - 1); bit; bit = bit >>> 1) { 5 | arr.push(bit & value ? 1 : 0); 6 | } 7 | } 8 | 9 | // {{{1 8bit encode 10 | function encode_8bit(data) { 11 | var len = data.length; 12 | var bits = []; 13 | 14 | for (var i = 0; i < len; i++) { 15 | pushBits(bits, 8, data[i]); 16 | } 17 | 18 | var res = {}; 19 | 20 | var d = [0, 1, 0, 0]; 21 | pushBits(d, 16, len); 22 | res.data10 = res.data27 = d.concat(bits); 23 | 24 | if (len < 256) { 25 | var d = [0, 1, 0, 0]; 26 | pushBits(d, 8, len); 27 | res.data1 = d.concat(bits); 28 | } 29 | 30 | return res; 31 | } 32 | 33 | // {{{1 alphanumeric encode 34 | var ALPHANUM = (function(s) { 35 | var res = {}; 36 | for (var i = 0; i < s.length; i++) { 37 | res[s[i]] = i; 38 | } 39 | return res; 40 | })('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'); 41 | 42 | function encode_alphanum(str) { 43 | var len = str.length; 44 | var bits = []; 45 | 46 | for (var i = 0; i < len; i += 2) { 47 | var b = 6; 48 | var n = ALPHANUM[str[i]]; 49 | if (str[i+1]) { 50 | b = 11; 51 | n = n * 45 + ALPHANUM[str[i+1]]; 52 | } 53 | pushBits(bits, b, n); 54 | } 55 | 56 | var res = {}; 57 | 58 | var d = [0, 0, 1, 0]; 59 | pushBits(d, 13, len); 60 | res.data27 = d.concat(bits); 61 | 62 | if (len < 2048) { 63 | var d = [0, 0, 1, 0]; 64 | pushBits(d, 11, len); 65 | res.data10 = d.concat(bits); 66 | } 67 | 68 | if (len < 512) { 69 | var d = [0, 0, 1, 0]; 70 | pushBits(d, 9, len); 71 | res.data1 = d.concat(bits); 72 | } 73 | 74 | return res; 75 | } 76 | 77 | // {{{1 numeric encode 78 | function encode_numeric(str) { 79 | var len = str.length; 80 | var bits = []; 81 | 82 | for (var i = 0; i < len; i += 3) { 83 | var s = str.substr(i, 3); 84 | var b = Math.ceil(s.length * 10 / 3); 85 | pushBits(bits, b, parseInt(s, 10)); 86 | } 87 | 88 | var res = {}; 89 | 90 | var d = [0, 0, 0, 1]; 91 | pushBits(d, 14, len); 92 | res.data27 = d.concat(bits); 93 | 94 | if (len < 4096) { 95 | var d = [0, 0, 0, 1]; 96 | pushBits(d, 12, len); 97 | res.data10 = d.concat(bits); 98 | } 99 | 100 | if (len < 1024) { 101 | var d = [0, 0, 0, 1]; 102 | pushBits(d, 10, len); 103 | res.data1 = d.concat(bits); 104 | } 105 | 106 | return res; 107 | } 108 | 109 | // {{{1 url encode 110 | function encode_url(str) { 111 | var slash = str.indexOf('/', 8) + 1 || str.length; 112 | var res = encode(str.slice(0, slash).toUpperCase(), false); 113 | 114 | if (slash >= str.length) { 115 | return res; 116 | } 117 | 118 | var path_res = encode(str.slice(slash), false); 119 | 120 | res.data27 = res.data27.concat(path_res.data27); 121 | 122 | if (res.data10 && path_res.data10) { 123 | res.data10 = res.data10.concat(path_res.data10); 124 | } 125 | 126 | if (res.data1 && path_res.data1) { 127 | res.data1 = res.data1.concat(path_res.data1); 128 | } 129 | 130 | return res; 131 | } 132 | 133 | // {{{1 Choose encode mode and generates struct with data for different version 134 | function encode(data, parse_url) { 135 | var str; 136 | var t = typeof data; 137 | 138 | if (t == 'string' || t == 'number') { 139 | str = '' + data; 140 | data = new Buffer(str); 141 | } else if (Buffer.isBuffer(data)) { 142 | str = data.toString(); 143 | } else if (Array.isArray(data)) { 144 | data = new Buffer(data); 145 | str = data.toString(); 146 | } else { 147 | throw new Error("Bad data"); 148 | } 149 | 150 | if (/^[0-9]+$/.test(str)) { 151 | if (data.length > 7089) { 152 | throw new Error("Too much data"); 153 | } 154 | return encode_numeric(str); 155 | } 156 | 157 | if (/^[0-9A-Z \$%\*\+\.\/\:\-]+$/.test(str)) { 158 | if (data.length > 4296) { 159 | throw new Error("Too much data"); 160 | } 161 | return encode_alphanum(str); 162 | } 163 | 164 | if (parse_url && /^https?:/i.test(str)) { 165 | return encode_url(str); 166 | } 167 | 168 | if (data.length > 2953) { 169 | throw new Error("Too much data"); 170 | } 171 | return encode_8bit(data); 172 | } 173 | 174 | // {{{1 export functions 175 | module.exports = encode; 176 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/qr-base.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var encode = require('./encode'); 4 | var calculateEC = require('./errorcode'); 5 | var matrix = require('./matrix'); 6 | 7 | function _deepCopy(obj) { 8 | return JSON.parse(JSON.stringify(obj)); 9 | } 10 | 11 | var EC_LEVELS = ['L', 'M', 'Q', 'H']; 12 | 13 | // {{{1 Versions 14 | var versions = [ 15 | [], // there is no version 0 16 | // total number of codewords, (number of ec codewords, number of blocks) * ( L, M, Q, H ) 17 | [26, 7, 1, 10, 1, 13, 1, 17, 1], 18 | [44, 10, 1, 16, 1, 22, 1, 28, 1], 19 | [70, 15, 1, 26, 1, 36, 2, 44, 2], 20 | [100, 20, 1, 36, 2, 52, 2, 64, 4], 21 | [134, 26, 1, 48, 2, 72, 4, 88, 4], // 5 22 | [172, 36, 2, 64, 4, 96, 4, 112, 4], 23 | [196, 40, 2, 72, 4, 108, 6, 130, 5], 24 | [242, 48, 2, 88, 4, 132, 6, 156, 6], 25 | [292, 60, 2, 110, 5, 160, 8, 192, 8], 26 | [346, 72, 4, 130, 5, 192, 8, 224, 8], // 10 27 | [404, 80, 4, 150, 5, 224, 8, 264, 11], 28 | [466, 96, 4, 176, 8, 260, 10, 308, 11], 29 | [532, 104, 4, 198, 9, 288, 12, 352, 16], 30 | [581, 120, 4, 216, 9, 320, 16, 384, 16], 31 | [655, 132, 6, 240, 10, 360, 12, 432, 18], // 15 32 | [733, 144, 6, 280, 10, 408, 17, 480, 16], 33 | [815, 168, 6, 308, 11, 448, 16, 532, 19], 34 | [901, 180, 6, 338, 13, 504, 18, 588, 21], 35 | [991, 196, 7, 364, 14, 546, 21, 650, 25], 36 | [1085, 224, 8, 416, 16, 600, 20, 700, 25], // 20 37 | [1156, 224, 8, 442, 17, 644, 23, 750, 25], 38 | [1258, 252, 9, 476, 17, 690, 23, 816, 34], 39 | [1364, 270, 9, 504, 18, 750, 25, 900, 30], 40 | [1474, 300, 10, 560, 20, 810, 27, 960, 32], 41 | [1588, 312, 12, 588, 21, 870, 29, 1050, 35], // 25 42 | [1706, 336, 12, 644, 23, 952, 34, 1110, 37], 43 | [1828, 360, 12, 700, 25, 1020, 34, 1200, 40], 44 | [1921, 390, 13, 728, 26, 1050, 35, 1260, 42], 45 | [2051, 420, 14, 784, 28, 1140, 38, 1350, 45], 46 | [2185, 450, 15, 812, 29, 1200, 40, 1440, 48], // 30 47 | [2323, 480, 16, 868, 31, 1290, 43, 1530, 51], 48 | [2465, 510, 17, 924, 33, 1350, 45, 1620, 54], 49 | [2611, 540, 18, 980, 35, 1440, 48, 1710, 57], 50 | [2761, 570, 19, 1036, 37, 1530, 51, 1800, 60], 51 | [2876, 570, 19, 1064, 38, 1590, 53, 1890, 63], // 35 52 | [3034, 600, 20, 1120, 40, 1680, 56, 1980, 66], 53 | [3196, 630, 21, 1204, 43, 1770, 59, 2100, 70], 54 | [3362, 660, 22, 1260, 45, 1860, 62, 2220, 74], 55 | [3532, 720, 24, 1316, 47, 1950, 65, 2310, 77], 56 | [3706, 750, 25, 1372, 49, 2040, 68, 2430, 81] // 40 57 | ]; 58 | 59 | versions = versions.map(function(v, index) { 60 | if (!index) return {}; 61 | 62 | var res = { 63 | } 64 | for (var i = 1; i < 8; i += 2) { 65 | var length = v[0] - v[i]; 66 | var num_template = v[i+1]; 67 | var ec_level = EC_LEVELS[(i/2)|0]; 68 | var level = { 69 | version: index, 70 | ec_level: ec_level, 71 | data_len: length, 72 | ec_len: v[i] / num_template, 73 | blocks: [], 74 | ec: [] 75 | } 76 | 77 | for (var k = num_template, n = length; k > 0; k--) { 78 | var block = (n / k)|0; 79 | level.blocks.push(block); 80 | n -= block; 81 | 82 | } 83 | res[ec_level] = level; 84 | } 85 | return res; 86 | }); 87 | 88 | // {{{1 Get version template 89 | function getTemplate(message, ec_level) { 90 | var i = 1; 91 | var len; 92 | 93 | if (message.data1) { 94 | len = Math.ceil(message.data1.length / 8); 95 | } else { 96 | i = 10; 97 | } 98 | for (/* i */; i < 10; i++) { 99 | var version = versions[i][ec_level]; 100 | if (version.data_len >= len) { 101 | return _deepCopy(version); 102 | } 103 | } 104 | 105 | if (message.data10) { 106 | len = Math.ceil(message.data10.length / 8); 107 | } else { 108 | i = 27; 109 | } 110 | for (/* i */; i < 27; i++) { 111 | var version = versions[i][ec_level]; 112 | if (version.data_len >= len) { 113 | return _deepCopy(version); 114 | } 115 | } 116 | 117 | len = Math.ceil(message.data27.length / 8); 118 | for (/* i */; i < 41; i++) { 119 | var version = versions[i][ec_level]; 120 | if (version.data_len >= len) { 121 | return _deepCopy(version); 122 | } 123 | } 124 | throw new Error("Too much data"); 125 | } 126 | 127 | // {{{1 Fill template 128 | function fillTemplate(message, template) { 129 | var blocks = new Buffer(template.data_len); 130 | blocks.fill(0); 131 | 132 | if (template.version < 10) { 133 | message = message.data1; 134 | } else if (template.version < 27) { 135 | message = message.data10; 136 | } else { 137 | message = message.data27; 138 | } 139 | 140 | var len = message.length; 141 | 142 | for (var i = 0; i < len; i += 8) { 143 | var b = 0; 144 | for (var j = 0; j < 8; j++) { 145 | b = (b << 1) | (message[i + j] ? 1 : 0); 146 | } 147 | blocks[i / 8] = b; 148 | } 149 | 150 | var pad = 236; 151 | for (var i = Math.ceil((len + 4) / 8); i < blocks.length; i++) { 152 | blocks[i] = pad; 153 | pad = (pad == 236) ? 17 : 236; 154 | } 155 | 156 | var offset = 0; 157 | template.blocks = template.blocks.map(function(n) { 158 | var b = blocks.slice(offset, offset + n); 159 | offset += n; 160 | template.ec.push(calculateEC(b, template.ec_len)); 161 | return b; 162 | }); 163 | 164 | return template; 165 | } 166 | 167 | // {{{1 All-in-one 168 | function QR(text, ec_level, parse_url) { 169 | ec_level = EC_LEVELS.indexOf(ec_level) > -1 ? ec_level : 'M'; 170 | var message = encode(text, parse_url); 171 | var data = fillTemplate(message, getTemplate(message, ec_level)); 172 | return matrix.getMatrix(data); 173 | } 174 | 175 | // {{{1 export functions 176 | module.exports = { 177 | QR: QR, 178 | getTemplate: getTemplate, 179 | fillTemplate: fillTemplate, 180 | } 181 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | 254 | # ========================= 255 | # Operating System Files 256 | # ========================= 257 | 258 | # OSX 259 | # ========================= 260 | 261 | .DS_Store 262 | .AppleDouble 263 | .LSOverride 264 | 265 | # Thumbnails 266 | ._* 267 | 268 | # Files that might appear in the root of a volume 269 | .DocumentRevisions-V100 270 | .fseventsd 271 | .Spotlight-V100 272 | .TemporaryItems 273 | .Trashes 274 | .VolumeIcon.icns 275 | 276 | # Directories potentially created on remote AFP share 277 | .AppleDB 278 | .AppleDesktop 279 | Network Trash Folder 280 | Temporary Items 281 | .apdisk 282 | 283 | # Windows 284 | # ========================= 285 | 286 | # Windows image file caches 287 | Thumbs.db 288 | ehthumbs.db 289 | 290 | # Folder config file 291 | Desktop.ini 292 | 293 | # Recycle Bin used on file shares 294 | $RECYCLE.BIN/ 295 | 296 | # Windows Installer files 297 | *.cab 298 | *.msi 299 | *.msm 300 | *.msp 301 | 302 | # Windows shortcuts 303 | *.lnk 304 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/vector.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function matrix2path(matrix) { 4 | var N = matrix.length; 5 | var filled = []; 6 | for (var row = -1; row <= N; row++) { 7 | filled[row] = []; 8 | } 9 | 10 | var path = []; 11 | for (var row = 0; row < N; row++) { 12 | for (var col = 0; col < N; col++) { 13 | if (filled[row][col]) continue; 14 | filled[row][col] = 1; 15 | if (isDark(row, col)) { 16 | if (!isDark(row - 1, col)) { 17 | path.push(plot(row, col, 'right')); 18 | } 19 | } else { 20 | if (isDark(row, col - 1)) { 21 | path.push(plot(row, col, 'down')); 22 | } 23 | } 24 | } 25 | } 26 | return path; 27 | 28 | function isDark(row, col) { 29 | if (row < 0 || col < 0 || row >= N || col >= N) return false; 30 | return !!matrix[row][col]; 31 | } 32 | 33 | function plot(row0, col0, dir) { 34 | filled[row0][col0] = 1; 35 | var res = []; 36 | res.push(['M', col0, row0 ]); 37 | var row = row0; 38 | var col = col0; 39 | var len = 0; 40 | do { 41 | switch (dir) { 42 | case 'right': 43 | filled[row][col] = 1; 44 | if (isDark(row, col)) { 45 | filled[row - 1][col] = 1; 46 | if (isDark(row - 1, col)) { 47 | res.push(['h', len]); 48 | len = 0; 49 | dir = 'up'; 50 | } else { 51 | len++; 52 | col++; 53 | } 54 | } else { 55 | res.push(['h', len]); 56 | len = 0; 57 | dir = 'down'; 58 | } 59 | break; 60 | case 'left': 61 | filled[row - 1][col - 1] = 1; 62 | if (isDark(row - 1, col - 1)) { 63 | filled[row][col - 1] = 1; 64 | if (isDark(row, col - 1)) { 65 | res.push(['h', -len]); 66 | len = 0; 67 | dir = 'down'; 68 | } else { 69 | len++; 70 | col--; 71 | } 72 | } else { 73 | res.push(['h', -len]); 74 | len = 0; 75 | dir = 'up'; 76 | } 77 | break; 78 | case 'down': 79 | filled[row][col - 1] = 1; 80 | if (isDark(row, col - 1)) { 81 | filled[row][col] = 1; 82 | if (isDark(row, col)) { 83 | res.push(['v', len]); 84 | len = 0; 85 | dir = 'right'; 86 | } else { 87 | len++; 88 | row++; 89 | } 90 | } else { 91 | res.push(['v', len]); 92 | len = 0; 93 | dir = 'left'; 94 | } 95 | break; 96 | case 'up': 97 | filled[row - 1][col] = 1; 98 | if (isDark(row - 1, col)) { 99 | filled[row - 1][col - 1] = 1; 100 | if (isDark(row - 1, col - 1)) { 101 | res.push(['v', -len]); 102 | len = 0; 103 | dir = 'left'; 104 | } else { 105 | len++; 106 | row--; 107 | } 108 | } else { 109 | res.push(['v', -len]); 110 | len = 0; 111 | dir = 'right'; 112 | } 113 | break; 114 | } 115 | } while (row != row0 || col != col0); 116 | return res; 117 | } 118 | } 119 | 120 | function pushSVGPath(matrix, stream, margin) { 121 | matrix2path(matrix).forEach(function(subpath) { 122 | var res = ''; 123 | for (var k = 0; k < subpath.length; k++) { 124 | var item = subpath[k]; 125 | switch (item[0]) { 126 | case 'M': 127 | res += 'M' + (item[1] + margin) + ' ' + (item[2] + margin); 128 | break; 129 | default: 130 | res += item.join(''); 131 | } 132 | } 133 | res += 'z'; 134 | stream.push(res); 135 | }); 136 | } 137 | 138 | function SVG_object(matrix, margin) { 139 | var stream = []; 140 | pushSVGPath(matrix, stream, margin); 141 | 142 | var result = { 143 | size: matrix.length + 2 * margin, 144 | path: stream.filter(Boolean).join('') 145 | } 146 | 147 | return result; 148 | } 149 | 150 | function SVG(matrix, stream, margin, size) { 151 | var X = matrix.length + 2 * margin; 152 | stream.push(' 0) { 154 | var XY = X * size; 155 | stream.push('width="' + XY + '" height="' + XY + '" '); 156 | } 157 | stream.push('viewBox="0 0 ' + X + ' ' + X + '">'); 158 | stream.push(''); 161 | stream.push(null); 162 | } 163 | 164 | function EPS(matrix, stream, margin) { 165 | var N = matrix.length; 166 | var scale = 9; 167 | var X = (N + 2 * margin) * scale; 168 | stream.push([ 169 | '%!PS-Adobe-3.0 EPSF-3.0', 170 | '%%BoundingBox: 0 0 ' + X + ' ' + X, 171 | '/h { 0 rlineto } bind def', 172 | '/v { 0 exch neg rlineto } bind def', 173 | '/M { neg ' + (N + margin) + ' add moveto } bind def', 174 | '/z { closepath } bind def', 175 | scale + ' ' + scale + ' scale', 176 | '' 177 | ].join('\n')); 178 | 179 | matrix2path(matrix).forEach(function(subpath) { 180 | var res = ''; 181 | for (var k = 0; k < subpath.length; k++) { 182 | var item = subpath[k]; 183 | switch (item[0]) { 184 | case 'M': 185 | res += (item[1] + margin) + ' ' + item[2] + ' M '; 186 | break; 187 | default: 188 | res += item[1] + ' ' + item[0] + ' '; 189 | } 190 | } 191 | res += 'z\n'; 192 | stream.push(res); 193 | }); 194 | 195 | stream.push('fill\n%%EOF\n'); 196 | stream.push(null); 197 | } 198 | 199 | function PDF(matrix, stream, margin) { 200 | // TODO deflate 201 | var N = matrix.length; 202 | var scale = 9; 203 | var X = (N + 2 * margin) * scale; 204 | var data = [ 205 | '%PDF-1.0\n\n', 206 | '1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj\n', 207 | '2 0 obj << /Type /Pages /Count 1 /Kids [ 3 0 R ] >> endobj\n', 208 | ]; 209 | data.push('3 0 obj << /Type /Page /Parent 2 0 R /Resources <<>> ' + 210 | '/Contents 4 0 R /MediaBox [ 0 0 ' + X + ' ' + X + ' ] >> endobj\n'); 211 | 212 | var path = scale + ' 0 0 ' + scale + ' 0 0 cm\n'; 213 | path += matrix2path(matrix).map(function(subpath) { 214 | var res = ''; 215 | var x, y; 216 | for (var k = 0; k < subpath.length; k++) { 217 | var item = subpath[k]; 218 | switch (item[0]) { 219 | case 'M': 220 | x = item[1] + margin; 221 | y = N - item[2] + margin; 222 | res += x + ' ' + y + ' m '; 223 | break; 224 | case 'h': 225 | x += item[1]; 226 | res += x + ' ' + y + ' l '; 227 | break; 228 | case 'v': 229 | y -= item[1]; 230 | res += x + ' ' + y + ' l '; 231 | break; 232 | } 233 | } 234 | res += 'h'; 235 | return res; 236 | }).join('\n'); 237 | path += '\nf\n'; 238 | data.push('4 0 obj << /Length ' + path.length + ' >> stream\n' + 239 | path + 'endstream\nendobj\n'); 240 | 241 | var xref = 'xref\n0 5\n0000000000 65535 f \n'; 242 | for (var i = 1, l = data[0].length; i < 5; i++) { 243 | xref += ('0000000000' + l).substr(-10) + ' 00000 n \n'; 244 | l += data[i].length; 245 | } 246 | data.push( 247 | xref, 248 | 'trailer << /Root 1 0 R /Size 5 >>\n', 249 | 'startxref\n' + l + '\n%%EOF\n' 250 | ); 251 | stream.push(data.join('')); 252 | stream.push(null); 253 | } 254 | 255 | module.exports = { 256 | svg: SVG, 257 | eps: EPS, 258 | pdf: PDF, 259 | svg_object: SVG_object 260 | } 261 | -------------------------------------------------------------------------------- /src/NodeServicesExample.WebApi/Scripts/qr-image/lib/matrix.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // {{{1 Initialize matrix with zeros 4 | function init(version) { 5 | var N = version * 4 + 17; 6 | var matrix = []; 7 | var zeros = new Buffer(N); 8 | zeros.fill(0); 9 | zeros = [].slice.call(zeros); 10 | for (var i = 0; i < N; i++) { 11 | matrix[i] = zeros.slice(); 12 | } 13 | return matrix; 14 | } 15 | 16 | // {{{1 Put finders into matrix 17 | function fillFinders(matrix) { 18 | var N = matrix.length; 19 | for (var i = -3; i <= 3; i++) { 20 | for (var j = -3; j <= 3; j++) { 21 | var max = Math.max(i, j); 22 | var min = Math.min(i, j); 23 | var pixel = (max == 2 && min >= -2) || (min == -2 && max <= 2) ? 0x80 : 0x81; 24 | matrix[3 + i][3 + j] = pixel; 25 | matrix[3 + i][N - 4 + j] = pixel; 26 | matrix[N - 4 + i][3 + j] = pixel; 27 | } 28 | } 29 | for (var i = 0; i < 8; i++) { 30 | matrix[7][i] = matrix[i][7] = 31 | matrix[7][N - i - 1] = matrix[i][N - 8] = 32 | matrix[N - 8][i] = matrix[N - 1 - i][7] = 0x80; 33 | } 34 | } 35 | 36 | // {{{1 Put align and timinig 37 | function fillAlignAndTiming(matrix) { 38 | var N = matrix.length; 39 | if (N > 21) { 40 | var len = N - 13; 41 | var delta = Math.round(len / Math.ceil(len / 28)); 42 | if (delta % 2) delta++; 43 | var res = []; 44 | for (var p = len + 6; p > 10; p -= delta) { 45 | res.unshift(p); 46 | } 47 | res.unshift(6); 48 | for (var i = 0; i < res.length; i++) { 49 | for (var j = 0; j < res.length; j++) { 50 | var x = res[i], y = res[j]; 51 | if (matrix[x][y]) continue; 52 | for (var r = -2; r <=2 ; r++) { 53 | for (var c = -2; c <=2 ; c++) { 54 | var max = Math.max(r, c); 55 | var min = Math.min(r, c); 56 | var pixel = (max == 1 && min >= -1) || (min == -1 && max <= 1) ? 0x80 : 0x81; 57 | matrix[x + r][y + c] = pixel; 58 | } 59 | } 60 | } 61 | } 62 | } 63 | for (var i = 8; i < N - 8; i++) { 64 | matrix[6][i] = matrix[i][6] = i % 2 ? 0x80 : 0x81; 65 | } 66 | } 67 | 68 | // {{{1 Fill reserved areas with zeroes 69 | function fillStub(matrix) { 70 | var N = matrix.length; 71 | for (var i = 0; i < 8; i++) { 72 | if (i != 6) { 73 | matrix[8][i] = matrix[i][8] = 0x80; 74 | } 75 | matrix[8][N - 1 - i] = 0x80; 76 | matrix[N - 1 - i][8] = 0x80; 77 | } 78 | matrix[8][8] = 0x80; 79 | matrix[N - 8][8] = 0x81; 80 | 81 | if (N < 45) return; 82 | 83 | for (var i = N - 11; i < N - 8; i++) { 84 | for (var j = 0; j < 6; j++) { 85 | matrix[i][j] = matrix[j][i] = 0x80; 86 | } 87 | } 88 | } 89 | 90 | // {{{1 Fill reserved areas 91 | var fillReserved = (function() { 92 | var FORMATS = Array(32); 93 | var VERSIONS = Array(40); 94 | 95 | var gf15 = 0x0537; 96 | var gf18 = 0x1f25; 97 | var formats_mask = 0x5412; 98 | 99 | for (var format = 0; format < 32; format++) { 100 | var res = format << 10; 101 | for (var i = 5; i > 0; i--) { 102 | if (res >>> (9 + i)) { 103 | res = res ^ (gf15 << (i - 1)); 104 | } 105 | } 106 | FORMATS[format] = (res | (format << 10)) ^ formats_mask; 107 | } 108 | 109 | for (var version = 7; version <= 40; version++) { 110 | var res = version << 12; 111 | for (var i = 6; i > 0; i--) { 112 | if (res >>> (11 + i)) { 113 | res = res ^ (gf18 << (i - 1)); 114 | } 115 | } 116 | VERSIONS[version] = (res | (version << 12)); 117 | } 118 | 119 | var EC_LEVELS = { L: 1, M: 0, Q: 3, H: 2 }; 120 | 121 | return function fillReserved(matrix, ec_level, mask) { 122 | var N = matrix.length; 123 | var format = FORMATS[EC_LEVELS[ec_level] << 3 | mask]; 124 | function F(k) { return format >> k & 1 ? 0x81 : 0x80 }; 125 | for (var i = 0; i < 8; i++) { 126 | matrix[8][N - 1 - i] = F(i); 127 | if (i < 6) matrix[i][8] = F(i); 128 | } 129 | for (var i = 8; i < 15; i++) { 130 | matrix[N - 15 + i][8] = F(i); 131 | if (i > 8) matrix[8][14 - i] = F(i); 132 | } 133 | matrix[7][8] = F(6); 134 | matrix[8][8] = F(7); 135 | matrix[8][7] = F(8); 136 | 137 | var version = VERSIONS[(N - 17)/4]; 138 | if (!version) return; 139 | function V(k) { return version >> k & 1 ? 0x81 : 0x80 }; 140 | for (var i = 0; i < 6; i++) { 141 | for (var j = 0; j < 3; j++) { 142 | matrix[N - 11 + j][i] = matrix[i][N - 11 + j] = V(i * 3 + j); 143 | } 144 | } 145 | } 146 | })(); 147 | 148 | // {{{1 Fill data 149 | var fillData = (function() { 150 | var MASK_FUNCTIONS = [ 151 | function(i, j) { return (i + j) % 2 == 0 }, 152 | function(i, j) { return i % 2 == 0 }, 153 | function(i, j) { return j % 3 == 0 }, 154 | function(i, j) { return (i + j) % 3 == 0 }, 155 | function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0 }, 156 | function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0 }, 157 | function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0 }, 158 | function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0 } 159 | ]; 160 | 161 | return function fillData(matrix, data, mask) { 162 | var N = matrix.length; 163 | var row, col, dir = -1; 164 | row = col = N - 1; 165 | var mask_fn = MASK_FUNCTIONS[mask]; 166 | var len = data.blocks[data.blocks.length - 1].length; 167 | 168 | for (var i = 0; i < len; i++) { 169 | for (var b = 0; b < data.blocks.length; b++) { 170 | if (data.blocks[b].length <= i) continue; 171 | put(data.blocks[b][i]); 172 | } 173 | } 174 | 175 | len = data.ec_len; 176 | for (var i = 0; i < len; i++) { 177 | for (var b = 0; b < data.ec.length; b++) { 178 | put(data.ec[b][i]); 179 | } 180 | } 181 | 182 | if (col > -1) { 183 | do { 184 | matrix[row][col] = mask_fn(row, col) ? 1 : 0; 185 | } while (next()); 186 | } 187 | 188 | function put(byte) { 189 | for (var mask = 0x80; mask; mask = mask >> 1) { 190 | var pixel = !!(mask & byte); 191 | if (mask_fn(row, col)) pixel = !pixel; 192 | matrix[row][col] = pixel ? 1 : 0; 193 | next(); 194 | } 195 | } 196 | 197 | function next() { 198 | do { 199 | if ((col % 2) ^ (col < 6)) { 200 | if (dir < 0 && row == 0 || dir > 0 && row == N - 1) { 201 | col--; 202 | dir = -dir; 203 | } else { 204 | col++; 205 | row += dir; 206 | } 207 | } else { 208 | col--; 209 | } 210 | if (col == 6) { 211 | col--; 212 | } 213 | if (col < 0) { 214 | return false; 215 | } 216 | } while (matrix[row][col] & 0xf0); 217 | return true; 218 | } 219 | } 220 | })(); 221 | 222 | // {{{1 Calculate penalty 223 | function calculatePenalty(matrix) { 224 | var N = matrix.length; 225 | var penalty = 0; 226 | // Rule 1 227 | for (var i = 0; i < N; i++) { 228 | var pixel = matrix[i][0] & 1; 229 | var len = 1; 230 | for (var j = 1; j < N; j++) { 231 | var p = matrix[i][j] & 1; 232 | if (p == pixel) { 233 | len++; 234 | continue; 235 | } 236 | if (len >= 5) { 237 | penalty += len - 2; 238 | } 239 | pixel = p; 240 | len = 1; 241 | } 242 | if (len >= 5) { 243 | penalty += len - 2; 244 | } 245 | } 246 | for (var j = 0; j < N; j++) { 247 | var pixel = matrix[0][j] & 1; 248 | var len = 1; 249 | for (var i = 1; i < N; i++) { 250 | var p = matrix[i][j] & 1; 251 | if (p == pixel) { 252 | len++; 253 | continue; 254 | } 255 | if (len >= 5) { 256 | penalty += len - 2; 257 | } 258 | pixel = p; 259 | len = 1; 260 | } 261 | if (len >= 5) { 262 | penalty += len - 2; 263 | } 264 | } 265 | 266 | // Rule 2 267 | for (var i = 0; i < N - 1; i++) { 268 | for (var j = 0; j < N - 1; j++) { 269 | var s = matrix[i][j] + matrix[i][j + 1] + matrix[i + 1][j] + matrix[i + 1][j + 1] & 7; 270 | if (s == 0 || s == 4) { 271 | penalty += 3; 272 | } 273 | } 274 | } 275 | 276 | // Rule 3 277 | function I(k) { return matrix[i][j + k] & 1 }; 278 | function J(k) { return matrix[i + k][j] & 1 }; 279 | for (var i = 0; i < N; i++) { 280 | for (var j = 0; j < N; j++) { 281 | if (j < N - 6 && I(0) && !I(1) && I(2) && I(3) && I(4) && !I(5) && I(6)) { 282 | if (j >= 4 && !(I(-4) || I(-3) || I(-2) || I(-1))) { 283 | penalty += 40; 284 | } 285 | if (j < N - 10 && !(I(7) || I(8) || I(9) || I(10))) { 286 | penalty += 40; 287 | } 288 | } 289 | 290 | if (i < N - 6 && J(0) && !J(1) && J(2) && J(3) && J(4) && !J(5) && J(6)) { 291 | if (i >= 4 && !(J(-4) || J(-3) || J(-2) || J(-1))) { 292 | penalty += 40; 293 | } 294 | if (i < N - 10 && !(J(7) || J(8) || J(9) || J(10))) { 295 | penalty += 40; 296 | } 297 | } 298 | } 299 | } 300 | 301 | // Rule 4 302 | var numDark = 0; 303 | for (var i = 0; i < N; i++) { 304 | for (var j = 0; j < N; j++) { 305 | if (matrix[i][j] & 1) numDark++; 306 | } 307 | } 308 | penalty += 10 * Math.floor(Math.abs(10 - 20 * numDark/(N * N))); 309 | 310 | return penalty; 311 | } 312 | 313 | // {{{1 All-in-one function 314 | function getMatrix(data) { 315 | var matrix = init(data.version); 316 | fillFinders(matrix); 317 | fillAlignAndTiming(matrix); 318 | fillStub(matrix); 319 | 320 | var penalty = Infinity; 321 | var bestMask = 0; 322 | for (var mask = 0; mask < 8; mask++) { 323 | fillData(matrix, data, mask); 324 | fillReserved(matrix, data.ec_level, mask); 325 | var p = calculatePenalty(matrix); 326 | if (p < penalty) { 327 | penalty = p; 328 | bestMask = mask; 329 | } 330 | } 331 | 332 | fillData(matrix, data, bestMask); 333 | fillReserved(matrix, data.ec_level, bestMask); 334 | 335 | return matrix.map(function(row) { 336 | return row.map(function(cell) { 337 | return cell & 1; 338 | }); 339 | }); 340 | } 341 | 342 | // {{{1 export functions 343 | module.exports = { 344 | getMatrix: getMatrix, 345 | init: init, 346 | fillFinders: fillFinders, 347 | fillAlignAndTiming: fillAlignAndTiming, 348 | fillStub: fillStub, 349 | fillReserved: fillReserved, 350 | fillData: fillData, 351 | calculatePenalty: calculatePenalty, 352 | } 353 | --------------------------------------------------------------------------------