barcode.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /**
  2. // https://github.com/alsey/wxbarcode
  3. // 最后一位显示 _ 问题
  4. // https://github.com/alsey/wxbarcode/issues/2
  5. // //ok some type of shift is nessecary if (shifter != -1) { result.push(shifter); result.push(codeValue(chr1));//把这里的chr2改成chr1即可。 }
  6. **/
  7. !(function () {
  8. var CHAR_TILDE = 126
  9. var CODE_FNC1 = 102
  10. var SET_STARTA = 103
  11. var SET_STARTB = 104
  12. var SET_STARTC = 105
  13. var SET_SHIFT = 98
  14. var SET_CODEA = 101
  15. var SET_CODEB = 100
  16. var SET_STOP = 106
  17. var REPLACE_CODES = {
  18. CHAR_TILDE: CODE_FNC1 //~ corresponds to FNC1 in GS1-128 standard
  19. }
  20. var CODESET = {
  21. ANY: 1,
  22. AB: 2,
  23. A: 3,
  24. B: 4,
  25. C: 5
  26. }
  27. function getBytes(str) {
  28. var bytes = []
  29. for (var i = 0; i < str.length; i++) {
  30. bytes.push(str.charCodeAt(i))
  31. }
  32. return bytes
  33. }
  34. exports.code128 = function (ctx, text, width, height) {
  35. width = parseInt(width)
  36. height = parseInt(height)
  37. var codes = stringToCode128(text)
  38. var g = new Graphics(ctx, width, height)
  39. var barWeight = g.area.width / ((codes.length - 3) * 11 + 35)
  40. var x = g.area.left
  41. var y = g.area.top
  42. for (var i = 0; i < codes.length; i++) {
  43. var c = codes[i]
  44. //two bars at a time: 1 black and 1 white
  45. for (var bar = 0; bar < 8; bar += 2) {
  46. var barW = PATTERNS[c][bar] * barWeight
  47. // var barH = height - y - this.border;
  48. var barH = height - y
  49. var spcW = PATTERNS[c][bar + 1] * barWeight
  50. //no need to draw if 0 width
  51. if (barW > 0) {
  52. g.fillFgRect(x, y, barW, barH)
  53. }
  54. x += barW + spcW
  55. }
  56. }
  57. ctx.draw()
  58. }
  59. function stringToCode128(text) {
  60. var barc = {
  61. currcs: CODESET.C
  62. }
  63. var bytes = getBytes(text)
  64. //decide starting codeset
  65. var index = bytes[0] == CHAR_TILDE ? 1 : 0
  66. var csa1 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB
  67. var csa2 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB
  68. barc.currcs = getBestStartSet(csa1, csa2)
  69. barc.currcs = perhapsCodeC(bytes, barc.currcs)
  70. //if no codeset changes this will end up with bytes.length+3
  71. //start, checksum and stop
  72. var codes = new Array()
  73. switch (barc.currcs) {
  74. case CODESET.A:
  75. codes.push(SET_STARTA)
  76. break
  77. case CODESET.B:
  78. codes.push(SET_STARTB)
  79. break
  80. default:
  81. codes.push(SET_STARTC)
  82. break
  83. }
  84. for (var i = 0; i < bytes.length; i++) {
  85. var b1 = bytes[i] //get the first of a pair
  86. //should we translate/replace
  87. if (b1 in REPLACE_CODES) {
  88. codes.push(REPLACE_CODES[b1])
  89. i++ //jump to next
  90. b1 = bytes[i]
  91. }
  92. //get the next in the pair if possible
  93. var b2 = bytes.length > i + 1 ? bytes[i + 1] : -1
  94. codes = codes.concat(codesForChar(b1, b2, barc.currcs))
  95. //code C takes 2 chars each time
  96. if (barc.currcs == CODESET.C) i++
  97. }
  98. //calculate checksum according to Code 128 standards
  99. var checksum = codes[0]
  100. for (var weight = 1; weight < codes.length; weight++) {
  101. checksum += weight * codes[weight]
  102. }
  103. codes.push(checksum % 103)
  104. codes.push(SET_STOP)
  105. //encoding should now be complete
  106. return codes
  107. function getBestStartSet(csa1, csa2) {
  108. //tries to figure out the best codeset
  109. //to start with to get the most compact code
  110. var vote = 0
  111. vote += csa1 == CODESET.A ? 1 : 0
  112. vote += csa1 == CODESET.B ? -1 : 0
  113. vote += csa2 == CODESET.A ? 1 : 0
  114. vote += csa2 == CODESET.B ? -1 : 0
  115. //tie goes to B due to my own predudices
  116. return vote > 0 ? CODESET.A : CODESET.B
  117. }
  118. function perhapsCodeC(bytes, codeset) {
  119. for (var i = 0; i < bytes.length; i++) {
  120. var b = bytes[i]
  121. if ((b < 48 || b > 57) && b != CHAR_TILDE) return codeset
  122. }
  123. return CODESET.C
  124. }
  125. //chr1 is current byte
  126. //chr2 is the next byte to process. looks ahead.
  127. function codesForChar(chr1, chr2, currcs) {
  128. var result = []
  129. var shifter = -1
  130. if (charCompatible(chr1, currcs)) {
  131. if (currcs == CODESET.C) {
  132. if (chr2 == -1) {
  133. shifter = SET_CODEB
  134. currcs = CODESET.B
  135. } else if (chr2 != -1 && !charCompatible(chr2, currcs)) {
  136. //need to check ahead as well
  137. if (charCompatible(chr2, CODESET.A)) {
  138. shifter = SET_CODEA
  139. currcs = CODESET.A
  140. } else {
  141. shifter = SET_CODEB
  142. currcs = CODESET.B
  143. }
  144. }
  145. }
  146. } else {
  147. //if there is a next char AND that next char is also not compatible
  148. if (chr2 != -1 && !charCompatible(chr2, currcs)) {
  149. //need to switch code sets
  150. switch (currcs) {
  151. case CODESET.A:
  152. shifter = SET_CODEB
  153. currcs = CODESET.B
  154. break
  155. case CODESET.B:
  156. shifter = SET_CODEA
  157. currcs = CODESET.A
  158. break
  159. }
  160. } else {
  161. //no need to shift code sets, a temporary SHIFT will suffice
  162. shifter = SET_SHIFT
  163. }
  164. }
  165. //ok some type of shift is nessecary
  166. if (shifter != -1) {
  167. result.push(shifter)
  168. result.push(codeValue(chr1))
  169. } else {
  170. if (currcs == CODESET.C) {
  171. //include next as well
  172. result.push(codeValue(chr1, chr2))
  173. } else {
  174. result.push(codeValue(chr1))
  175. }
  176. }
  177. barc.currcs = currcs
  178. return result
  179. }
  180. }
  181. //reduce the ascii code to fit into the Code128 char table
  182. function codeValue(chr1, chr2) {
  183. if (typeof chr2 == 'undefined') {
  184. return chr1 >= 32 ? chr1 - 32 : chr1 + 64
  185. } else {
  186. return parseInt(String.fromCharCode(chr1) + String.fromCharCode(chr2))
  187. }
  188. }
  189. function charCompatible(chr, codeset) {
  190. var csa = codeSetAllowedFor(chr)
  191. if (csa == CODESET.ANY) return true
  192. //if we need to change from current
  193. if (csa == CODESET.AB) return true
  194. if (csa == CODESET.A && codeset == CODESET.A) return true
  195. if (csa == CODESET.B && codeset == CODESET.B) return true
  196. return false
  197. }
  198. function codeSetAllowedFor(chr) {
  199. if (chr >= 48 && chr <= 57) {
  200. //0-9
  201. return CODESET.ANY
  202. } else if (chr >= 32 && chr <= 95) {
  203. //0-9 A-Z
  204. return CODESET.AB
  205. } else {
  206. //if non printable
  207. return chr < 32 ? CODESET.A : CODESET.B
  208. }
  209. }
  210. var Graphics = function (ctx, width, height) {
  211. this.width = width
  212. this.height = height
  213. this.quiet = Math.round(this.width / 40)
  214. this.border_size = 0
  215. this.padding_width = 0
  216. this.area = {
  217. width: width - this.padding_width * 2 - this.quiet * 2,
  218. height: height - this.border_size * 2,
  219. top: this.border_size - 4,
  220. left: this.padding_width + this.quiet
  221. }
  222. this.ctx = ctx
  223. this.fg = '#000000'
  224. this.bg = '#ffffff'
  225. // fill background
  226. this.fillBgRect(0, 0, width, height)
  227. // fill center to create border
  228. this.fillBgRect(0, this.border_size, width, height - this.border_size * 2)
  229. }
  230. //use native color
  231. Graphics.prototype._fillRect = function (x, y, width, height, color) {
  232. this.ctx.setFillStyle(color)
  233. this.ctx.fillRect(x, y, width, height)
  234. }
  235. Graphics.prototype.fillFgRect = function (x, y, width, height) {
  236. this._fillRect(x, y, width, height, this.fg)
  237. }
  238. Graphics.prototype.fillBgRect = function (x, y, width, height) {
  239. this._fillRect(x, y, width, height, this.bg)
  240. }
  241. var PATTERNS = [
  242. [2, 1, 2, 2, 2, 2, 0, 0], // 0
  243. [2, 2, 2, 1, 2, 2, 0, 0], // 1
  244. [2, 2, 2, 2, 2, 1, 0, 0], // 2
  245. [1, 2, 1, 2, 2, 3, 0, 0], // 3
  246. [1, 2, 1, 3, 2, 2, 0, 0], // 4
  247. [1, 3, 1, 2, 2, 2, 0, 0], // 5
  248. [1, 2, 2, 2, 1, 3, 0, 0], // 6
  249. [1, 2, 2, 3, 1, 2, 0, 0], // 7
  250. [1, 3, 2, 2, 1, 2, 0, 0], // 8
  251. [2, 2, 1, 2, 1, 3, 0, 0], // 9
  252. [2, 2, 1, 3, 1, 2, 0, 0], // 10
  253. [2, 3, 1, 2, 1, 2, 0, 0], // 11
  254. [1, 1, 2, 2, 3, 2, 0, 0], // 12
  255. [1, 2, 2, 1, 3, 2, 0, 0], // 13
  256. [1, 2, 2, 2, 3, 1, 0, 0], // 14
  257. [1, 1, 3, 2, 2, 2, 0, 0], // 15
  258. [1, 2, 3, 1, 2, 2, 0, 0], // 16
  259. [1, 2, 3, 2, 2, 1, 0, 0], // 17
  260. [2, 2, 3, 2, 1, 1, 0, 0], // 18
  261. [2, 2, 1, 1, 3, 2, 0, 0], // 19
  262. [2, 2, 1, 2, 3, 1, 0, 0], // 20
  263. [2, 1, 3, 2, 1, 2, 0, 0], // 21
  264. [2, 2, 3, 1, 1, 2, 0, 0], // 22
  265. [3, 1, 2, 1, 3, 1, 0, 0], // 23
  266. [3, 1, 1, 2, 2, 2, 0, 0], // 24
  267. [3, 2, 1, 1, 2, 2, 0, 0], // 25
  268. [3, 2, 1, 2, 2, 1, 0, 0], // 26
  269. [3, 1, 2, 2, 1, 2, 0, 0], // 27
  270. [3, 2, 2, 1, 1, 2, 0, 0], // 28
  271. [3, 2, 2, 2, 1, 1, 0, 0], // 29
  272. [2, 1, 2, 1, 2, 3, 0, 0], // 30
  273. [2, 1, 2, 3, 2, 1, 0, 0], // 31
  274. [2, 3, 2, 1, 2, 1, 0, 0], // 32
  275. [1, 1, 1, 3, 2, 3, 0, 0], // 33
  276. [1, 3, 1, 1, 2, 3, 0, 0], // 34
  277. [1, 3, 1, 3, 2, 1, 0, 0], // 35
  278. [1, 1, 2, 3, 1, 3, 0, 0], // 36
  279. [1, 3, 2, 1, 1, 3, 0, 0], // 37
  280. [1, 3, 2, 3, 1, 1, 0, 0], // 38
  281. [2, 1, 1, 3, 1, 3, 0, 0], // 39
  282. [2, 3, 1, 1, 1, 3, 0, 0], // 40
  283. [2, 3, 1, 3, 1, 1, 0, 0], // 41
  284. [1, 1, 2, 1, 3, 3, 0, 0], // 42
  285. [1, 1, 2, 3, 3, 1, 0, 0], // 43
  286. [1, 3, 2, 1, 3, 1, 0, 0], // 44
  287. [1, 1, 3, 1, 2, 3, 0, 0], // 45
  288. [1, 1, 3, 3, 2, 1, 0, 0], // 46
  289. [1, 3, 3, 1, 2, 1, 0, 0], // 47
  290. [3, 1, 3, 1, 2, 1, 0, 0], // 48
  291. [2, 1, 1, 3, 3, 1, 0, 0], // 49
  292. [2, 3, 1, 1, 3, 1, 0, 0], // 50
  293. [2, 1, 3, 1, 1, 3, 0, 0], // 51
  294. [2, 1, 3, 3, 1, 1, 0, 0], // 52
  295. [2, 1, 3, 1, 3, 1, 0, 0], // 53
  296. [3, 1, 1, 1, 2, 3, 0, 0], // 54
  297. [3, 1, 1, 3, 2, 1, 0, 0], // 55
  298. [3, 3, 1, 1, 2, 1, 0, 0], // 56
  299. [3, 1, 2, 1, 1, 3, 0, 0], // 57
  300. [3, 1, 2, 3, 1, 1, 0, 0], // 58
  301. [3, 3, 2, 1, 1, 1, 0, 0], // 59
  302. [3, 1, 4, 1, 1, 1, 0, 0], // 60
  303. [2, 2, 1, 4, 1, 1, 0, 0], // 61
  304. [4, 3, 1, 1, 1, 1, 0, 0], // 62
  305. [1, 1, 1, 2, 2, 4, 0, 0], // 63
  306. [1, 1, 1, 4, 2, 2, 0, 0], // 64
  307. [1, 2, 1, 1, 2, 4, 0, 0], // 65
  308. [1, 2, 1, 4, 2, 1, 0, 0], // 66
  309. [1, 4, 1, 1, 2, 2, 0, 0], // 67
  310. [1, 4, 1, 2, 2, 1, 0, 0], // 68
  311. [1, 1, 2, 2, 1, 4, 0, 0], // 69
  312. [1, 1, 2, 4, 1, 2, 0, 0], // 70
  313. [1, 2, 2, 1, 1, 4, 0, 0], // 71
  314. [1, 2, 2, 4, 1, 1, 0, 0], // 72
  315. [1, 4, 2, 1, 1, 2, 0, 0], // 73
  316. [1, 4, 2, 2, 1, 1, 0, 0], // 74
  317. [2, 4, 1, 2, 1, 1, 0, 0], // 75
  318. [2, 2, 1, 1, 1, 4, 0, 0], // 76
  319. [4, 1, 3, 1, 1, 1, 0, 0], // 77
  320. [2, 4, 1, 1, 1, 2, 0, 0], // 78
  321. [1, 3, 4, 1, 1, 1, 0, 0], // 79
  322. [1, 1, 1, 2, 4, 2, 0, 0], // 80
  323. [1, 2, 1, 1, 4, 2, 0, 0], // 81
  324. [1, 2, 1, 2, 4, 1, 0, 0], // 82
  325. [1, 1, 4, 2, 1, 2, 0, 0], // 83
  326. [1, 2, 4, 1, 1, 2, 0, 0], // 84
  327. [1, 2, 4, 2, 1, 1, 0, 0], // 85
  328. [4, 1, 1, 2, 1, 2, 0, 0], // 86
  329. [4, 2, 1, 1, 1, 2, 0, 0], // 87
  330. [4, 2, 1, 2, 1, 1, 0, 0], // 88
  331. [2, 1, 2, 1, 4, 1, 0, 0], // 89
  332. [2, 1, 4, 1, 2, 1, 0, 0], // 90
  333. [4, 1, 2, 1, 2, 1, 0, 0], // 91
  334. [1, 1, 1, 1, 4, 3, 0, 0], // 92
  335. [1, 1, 1, 3, 4, 1, 0, 0], // 93
  336. [1, 3, 1, 1, 4, 1, 0, 0], // 94
  337. [1, 1, 4, 1, 1, 3, 0, 0], // 95
  338. [1, 1, 4, 3, 1, 1, 0, 0], // 96
  339. [4, 1, 1, 1, 1, 3, 0, 0], // 97
  340. [4, 1, 1, 3, 1, 1, 0, 0], // 98
  341. [1, 1, 3, 1, 4, 1, 0, 0], // 99
  342. [1, 1, 4, 1, 3, 1, 0, 0], // 100
  343. [3, 1, 1, 1, 4, 1, 0, 0], // 101
  344. [4, 1, 1, 1, 3, 1, 0, 0], // 102
  345. [2, 1, 1, 4, 1, 2, 0, 0], // 103
  346. [2, 1, 1, 2, 1, 4, 0, 0], // 104
  347. [2, 1, 1, 2, 3, 2, 0, 0], // 105
  348. [2, 3, 3, 1, 1, 1, 2, 0] // 106
  349. ]
  350. })()