upc-e.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * barcode generator - UPC-E
  3. */
  4. var Barcode1D = require('./utils/draw1D'),
  5. getCheckDigit = require('./utils/checksums').weight3odd10;
  6. // BARMAP[parity][digit]
  7. const BARMAP = [
  8. [
  9. [1,1,2,3], [1,2,2,2], [2,2,1,2], [1,1,4,1], [2,3,1,1],
  10. [1,3,2,1], [4,1,1,1], [2,1,3,1], [3,1,2,1], [2,1,1,3]
  11. ],
  12. [
  13. [3,2,1,1], [2,2,2,1], [2,1,2,2], [1,4,1,1], [1,1,3,2],
  14. [1,2,3,1], [1,1,1,4], [1,3,1,2], [1,2,1,3], [3,1,1,2]
  15. ]
  16. ];
  17. // PAIRITYMAP[check][lead]
  18. const PAIRITYMAP = [
  19. [ [0,0,0,1,1,1],[1,1,1,0,0,0] ],
  20. [ [0,0,1,0,1,1],[1,1,0,1,0,0] ],
  21. [ [0,0,1,1,0,1],[1,1,0,0,1,0] ],
  22. [ [0,0,1,1,1,0],[1,1,0,0,0,1] ],
  23. [ [0,1,0,0,1,1],[1,0,1,1,0,0] ],
  24. [ [0,1,1,0,0,1],[1,0,0,1,1,0] ],
  25. [ [0,1,1,1,0,0],[1,0,0,0,1,1] ],
  26. [ [0,1,0,1,0,1],[1,0,1,0,1,0] ],
  27. [ [0,1,0,1,1,0],[1,0,1,0,0,1] ],
  28. [ [0,1,1,0,1,0],[1,0,0,1,0,1] ]
  29. ];
  30. const START = [1,1,1];
  31. const END = [1,1,1,1,1,1]
  32. /*
  33. * This will be the same with all UPC-Es
  34. * 3 Start
  35. * 42 Data (6x7)
  36. * + 6 End
  37. * ---------------
  38. * 51 Fixed width
  39. */
  40. const MODULE_WIDTH = 51;
  41. /*
  42. * Get a valid UPC-E pattern from UPC-A
  43. * NOTE: This gets the pattern only! It does not provide you with parity data
  44. * nor does it provide you with check digits, it ignores all that in the input
  45. *
  46. * @param String - UPC-A String
  47. * @return String - UPC-E code pattern. Empty string if invalid
  48. */
  49. function fromUpcA(upcastr) {
  50. var upca = upcastr.split('');
  51. if (upca.length == 12) {
  52. upca.pop();
  53. }
  54. var first = upca.shift();
  55. if (upca.length != 10 || first != 1 && first != 0) {
  56. return '';
  57. }
  58. var upcamask = upca.join(''),
  59. match = null,
  60. upce = '';
  61. // case 0-2
  62. if (match = upcamask.match(/^([0-9]{2})([0-2])0{4}([0-9]{3})$/ )) {
  63. upce = match[1] + match[3] + match[2];
  64. }
  65. // case 3
  66. else if (match = upcamask.match(/^([0-9]{3})0{5}([0-9]{2})$/)) {
  67. upce = match[1] + match[2] + '3';
  68. }
  69. // case 4
  70. else if (match = upcamask.match(/^([0-9]{4})0{5}([0-9])$/)) {
  71. upce = match[1] + match[2] + '4';
  72. }
  73. // case 5-9
  74. else if (match = upcamask.match(/^([0-9]{5})0{4}([5-9])$/)) {
  75. upce = match[1] + match[2];
  76. }
  77. return upce;
  78. }
  79. /*
  80. * generate sequence
  81. * @param String pattern
  82. * @param Number parity
  83. * @param Number check
  84. */
  85. function generateSequence(pattern, parity, check) {
  86. if (pattern.length !== 6) {
  87. return null;
  88. }
  89. check = parseInt(check);
  90. parity = parseInt(parity);
  91. var p = PAIRITYMAP[check][parity],
  92. seq = START;
  93. for (var i = 0; i < 6; i++) {
  94. seq = seq.concat( BARMAP[ p[i] ][ parseInt(pattern[i]) ] );
  95. }
  96. return seq.concat(END);
  97. }
  98. function createCode(options, callback) {
  99. if (!options.w || !options.h) {
  100. return callback(new Error('Width and Height must be non-zero'), {});
  101. }
  102. var barWidth = options.w / MODULE_WIDTH >> 0;
  103. if (!barWidth) {
  104. return callback(new Error('Width will result in a degenerate barcode'), {});
  105. }
  106. var pattern = fromUpcA(options.data),
  107. parity = parseInt(options.data.substr(0,1));
  108. var check = getCheckDigit(options.data.substr(0,11));
  109. if (!pattern || parity > 1) {
  110. return callback(new Error('UPC-E Requires a valid UPC-A code starting with 0 or 1'), {});
  111. }
  112. // NOTE: Sequence is just one long array, not an array of arrays.
  113. var seq = generateSequence(pattern, parity, check);
  114. new Barcode1D().setWidth(options.w)
  115. .setHeight(options.h)
  116. .setModuleWidth(MODULE_WIDTH)
  117. .draw(seq, callback);
  118. }
  119. module.exports.generateSequence = generateSequence;
  120. module.exports.createCode = createCode;
  121. module.exports.fromUpcA = fromUpcA;