Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to support Numeric mode data encoding #253

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions qrcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,33 @@ var QRCode;
}
}
};

function QRNumberByte(data) {
this.mode = QRMode.MODE_NUMBER;
this.data = data;
this.parsedData = [];

// Added to support UTF-8 Characters
for (var i = 0, l = this.data.length; i < l; i += 3) {
this.parsedData.push(parseInt(this.data.slice(i, i + 3)));
}
}

QRNumberByte.prototype = {
getLength: function (buffer) {
return this.data.length;
},
write: function (buffer) {
var i = 0;
var l = this.parsedData.length - 1;
while(i < l){
buffer.put(this.parsedData[i], 10);
i++;
}
var d = this.parsedData[i];
buffer.put(d, d > 99 ? 10 : (d > 9 ? 7 : 4));
}
};

function QRCodeModel(typeNumber, errorCorrectLevel) {
this.typeNumber = typeNumber;
Expand All @@ -84,7 +111,7 @@ var QRCode;
this.dataList = [];
}

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);}
QRCodeModel.prototype={addData:function(data){var newData= isNaN(data) ? new QR8bitByte(data) : new QRNumberByte(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);}
Expand Down Expand Up @@ -150,7 +177,7 @@ var QRCode;
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]];

var QRNCodeLimitLength = [[41,34,27,17],[77,63,48,34],[127,101,77,58],[187,149,111,82],[255,202,144,106],[322,255,178,139],[370,293,207,154],[461,365,259,202],[552,432,312,235],[652,513,364,288],[772,604,427,331],[883,691,489,374],[1022,796,580,427],[1101,871,621,468],[1250,991,703,530],[1408,1082,775,602],[1548,1212,876,674],[1725,1346,948,746],[1903,1500,1063,813],[2061,1600,1159,919],[2232,1708,1224,969],[2409,1872,1358,1056],[2620,2059,1468,1108],[2812,2188,1588,1228],[3057,2395,1718,1286],[3283,2544,1804,1425],[3517,2701,1933,1501],[3669,2857,2085,1581],[3909,3035,2181,1677],[4158,3289,2358,1782],[4417,3486,2473,1897],[4686,3693,2670,2022],[4965,3909,2805,2157],[5253,4134,2949,2301],[5529,4343,3081,2361],[5836,4588,3244,2524],[6153,4775,3417,2625],[6479,5039,3599,2735],[6743,5313,3791,2927],[7089,5596,3993,3057]];
function _isSupportCanvas() {
return typeof CanvasRenderingContext2D != "undefined";
}
Expand Down Expand Up @@ -469,22 +496,23 @@ var QRCode;
function _getTypeNumber(sText, nCorrectLevel) {
var nType = 1;
var length = _getUTF8Length(sText);
var limits = isNaN(sText) ? QRCodeLimitLength : QRNCodeLimitLength;

for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {
for (var i = 0, len = limits.length; i <= len; i++) {
var nLimit = 0;

switch (nCorrectLevel) {
case QRErrorCorrectLevel.L :
nLimit = QRCodeLimitLength[i][0];
nLimit = limits[i][0];
break;
case QRErrorCorrectLevel.M :
nLimit = QRCodeLimitLength[i][1];
nLimit = limits[i][1];
break;
case QRErrorCorrectLevel.Q :
nLimit = QRCodeLimitLength[i][2];
nLimit = limits[i][2];
break;
case QRErrorCorrectLevel.H :
nLimit = QRCodeLimitLength[i][3];
nLimit = limits[i][3];
break;
}

Expand All @@ -495,14 +523,17 @@ var QRCode;
}
}

if (nType > QRCodeLimitLength.length) {
if (nType > limits.length) {
throw new Error("Too long data");
}

return nType;
}

function _getUTF8Length(sText) {
if(!isNaN(sText)){
return sText.length;
}
var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a');
return replacedText.length + (replacedText.length != sText ? 3 : 0);
}
Expand Down