encoder.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Package ean can create EAN 8 and EAN 13 barcodes.
  2. package ean
  3. import (
  4. "errors"
  5. "github.com/boombuler/barcode"
  6. "github.com/boombuler/barcode/utils"
  7. )
  8. type encodedNumber struct {
  9. LeftOdd []bool
  10. LeftEven []bool
  11. Right []bool
  12. CheckSum []bool
  13. }
  14. var encoderTable = map[rune]encodedNumber{
  15. '0': encodedNumber{
  16. []bool{false, false, false, true, true, false, true},
  17. []bool{false, true, false, false, true, true, true},
  18. []bool{true, true, true, false, false, true, false},
  19. []bool{false, false, false, false, false, false},
  20. },
  21. '1': encodedNumber{
  22. []bool{false, false, true, true, false, false, true},
  23. []bool{false, true, true, false, false, true, true},
  24. []bool{true, true, false, false, true, true, false},
  25. []bool{false, false, true, false, true, true},
  26. },
  27. '2': encodedNumber{
  28. []bool{false, false, true, false, false, true, true},
  29. []bool{false, false, true, true, false, true, true},
  30. []bool{true, true, false, true, true, false, false},
  31. []bool{false, false, true, true, false, true},
  32. },
  33. '3': encodedNumber{
  34. []bool{false, true, true, true, true, false, true},
  35. []bool{false, true, false, false, false, false, true},
  36. []bool{true, false, false, false, false, true, false},
  37. []bool{false, false, true, true, true, false},
  38. },
  39. '4': encodedNumber{
  40. []bool{false, true, false, false, false, true, true},
  41. []bool{false, false, true, true, true, false, true},
  42. []bool{true, false, true, true, true, false, false},
  43. []bool{false, true, false, false, true, true},
  44. },
  45. '5': encodedNumber{
  46. []bool{false, true, true, false, false, false, true},
  47. []bool{false, true, true, true, false, false, true},
  48. []bool{true, false, false, true, true, true, false},
  49. []bool{false, true, true, false, false, true},
  50. },
  51. '6': encodedNumber{
  52. []bool{false, true, false, true, true, true, true},
  53. []bool{false, false, false, false, true, false, true},
  54. []bool{true, false, true, false, false, false, false},
  55. []bool{false, true, true, true, false, false},
  56. },
  57. '7': encodedNumber{
  58. []bool{false, true, true, true, false, true, true},
  59. []bool{false, false, true, false, false, false, true},
  60. []bool{true, false, false, false, true, false, false},
  61. []bool{false, true, false, true, false, true},
  62. },
  63. '8': encodedNumber{
  64. []bool{false, true, true, false, true, true, true},
  65. []bool{false, false, false, true, false, false, true},
  66. []bool{true, false, false, true, false, false, false},
  67. []bool{false, true, false, true, true, false},
  68. },
  69. '9': encodedNumber{
  70. []bool{false, false, false, true, false, true, true},
  71. []bool{false, false, true, false, true, true, true},
  72. []bool{true, true, true, false, true, false, false},
  73. []bool{false, true, true, false, true, false},
  74. },
  75. }
  76. func runeToInt(r rune) int {
  77. if r >= '0' && r <= '9' {
  78. return int(r - '0')
  79. }
  80. return -1
  81. }
  82. func intToRune(i int) rune {
  83. if i >= 0 && i <= 9 {
  84. return rune(i + '0')
  85. }
  86. return 'F'
  87. }
  88. func calcCheckNum(code string) rune {
  89. x3 := len(code) == 7
  90. sum := 0
  91. for _, r := range code {
  92. curNum := runeToInt(r)
  93. if curNum < 0 || curNum > 9 {
  94. return 'B'
  95. }
  96. if x3 {
  97. curNum = curNum * 3
  98. }
  99. x3 = !x3
  100. sum += curNum
  101. }
  102. return intToRune((10 - (sum % 10)) % 10)
  103. }
  104. func encodeEAN8(code string) *utils.BitList {
  105. result := new(utils.BitList)
  106. result.AddBit(true, false, true)
  107. for cpos, r := range code {
  108. num, ok := encoderTable[r]
  109. if !ok {
  110. return nil
  111. }
  112. var data []bool
  113. if cpos < 4 {
  114. data = num.LeftOdd
  115. } else {
  116. data = num.Right
  117. }
  118. if cpos == 4 {
  119. result.AddBit(false, true, false, true, false)
  120. }
  121. result.AddBit(data...)
  122. }
  123. result.AddBit(true, false, true)
  124. return result
  125. }
  126. func encodeEAN13(code string) *utils.BitList {
  127. result := new(utils.BitList)
  128. result.AddBit(true, false, true)
  129. var firstNum []bool
  130. for cpos, r := range code {
  131. num, ok := encoderTable[r]
  132. if !ok {
  133. return nil
  134. }
  135. if cpos == 0 {
  136. firstNum = num.CheckSum
  137. continue
  138. }
  139. var data []bool
  140. if cpos < 7 { // Left
  141. if firstNum[cpos-1] {
  142. data = num.LeftEven
  143. } else {
  144. data = num.LeftOdd
  145. }
  146. } else {
  147. data = num.Right
  148. }
  149. if cpos == 7 {
  150. result.AddBit(false, true, false, true, false)
  151. }
  152. result.AddBit(data...)
  153. }
  154. result.AddBit(true, false, true)
  155. return result
  156. }
  157. // Encode returns a EAN 8 or EAN 13 barcode for the given code
  158. func Encode(code string) (barcode.Barcode, error) {
  159. if len(code) == 7 || len(code) == 12 {
  160. code += string(calcCheckNum(code))
  161. } else if len(code) == 8 || len(code) == 13 {
  162. check := code[0 : len(code)-1]
  163. check += string(calcCheckNum(check))
  164. if check != code {
  165. return nil, errors.New("checksum missmatch")
  166. }
  167. }
  168. if len(code) == 8 {
  169. result := encodeEAN8(code)
  170. if result != nil {
  171. return utils.New1DCode("EAN 8", code, result), nil
  172. }
  173. } else if len(code) == 13 {
  174. result := encodeEAN13(code)
  175. if result != nil {
  176. return utils.New1DCode("EAN 13", code, result), nil
  177. }
  178. }
  179. return nil, errors.New("invalid ean code data")
  180. }