Giter Site home page Giter Site logo

qrcode-svg's Introduction

Introduction

This library has been written to generate a SVG image of QR Code in Node.js, goals:

  • pure JavaScript
  • no browser requirement
  • no external dependencies
  • generate SVG output

Getting Started

Install the package:

npm install qrcode-svg

Inline example:

var QRCode = require("qrcode-svg");
var svg = new QRCode("Hello World!").svg();

More options:

var qrcode = new QRCode({
  content: "http://github.com/",
  padding: 4,
  width: 256,
  height: 256,
  color: "#000000",
  background: "#ffffff",
  ecl: "M",
});
qrcode.save("sample.svg", function(error) {
  if (error) throw error;
  console.log("Done!");
});

Options

List of options:

  • content - QR Code content, the only required parameter
  • padding - white space padding, 4 modules by default, 0 for no border
  • width - QR Code width in pixels
  • height - QR Code height in pixels
  • color - color of modules (squares), color name or hex string, e.g. #000000
  • background - color of background, color name or hex string, e.g. white
  • ecl - error correction level: L, M, H, Q
  • join - join modules (squares) into one shape, into the SVG path element, recommended for web and responsive use, default: false
  • predefined - to create a squares as pattern, then populate the canvas, default: false, see the output examples below
  • pretty - apply indents and new lines, default: true
  • swap - swap X and Y modules, only if you have issues with some QR readers, default: false
  • xmlDeclaration - prepend XML declaration to the SVG document, i.e. <?xml version="1.0" standalone="yes"?>, default: true
  • container - wrapping element, default: svg, see below

Container options:

  • svg - populate squares in a SVG document with width and height attriute, recommended for converting to raster images or PDF where QR Code is being static (exact size)
  • svg-viewbox - populate squares in a SVG document with viewBox attriute, recommended for responsive web pages
  • g - put squares in g element, useful when you need to put multiple QR Codes in a single SVG document
  • none - no wrapper

SVG output

Editable squares

This mode is useful for designers to manipulate with particular squares. Thus, one can open the QR Code in an editor, select particular modules, move around, change color, etc. However, some old SVG viewers may generate minor gaps between the squares - the side effect when rendering an image at certain zoom level.

Default options

var qrcode = new QRCode({
  content: "Pretty Fox",
  join: false,
  predefined: false
});

Output with rect elements

<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="256" height="256">
  <rect x="0" y="0" width="256" height="256" style="fill:#ffffff;shape-rendering:crispEdges;"/>
  <rect x="16" y="16" width="8" height="8" style="fill:#000000;shape-rendering:crispEdges;"/>
  <rect x="24" y="16" width="8" height="8" style="fill:#000000;shape-rendering:crispEdges;"/>
  <rect x="32" y="16" width="8" height="8" style="fill:#000000;shape-rendering:crispEdges;"/>
  ...
</svg>

Responsive web page

Squares joined into one path shape produce a compact file size, i.e. 4-5x reduced compared with rect elements. A single path element will result in an optimized rendering, thus not producing any minor gaps between the squares. Also using the container with viewBox attribute may contribute to the responsive scaling on the web.

Set join to true

var qrcode = new QRCode({
  content: "Pretty Fox",
  join: true,
  container: "svg-viewbox" //Useful but not required
});

Output with path element

<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 256 256">
  <rect x="0" y="0" width="256" height="256" style="fill:beige;shape-rendering:crispEdges;"/>
  <path x="0" y="0" style="fill:blue;shape-rendering:crispEdges;" d="M35.31,35.31 V44.14 H44.14 V35.31 H35.31 Z..." />
</svg>

Predefined pattern

Algorithm defines the square pattern once before populating a canvas. Useful if you want to generate QR Code with candies. However, some SVG software and converters do not support defs or use elements.

Set predefined to true

var qrcode = new QRCode({
  content: "Pretty Fox",
  predefined: true
});

Output with defs and use elements

<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="256" height="256">
  <defs><path id="qrmodule" d="M0 0 h8.827586206896552 v8.827586206896552 H0 z" style="fill:maroon;shape-rendering:crispEdges;" /></defs>
  <rect x="0" y="0" width="256" height="256" style="fill:beige;shape-rendering:crispEdges;"/>
  <use x="35.310344827586206" y="35.310344827586206" href="#qrmodule" />
  <use x="44.13793103448276" y="35.310344827586206" href="#qrmodule" />
  <use x="52.96551724137931" y="35.310344827586206" href="#qrmodule" />
  <use x="61.79310344827586" y="35.310344827586206" href="#qrmodule" />
  <use x="70.62068965517241" y="35.310344827586206" href="#qrmodule" />
  ...
</svg>

Command Line

Usage:
  qrcode-svg [options] <content>

Options:
  --help                 Print this message
  --version, -v          Print version number
  --padding , -p [value] Offset in number of modules
  --width, -w [px]       Image width in pixels
  --height, -h [px]      Image height in pixels
  --color, -fg [color]   Foreground color, hex or name
  --background [color]   Background color, hex or name
  --ecl [value]          Error correction level: L, M, H, Q
  --join                 Join modules into one SVG path, i.e. for crisp rendering
  --predefined           Use 'defs' and 'use' elements in SVG, i.e. for compact output
  --no-prettify          Avoid indenting and new lines in SVG, i.e. for compact output
  --viewbox              Use 'viewBox' instead of 'width' and 'height' attributes
  --swap-fix             Swap X and Y modules to fix issues with some QR readers
  --output, -o [file]    Output file name
  --force, -f            Force overwrite

Examples:
  qrcode-svg http://github.com
  qrcode-svg -f -o hello.svg "Hello World"
  qrcode-svg -p 4 -w 256 -h 256 --join --viewbox "Responsive..."
  qrcode-svg --padding 2 --width 120 --height 120 "Little fox..."
  qrcode-svg --color blue --background #ececec "...jumps over" 

Usage Scenarios

Convert to other formats

Using html-pdf to convert SVG to PDF (or PNG or JPEG)

var QRCode = require('qrcode-svg');
var svg = new QRCode('hello').svg();
...
var pdf = require('html-pdf');
pdf.create(svg, { border: 0, type: 'pdf' }).toFile('output.pdf', function(err, res) {
  ...
});

ASCII modules

QR Code in ASCII to output in a shell

var QRCode = require('qrcode-svg');

var hello = new QRCode("Hello World!");
var modules = hello.qrcode.modules;

var ascii = '';
var length = modules.length;
for (var y = 0; y < length; y++) {
  for (var x = 0; x < length; x++) {
    var module = modules[x][y];
    ascii += (module ? 'x' : ' ');
  }
  ascii += '\r\n';
}
console.log(ascii);


    xxxxxxx xx    x x xxxxxxx
    x     x  xxxx x x x     x
    x xxx x xx  xx  x x xxx x
    x xxx x       xx  x xxx x
    x xxx x  x   x  x x xxx x
    x     x  x  xx xx x     x
    xxxxxxx x x x x x xxxxxxx
            xx     xx        
    x x  xx    x x   xx   x x
       x x  xx x    xx x xx x
     x  x xx   x x x  xx   xx
     x xx  xxx xx x x  x  x x
     xx  xxxx       xxxx    x
    x x  x xx x xx xx x xx xx
    x    xx   xxxx    xxxx   
    xx xx   x  x  x x xx    x
       xxxx xxxx    xxxxxx  x
                    x   x x  
    xxxxxxx  x  xxx x x x   x
    x     x xxx  x xx   x  x 
    x xxx x        xxxxxxxxxx
    x xxx x  xxxxxxxxx  x xx 
    x xxx x xxx  xx  x    x x
    x     x    x    x     x  
    xxxxxxx xxx xxx   x   x x


Web browser

Use on a HTML page with JavaScript

<!DOCTYPE html>
<html>
<body>
<div id="container"></div>
<script src="dist/qrcode.min.js"></script>
<script>
var qrcode = new QRCode({
  content: "Hello World!",
  container: "svg-viewbox", //Responsive use
  join: true //Crisp rendering and 4-5x reduced file size
});
var svg = qrcode.svg();
document.getElementById("container").innerHTML = svg;
</script>
</body>
</html>

Thanks

Thanks to davidshimjs for the base library.

Thanks to Kazuhiko Arase for the original QR Code in JavaScript algorithm.

Thanks to all contributors on the GitHub.

Legal notice

Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php

The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
http://www.denso-wave.com/qrcode/faqpatent-e.html

qrcode-svg's People

Contributors

papnkukn avatar stephanhoyer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

qrcode-svg's Issues

How to make the s SVG full width?

Hi Everyone,

Hope someone can guide me in the right direction, please.

I am trying to make the SVG 100% width, but it does not work. I have tried the list of options and tried width: 100% in CSS, which works, but the QR code just moves to the center with whitespace on the left and right. It does not show the QR code to scan as 100% width.

I have also tried the width and heights props, but it has the same effect.

image

length overflow for emojis?

const hello = new QRCode("🖤🌹");

qrcode.js:106 Uncaught Error: code length overflow. (132>128)
at QRCodeModel.createData (qrcode.js:106:47)
at QRCodeModel.makeImpl (qrcode.js:91:26)
at QRCodeModel.getBestMaskPattern (qrcode.js:92:473)
at QRCodeModel.make (qrcode.js:89:101)

Is it possible to encode emojis inside the qrcode?

support generating svg path only

hi there! great library. using it in react pdf, which requires us to use its own Svg and Path components. it would be useful to have an option to generate just the path of an svg without anything surrounding it. for reference, currently this is my workaround:

const generateQrCodePath = (content: string, size: number) => {
  const htmlStr = new QRCode({ content, join: true, width: size, height: size }).svg({container: 'none'});
  const parsableHtml = new DOMParser().parseFromString(htmlStr, 'text/html');
  return parsableHtml.querySelector('html > body > rect > path')?.getAttribute('d') ?? '';
};
import QRCode from 'qrcode-svg';
...
// in react pdf
return (
  <Svg>
    <Path d={generateQrCodePath(content, size)} fill='black' />
  </Svg>
);

Add ES6 module

Please add ES6 module support.

Are you still around (the developer)?

I will probably fork and add ES6 module support, would you merge a pull request with ES6 Module support?

What's with the obfuscated code?

qrcode-svg/lib/qrcode.js

Lines 88 to 153 in 47d56ec

QRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+","+col);}
return this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row<this.moduleCount;row++){this.modules[row]=new Array(this.moduleCount);for(var col=0;col<this.moduleCount;col++){this.modules[row][col]=null;}}
this.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(test,maskPattern);if(this.typeNumber>=7){this.setupTypeNumber(test);}
if(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);}
this.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}}
return pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row<this.modules.length;row++){var y=row*cs;for(var col=0;col<this.modules[row].length;col++){var x=col*cs;var dark=this.modules[row][col];if(dark){qr_mc.beginFill(0,100);qr_mc.moveTo(x,y);qr_mc.lineTo(x+cs,y);qr_mc.lineTo(x+cs,y+cs);qr_mc.lineTo(x,y+cs);qr_mc.endFill();}}}
return qr_mc;},setupTimingPattern:function(){for(var r=8;r<this.moduleCount-8;r++){if(this.modules[r][6]!=null){continue;}
this.modules[r][6]=(r%2==0);}
for(var c=8;c<this.moduleCount-8;c++){if(this.modules[6][c]!=null){continue;}
this.modules[6][c]=(c%2==0);}},setupPositionAdjustPattern:function(){var pos=QRUtil.getPatternPosition(this.typeNumber);for(var i=0;i<pos.length;i++){for(var j=0;j<pos.length;j++){var row=pos[i];var col=pos[j];if(this.modules[row][col]!=null){continue;}
for(var r=-2;r<=2;r++){for(var c=-2;c<=2;c++){if(r==-2||r==2||c==-2||c==2||(r==0&&c==0)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}}}},setupTypeNumber:function(test){var bits=QRUtil.getBCHTypeNumber(this.typeNumber);for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;}
for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}}
for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}}
this.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex<data.length){dark=(((data[byteIndex]>>>bitIndex)&1)==1);}
var mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;}
this.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}}
row+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;i<dataList.length;i++){var data=dataList[i];buffer.put(data.mode,4);buffer.put(data.getLength(),QRUtil.getLengthInBits(data.mode,typeNumber));data.write(buffer);}
var totalDataCount=0;for(var i=0;i<rsBlocks.length;i++){totalDataCount+=rsBlocks[i].dataCount;}
if(buffer.getLengthInBits()>totalDataCount*8){throw new Error("code length overflow. ("
+buffer.getLengthInBits()
+">"
+totalDataCount*8
+")");}
if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);}
while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);}
while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;}
buffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;}
buffer.put(QRCodeModel.PAD1,8);}
return QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r<rsBlocks.length;r++){var dcCount=rsBlocks[r].dataCount;var ecCount=rsBlocks[r].totalCount-dcCount;maxDcCount=Math.max(maxDcCount,dcCount);maxEcCount=Math.max(maxEcCount,ecCount);dcdata[r]=new Array(dcCount);for(var i=0;i<dcdata[r].length;i++){dcdata[r][i]=0xff&buffer.buffer[i+offset];}
offset+=dcCount;var rsPoly=QRUtil.getErrorCorrectPolynomial(ecCount);var rawPoly=new QRPolynomial(dcdata[r],rsPoly.getLength()-1);var modPoly=rawPoly.mod(rsPoly);ecdata[r]=new Array(rsPoly.getLength()-1);for(var i=0;i<ecdata[r].length;i++){var modIndex=i+modPoly.getLength()-ecdata[r].length;ecdata[r][i]=(modIndex>=0)?modPoly.get(modIndex):0;}}
var totalCodeCount=0;for(var i=0;i<rsBlocks.length;i++){totalCodeCount+=rsBlocks[i].totalCount;}
var data=new Array(totalCodeCount);var index=0;for(var i=0;i<maxDcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<dcdata[r].length){data[index++]=dcdata[r][i];}}}
for(var i=0;i<maxEcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<ecdata[r].length){data[index++]=ecdata[r][i];}}}
return data;};var QRMode={MODE_NUMBER:1<<0,MODE_ALPHA_NUM:1<<1,MODE_8BIT_BYTE:1<<2,MODE_KANJI:1<<3};var QRErrorCorrectLevel={L:1,M:0,Q:3,H:2};var QRMaskPattern={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var QRUtil={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:(1<<10)|(1<<8)|(1<<5)|(1<<4)|(1<<2)|(1<<1)|(1<<0),G18:(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<5)|(1<<2)|(1<<0),G15_MASK:(1<<14)|(1<<12)|(1<<10)|(1<<4)|(1<<1),getBCHTypeInfo:function(data){var d=data<<10;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)>=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));}
return((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));}
return(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;}
return digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error("bad maskPattern:"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i<errorCorrectLength;i++){a=a.multiply(new QRPolynomial([1,QRMath.gexp(i)],0));}
return a;},getLengthInBits:function(mode,type){if(1<=type&&type<10){switch(mode){case QRMode.MODE_NUMBER:return 10;case QRMode.MODE_ALPHA_NUM:return 9;case QRMode.MODE_8BIT_BYTE:return 8;case QRMode.MODE_KANJI:return 8;default:throw new Error("mode:"+mode);}}else if(type<27){switch(mode){case QRMode.MODE_NUMBER:return 12;case QRMode.MODE_ALPHA_NUM:return 11;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 10;default:throw new Error("mode:"+mode);}}else if(type<41){switch(mode){case QRMode.MODE_NUMBER:return 14;case QRMode.MODE_ALPHA_NUM:return 13;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 12;default:throw new Error("mode:"+mode);}}else{throw new Error("type:"+type);}},getLostPoint:function(qrCode){var moduleCount=qrCode.getModuleCount();var lostPoint=0;for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount;col++){var sameCount=0;var dark=qrCode.isDark(row,col);for(var r=-1;r<=1;r++){if(row+r<0||moduleCount<=row+r){continue;}
for(var c=-1;c<=1;c++){if(col+c<0||moduleCount<=col+c){continue;}
if(r==0&&c==0){continue;}
if(dark==qrCode.isDark(row+r,col+c)){sameCount++;}}}
if(sameCount>5){lostPoint+=(3+sameCount-5);}}}
for(var row=0;row<moduleCount-1;row++){for(var col=0;col<moduleCount-1;col++){var count=0;if(qrCode.isDark(row,col))count++;if(qrCode.isDark(row+1,col))count++;if(qrCode.isDark(row,col+1))count++;if(qrCode.isDark(row+1,col+1))count++;if(count==0||count==4){lostPoint+=3;}}}
for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount-6;col++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row,col+1)&&qrCode.isDark(row,col+2)&&qrCode.isDark(row,col+3)&&qrCode.isDark(row,col+4)&&!qrCode.isDark(row,col+5)&&qrCode.isDark(row,col+6)){lostPoint+=40;}}}
for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount-6;row++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row+1,col)&&qrCode.isDark(row+2,col)&&qrCode.isDark(row+3,col)&&qrCode.isDark(row+4,col)&&!qrCode.isDark(row+5,col)&&qrCode.isDark(row+6,col)){lostPoint+=40;}}}
var darkCount=0;for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount;row++){if(qrCode.isDark(row,col)){darkCount++;}}}
var ratio=Math.abs(100*darkCount/moduleCount/moduleCount-50)/5;lostPoint+=ratio*10;return lostPoint;}};var QRMath={glog:function(n){if(n<1){throw new Error("glog("+n+")");}
return QRMath.LOG_TABLE[n];},gexp:function(n){while(n<0){n+=255;}
while(n>=256){n-=255;}
return QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<<i;}
for(var i=8;i<256;i++){QRMath.EXP_TABLE[i]=QRMath.EXP_TABLE[i-4]^QRMath.EXP_TABLE[i-5]^QRMath.EXP_TABLE[i-6]^QRMath.EXP_TABLE[i-8];}
for(var i=0;i<255;i++){QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]]=i;}
function QRPolynomial(num,shift){if(num.length==undefined){throw new Error(num.length+"/"+shift);}
var offset=0;while(offset<num.length&&num[offset]==0){offset++;}
this.num=new Array(num.length-offset+shift);for(var i=0;i<num.length-offset;i++){this.num[i]=num[i+offset];}}
QRPolynomial.prototype={get:function(index){return this.num[index];},getLength:function(){return this.num.length;},multiply:function(e){var num=new Array(this.getLength()+e.getLength()-1);for(var i=0;i<this.getLength();i++){for(var j=0;j<e.getLength();j++){num[i+j]^=QRMath.gexp(QRMath.glog(this.get(i))+QRMath.glog(e.get(j)));}}
return new QRPolynomial(num,0);},mod:function(e){if(this.getLength()-e.getLength()<0){return this;}
var ratio=QRMath.glog(this.get(0))-QRMath.glog(e.get(0));var num=new Array(this.getLength());for(var i=0;i<this.getLength();i++){num[i]=this.get(i);}
for(var i=0;i<e.getLength();i++){num[i]^=QRMath.gexp(QRMath.glog(e.get(i))+ratio);}
return new QRPolynomial(num,0).mod(e);}};function QRRSBlock(totalCount,dataCount){this.totalCount=totalCount;this.dataCount=dataCount;}
QRRSBlock.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];QRRSBlock.getRSBlocks=function(typeNumber,errorCorrectLevel){var rsBlock=QRRSBlock.getRsBlockTable(typeNumber,errorCorrectLevel);if(rsBlock==undefined){throw new Error("bad rs block @ typeNumber:"+typeNumber+"/errorCorrectLevel:"+errorCorrectLevel);}
var length=rsBlock.length/3;var list=[];for(var i=0;i<length;i++){var count=rsBlock[i*3+0];var totalCount=rsBlock[i*3+1];var dataCount=rsBlock[i*3+2];for(var j=0;j<count;j++){list.push(new QRRSBlock(totalCount,dataCount));}}
return list;};QRRSBlock.getRsBlockTable=function(typeNumber,errorCorrectLevel){switch(errorCorrectLevel){case QRErrorCorrectLevel.L:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+0];case QRErrorCorrectLevel.M:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+1];case QRErrorCorrectLevel.Q:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+2];case QRErrorCorrectLevel.H:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+3];default:return undefined;}};function QRBitBuffer(){this.buffer=[];this.length=0;}
QRBitBuffer.prototype={get:function(index){var bufIndex=Math.floor(index/8);return((this.buffer[bufIndex]>>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i<length;i++){this.putBit(((num>>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);}
if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));}
this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]];

Use of template for the QR eyes + insert an image in center

First, thank you for this so usefull lib.

As for square predefined square template, do you think you could add two others options :

  • Predefined QR eyes
  • image centered inclusion as a little logo for example with a little add like this :
<filter id="blurMe">
	<feGaussianBlur in="SourceGraphic" stdDeviation="10" />
</filter>
<circle cx="100" 
	cy="100" 
	r="40" 
	fill="#FFFFFF" 
	fill-opacity="1.0" 
	filter="url(#blurMe)"/>
<image xlink:href="data:image/png;base64,iVBzhL15vz+JEAAAAASUVORK5CYII=" 
	x="80" 
	y="80" 
	width="50" 
	height="50"/>

This image inclusion example give something like here

To illustrate my request , you can have a look on Unitag qr generator that provides lot of different angle template and logo inclusion.

Incompatible with secure CSP

qrcode-svg/lib/qrcode.js

Lines 312 to 317 in 47d56ec

//Populate with predefined shape instead of "rect" elements, thanks to @kkocdko
var predefined = typeof options.predefined != "undefined" ? !!options.predefined : false;
var defs = predefined ? indent + '<defs><path id="qrmodule" d="M0 0 h' + ysize + ' v' + xsize + ' H0 z" style="fill:' + options.color + ';shape-rendering:crispEdges;" /></defs>' + EOL : '';
//Background rectangle
var bgrect = indent + '<rect x="0" y="0" width="' + width + '" height="' + height + '" style="fill:' + options.background + ';shape-rendering:crispEdges;"/>' + EOL;

Please don't do this, for those of us using this library on the web it will break on every sufficiently secured site which doesn't allow script-src 'unsafe-inline'.

For setting the fill colour, there's a perfectly good fill attribute you can use instead. For e.g. the crisp edges rendering, please just put the CSS in the README and let us apply it ourselves

Support Numeric and Alphanumeric encoding modes

QR codes can also be encoded with numeric or alphanumeric encoding for optimal data density. Quoting https://en.wikipedia.org/wiki/QR_code

Input mode Bits/char. Possible characters, default encoding
Numeric only 3⅓ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Alphanumeric 0–9, A–Z (upper-case only), space, $, %, *, +, -, ., /, :
Binary/byte 8 ISO 8859-1
Kanji/kana 13 Shift JIS X 0208

Is this done automatically in this library? How can I configure what encoding should be used?

Scanner/website not working

We have an issue with our QR code implementation not being detected on certain scanners. It does work on some which is the confusing part.

Not working:
https://qrcoderaptor.com/
https://www.amazon.com/Handsfree-Standard-Scanner-Shielded-DS9208-SR4NNU21Z/dp/B01C65YOE4/ref=sr_1_3?keywords=zebra+symbol+ds9208&qid=1666968387&qu=eyJxc2MiOiIyLjA3IiwicXNhIjoiMi4xNCIsInFzcCI6IjEuOTEifQ%3D%3D&sprefix=zebra+symbol+ds%2Caps%2C83&sr=8-3&ufe=app_do%3Aamzn1.fos.f5122f16-c3e8-4386-bf32-63e904010ad0

Working:
https://www.amazon.com/Desktop-Omnidirectional-Hands-Free-Automatic-Barcodes/dp/B087CSV7NL/?th=1
-Iphones
Things I have tried without success

  1. Setting a white background
  2. Changing both predefined and join to true
  3. Increase size

Webpack Module not found: Error: Can't resolve 'fs' in 'node_modules/qrcode-svg/lib'

Can you please remove .save()?

qrcode-svg/lib/qrcode.js

Lines 405 to 420 in 47d56ec

/** Writes QR Code image to a file */
QRCode.prototype.save = function(file, callback) {
var data = this.svg();
if (typeof callback != "function") {
callback = function(error, result) { };
}
try {
//Package 'fs' is available in node.js but not in a web browser
var fs = require('fs');
fs.writeFile(file, data, callback);
}
catch (e) {
//Sorry, 'fs' is not available
callback(e);
}
};

Saving files to disk is very easy in node and the developer can decide wether they need to use sync or async:

fs.writeFileSync("qr.svg", new QRCode("abc").svg());

Can't resolve 'fs'

When requiring this library for browser frontend use, I get this error.

Everything works otherwise, it's just this error showing in the console is annoying.

Please add an option for `shape-rendering` property.

Default value crispEdges looks well in most browsers.
Except macOS Safari.

Here are the screenshots:

crispEdges or optimizespeed in Firefox or Chrome:
crispEdges in Firefox

crispEdges in macOS Safari:
crispEdges in macOS Safari

optimizespeed in macOS Safari:
optimizespeed in macOS Safari

The output svg code can be more concise

Before:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="250" height="250">
    <rect x="0" y="0" width="10" height="10" style="fill:#000000;shape-rendering:crispEdges;"/>
    <rect x="10" y="0" width="10" height="10" style="fill:#ffffff;shape-rendering:crispEdges;"/>
    <rect x="20" y="0" width="10" height="10" style="fill:#000000;shape-rendering:crispEdges;"/>
    ...

After

<svg xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges" viewBox="0 0 250 250">
    <defs><path id="c" d="M0 0h10v10H0z"/></defs>
    <use x="0" y="0" href="#c"/>
    <use x="20" y="0" href="#c"/>
    ...

My method:

/**
 * Output to svg
 * @param  {number}   moduleLength   Every modules' length of side
 * @return {string}   Svg content string
 */
this.toSvg = function(moduleLength) {
    var moduleArr = this.qrcode.modules;
    var length = moduleArr.length;
    var svgContent = '';
    var viewBoxLengthStr = length * moduleLength;
    svgContent += `<svg xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges" viewBox="0 0 ${viewBoxLengthStr} ${viewBoxLengthStr}"><defs><path id="c" d="M0 0h${moduleLength}v${moduleLength}H0z"/></defs>`;
    for (var y in moduleArr) {
        for (var x in moduleArr) {
            var module = moduleArr[x][y];
            if (module == true) {
                var coordinateX = x * moduleLength;
                var coordinateY = y * moduleLength;
                svgContent += `<use href="#c" x="${coordinateX}" y="${coordinateY}"/>`;
            }
        }
    }
    svgContent += '</svg>';
    return svgContent;
};

Feature request: add viewBox property

It would be nice to add the viewBox property in the SVG string.
This make it much easier to scale a single generated SVG using CSS styles.

In my own project, I've solved this in a hacky way by adding viewBox="0 0 250 250" myself after generating the SVG string.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.