encoder.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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 calcCheckNum(code string) rune {
  77. x3 := len(code) == 7
  78. sum := 0
  79. for _, r := range code {
  80. curNum := utils.RuneToInt(r)
  81. if curNum < 0 || curNum > 9 {
  82. return 'B'
  83. }
  84. if x3 {
  85. curNum = curNum * 3
  86. }
  87. x3 = !x3
  88. sum += curNum
  89. }
  90. return utils.IntToRune((10 - (sum % 10)) % 10)
  91. }
  92. func encodeEAN8(code string) *utils.BitList {
  93. result := new(utils.BitList)
  94. result.AddBit(true, false, true)
  95. for cpos, r := range code {
  96. num, ok := encoderTable[r]
  97. if !ok {
  98. return nil
  99. }
  100. var data []bool
  101. if cpos < 4 {
  102. data = num.LeftOdd
  103. } else {
  104. data = num.Right
  105. }
  106. if cpos == 4 {
  107. result.AddBit(false, true, false, true, false)
  108. }
  109. result.AddBit(data...)
  110. }
  111. result.AddBit(true, false, true)
  112. return result
  113. }
  114. func encodeEAN13(code string) *utils.BitList {
  115. result := new(utils.BitList)
  116. result.AddBit(true, false, true)
  117. var firstNum []bool
  118. for cpos, r := range code {
  119. num, ok := encoderTable[r]
  120. if !ok {
  121. return nil
  122. }
  123. if cpos == 0 {
  124. firstNum = num.CheckSum
  125. continue
  126. }
  127. var data []bool
  128. if cpos < 7 { // Left
  129. if firstNum[cpos-1] {
  130. data = num.LeftEven
  131. } else {
  132. data = num.LeftOdd
  133. }
  134. } else {
  135. data = num.Right
  136. }
  137. if cpos == 7 {
  138. result.AddBit(false, true, false, true, false)
  139. }
  140. result.AddBit(data...)
  141. }
  142. result.AddBit(true, false, true)
  143. return result
  144. }
  145. // Encode returns a EAN 8 or EAN 13 barcode for the given code
  146. func Encode(code string) (barcode.BarcodeIntCS, error) {
  147. var checkSum int
  148. if len(code) == 7 || len(code) == 12 {
  149. code += string(calcCheckNum(code))
  150. checkSum = utils.RuneToInt(calcCheckNum(code))
  151. } else if len(code) == 8 || len(code) == 13 {
  152. check := code[0 : len(code)-1]
  153. check += string(calcCheckNum(check))
  154. if check != code {
  155. return nil, errors.New("checksum missmatch")
  156. }
  157. checkSum = utils.RuneToInt(rune(code[len(code)-1]))
  158. }
  159. if len(code) == 8 {
  160. result := encodeEAN8(code)
  161. if result != nil {
  162. return utils.New1DCodeIntCheckSum(barcode.TypeEAN8, code, result, checkSum), nil
  163. }
  164. } else if len(code) == 13 {
  165. result := encodeEAN13(code)
  166. if result != nil {
  167. return utils.New1DCodeIntCheckSum(barcode.TypeEAN13, code, result, checkSum), nil
  168. }
  169. }
  170. return nil, errors.New("invalid ean code data")
  171. }