Add support for svg output

This commit is contained in:
Vincenzo Greco 2016-09-19 00:44:00 +02:00
parent ac8f9d571a
commit 6cdcb439f6
6 changed files with 612 additions and 7 deletions

View file

@ -13,7 +13,7 @@ if (text && text.length) {
if(file && file.length){
qr.save(file,text,function(err,data){
if(!err) {
process.stdout.write("saved qrcode png to: "+file+"\n");
process.stdout.write("saved qrcode to: "+file+"\n");
} else {
process.stderr.write("failed to save qrcode\n");
throw err;
@ -26,5 +26,5 @@ if (text && text.length) {
});
}
} else {
process.stderr.write("text\n\trequired as first argument.\nfile name [optional]\n\tto save png qrcode may be provided as optional second argument\n");
process.stderr.write("text\n\trequired as first argument.\nfile name [optional]\n\tto save png or svg qrcode may be provided as optional second argument\n");
}

44
lib/svgrender.js Normal file
View file

@ -0,0 +1,44 @@
module.exports.renderBits = renderBits;
function renderBits(bits,width,options) {
if (typeof bits === 'undefined' || !(bits instanceof Array)) {
throw new Error('"bits" must be a valid Array');
}
if (typeof bits === 'undefined' || isNaN(width)) {
throw new Error('"width" must be a valid number');
}
var dotsize = options.scale || 4;
var margin = options.margin || 20;
var qrcodesize = width * dotsize + margin * 2;
var lightColor = options.lightColor || '#ffffff';
var darkColor = options.darkColor || '#000000';
var xmlStr = '<?xml version="1.0" encoding="utf-8"?>\n';
xmlStr += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
xmlStr += '<svg version="1.1" baseProfile="full"';
xmlStr += ' width="' + qrcodesize + '" height="' + qrcodesize + '"';
xmlStr += ' viewBox="0 0 '+ qrcodesize + ' ' + qrcodesize + '"';
xmlStr += ' xmlns="http://www.w3.org/2000/svg"';
xmlStr += ' xmlns:xlink="http://www.w3.org/1999/xlink"';
xmlStr += ' xmlns:ev="http://www.w3.org/2001/xml-events">\n';
xmlStr += '<rect x="0" y="0" width="' + qrcodesize + '" height="' + qrcodesize + '" fill="' + lightColor + '" />\n';
xmlStr += '<defs><rect id="p" width="'+ dotsize +'" height="'+ dotsize + '" /></defs>\n';
xmlStr += '<g fill="' + darkColor + '">\n';
xmlStr = bits.reduce(function (xml, bit, index) {
if (!bit) return xml;
var x = margin + (index % width) * dotsize;
var y = margin + Math.floor(index / width) * dotsize;
return xml += '<use x="' + x + '" y="' + y + '" xlink:href="#p" />\n'
}, xmlStr);
xmlStr += '</g>\n';
xmlStr += '</svg>';
return xmlStr
}

View file

@ -14,7 +14,7 @@
"scripts": {
"pretest": "node build.js",
"prepublish": "node build.js",
"test": "tap test/url.js"
"test": "tap test/url.js test/svg.js"
},
"bin": {
"qrcode": "./bin/qrcode"
@ -25,11 +25,12 @@
"bops": "0.0.6"
},
"devDependencies": {
"express": "2.5.x",
"browserify": "~2.29.0",
"uglify-js": "1.2.x",
"canvasutil": "*",
"tap": "*"
"express": "2.5.x",
"libxmljs": "^0.18.0",
"tap": "*",
"uglify-js": "1.2.x"
},
"repository": {
"type": "git",

View file

@ -11,6 +11,7 @@
var QRCodeLib = require('./lib/qrcode-draw')
, terminalRender = require('./lib/termialrender.js')
, svgRender = require('./lib/svgrender')
, Canvas = require('canvas')
, fs = require('fs');
@ -134,6 +135,16 @@ exports.save = function(path,text,options,cb){
options = {};
}
var fileExt = path.slice((path.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
if (fileExt === 'svg') {
saveSvg(path,text,options,cb);
} else {
savePng(path,text,options,cb);
}
};
function savePng(path,text,options,cb){
draw(text, options, function(error,canvas){
var fd,buf,fdAndBuf = function(){
@ -157,7 +168,17 @@ exports.save = function(path,text,options,cb){
});
});
};
}
function saveSvg(path,text,options,cb){
exports.drawSvg(text,function(error,code){
if (!error) {
fs.writeFile(path, code, function(fsErr) {
return cb(fsErr, fsErr ? null : code);
});
}
});
}
//
@ -199,3 +220,19 @@ exports.drawText = function(text,options,cb){
});
}
exports.drawSvg = function(text,options,cb){
if(typeof options == 'function'){
cb = options;
options = {};
}
var drawInstance = new QRCodeDraw();
drawInstance.drawBitArray(text,function(error,bits,width){
if (!error) {
var code = svgRender.renderBits(bits,width,options);
cb(error,code);
} else {
cb(error,null);
}
});
}

442
test/fixtures/expected-output.svg vendored Normal file
View file

@ -0,0 +1,442 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" width="156" height="156" viewBox="0 0 156 156" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events">
<rect x="0" y="0" width="156" height="156" fill="#ffffff" />
<defs><rect id="p" width="4" height="4" /></defs>
<g fill="#000000">
<use x="20" y="20" xlink:href="#p" />
<use x="24" y="20" xlink:href="#p" />
<use x="28" y="20" xlink:href="#p" />
<use x="32" y="20" xlink:href="#p" />
<use x="36" y="20" xlink:href="#p" />
<use x="40" y="20" xlink:href="#p" />
<use x="44" y="20" xlink:href="#p" />
<use x="52" y="20" xlink:href="#p" />
<use x="56" y="20" xlink:href="#p" />
<use x="64" y="20" xlink:href="#p" />
<use x="68" y="20" xlink:href="#p" />
<use x="76" y="20" xlink:href="#p" />
<use x="84" y="20" xlink:href="#p" />
<use x="88" y="20" xlink:href="#p" />
<use x="100" y="20" xlink:href="#p" />
<use x="108" y="20" xlink:href="#p" />
<use x="112" y="20" xlink:href="#p" />
<use x="116" y="20" xlink:href="#p" />
<use x="120" y="20" xlink:href="#p" />
<use x="124" y="20" xlink:href="#p" />
<use x="128" y="20" xlink:href="#p" />
<use x="132" y="20" xlink:href="#p" />
<use x="20" y="24" xlink:href="#p" />
<use x="44" y="24" xlink:href="#p" />
<use x="56" y="24" xlink:href="#p" />
<use x="64" y="24" xlink:href="#p" />
<use x="76" y="24" xlink:href="#p" />
<use x="92" y="24" xlink:href="#p" />
<use x="96" y="24" xlink:href="#p" />
<use x="100" y="24" xlink:href="#p" />
<use x="108" y="24" xlink:href="#p" />
<use x="132" y="24" xlink:href="#p" />
<use x="20" y="28" xlink:href="#p" />
<use x="28" y="28" xlink:href="#p" />
<use x="32" y="28" xlink:href="#p" />
<use x="36" y="28" xlink:href="#p" />
<use x="44" y="28" xlink:href="#p" />
<use x="56" y="28" xlink:href="#p" />
<use x="60" y="28" xlink:href="#p" />
<use x="64" y="28" xlink:href="#p" />
<use x="68" y="28" xlink:href="#p" />
<use x="72" y="28" xlink:href="#p" />
<use x="92" y="28" xlink:href="#p" />
<use x="100" y="28" xlink:href="#p" />
<use x="108" y="28" xlink:href="#p" />
<use x="116" y="28" xlink:href="#p" />
<use x="120" y="28" xlink:href="#p" />
<use x="124" y="28" xlink:href="#p" />
<use x="132" y="28" xlink:href="#p" />
<use x="20" y="32" xlink:href="#p" />
<use x="28" y="32" xlink:href="#p" />
<use x="32" y="32" xlink:href="#p" />
<use x="36" y="32" xlink:href="#p" />
<use x="44" y="32" xlink:href="#p" />
<use x="52" y="32" xlink:href="#p" />
<use x="60" y="32" xlink:href="#p" />
<use x="72" y="32" xlink:href="#p" />
<use x="80" y="32" xlink:href="#p" />
<use x="84" y="32" xlink:href="#p" />
<use x="92" y="32" xlink:href="#p" />
<use x="96" y="32" xlink:href="#p" />
<use x="108" y="32" xlink:href="#p" />
<use x="116" y="32" xlink:href="#p" />
<use x="120" y="32" xlink:href="#p" />
<use x="124" y="32" xlink:href="#p" />
<use x="132" y="32" xlink:href="#p" />
<use x="20" y="36" xlink:href="#p" />
<use x="28" y="36" xlink:href="#p" />
<use x="32" y="36" xlink:href="#p" />
<use x="36" y="36" xlink:href="#p" />
<use x="44" y="36" xlink:href="#p" />
<use x="56" y="36" xlink:href="#p" />
<use x="64" y="36" xlink:href="#p" />
<use x="68" y="36" xlink:href="#p" />
<use x="84" y="36" xlink:href="#p" />
<use x="88" y="36" xlink:href="#p" />
<use x="92" y="36" xlink:href="#p" />
<use x="96" y="36" xlink:href="#p" />
<use x="100" y="36" xlink:href="#p" />
<use x="108" y="36" xlink:href="#p" />
<use x="116" y="36" xlink:href="#p" />
<use x="120" y="36" xlink:href="#p" />
<use x="124" y="36" xlink:href="#p" />
<use x="132" y="36" xlink:href="#p" />
<use x="20" y="40" xlink:href="#p" />
<use x="44" y="40" xlink:href="#p" />
<use x="60" y="40" xlink:href="#p" />
<use x="64" y="40" xlink:href="#p" />
<use x="76" y="40" xlink:href="#p" />
<use x="80" y="40" xlink:href="#p" />
<use x="92" y="40" xlink:href="#p" />
<use x="96" y="40" xlink:href="#p" />
<use x="100" y="40" xlink:href="#p" />
<use x="108" y="40" xlink:href="#p" />
<use x="132" y="40" xlink:href="#p" />
<use x="20" y="44" xlink:href="#p" />
<use x="24" y="44" xlink:href="#p" />
<use x="28" y="44" xlink:href="#p" />
<use x="32" y="44" xlink:href="#p" />
<use x="36" y="44" xlink:href="#p" />
<use x="40" y="44" xlink:href="#p" />
<use x="44" y="44" xlink:href="#p" />
<use x="52" y="44" xlink:href="#p" />
<use x="60" y="44" xlink:href="#p" />
<use x="68" y="44" xlink:href="#p" />
<use x="76" y="44" xlink:href="#p" />
<use x="84" y="44" xlink:href="#p" />
<use x="92" y="44" xlink:href="#p" />
<use x="100" y="44" xlink:href="#p" />
<use x="108" y="44" xlink:href="#p" />
<use x="112" y="44" xlink:href="#p" />
<use x="116" y="44" xlink:href="#p" />
<use x="120" y="44" xlink:href="#p" />
<use x="124" y="44" xlink:href="#p" />
<use x="128" y="44" xlink:href="#p" />
<use x="132" y="44" xlink:href="#p" />
<use x="60" y="48" xlink:href="#p" />
<use x="64" y="48" xlink:href="#p" />
<use x="68" y="48" xlink:href="#p" />
<use x="72" y="48" xlink:href="#p" />
<use x="76" y="48" xlink:href="#p" />
<use x="84" y="48" xlink:href="#p" />
<use x="100" y="48" xlink:href="#p" />
<use x="28" y="52" xlink:href="#p" />
<use x="36" y="52" xlink:href="#p" />
<use x="40" y="52" xlink:href="#p" />
<use x="44" y="52" xlink:href="#p" />
<use x="52" y="52" xlink:href="#p" />
<use x="56" y="52" xlink:href="#p" />
<use x="60" y="52" xlink:href="#p" />
<use x="72" y="52" xlink:href="#p" />
<use x="80" y="52" xlink:href="#p" />
<use x="100" y="52" xlink:href="#p" />
<use x="104" y="52" xlink:href="#p" />
<use x="120" y="52" xlink:href="#p" />
<use x="132" y="52" xlink:href="#p" />
<use x="20" y="56" xlink:href="#p" />
<use x="24" y="56" xlink:href="#p" />
<use x="28" y="56" xlink:href="#p" />
<use x="32" y="56" xlink:href="#p" />
<use x="40" y="56" xlink:href="#p" />
<use x="52" y="56" xlink:href="#p" />
<use x="56" y="56" xlink:href="#p" />
<use x="60" y="56" xlink:href="#p" />
<use x="64" y="56" xlink:href="#p" />
<use x="68" y="56" xlink:href="#p" />
<use x="76" y="56" xlink:href="#p" />
<use x="84" y="56" xlink:href="#p" />
<use x="88" y="56" xlink:href="#p" />
<use x="96" y="56" xlink:href="#p" />
<use x="100" y="56" xlink:href="#p" />
<use x="104" y="56" xlink:href="#p" />
<use x="108" y="56" xlink:href="#p" />
<use x="124" y="56" xlink:href="#p" />
<use x="132" y="56" xlink:href="#p" />
<use x="32" y="60" xlink:href="#p" />
<use x="36" y="60" xlink:href="#p" />
<use x="40" y="60" xlink:href="#p" />
<use x="44" y="60" xlink:href="#p" />
<use x="48" y="60" xlink:href="#p" />
<use x="52" y="60" xlink:href="#p" />
<use x="60" y="60" xlink:href="#p" />
<use x="68" y="60" xlink:href="#p" />
<use x="72" y="60" xlink:href="#p" />
<use x="76" y="60" xlink:href="#p" />
<use x="80" y="60" xlink:href="#p" />
<use x="88" y="60" xlink:href="#p" />
<use x="96" y="60" xlink:href="#p" />
<use x="100" y="60" xlink:href="#p" />
<use x="104" y="60" xlink:href="#p" />
<use x="120" y="60" xlink:href="#p" />
<use x="128" y="60" xlink:href="#p" />
<use x="132" y="60" xlink:href="#p" />
<use x="20" y="64" xlink:href="#p" />
<use x="24" y="64" xlink:href="#p" />
<use x="36" y="64" xlink:href="#p" />
<use x="40" y="64" xlink:href="#p" />
<use x="80" y="64" xlink:href="#p" />
<use x="88" y="64" xlink:href="#p" />
<use x="100" y="64" xlink:href="#p" />
<use x="108" y="64" xlink:href="#p" />
<use x="116" y="64" xlink:href="#p" />
<use x="128" y="64" xlink:href="#p" />
<use x="20" y="68" xlink:href="#p" />
<use x="32" y="68" xlink:href="#p" />
<use x="36" y="68" xlink:href="#p" />
<use x="44" y="68" xlink:href="#p" />
<use x="52" y="68" xlink:href="#p" />
<use x="56" y="68" xlink:href="#p" />
<use x="60" y="68" xlink:href="#p" />
<use x="64" y="68" xlink:href="#p" />
<use x="68" y="68" xlink:href="#p" />
<use x="72" y="68" xlink:href="#p" />
<use x="80" y="68" xlink:href="#p" />
<use x="96" y="68" xlink:href="#p" />
<use x="108" y="68" xlink:href="#p" />
<use x="24" y="72" xlink:href="#p" />
<use x="56" y="72" xlink:href="#p" />
<use x="64" y="72" xlink:href="#p" />
<use x="68" y="72" xlink:href="#p" />
<use x="76" y="72" xlink:href="#p" />
<use x="84" y="72" xlink:href="#p" />
<use x="88" y="72" xlink:href="#p" />
<use x="100" y="72" xlink:href="#p" />
<use x="104" y="72" xlink:href="#p" />
<use x="108" y="72" xlink:href="#p" />
<use x="112" y="72" xlink:href="#p" />
<use x="128" y="72" xlink:href="#p" />
<use x="132" y="72" xlink:href="#p" />
<use x="32" y="76" xlink:href="#p" />
<use x="36" y="76" xlink:href="#p" />
<use x="40" y="76" xlink:href="#p" />
<use x="44" y="76" xlink:href="#p" />
<use x="48" y="76" xlink:href="#p" />
<use x="52" y="76" xlink:href="#p" />
<use x="56" y="76" xlink:href="#p" />
<use x="64" y="76" xlink:href="#p" />
<use x="72" y="76" xlink:href="#p" />
<use x="80" y="76" xlink:href="#p" />
<use x="108" y="76" xlink:href="#p" />
<use x="124" y="76" xlink:href="#p" />
<use x="128" y="76" xlink:href="#p" />
<use x="132" y="76" xlink:href="#p" />
<use x="20" y="80" xlink:href="#p" />
<use x="28" y="80" xlink:href="#p" />
<use x="32" y="80" xlink:href="#p" />
<use x="40" y="80" xlink:href="#p" />
<use x="84" y="80" xlink:href="#p" />
<use x="88" y="80" xlink:href="#p" />
<use x="92" y="80" xlink:href="#p" />
<use x="100" y="80" xlink:href="#p" />
<use x="108" y="80" xlink:href="#p" />
<use x="112" y="80" xlink:href="#p" />
<use x="116" y="80" xlink:href="#p" />
<use x="132" y="80" xlink:href="#p" />
<use x="20" y="84" xlink:href="#p" />
<use x="28" y="84" xlink:href="#p" />
<use x="32" y="84" xlink:href="#p" />
<use x="40" y="84" xlink:href="#p" />
<use x="44" y="84" xlink:href="#p" />
<use x="48" y="84" xlink:href="#p" />
<use x="60" y="84" xlink:href="#p" />
<use x="68" y="84" xlink:href="#p" />
<use x="76" y="84" xlink:href="#p" />
<use x="80" y="84" xlink:href="#p" />
<use x="84" y="84" xlink:href="#p" />
<use x="88" y="84" xlink:href="#p" />
<use x="92" y="84" xlink:href="#p" />
<use x="100" y="84" xlink:href="#p" />
<use x="104" y="84" xlink:href="#p" />
<use x="108" y="84" xlink:href="#p" />
<use x="120" y="84" xlink:href="#p" />
<use x="128" y="84" xlink:href="#p" />
<use x="24" y="88" xlink:href="#p" />
<use x="28" y="88" xlink:href="#p" />
<use x="40" y="88" xlink:href="#p" />
<use x="48" y="88" xlink:href="#p" />
<use x="52" y="88" xlink:href="#p" />
<use x="60" y="88" xlink:href="#p" />
<use x="68" y="88" xlink:href="#p" />
<use x="72" y="88" xlink:href="#p" />
<use x="80" y="88" xlink:href="#p" />
<use x="88" y="88" xlink:href="#p" />
<use x="92" y="88" xlink:href="#p" />
<use x="96" y="88" xlink:href="#p" />
<use x="104" y="88" xlink:href="#p" />
<use x="108" y="88" xlink:href="#p" />
<use x="112" y="88" xlink:href="#p" />
<use x="128" y="88" xlink:href="#p" />
<use x="132" y="88" xlink:href="#p" />
<use x="20" y="92" xlink:href="#p" />
<use x="28" y="92" xlink:href="#p" />
<use x="44" y="92" xlink:href="#p" />
<use x="52" y="92" xlink:href="#p" />
<use x="56" y="92" xlink:href="#p" />
<use x="60" y="92" xlink:href="#p" />
<use x="64" y="92" xlink:href="#p" />
<use x="68" y="92" xlink:href="#p" />
<use x="72" y="92" xlink:href="#p" />
<use x="84" y="92" xlink:href="#p" />
<use x="92" y="92" xlink:href="#p" />
<use x="104" y="92" xlink:href="#p" />
<use x="112" y="92" xlink:href="#p" />
<use x="116" y="92" xlink:href="#p" />
<use x="120" y="92" xlink:href="#p" />
<use x="128" y="92" xlink:href="#p" />
<use x="132" y="92" xlink:href="#p" />
<use x="24" y="96" xlink:href="#p" />
<use x="36" y="96" xlink:href="#p" />
<use x="40" y="96" xlink:href="#p" />
<use x="48" y="96" xlink:href="#p" />
<use x="52" y="96" xlink:href="#p" />
<use x="72" y="96" xlink:href="#p" />
<use x="84" y="96" xlink:href="#p" />
<use x="96" y="96" xlink:href="#p" />
<use x="100" y="96" xlink:href="#p" />
<use x="108" y="96" xlink:href="#p" />
<use x="20" y="100" xlink:href="#p" />
<use x="32" y="100" xlink:href="#p" />
<use x="40" y="100" xlink:href="#p" />
<use x="44" y="100" xlink:href="#p" />
<use x="52" y="100" xlink:href="#p" />
<use x="56" y="100" xlink:href="#p" />
<use x="64" y="100" xlink:href="#p" />
<use x="68" y="100" xlink:href="#p" />
<use x="76" y="100" xlink:href="#p" />
<use x="84" y="100" xlink:href="#p" />
<use x="92" y="100" xlink:href="#p" />
<use x="96" y="100" xlink:href="#p" />
<use x="100" y="100" xlink:href="#p" />
<use x="104" y="100" xlink:href="#p" />
<use x="108" y="100" xlink:href="#p" />
<use x="112" y="100" xlink:href="#p" />
<use x="116" y="100" xlink:href="#p" />
<use x="128" y="100" xlink:href="#p" />
<use x="132" y="100" xlink:href="#p" />
<use x="52" y="104" xlink:href="#p" />
<use x="64" y="104" xlink:href="#p" />
<use x="68" y="104" xlink:href="#p" />
<use x="76" y="104" xlink:href="#p" />
<use x="80" y="104" xlink:href="#p" />
<use x="84" y="104" xlink:href="#p" />
<use x="100" y="104" xlink:href="#p" />
<use x="116" y="104" xlink:href="#p" />
<use x="128" y="104" xlink:href="#p" />
<use x="132" y="104" xlink:href="#p" />
<use x="20" y="108" xlink:href="#p" />
<use x="24" y="108" xlink:href="#p" />
<use x="28" y="108" xlink:href="#p" />
<use x="32" y="108" xlink:href="#p" />
<use x="36" y="108" xlink:href="#p" />
<use x="40" y="108" xlink:href="#p" />
<use x="44" y="108" xlink:href="#p" />
<use x="64" y="108" xlink:href="#p" />
<use x="76" y="108" xlink:href="#p" />
<use x="80" y="108" xlink:href="#p" />
<use x="84" y="108" xlink:href="#p" />
<use x="88" y="108" xlink:href="#p" />
<use x="96" y="108" xlink:href="#p" />
<use x="100" y="108" xlink:href="#p" />
<use x="108" y="108" xlink:href="#p" />
<use x="116" y="108" xlink:href="#p" />
<use x="124" y="108" xlink:href="#p" />
<use x="128" y="108" xlink:href="#p" />
<use x="132" y="108" xlink:href="#p" />
<use x="20" y="112" xlink:href="#p" />
<use x="44" y="112" xlink:href="#p" />
<use x="52" y="112" xlink:href="#p" />
<use x="56" y="112" xlink:href="#p" />
<use x="68" y="112" xlink:href="#p" />
<use x="76" y="112" xlink:href="#p" />
<use x="80" y="112" xlink:href="#p" />
<use x="92" y="112" xlink:href="#p" />
<use x="100" y="112" xlink:href="#p" />
<use x="116" y="112" xlink:href="#p" />
<use x="132" y="112" xlink:href="#p" />
<use x="20" y="116" xlink:href="#p" />
<use x="28" y="116" xlink:href="#p" />
<use x="32" y="116" xlink:href="#p" />
<use x="36" y="116" xlink:href="#p" />
<use x="44" y="116" xlink:href="#p" />
<use x="52" y="116" xlink:href="#p" />
<use x="56" y="116" xlink:href="#p" />
<use x="80" y="116" xlink:href="#p" />
<use x="100" y="116" xlink:href="#p" />
<use x="104" y="116" xlink:href="#p" />
<use x="108" y="116" xlink:href="#p" />
<use x="112" y="116" xlink:href="#p" />
<use x="116" y="116" xlink:href="#p" />
<use x="120" y="116" xlink:href="#p" />
<use x="128" y="116" xlink:href="#p" />
<use x="132" y="116" xlink:href="#p" />
<use x="20" y="120" xlink:href="#p" />
<use x="28" y="120" xlink:href="#p" />
<use x="32" y="120" xlink:href="#p" />
<use x="36" y="120" xlink:href="#p" />
<use x="44" y="120" xlink:href="#p" />
<use x="56" y="120" xlink:href="#p" />
<use x="72" y="120" xlink:href="#p" />
<use x="76" y="120" xlink:href="#p" />
<use x="84" y="120" xlink:href="#p" />
<use x="92" y="120" xlink:href="#p" />
<use x="100" y="120" xlink:href="#p" />
<use x="116" y="120" xlink:href="#p" />
<use x="124" y="120" xlink:href="#p" />
<use x="20" y="124" xlink:href="#p" />
<use x="28" y="124" xlink:href="#p" />
<use x="32" y="124" xlink:href="#p" />
<use x="36" y="124" xlink:href="#p" />
<use x="44" y="124" xlink:href="#p" />
<use x="52" y="124" xlink:href="#p" />
<use x="56" y="124" xlink:href="#p" />
<use x="68" y="124" xlink:href="#p" />
<use x="76" y="124" xlink:href="#p" />
<use x="80" y="124" xlink:href="#p" />
<use x="88" y="124" xlink:href="#p" />
<use x="96" y="124" xlink:href="#p" />
<use x="100" y="124" xlink:href="#p" />
<use x="104" y="124" xlink:href="#p" />
<use x="116" y="124" xlink:href="#p" />
<use x="124" y="124" xlink:href="#p" />
<use x="132" y="124" xlink:href="#p" />
<use x="20" y="128" xlink:href="#p" />
<use x="44" y="128" xlink:href="#p" />
<use x="56" y="128" xlink:href="#p" />
<use x="64" y="128" xlink:href="#p" />
<use x="68" y="128" xlink:href="#p" />
<use x="72" y="128" xlink:href="#p" />
<use x="76" y="128" xlink:href="#p" />
<use x="80" y="128" xlink:href="#p" />
<use x="84" y="128" xlink:href="#p" />
<use x="96" y="128" xlink:href="#p" />
<use x="100" y="128" xlink:href="#p" />
<use x="108" y="128" xlink:href="#p" />
<use x="112" y="128" xlink:href="#p" />
<use x="128" y="128" xlink:href="#p" />
<use x="20" y="132" xlink:href="#p" />
<use x="24" y="132" xlink:href="#p" />
<use x="28" y="132" xlink:href="#p" />
<use x="32" y="132" xlink:href="#p" />
<use x="36" y="132" xlink:href="#p" />
<use x="40" y="132" xlink:href="#p" />
<use x="44" y="132" xlink:href="#p" />
<use x="60" y="132" xlink:href="#p" />
<use x="68" y="132" xlink:href="#p" />
<use x="76" y="132" xlink:href="#p" />
<use x="80" y="132" xlink:href="#p" />
<use x="92" y="132" xlink:href="#p" />
<use x="96" y="132" xlink:href="#p" />
<use x="100" y="132" xlink:href="#p" />
<use x="104" y="132" xlink:href="#p" />
<use x="116" y="132" xlink:href="#p" />
<use x="128" y="132" xlink:href="#p" />
<use x="132" y="132" xlink:href="#p" />
</g>
</svg>

After

(image error) Size: 17 KiB

81
test/svg.js Normal file
View file

@ -0,0 +1,81 @@
var test = require('tap').test;
var libxml = require("libxmljs");
var fs = require('fs');
var svgRender = require('../lib/svgrender');
var QRCode = require('../qrcode');
test('svgrender interface', function(t) {
t.ok(svgRender.hasOwnProperty('renderBits'), 'function "renderBits" should be defined');
t.throws(function() { svgrender.renderBits(); }, 'should throws if called without params');
t.throws(function() { svgrender.renderBits([]); }, 'should throws if called without "width" param');
t.throws(function() { svgrender.renderBits([], ""); }, 'should throws if called with invalid "width" param');
t.throws(function() { svgrender.renderBits(null, 0); }, 'should throws if called with undefined "bits" param');
t.throws(function() { svgrender.renderBits("", 0); }, 'should throws if "bits" param is not an array');
t.end();
});
test('svgrender output', function(t) {
var expectedWidth = 2;
var expectedMargin = 8;
var expectedScale = 5;
var expectedQrCodeSize = '26'; // qrcode size = width * scale + margin * 2
var expectedLightColor = '#AAAAAA';
var expectedDarkColor = '#555555';
var bits = [1, 1, 0, 1];
var expectedTrueBitNumber = bits.filter(function(b) { return b; }).length;
var xml = svgRender.renderBits(bits, expectedWidth, {
scale: expectedScale,
margin: expectedMargin,
lightColor: expectedLightColor,
darkColor: expectedDarkColor
});
var xmlDoc = libxml.parseXml(xml);
t.equal(xmlDoc.errors.length, 0, 'should output a valid xml');
var rootElem = xmlDoc.root();
t.equal('svg', rootElem.name(), 'should have <svg> has root element');
t.equal(rootElem.attr('width').value(), expectedQrCodeSize, 'should have a valid width');
t.equal(rootElem.attr('height').value(), expectedQrCodeSize, 'should have a valid height');
var rectElem = rootElem.child(1);
t.equal(rectElem.name(), 'rect', 'should have <rect> as first child element');
t.equal(rectElem.attr('width').value(), expectedQrCodeSize, 'should have a valid rect width');
t.equal(rectElem.attr('height').value(), expectedQrCodeSize, 'should have a valid rect height');
t.equal(rectElem.attr('fill').value(), expectedLightColor, 'should have the background color specified in options');
var dotDef = rectElem.nextElement();
t.equal(dotDef.name(), 'defs', 'should have a <defs> element');
var dotRect = dotDef.child(0);
t.equal(dotRect.name(), 'rect', 'should have a <rect> definition');
t.equal(dotRect.attr('width').value(), expectedScale.toString(), 'should have a valid rect width');
t.equal(dotRect.attr('height').value(), expectedScale.toString(), 'should have a valid rect height');
var gElem = dotDef.nextElement();
t.equal(gElem.name(), 'g', 'should have a <g> element');
t.equal(gElem.attr('fill').value(), expectedDarkColor, 'should have the color specified in options');
var useElems = gElem.find('*');
t.equal(useElems.length, expectedTrueBitNumber, 'should have one element for each "true" bit');
t.equal(useElems[0].attr('x').value(), expectedMargin.toString(), 'should have a left margin as specified in options');
t.equal(useElems[0].attr('y').value(), expectedMargin.toString(), 'should have a top margin as specified in options');
t.end();
});
test('drawSvg', function(t) {
var expectedSvg = fs.readFileSync(__dirname + '/fixtures/expected-output.svg', 'UTF-8');
QRCode.drawSvg('http://www.google.com', function(err, code) {
t.ok(!err, 'there should be no error');
t.equal(code, expectedSvg, 'should output a valid svg');
t.end()
});
});