Skip to content

Commit 40a8a25

Browse files
Merge pull request #54 from ahwayakchih/feature/createASCII
Feature: add `createASCII` method
2 parents e2913bf + fee5692 commit 40a8a25

5 files changed

Lines changed: 204 additions & 1 deletion

File tree

js/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ _[Note] call make() before this function._
7272
#### createImgTag(cellSize, margin, alt) => <code>string</code>
7373
#### createSvgTag(cellSize, margin) => <code>string</code>
7474
#### createTableTag(cellSize, margin) => <code>string</code>
75+
#### createASCII(cellSize, margin) => <code>string</code>
7576
Helper functions for HTML.
7677
_[Note] call make() before these functions._
7778

js/package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,14 @@
1717
"qrcode",
1818
"generator"
1919
],
20-
"license": "MIT"
20+
"license": "MIT",
21+
"directories": {
22+
"test": "test"
23+
},
24+
"scripts": {
25+
"test": "mocha"
26+
},
27+
"devDependencies": {
28+
"mocha": "^5.2.0"
29+
}
2130
}

js/qrcode.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ interface QRCode {
4444
createSvgTag(cellSize?: number, margin?: number) : string;
4545
createDataURL(cellSize?: number, margin?: number) : string;
4646
createTableTag(cellSize?: number, margin?: number) : string;
47+
createASCII(cellSize?: number, margin?: number) : string;
4748
renderTo2dContext(context: CanvasRenderingContext2D, cellSize?: number): void;
4849
}
4950

js/qrcode.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,98 @@ var qrcode = function() {
574574
return img;
575575
};
576576

577+
var _createHalfASCII = function(margin) {
578+
var cellSize = 1;
579+
margin = (typeof margin == 'undefined')? cellSize * 2 : margin;
580+
581+
var size = _this.getModuleCount() * cellSize + margin * 2;
582+
var min = margin;
583+
var max = size - margin;
584+
585+
var y, x, r1, r2, p;
586+
587+
var blocks = {
588+
'██': '█',
589+
'█ ': '▀',
590+
' █': '▄',
591+
' ': ' '
592+
};
593+
594+
var ascii = '';
595+
for (y = 0; y < size; y += 2) {
596+
r1 = Math.floor((y - min) / cellSize);
597+
r2 = Math.floor((y + 1 - min) / cellSize);
598+
for (x = 0; x < size; x += 1) {
599+
p = '█';
600+
601+
if (min <= x && x < max && min <= y && y < max && _this.isDark(r1, Math.floor((x - min) / cellSize))) {
602+
p = ' ';
603+
}
604+
605+
if (min <= x && x < max && min <= y+1 && y+1 < max && _this.isDark(r2, Math.floor((x - min) / cellSize))) {
606+
p += ' ';
607+
}
608+
else {
609+
p += '█';
610+
}
611+
612+
// Output 2 characters per pixel, to create full square. 1 character per pixels gives only half width of square.
613+
ascii += blocks[p];
614+
}
615+
616+
ascii += '\n';
617+
}
618+
619+
if (size % 2) {
620+
return ascii.substring(0, ascii.length - size - 1) + Array(size+1).join('▀');
621+
}
622+
623+
return ascii.substring(0, ascii.length-1);
624+
};
625+
626+
_this.createASCII = function(cellSize, margin) {
627+
cellSize = cellSize || 1;
628+
629+
if (cellSize < 2) {
630+
return _createHalfASCII(margin);
631+
}
632+
633+
cellSize -= 1;
634+
margin = (typeof margin == 'undefined')? cellSize * 2 : margin;
635+
636+
var size = _this.getModuleCount() * cellSize + margin * 2;
637+
var min = margin;
638+
var max = size - margin;
639+
640+
var y, x, r, p;
641+
642+
var white = Array(cellSize+1).join('██');
643+
var black = Array(cellSize+1).join(' ');
644+
645+
var ascii = '';
646+
var line = '';
647+
for (y = 0; y < size; y += 1) {
648+
r = Math.floor( (y - min) / cellSize);
649+
line = '';
650+
for (x = 0; x < size; x += 1) {
651+
p = 1;
652+
653+
if (min <= x && x < max && min <= y && y < max && _this.isDark(r, Math.floor((x - min) / cellSize))) {
654+
p = 0;
655+
}
656+
657+
// Output 2 characters per pixel, to create full square. 1 character per pixels gives only half width of square.
658+
line += p ? white : black;
659+
}
660+
661+
for (r = 0; r < cellSize; r += 1) {
662+
ascii += line + '\n';
663+
}
664+
}
665+
666+
return ascii.substring(0, ascii.length-1);
667+
};
668+
577669
_this.renderTo2dContext = function(context, cellSize) {
578670
cellSize = cellSize || 2;
579671
var length = _this.getModuleCount();

js/test/qrcode.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
var assert = require('assert');
2+
var qrcode = require('../qrcode.js');
3+
4+
describe('QRCode', function(){
5+
it('should exist', function(){
6+
assert.ok(qrcode);
7+
});
8+
9+
it('should be a callable function', function(){
10+
assert.ok(qrcode instanceof Function);
11+
});
12+
13+
it('should generate correct GIF image tag', function(){
14+
var sourceText = 'http://www.example.com/ążśźęćńół';
15+
var correctImgTag = '<img src="data:image/gif;base64,R0lGODdhSgBKAIAAAAAAAP///ywAAAAASgBKAAAC/4yPqcvtD6OctNqLs968+w+G4kiWZgKk6roa7ZEiccACco1TeE6r9997uXYsna0xmw0VLyXsyHBCpKijk9qEPh1UrrXYAy4Xu3FtLEmCr9pucP3NGofyN9peBZ7DE3W9Tqd15+fDlxZXiPVlltiGqDb3BpnHRzj4uNgnSHkjZCiZGbXpRVrlyQZINopE9Jc5CdtaeCj7asvIWEvimet4oqkYKDZiCSrMWtobmcW8esfki2exN4XY2cj7aZQtehxIGHwR+41dDg3tdogLCm7N+ZTOOom+irqZGk//DF/vqDiv7cEpTMW4CZxVYSC5gghpOTt46dg4PGxE5aNUkeItje3Drm3zh9DewIytPl7LuBCkHiImpbEjaAvlloTm+DVzJXNftZM89lAz5vLiOZs94YysqZNmtZ8/vQiFeJApmKUPu30qU6mhKola1V0t6g2ZxqcaAK4biraE2axW004LyeNs1loGHfIkGY3uVLV7Ge4rSayvu7WAHQIGGMvn4KqqdLGd2S5xKE2lit2dfIlswJVhU/5VSRmoyEbr9NbdKhqkq156l8GJCFQZ0aRWFcOWGtZ2aN2IN3LlvPv149Kg8UZqi5ElP+JvkyXH+ns4MFnR/+0F/vEw6YDQk//6Dj68+PHky5s/jz69+vULCgAAOw==" width="74" height="74"/>';
16+
17+
var qr = qrcode(-1, 'M');
18+
qr.addData(unescape(encodeURI(sourceText)));
19+
qr.make();
20+
21+
assert.strictEqual(qr.createImgTag(), correctImgTag);
22+
});
23+
24+
it('should generate correct GIF image data', function(){
25+
var sourceText = 'http://www.example.com/ążśźęćńół';
26+
var correctImgData = 'R0lGODdhSgBKAIAAAAAAAP///ywAAAAASgBKAAAC/4yPqcvtD6OctNqLs968+w+G4kiWZgKk6roa7ZEiccACco1TeE6r9997uXYsna0xmw0VLyXsyHBCpKijk9qEPh1UrrXYAy4Xu3FtLEmCr9pucP3NGofyN9peBZ7DE3W9Tqd15+fDlxZXiPVlltiGqDb3BpnHRzj4uNgnSHkjZCiZGbXpRVrlyQZINopE9Jc5CdtaeCj7asvIWEvimet4oqkYKDZiCSrMWtobmcW8esfki2exN4XY2cj7aZQtehxIGHwR+41dDg3tdogLCm7N+ZTOOom+irqZGk//DF/vqDiv7cEpTMW4CZxVYSC5gghpOTt46dg4PGxE5aNUkeItje3Drm3zh9DewIytPl7LuBCkHiImpbEjaAvlloTm+DVzJXNftZM89lAz5vLiOZs94YysqZNmtZ8/vQiFeJApmKUPu30qU6mhKola1V0t6g2ZxqcaAK4biraE2axW004LyeNs1loGHfIkGY3uVLV7Ge4rSayvu7WAHQIGGMvn4KqqdLGd2S5xKE2lit2dfIlswJVhU/5VSRmoyEbr9NbdKhqkq156l8GJCFQZ0aRWFcOWGtZ2aN2IN3LlvPv149Kg8UZqi5ElP+JvkyXH+ns4MFnR/+0F/vEw6YDQk//6Dj68+PHky5s/jz69+vULCgAAOw==';
27+
28+
var qr = qrcode(-1, 'M');
29+
qr.addData(unescape(encodeURI(sourceText)));
30+
qr.make();
31+
32+
var data = Buffer.from(qr.createDataURL().replace('data:image/gif;base64,', ''), 'base64');
33+
34+
assert.strictEqual(data.toString('base64'), correctImgData);
35+
});
36+
37+
it('should generate correct UTF8 text data', function(){
38+
var sourceText = 'http://www.example.com/ążśźęćńół';
39+
var correctTextData1 = [
40+
'█████████████████████████████████',
41+
'██ ▄▄▄▄▄ █ ▄█▀▄██ ▀▄ ▄██ ▄▄▄▄▄ ██',
42+
'██ █ █ █▀ █▀▄█▀▀█▄▄ ▄█ █ █ ██',
43+
'██ █▄▄▄█ ███ ▀ █▄▀▄▄▀ ▀█ █▄▄▄█ ██',
44+
'██▄▄▄▄▄▄▄█ ▀▄█▄▀▄▀ █▄▀▄█▄▄▄▄▄▄▄██',
45+
'██▄█ ▀▄▄▄█▄▄█▀█▀▀▄█▀▀▀█ ▀▀▄█▄ ██',
46+
'██▀▀▄▀▄█▄█ ▄▄█▄ ▄█ ███ ▀█▀▄▄▀██',
47+
'██ ▄▀█▄▀▄ ▄▀▄ █ ▄▀▀█▀██▀██▄▄▀▀██',
48+
'██ █▀ ▄▄▀▀ ▀█ █▀▄ ▀█▄▀▄▄▄ ▄██',
49+
'██▄██ ▄▄▄▄▄█ ▀▄▄ ▀▀▄▄▄█▄▄█▀ ███',
50+
'██▄█▄██▄▄▄ █ █▄▄▀█▀███▄▀▄▄█▄ ████',
51+
'███▄▄██▄▄▄ ▀▀▄█ █▀ █ ▄ ▄▄▄ ▀▀██',
52+
'██ ▄▄▄▄▄ █ █ ▀█▄█ ▀ ▄ █▄█ ▄█ ▀██',
53+
'██ █ █ █▀▄▄ ▄▀ ▀▄█ █ ▄▄ ▄ ██',
54+
'██ █▄▄▄█ █▄█▄▀█ ▀ ▀ ██ █ █▀▄▀▄██',
55+
'██▄▄▄▄▄▄▄█▄▄█▄█▄███▄▄▄▄████▄█▄███',
56+
'▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀'].join('\n');
57+
58+
var correctTextData2 = [
59+
'██████████████████████████████████████████████████████████████████',
60+
'██████████████████████████████████████████████████████████████████',
61+
'████ ██ ████ ████ ██ ████ ████',
62+
'████ ██████████ ██ ████ ██████ ██ ██████ ██████████ ████',
63+
'████ ██ ██ ████ ████ ████████ ██ ██ ██ ████',
64+
'████ ██ ██ ██ ██ ████ ██████ ████ ██ ██ ████',
65+
'████ ██ ██ ██████ ██ ██ ██ ██ ████ ██ ██ ████',
66+
'████ ██████████ ██████ ████ ████ ██ ██████████ ████',
67+
'████ ██ ██ ██ ██ ██ ██ ██ ██ ████',
68+
'████████████████████ ██████ ██ ████ ██████████████████████',
69+
'████ ██ ██ ██ ██████████ ██████████ ████ ██ ████',
70+
'████████ ██████████████ ██ ████ ██ ██████ ████',
71+
'████████ ██ ██ ██ ██ ██ ██████ ██████ ██████',
72+
'████ ██ ████████ ████████ ████ ██████ ██ ████ ████',
73+
'████ ████ ██ ██ ██ ██████████████████ ████████',
74+
'████ ██ ████ ██ ██ ██ ██ ██ ██ ████ ████████ ████',
75+
'████ ████ ████ ████ ████ ████ ██ ████',
76+
'████ ██ ████ ██ ██ ██ ████ ██████ ██████',
77+
'████ ████ ██ ██ ████ ██ ████ ██████',
78+
'██████████ ████████████ ████ ██████████████ ██████',
79+
'████ ██ ████ ██ ██ ████████████ ██ ██ ████████',
80+
'████████████████████ ██ ██████ ██ ████████ ████████ ████████',
81+
'██████ ████ ████ ██ ████ ██ ████████',
82+
'████████████████████ ████ ██ ██ ██ ██████ ████',
83+
'████ ██ ██ ████ ██ ██ ██ ██ ██ ██████',
84+
'████ ██████████ ██ ██ ██████ ██ ██████ ████ ████',
85+
'████ ██ ██ ████ ██ ██ ██ ██ ████',
86+
'████ ██ ██ ██ ████ ██ ████ ██ ████ ██ ████',
87+
'████ ██ ██ ██ ██ ████ ██ ██ ████ ██ ████ ██ ████',
88+
'████ ██████████ ████████ ██ ████ ██ ██ ██ ██████',
89+
'████ ██ ██ ██ ██████ ████████ ██ ██████',
90+
'██████████████████████████████████████████████████████████████████',
91+
'██████████████████████████████████████████████████████████████████',].join('\n');
92+
93+
var qr = qrcode(-1, 'M');
94+
qr.addData(unescape(encodeURI(sourceText)));
95+
qr.make();
96+
97+
assert.strictEqual(qr.createASCII(), correctTextData1, 'ASCII QRCode of size 1 is incorrect');
98+
assert.strictEqual(qr.createASCII(2), correctTextData2, 'ASCII QRCode of size 2 is incorrect');
99+
});
100+
});

0 commit comments

Comments
 (0)