barcode
Version:
Generate 1D and 2D barcodes
146 lines (121 loc) • 3.54 kB
JavaScript
/*
* barcode generator - UPC-E
*/
var Barcode1D = require('./utils/draw1D'),
getCheckDigit = require('./utils/checksums').weight3odd10;
// BARMAP[parity][digit]
const BARMAP = [
[
[1,1,2,3], [1,2,2,2], [2,2,1,2], [1,1,4,1], [2,3,1,1],
[1,3,2,1], [4,1,1,1], [2,1,3,1], [3,1,2,1], [2,1,1,3]
],
[
[3,2,1,1], [2,2,2,1], [2,1,2,2], [1,4,1,1], [1,1,3,2],
[1,2,3,1], [1,1,1,4], [1,3,1,2], [1,2,1,3], [3,1,1,2]
]
];
// PAIRITYMAP[check][lead]
const PAIRITYMAP = [
[ [0,0,0,1,1,1],[1,1,1,0,0,0] ],
[ [0,0,1,0,1,1],[1,1,0,1,0,0] ],
[ [0,0,1,1,0,1],[1,1,0,0,1,0] ],
[ [0,0,1,1,1,0],[1,1,0,0,0,1] ],
[ [0,1,0,0,1,1],[1,0,1,1,0,0] ],
[ [0,1,1,0,0,1],[1,0,0,1,1,0] ],
[ [0,1,1,1,0,0],[1,0,0,0,1,1] ],
[ [0,1,0,1,0,1],[1,0,1,0,1,0] ],
[ [0,1,0,1,1,0],[1,0,1,0,0,1] ],
[ [0,1,1,0,1,0],[1,0,0,1,0,1] ]
];
const START = [1,1,1];
const END = [1,1,1,1,1,1]
/*
* This will be the same with all UPC-Es
* 3 Start
* 42 Data (6x7)
* + 6 End
* ---------------
* 51 Fixed width
*/
const MODULE_WIDTH = 51;
/*
* Get a valid UPC-E pattern from UPC-A
* NOTE: This gets the pattern only! It does not provide you with parity data
* nor does it provide you with check digits, it ignores all that in the input
*
* @param String - UPC-A String
* @return String - UPC-E code pattern. Empty string if invalid
*/
function fromUpcA(upcastr) {
var upca = upcastr.split('');
if (upca.length == 12) {
upca.pop();
}
var first = upca.shift();
if (upca.length != 10 || first != 1 && first != 0) {
return '';
}
var upcamask = upca.join(''),
match = null,
upce = '';
// case 0-2
if (match = upcamask.match(/^([0-9]{2})([0-2])0{4}([0-9]{3})$/ )) {
upce = match[1] + match[3] + match[2];
}
// case 3
else if (match = upcamask.match(/^([0-9]{3})0{5}([0-9]{2})$/)) {
upce = match[1] + match[2] + '3';
}
// case 4
else if (match = upcamask.match(/^([0-9]{4})0{5}([0-9])$/)) {
upce = match[1] + match[2] + '4';
}
// case 5-9
else if (match = upcamask.match(/^([0-9]{5})0{4}([5-9])$/)) {
upce = match[1] + match[2];
}
return upce;
}
/*
* generate sequence
* @param String pattern
* @param Number parity
* @param Number check
*/
function generateSequence(pattern, parity, check) {
if (pattern.length !== 6) {
return null;
}
check = parseInt(check);
parity = parseInt(parity);
var p = PAIRITYMAP[check][parity],
seq = START;
for (var i = 0; i < 6; i++) {
seq = seq.concat( BARMAP[ p[i] ][ parseInt(pattern[i]) ] );
}
return seq.concat(END);
}
function createCode(options, callback) {
if (!options.w || !options.h) {
return callback(new Error('Width and Height must be non-zero'), {});
}
var barWidth = options.w / MODULE_WIDTH >> 0;
if (!barWidth) {
return callback(new Error('Width will result in a degenerate barcode'), {});
}
var pattern = fromUpcA(options.data),
parity = parseInt(options.data.substr(0,1));
var check = getCheckDigit(options.data.substr(0,11));
if (!pattern || parity > 1) {
return callback(new Error('UPC-E Requires a valid UPC-A code starting with 0 or 1'), {});
}
// NOTE: Sequence is just one long array, not an array of arrays.
var seq = generateSequence(pattern, parity, check);
new Barcode1D().setWidth(options.w)
.setHeight(options.h)
.setModuleWidth(MODULE_WIDTH)
.draw(seq, callback);
}
module.exports.generateSequence = generateSequence;
module.exports.createCode = createCode;
module.exports.fromUpcA = fromUpcA;