diff --git a/js/README.md b/js/README.md
index b34984a..167d75f 100644
--- a/js/README.md
+++ b/js/README.md
@@ -72,6 +72,7 @@ _[Note] call make() before this function._
#### createImgTag(cellSize, margin, alt) => string
#### createSvgTag(cellSize, margin) => string
#### createTableTag(cellSize, margin) => string
+#### createASCII(cellSize, margin) => string
Helper functions for HTML.
_[Note] call make() before these functions._
diff --git a/js/package.json b/js/package.json
index caf01c6..3b0ebd4 100644
--- a/js/package.json
+++ b/js/package.json
@@ -17,5 +17,14 @@
"qrcode",
"generator"
],
- "license": "MIT"
+ "license": "MIT",
+ "directories": {
+ "test": "test"
+ },
+ "scripts": {
+ "test": "mocha"
+ },
+ "devDependencies": {
+ "mocha": "^5.2.0"
+ }
}
diff --git a/js/qrcode.d.ts b/js/qrcode.d.ts
index dbe4305..ad55e39 100644
--- a/js/qrcode.d.ts
+++ b/js/qrcode.d.ts
@@ -43,6 +43,7 @@ interface QRCode {
createImgTag(cellSize?: number, margin?: number) : string;
createSvgTag(cellSize?: number, margin?: number) : string;
createTableTag(cellSize?: number, margin?: number) : string;
+ createASCII(cellSize?: number, margin?: number) : string;
renderTo2dContext(context: CanvasRenderingContext2D, cellSize?: number): void;
}
diff --git a/js/qrcode.js b/js/qrcode.js
index 8e93c2e..ce6ace3 100644
--- a/js/qrcode.js
+++ b/js/qrcode.js
@@ -574,6 +574,98 @@ var qrcode = function() {
return img;
};
+ var _createHalfASCII = function(margin) {
+ var cellSize = 1;
+ margin = (typeof margin == 'undefined')? cellSize * 2 : margin;
+
+ var size = _this.getModuleCount() * cellSize + margin * 2;
+ var min = margin;
+ var max = size - margin;
+
+ var y, x, r1, r2, p;
+
+ var blocks = {
+ '██': '█',
+ '█ ': '▀',
+ ' █': '▄',
+ ' ': ' '
+ };
+
+ var ascii = '';
+ for (y = 0; y < size; y += 2) {
+ r1 = Math.floor((y - min) / cellSize);
+ r2 = Math.floor((y + 1 - min) / cellSize);
+ for (x = 0; x < size; x += 1) {
+ p = '█';
+
+ if (min <= x && x < max && min <= y && y < max && _this.isDark(r1, Math.floor((x - min) / cellSize))) {
+ p = ' ';
+ }
+
+ if (min <= x && x < max && min <= y+1 && y+1 < max && _this.isDark(r2, Math.floor((x - min) / cellSize))) {
+ p += ' ';
+ }
+ else {
+ p += '█';
+ }
+
+ // Output 2 characters per pixel, to create full square. 1 character per pixels gives only half width of square.
+ ascii += blocks[p];
+ }
+
+ ascii += '\n';
+ }
+
+ if (size % 2) {
+ return ascii.substring(0, ascii.length - size - 1) + Array(size+1).join('▀');
+ }
+
+ return ascii.substring(0, ascii.length-1);
+ };
+
+ _this.createASCII = function(cellSize, margin) {
+ cellSize = cellSize || 1;
+
+ if (cellSize < 2) {
+ return _createHalfASCII(margin);
+ }
+
+ cellSize -= 1;
+ margin = (typeof margin == 'undefined')? cellSize * 2 : margin;
+
+ var size = _this.getModuleCount() * cellSize + margin * 2;
+ var min = margin;
+ var max = size - margin;
+
+ var y, x, r, p;
+
+ var white = Array(cellSize+1).join('██');
+ var black = Array(cellSize+1).join(' ');
+
+ var ascii = '';
+ var line = '';
+ for (y = 0; y < size; y += 1) {
+ r = Math.floor( (y - min) / cellSize);
+ line = '';
+ for (x = 0; x < size; x += 1) {
+ p = 1;
+
+ if (min <= x && x < max && min <= y && y < max && _this.isDark(r, Math.floor((x - min) / cellSize))) {
+ p = 0;
+ }
+
+ // Output 2 characters per pixel, to create full square. 1 character per pixels gives only half width of square.
+ line += p ? white : black;
+ }
+
+ for (r = 0; r < cellSize; r += 1) {
+ ascii += line + '\n';
+ }
+ }
+
+ return ascii.substring(0, ascii.length-1);
+ };
+
_this.renderTo2dContext = function(context, cellSize) {
cellSize = cellSize || 2;
var length = _this.getModuleCount();
diff --git a/js/test/qrcode.js b/js/test/qrcode.js
new file mode 100644
index 0000000..1da6651
--- /dev/null
+++ b/js/test/qrcode.js
@@ -0,0 +1,100 @@
+var assert = require('assert');
+var qrcode = require('../qrcode.js');
+
+describe('QRCode', function(){
+ it('should exist', function(){
+ assert.ok(qrcode);
+ });
+
+ it('should be a callable function', function(){
+ assert.ok(qrcode instanceof Function);
+ });
+
+ it('should generate correct GIF image tag', function(){
+ var sourceText = 'http://www.example.com/ążśźęćńół';
+ var correctImgTag = '
';
+
+ var qr = qrcode(-1, 'M');
+ qr.addData(unescape(encodeURI(sourceText)));
+ qr.make();
+
+ assert.strictEqual(qr.createImgTag(), correctImgTag);
+ });
+
+ it('should generate correct GIF image data', function(){
+ var sourceText = 'http://www.example.com/ążśźęćńół';
+ var correctImgData = 'R0lGODdhSgBKAIAAAAAAAP///ywAAAAASgBKAAAC/4yPqcvtD6OctNqLs968+w+G4kiWZgKk6roa7ZEiccACco1TeE6r9997uXYsna0xmw0VLyXsyHBCpKijk9qEPh1UrrXYAy4Xu3FtLEmCr9pucP3NGofyN9peBZ7DE3W9Tqd15+fDlxZXiPVlltiGqDb3BpnHRzj4uNgnSHkjZCiZGbXpRVrlyQZINopE9Jc5CdtaeCj7asvIWEvimet4oqkYKDZiCSrMWtobmcW8esfki2exN4XY2cj7aZQtehxIGHwR+41dDg3tdogLCm7N+ZTOOom+irqZGk//DF/vqDiv7cEpTMW4CZxVYSC5gghpOTt46dg4PGxE5aNUkeItje3Drm3zh9DewIytPl7LuBCkHiImpbEjaAvlloTm+DVzJXNftZM89lAz5vLiOZs94YysqZNmtZ8/vQiFeJApmKUPu30qU6mhKola1V0t6g2ZxqcaAK4biraE2axW004LyeNs1loGHfIkGY3uVLV7Ge4rSayvu7WAHQIGGMvn4KqqdLGd2S5xKE2lit2dfIlswJVhU/5VSRmoyEbr9NbdKhqkq156l8GJCFQZ0aRWFcOWGtZ2aN2IN3LlvPv149Kg8UZqi5ElP+JvkyXH+ns4MFnR/+0F/vEw6YDQk//6Dj68+PHky5s/jz69+vULCgAAOw==';
+
+ var qr = qrcode(-1, 'M');
+ qr.addData(unescape(encodeURI(sourceText)));
+ qr.make();
+
+ var data = Buffer.from(qr.createDataURL().replace('data:image/gif;base64,', ''), 'base64');
+
+ assert.strictEqual(data.toString('base64'), correctImgData);
+ });
+
+ it('should generate correct UTF8 text data', function(){
+ var sourceText = 'http://www.example.com/ążśźęćńół';
+ var correctTextData1 = [
+ '█████████████████████████████████',
+ '██ ▄▄▄▄▄ █ ▄█▀▄██ ▀▄ ▄██ ▄▄▄▄▄ ██',
+ '██ █ █ █▀ █▀▄█▀▀█▄▄ ▄█ █ █ ██',
+ '██ █▄▄▄█ ███ ▀ █▄▀▄▄▀ ▀█ █▄▄▄█ ██',
+ '██▄▄▄▄▄▄▄█ ▀▄█▄▀▄▀ █▄▀▄█▄▄▄▄▄▄▄██',
+ '██▄█ ▀▄▄▄█▄▄█▀█▀▀▄█▀▀▀█ ▀▀▄█▄ ██',
+ '██▀▀▄▀▄█▄█ ▄▄█▄ ▄█ ███ ▀█▀▄▄▀██',
+ '██ ▄▀█▄▀▄ ▄▀▄ █ ▄▀▀█▀██▀██▄▄▀▀██',
+ '██ █▀ ▄▄▀▀ ▀█ █▀▄ ▀█▄▀▄▄▄ ▄██',
+ '██▄██ ▄▄▄▄▄█ ▀▄▄ ▀▀▄▄▄█▄▄█▀ ███',
+ '██▄█▄██▄▄▄ █ █▄▄▀█▀███▄▀▄▄█▄ ████',
+ '███▄▄██▄▄▄ ▀▀▄█ █▀ █ ▄ ▄▄▄ ▀▀██',
+ '██ ▄▄▄▄▄ █ █ ▀█▄█ ▀ ▄ █▄█ ▄█ ▀██',
+ '██ █ █ █▀▄▄ ▄▀ ▀▄█ █ ▄▄ ▄ ██',
+ '██ █▄▄▄█ █▄█▄▀█ ▀ ▀ ██ █ █▀▄▀▄██',
+ '██▄▄▄▄▄▄▄█▄▄█▄█▄███▄▄▄▄████▄█▄███',
+ '▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀'].join('\n');
+
+ var correctTextData2 = [
+ '██████████████████████████████████████████████████████████████████',
+ '██████████████████████████████████████████████████████████████████',
+ '████ ██ ████ ████ ██ ████ ████',
+ '████ ██████████ ██ ████ ██████ ██ ██████ ██████████ ████',
+ '████ ██ ██ ████ ████ ████████ ██ ██ ██ ████',
+ '████ ██ ██ ██ ██ ████ ██████ ████ ██ ██ ████',
+ '████ ██ ██ ██████ ██ ██ ██ ██ ████ ██ ██ ████',
+ '████ ██████████ ██████ ████ ████ ██ ██████████ ████',
+ '████ ██ ██ ██ ██ ██ ██ ██ ██ ████',
+ '████████████████████ ██████ ██ ████ ██████████████████████',
+ '████ ██ ██ ██ ██████████ ██████████ ████ ██ ████',
+ '████████ ██████████████ ██ ████ ██ ██████ ████',
+ '████████ ██ ██ ██ ██ ██ ██████ ██████ ██████',
+ '████ ██ ████████ ████████ ████ ██████ ██ ████ ████',
+ '████ ████ ██ ██ ██ ██████████████████ ████████',
+ '████ ██ ████ ██ ██ ██ ██ ██ ██ ████ ████████ ████',
+ '████ ████ ████ ████ ████ ████ ██ ████',
+ '████ ██ ████ ██ ██ ██ ████ ██████ ██████',
+ '████ ████ ██ ██ ████ ██ ████ ██████',
+ '██████████ ████████████ ████ ██████████████ ██████',
+ '████ ██ ████ ██ ██ ████████████ ██ ██ ████████',
+ '████████████████████ ██ ██████ ██ ████████ ████████ ████████',
+ '██████ ████ ████ ██ ████ ██ ████████',
+ '████████████████████ ████ ██ ██ ██ ██████ ████',
+ '████ ██ ██ ████ ██ ██ ██ ██ ██ ██████',
+ '████ ██████████ ██ ██ ██████ ██ ██████ ████ ████',
+ '████ ██ ██ ████ ██ ██ ██ ██ ████',
+ '████ ██ ██ ██ ████ ██ ████ ██ ████ ██ ████',
+ '████ ██ ██ ██ ██ ████ ██ ██ ████ ██ ████ ██ ████',
+ '████ ██████████ ████████ ██ ████ ██ ██ ██ ██████',
+ '████ ██ ██ ██ ██████ ████████ ██ ██████',
+ '██████████████████████████████████████████████████████████████████',
+ '██████████████████████████████████████████████████████████████████',].join('\n');
+
+ var qr = qrcode(-1, 'M');
+ qr.addData(unescape(encodeURI(sourceText)));
+ qr.make();
+
+ assert.strictEqual(qr.createASCII(), correctTextData1, 'ASCII QRCode of size 1 is incorrect');
+ assert.strictEqual(qr.createASCII(2), correctTextData2, 'ASCII QRCode of size 2 is incorrect');
+ });
+});
\ No newline at end of file