encoder.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package ean
  2. import (
  3. "errors"
  4. "github.com/boombuler/barcode"
  5. )
  6. type encodedNumber struct {
  7. LeftOdd []bool
  8. LeftEven []bool
  9. Right []bool
  10. CheckSum []bool
  11. }
  12. var encoderTable map[rune]encodedNumber = map[rune]encodedNumber{
  13. '0': encodedNumber{
  14. []bool{false, false, false, true, true, false, true},
  15. []bool{false, true, false, false, true, true, true},
  16. []bool{true, true, true, false, false, true, false},
  17. []bool{false, false, false, false, false, false},
  18. },
  19. '1': encodedNumber{
  20. []bool{false, false, true, true, false, false, true},
  21. []bool{false, true, true, false, false, true, true},
  22. []bool{true, true, false, false, true, true, false},
  23. []bool{false, false, true, false, true, true},
  24. },
  25. '2': encodedNumber{
  26. []bool{false, false, true, false, false, true, true},
  27. []bool{false, false, true, true, false, true, true},
  28. []bool{true, true, false, true, true, false, false},
  29. []bool{false, false, true, true, false, true},
  30. },
  31. '3': encodedNumber{
  32. []bool{false, true, true, true, true, false, true},
  33. []bool{false, true, false, false, false, false, true},
  34. []bool{true, false, false, false, false, true, false},
  35. []bool{false, false, true, true, true, false},
  36. },
  37. '4': encodedNumber{
  38. []bool{false, true, false, false, false, true, true},
  39. []bool{false, false, true, true, true, false, true},
  40. []bool{true, false, true, true, true, false, false},
  41. []bool{false, true, false, false, true, true},
  42. },
  43. '5': encodedNumber{
  44. []bool{false, true, true, false, false, false, true},
  45. []bool{false, true, true, true, false, false, true},
  46. []bool{true, false, false, true, true, true, false},
  47. []bool{false, true, true, false, false, true},
  48. },
  49. '6': encodedNumber{
  50. []bool{false, true, false, true, true, true, true},
  51. []bool{false, false, false, false, true, false, true},
  52. []bool{true, false, true, false, false, false, false},
  53. []bool{false, true, true, true, false, false},
  54. },
  55. '7': encodedNumber{
  56. []bool{false, true, true, true, false, true, true},
  57. []bool{false, false, true, false, false, false, true},
  58. []bool{true, false, false, false, true, false, false},
  59. []bool{false, true, false, true, false, true},
  60. },
  61. '8': encodedNumber{
  62. []bool{false, true, true, false, true, true, true},
  63. []bool{false, false, false, true, false, false, true},
  64. []bool{true, false, false, true, false, false, false},
  65. []bool{false, true, false, true, true, false},
  66. },
  67. '9': encodedNumber{
  68. []bool{false, false, false, true, false, true, true},
  69. []bool{false, false, true, false, true, true, true},
  70. []bool{true, true, true, false, true, false, false},
  71. []bool{false, true, true, false, true, false},
  72. },
  73. }
  74. func runeToInt(r rune) int {
  75. switch r {
  76. case '0':
  77. return 0
  78. case '1':
  79. return 1
  80. case '2':
  81. return 2
  82. case '3':
  83. return 3
  84. case '4':
  85. return 4
  86. case '5':
  87. return 5
  88. case '6':
  89. return 6
  90. case '7':
  91. return 7
  92. case '8':
  93. return 8
  94. case '9':
  95. return 9
  96. }
  97. return -1
  98. }
  99. func intToRune(i int) rune {
  100. switch i {
  101. case 0:
  102. return '0'
  103. case 1:
  104. return '1'
  105. case 2:
  106. return '2'
  107. case 3:
  108. return '3'
  109. case 4:
  110. return '4'
  111. case 5:
  112. return '5'
  113. case 6:
  114. return '6'
  115. case 7:
  116. return '7'
  117. case 8:
  118. return '8'
  119. case 9:
  120. return '9'
  121. }
  122. return 'F'
  123. }
  124. func calcCheckNum(code string) rune {
  125. x3 := len(code) == 7
  126. sum := 0
  127. for _, r := range code {
  128. curNum := runeToInt(r)
  129. if curNum < 0 || curNum > 9 {
  130. return 'B'
  131. }
  132. if x3 {
  133. curNum = curNum * 3
  134. }
  135. x3 = !x3
  136. sum += curNum
  137. }
  138. return intToRune((10 - (sum % 10)) % 10)
  139. }
  140. func encodeEAN8(code string, result *eancode) bool {
  141. pos := 0
  142. appendBit := func(b bool) {
  143. result.SetBit(pos, b)
  144. pos++
  145. }
  146. appendBit(true)
  147. appendBit(false)
  148. appendBit(true)
  149. for cpos, r := range code {
  150. num, ok := encoderTable[r]
  151. if !ok {
  152. return false
  153. }
  154. var data []bool
  155. if cpos < 4 {
  156. data = num.LeftOdd
  157. } else {
  158. data = num.Right
  159. }
  160. if cpos == 4 {
  161. appendBit(false)
  162. appendBit(true)
  163. appendBit(false)
  164. appendBit(true)
  165. appendBit(false)
  166. }
  167. for _, bit := range data {
  168. appendBit(bit)
  169. }
  170. }
  171. appendBit(true)
  172. appendBit(false)
  173. appendBit(true)
  174. return true
  175. }
  176. func encodeEAN13(code string, result *eancode) bool {
  177. pos := 0
  178. appendBit := func(b bool) {
  179. result.SetBit(pos, b)
  180. pos++
  181. }
  182. appendBit(true)
  183. appendBit(false)
  184. appendBit(true)
  185. var firstNum []bool
  186. for cpos, r := range code {
  187. num, ok := encoderTable[r]
  188. if !ok {
  189. return false
  190. }
  191. if cpos == 0 {
  192. firstNum = num.CheckSum
  193. continue
  194. }
  195. var data []bool
  196. if cpos < 7 { // Left
  197. if firstNum[cpos-1] {
  198. data = num.LeftEven
  199. } else {
  200. data = num.LeftOdd
  201. }
  202. } else {
  203. data = num.Right
  204. }
  205. if cpos == 7 {
  206. appendBit(false)
  207. appendBit(true)
  208. appendBit(false)
  209. appendBit(true)
  210. appendBit(false)
  211. }
  212. for _, bit := range data {
  213. appendBit(bit)
  214. }
  215. }
  216. appendBit(true)
  217. appendBit(false)
  218. appendBit(true)
  219. return true
  220. }
  221. func Encode(code string) (barcode.Barcode, error) {
  222. if len(code) == 7 || len(code) == 12 {
  223. code += string(calcCheckNum(code))
  224. } else if len(code) == 8 || len(code) == 13 {
  225. check := code[0 : len(code)-1]
  226. check += string(calcCheckNum(check))
  227. if check != code {
  228. return nil, errors.New("checksum missmatch!")
  229. }
  230. }
  231. ean8 := false
  232. if len(code) == 8 {
  233. ean8 = true
  234. } else if len(code) != 13 {
  235. return nil, errors.New("invalid ean code data")
  236. }
  237. result := newEANCode(ean8)
  238. if (ean8 && encodeEAN8(code, result)) || (!ean8 && encodeEAN13(code, result)) {
  239. result.content = code
  240. return result, nil
  241. }
  242. return nil, errors.New("ean code contains invalid characters")
  243. }