mini-code
Version:
Barcode and QRCode for miniprogram and miniprogram plugin.
458 lines (406 loc) • 13.7 kB
JavaScript
var CHAR_TILDE = 126;
var CODE_FNC1 = 102;
var SET_STARTA = 103;
var SET_STARTB = 104;
var SET_STARTC = 105;
var SET_SHIFT = 98;
var SET_CODEA = 101;
var SET_CODEB = 100;
var SET_STOP = 106;
var REPLACE_CODES = {
CHAR_TILDE: CODE_FNC1 //~ corresponds to FNC1 in GS1-128 standard
}
var CODESET = {
ANY: 1,
AB: 2,
A: 3,
B: 4,
C: 5
};
function getBytes(str) {
var bytes = [];
for (var i = 0; i < str.length; i++) {
bytes.push(str.charCodeAt(i));
}
return bytes;
}
exports.formatBarCode = function ( code, space) {
var length = code.length;
var span = 4;
var spanCount = length % 4 == 0 ? length / span : length / span + 1; //2
if (spanCount > 1) {
var sb=[];
for (var i = 0; i < spanCount; i++) {
if (i == spanCount - 1) {
sb.push(code.slice(i * span, length));
} else {
sb.push(code.slice(i * span, span * (i + 1)) + space);
}
}
return sb.join('');
}
return code;
}
exports.draw = function (options) {//show barcode on vertical when vertical parameter is exist.
var ctx = options.canvas,
text = options.code,
width = options.width || 660,
height = options.height || 200,
vertical = options.vertical || false;
if(!ctx){
console.error('No canvas provided to draw bar code!')
return
}
if(!text){
console.error('No code content provided to draw bar code')
return
}
width = parseInt(width);
height = parseInt(height);
var codes = stringToCode128(text);
var startTime = new Date().getTime();
function loop () {
// if(vertical){
// ctx.translate(width/2, height/2)
// ctx.rotate(Math.PI/2);
// }
if(vertical){
// var curTime = new Date().getTime();
// var delta = ( Math.PI / 2 / 300) * (curTime - startTime);
// if(Math.abs(Math.PI / 2 - delta) < 0.2){
// delta = Math.PI / 2;
// }
// var deltaX = (width / 2 /300) * ( curTime - startTime);
// var deltaY = (height / 2 /300) * ( curTime - startTime)
// ctx.translate(deltaX, deltaY)
// ctx.rotate(delta);
ctx.translate(width/2, height/2)
ctx.rotate(Math.PI/2);
}
var g = new Graphics(ctx, width, height);
var barWeight = g.area.width / ((codes.length - 3) * 11 + 35);
var x = g.area.left;
var y = g.area.top;
for (var i = 0; i < codes.length; i++) {
var c = codes[i];
//two bars at a time: 1 black and 1 white
for (var bar = 0; bar < 8; bar += 2) {
var barW = PATTERNS[c][bar] * barWeight;
// var barH = height - y - this.border;
var barH = height - y;
var spcW = PATTERNS[c][bar + 1] * barWeight;
//no need to draw if 0 width
if (barW > 0) {
g.fillFgRect(x, y, barW, barH);
}
x += barW + spcW;
}
}
ctx.draw();
// if(vertical && (curTime - startTime) < 300){
// setTimeout(loop, 1 / 60 * 1000)
// }
}
loop();
}
function stringToCode128(text) {
var barc = {
currcs: CODESET.C
};
var bytes = getBytes(text);
//decide starting codeset
var index = bytes[0] == CHAR_TILDE ? 1 : 0;
var csa1 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB;
var csa2 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB;
barc.currcs = getBestStartSet(csa1, csa2);
barc.currcs = perhapsCodeC(bytes, barc.currcs);
//if no codeset changes this will end up with bytes.length+3
//start, checksum and stop
var codes = new Array();
switch (barc.currcs) {
case CODESET.A:
codes.push(SET_STARTA);
break;
case CODESET.B:
codes.push(SET_STARTB);
break;
default:
codes.push(SET_STARTC);
break;
}
for (var i = 0; i < bytes.length; i++) {
var b1 = bytes[i]; //get the first of a pair
//should we translate/replace
if (b1 in REPLACE_CODES) {
codes.push(REPLACE_CODES[b1]);
i++ //jump to next
b1 = bytes[i];
}
//get the next in the pair if possible
var b2 = bytes.length > (i + 1) ? bytes[i + 1] : -1;
codes = codes.concat(codesForChar(b1, b2, barc.currcs));
//code C takes 2 chars each time
if (barc.currcs == CODESET.C) i++;
}
//calculate checksum according to Code 128 standards
var checksum = codes[0];
for (var weight = 1; weight < codes.length; weight++) {
checksum += (weight * codes[weight]);
}
codes.push(checksum % 103);
codes.push(SET_STOP);
//encoding should now be complete
return codes;
function getBestStartSet(csa1, csa2) {
//tries to figure out the best codeset
//to start with to get the most compact code
var vote = 0;
vote += csa1 == CODESET.A ? 1 : 0;
vote += csa1 == CODESET.B ? -1 : 0;
vote += csa2 == CODESET.A ? 1 : 0;
vote += csa2 == CODESET.B ? -1 : 0;
//tie goes to B due to my own predudices
return vote > 0 ? CODESET.A : CODESET.B;
}
function perhapsCodeC(bytes, codeset) {
for (var i = 0; i < bytes.length; i++) {
var b = bytes[i]
if ((b < 48 || b > 57) && b != CHAR_TILDE)
return codeset;
}
return CODESET.C;
}
//chr1 is current byte
//chr2 is the next byte to process. looks ahead.
function codesForChar(chr1, chr2, currcs) {
var result = [];
var shifter = -1;
if (charCompatible(chr1, currcs)) {
if (currcs == CODESET.C) {
if (chr2 == -1) {
shifter = SET_CODEB;
currcs = CODESET.B;
}
else if ((chr2 != -1) && !charCompatible(chr2, currcs)) {
//need to check ahead as well
if (charCompatible(chr2, CODESET.A)) {
shifter = SET_CODEA;
currcs = CODESET.A;
}
else {
shifter = SET_CODEB;
currcs = CODESET.B;
}
}
}
}
else {
//if there is a next char AND that next char is also not compatible
if ((chr2 != -1) && !charCompatible(chr2, currcs)) {
//need to switch code sets
switch (currcs) {
case CODESET.A:
shifter = SET_CODEB;
currcs = CODESET.B;
break;
case CODESET.B:
shifter = SET_CODEA;
currcs = CODESET.A;
break;
}
}
else {
//no need to shift code sets, a temporary SHIFT will suffice
shifter = SET_SHIFT;
}
}
//ok some type of shift is nessecary
if (shifter != -1) {
result.push(shifter);
result.push(codeValue(chr2));
}
else {
if (currcs == CODESET.C) {
//include next as well
result.push(codeValue(chr1, chr2));
}
else {
result.push(codeValue(chr1));
}
}
barc.currcs = currcs;
return result;
}
}
//reduce the ascii code to fit into the Code128 char table
function codeValue(chr1, chr2) {
if (typeof chr2 == "undefined") {
return chr1 >= 32 ? chr1 - 32 : chr1 + 64;
}
else {
return parseInt(String.fromCharCode(chr1) + String.fromCharCode(chr2));
}
}
function charCompatible(chr, codeset) {
var csa = codeSetAllowedFor(chr);
if (csa == CODESET.ANY) return true;
//if we need to change from current
if (csa == CODESET.AB) return true;
if (csa == CODESET.A && codeset == CODESET.A) return true;
if (csa == CODESET.B && codeset == CODESET.B) return true;
return false;
}
function codeSetAllowedFor(chr) {
if (chr >= 48 && chr <= 57) {
//0-9
return CODESET.ANY;
}
else if (chr >= 32 && chr <= 95) {
//0-9 A-Z
return CODESET.AB;
}
else {
//if non printable
return chr < 32 ? CODESET.A : CODESET.B;
}
}
var Graphics = function(ctx, width, height) {
this.width = width;
this.height = height;
this.quiet = Math.round(this.width / 40);
this.border_size = 0;
this.padding_width = 0;
this.area = {
width : width - this.padding_width * 2 - this.quiet * 2,
height: height - this.border_size * 2,
top : this.border_size - 4,
left : this.padding_width + this.quiet
};
this.ctx = ctx;
this.fg = "#000000";
this.bg = "#ffffff";
// fill background
this.fillBgRect(0,0, width, height);
// fill center to create border
this.fillBgRect(0, this.border_size, width, height - this.border_size * 2);
}
//use native color
Graphics.prototype._fillRect = function(x, y, width, height, color) {
this.ctx.setFillStyle(color)
this.ctx.fillRect(x, y, width, height)
}
Graphics.prototype.fillFgRect = function(x,y, width, height) {
this._fillRect(x, y, width, height, this.fg);
}
Graphics.prototype.fillBgRect = function(x,y, width, height) {
this._fillRect(x, y, width, height, this.bg);
}
var PATTERNS = [
[ ], // 0
[ ], // 1
[ ], // 2
[ ], // 3
[ ], // 4
[ ], // 5
[ ], // 6
[ ], // 7
[ ], // 8
[ ], // 9
[ ], // 10
[ ], // 11
[ ], // 12
[ ], // 13
[ ], // 14
[ ], // 15
[ ], // 16
[ ], // 17
[ ], // 18
[ ], // 19
[ ], // 20
[ ], // 21
[ ], // 22
[ ], // 23
[ ], // 24
[ ], // 25
[ ], // 26
[ ], // 27
[ ], // 28
[ ], // 29
[ ], // 30
[ ], // 31
[ ], // 32
[ ], // 33
[ ], // 34
[ ], // 35
[ ], // 36
[ ], // 37
[ ], // 38
[ ], // 39
[ ], // 40
[ ], // 41
[ ], // 42
[ ], // 43
[ ], // 44
[ ], // 45
[ ], // 46
[ ], // 47
[ ], // 48
[ ], // 49
[ ], // 50
[ ], // 51
[ ], // 52
[ ], // 53
[ ], // 54
[ ], // 55
[ ], // 56
[ ], // 57
[ ], // 58
[ ], // 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
[ ], // 92
[ ], // 93
[ ], // 94
[ ], // 95
[ ], // 96
[ ], // 97
[ ], // 98
[ ], // 99
[ ], // 100
[ ], // 101
[ ], // 102
[ ], // 103
[ ], // 104
[ ], // 105
[ ] // 106
]