code128.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * barcode generator - code128
  3. */
  4. var gm = require('gm');
  5. const BARMAP = [
  6. [2,1,2,2,2,2], [2,2,2,1,2,2], [2,2,2,2,2,1], [1,2,1,2,2,3], [1,2,1,3,2,2],
  7. [1,3,1,2,2,2], [1,2,2,2,1,3], [1,2,2,3,1,2], [1,3,2,2,1,2], [2,2,1,2,1,3],
  8. [2,2,1,3,1,2], [2,3,1,2,1,2], [1,1,2,2,3,2], [1,2,2,1,3,2], [1,2,2,2,3,1],
  9. [1,1,3,2,2,2], [1,2,3,1,2,2], [1,2,3,2,2,1], [2,2,3,2,1,1], [2,2,1,1,3,2],
  10. [2,2,1,2,3,1], [2,1,3,2,1,2], [2,2,3,1,1,2], [3,1,2,1,3,1], [3,1,1,2,2,2],
  11. [3,2,1,1,2,2], [3,2,1,2,2,1], [3,1,2,2,1,2], [3,2,2,1,1,2], [3,2,2,2,1,1],
  12. [2,1,2,1,2,3], [2,1,2,3,2,1], [2,3,2,1,2,1], [1,1,1,3,2,3], [1,3,1,1,2,3],
  13. [1,3,1,3,2,1], [1,1,2,3,1,3], [1,3,2,1,1,3], [1,3,2,3,1,1], [2,1,1,3,1,3],
  14. [2,3,1,1,1,3], [2,3,1,3,1,1], [1,1,2,1,3,3], [1,1,2,3,3,1], [1,3,2,1,3,1],
  15. [1,1,3,1,2,3], [1,1,3,3,2,1], [1,3,3,1,2,1], [3,1,3,1,2,1], [2,1,1,3,3,1],
  16. [2,3,1,1,3,1], [2,1,3,1,1,3], [2,1,3,3,1,1], [2,1,3,1,3,1], [3,1,1,1,2,3],
  17. [3,1,1,3,2,1], [3,3,1,1,2,1], [3,1,2,1,1,3], [3,1,2,3,1,1], [3,3,2,1,1,1],
  18. [3,1,4,1,1,1], [2,2,1,4,1,1], [4,3,1,1,1,1], [1,1,1,2,2,4], [1,1,1,4,2,2],
  19. [1,2,1,1,2,4], [1,2,1,4,2,1], [1,4,1,1,2,2], [1,4,1,2,2,1], [1,1,2,2,1,4],
  20. [1,1,2,4,1,2], [1,2,2,1,1,4], [1,2,2,4,1,1], [1,4,2,1,1,2], [1,4,2,2,1,1],
  21. [2,4,1,2,1,1], [2,2,1,1,1,4], [4,1,3,1,1,1], [2,4,1,1,1,2], [1,3,4,1,1,1],
  22. [1,1,1,2,4,2], [1,2,1,1,4,2], [1,2,1,2,4,1], [1,1,4,2,1,2], [1,2,4,1,1,2],
  23. [1,2,4,2,1,1], [4,1,1,2,1,2], [4,2,1,1,1,2], [4,2,1,2,1,1], [2,1,2,1,4,1],
  24. [2,1,4,1,2,1], [4,1,2,1,2,1], [1,1,1,1,4,3], [1,1,1,3,4,1], [1,3,1,1,4,1],
  25. [1,1,4,1,1,3], [1,1,4,3,1,1], [4,1,1,1,1,3], [4,1,1,3,1,1], [1,1,3,1,4,1],
  26. [1,1,4,1,3,1], [3,1,1,1,4,1], [4,1,1,1,3,1], [2,1,1,4,1,2], [2,1,1,2,1,4],
  27. [2,1,1,2,3,2], [2,3,3,1,1,1,2], [2,1,1,1,3,3]
  28. ];
  29. const CODEMAPS = {
  30. 'A': [
  31. ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
  32. '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=',
  33. '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
  34. 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[',
  35. '\\', ']', '^', '_', 'NUL', 'SOH', 'STX', 'ETX', 'EOT', 'ENQ', 'ACK', 'BEL',
  36. 'BS', 'HT', 'LF', 'VT', 'FF', 'CR', 'SO', 'SI', 'DLE', 'DC1', 'DC2', 'DC3',
  37. 'DC4', 'NAK', 'SYN', 'ETB', 'CAN', 'EM', 'SUB', 'ESC', 'FS', 'GS', 'RS', 'US',
  38. 'FNC3', 'FNC3', 'SHIFTB', 'CODEC', 'CODEB', 'FNC4', 'FNC1'
  39. ],
  40. 'B': [
  41. ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
  42. '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=',
  43. '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
  44. 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[',
  45. '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
  46. 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
  47. 'z', '{', '|', '}', '~', 'DEL', 'FNC3', 'FNC2', 'SHIFTA', 'CODEC', 'FNC4',
  48. 'CODEA', 'FNC1'
  49. ],
  50. 'C': [
  51. '00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
  52. '10', '11', '12', '13', '14', '15', '16', '17', '18', '19',
  53. '20', '21', '22', '23', '24', '25', '26', '27', '28', '29',
  54. '30', '31', '32', '33', '34', '35', '36', '37', '38', '39',
  55. '40', '41', '42', '43', '44', '45', '46', '47', '48', '49',
  56. '50', '51', '52', '53', '54', '55', '56', '57', '58', '59',
  57. '60', '61', '62', '63', '64', '65', '66', '67', '68', '69',
  58. '70', '71', '72', '73', '74', '75', '76', '77', '78', '79',
  59. '80', '81', '82', '83', '84', '85', '86', '87', '88', '89',
  60. '90', '91', '92', '93', '94', '95', '96', '97', '98', '99',
  61. 'CODEB', 'CODEA', 'FNC1',
  62. ]
  63. };
  64. const STARTA = BARMAP[103];
  65. const STARTB = BARMAP[104];
  66. const STARTC = BARMAP[105];
  67. const STOP = BARMAP[106];
  68. const START = {
  69. 'A': STARTA,
  70. 'B': STARTB,
  71. 'C': STARTC
  72. };
  73. function getVal(mode, ch) {
  74. return i = mode.toUpperCase() in CODEMAPS &&
  75. CODEMAPS[mode.toUpperCase()].indexOf(ch) ||
  76. 0;
  77. }
  78. module.exports.createCode = function (options, callback) {
  79. if (!options.data) {
  80. return callback(new Error('No data given'), {});
  81. }
  82. if (!options.w || !options.h) {
  83. return callback(new Error('Width and Height must be non-zero'), {});
  84. }
  85. // @todo refactor ------------------------------------------------------------
  86. // we want to detect and optimize the best mode switching for the shortest
  87. // code and the best space utilization.
  88. var mode = options.mode || 'B';
  89. // START + CHECK + END + DATA
  90. var baseWidth = 11 + 11 + 13 + options.data.length * 11;
  91. var barWidth = options.w / baseWidth >> 0;
  92. if (!barWidth) {
  93. return callback(new Error('Width will result in a degenerate barcode'), {});
  94. }
  95. // encode
  96. var encoded = [ START[mode] ];
  97. var checkSum = (mode == 'A') ? 103 : (mode == 'B' ? 104 : 105);
  98. for(var i in options.data) {
  99. i = parseInt(i); // shoudn't i already be a number? It's not.
  100. var val = getVal(mode, options.data[i] );
  101. encoded.push( BARMAP[val] );
  102. checkSum += (i + 1) * val;
  103. }
  104. // add on check digit
  105. encoded.push(BARMAP[ checkSum % 103 ]);
  106. encoded.push(STOP);
  107. // @todo end -----------------------------------------------------------------
  108. var img = gm(options.w, options.h, options.bgcolor),
  109. count = 0,
  110. pos = 0,
  111. w;
  112. img.stroke(options.barcolor, 1);
  113. pos = (options.w - baseWidth * barWidth) / 2 >> 0;
  114. for (var i in encoded) {
  115. for (var k in encoded[i]) {
  116. w = encoded[i][k] * barWidth;
  117. // only draw even indecies
  118. if ( ! (k % 2) ) {
  119. for (var m = 0; m < w; m++) {
  120. img.drawLine(pos + m, 0, pos + m, options.h);
  121. }
  122. }
  123. pos += w;
  124. }
  125. }
  126. img.stream(options.type, function (err, stdout, stderr) {
  127. callback(err, stdout);
  128. });
  129. };