encoder.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package code39
  2. import (
  3. "errors"
  4. "github.com/boombuler/barcode"
  5. "github.com/boombuler/barcode/utils"
  6. "strings"
  7. )
  8. type encodeInfo struct {
  9. value int
  10. data []bool
  11. }
  12. var encodeTable map[rune]encodeInfo = map[rune]encodeInfo{
  13. '0': encodeInfo{0, []bool{true, false, true, false, false, true, true, false, true, true, false, true}},
  14. '1': encodeInfo{1, []bool{true, true, false, true, false, false, true, false, true, false, true, true}},
  15. '2': encodeInfo{2, []bool{true, false, true, true, false, false, true, false, true, false, true, true}},
  16. '3': encodeInfo{3, []bool{true, true, false, true, true, false, false, true, false, true, false, true}},
  17. '4': encodeInfo{4, []bool{true, false, true, false, false, true, true, false, true, false, true, true}},
  18. '5': encodeInfo{5, []bool{true, true, false, true, false, false, true, true, false, true, false, true}},
  19. '6': encodeInfo{6, []bool{true, false, true, true, false, false, true, true, false, true, false, true}},
  20. '7': encodeInfo{7, []bool{true, false, true, false, false, true, false, true, true, false, true, true}},
  21. '8': encodeInfo{8, []bool{true, true, false, true, false, false, true, false, true, true, false, true}},
  22. '9': encodeInfo{9, []bool{true, false, true, true, false, false, true, false, true, true, false, true}},
  23. 'A': encodeInfo{10, []bool{true, true, false, true, false, true, false, false, true, false, true, true}},
  24. 'B': encodeInfo{11, []bool{true, false, true, true, false, true, false, false, true, false, true, true}},
  25. 'C': encodeInfo{12, []bool{true, true, false, true, true, false, true, false, false, true, false, true}},
  26. 'D': encodeInfo{13, []bool{true, false, true, false, true, true, false, false, true, false, true, true}},
  27. 'E': encodeInfo{14, []bool{true, true, false, true, false, true, true, false, false, true, false, true}},
  28. 'F': encodeInfo{15, []bool{true, false, true, true, false, true, true, false, false, true, false, true}},
  29. 'G': encodeInfo{16, []bool{true, false, true, false, true, false, false, true, true, false, true, true}},
  30. 'H': encodeInfo{17, []bool{true, true, false, true, false, true, false, false, true, true, false, true}},
  31. 'I': encodeInfo{18, []bool{true, false, true, true, false, true, false, false, true, true, false, true}},
  32. 'J': encodeInfo{19, []bool{true, false, true, false, true, true, false, false, true, true, false, true}},
  33. 'K': encodeInfo{20, []bool{true, true, false, true, false, true, false, true, false, false, true, true}},
  34. 'L': encodeInfo{21, []bool{true, false, true, true, false, true, false, true, false, false, true, true}},
  35. 'M': encodeInfo{22, []bool{true, true, false, true, true, false, true, false, true, false, false, true}},
  36. 'N': encodeInfo{23, []bool{true, false, true, false, true, true, false, true, false, false, true, true}},
  37. 'O': encodeInfo{24, []bool{true, true, false, true, false, true, true, false, true, false, false, true}},
  38. 'P': encodeInfo{25, []bool{true, false, true, true, false, true, true, false, true, false, false, true}},
  39. 'Q': encodeInfo{26, []bool{true, false, true, false, true, false, true, true, false, false, true, true}},
  40. 'R': encodeInfo{27, []bool{true, true, false, true, false, true, false, true, true, false, false, true}},
  41. 'S': encodeInfo{28, []bool{true, false, true, true, false, true, false, true, true, false, false, true}},
  42. 'T': encodeInfo{29, []bool{true, false, true, false, true, true, false, true, true, false, false, true}},
  43. 'U': encodeInfo{30, []bool{true, true, false, false, true, false, true, false, true, false, true, true}},
  44. 'V': encodeInfo{31, []bool{true, false, false, true, true, false, true, false, true, false, true, true}},
  45. 'W': encodeInfo{32, []bool{true, true, false, false, true, true, false, true, false, true, false, true}},
  46. 'X': encodeInfo{33, []bool{true, false, false, true, false, true, true, false, true, false, true, true}},
  47. 'Y': encodeInfo{34, []bool{true, true, false, false, true, false, true, true, false, true, false, true}},
  48. 'Z': encodeInfo{35, []bool{true, false, false, true, true, false, true, true, false, true, false, true}},
  49. '-': encodeInfo{36, []bool{true, false, false, true, false, true, false, true, true, false, true, true}},
  50. '.': encodeInfo{37, []bool{true, true, false, false, true, false, true, false, true, true, false, true}},
  51. ' ': encodeInfo{38, []bool{true, false, false, true, true, false, true, false, true, true, false, true}},
  52. '$': encodeInfo{39, []bool{true, false, false, true, false, false, true, false, false, true, false, true}},
  53. '/': encodeInfo{40, []bool{true, false, false, true, false, false, true, false, true, false, false, true}},
  54. '+': encodeInfo{41, []bool{true, false, false, true, false, true, false, false, true, false, false, true}},
  55. '%': encodeInfo{42, []bool{true, false, true, false, false, true, false, false, true, false, false, true}},
  56. '*': encodeInfo{-1, []bool{true, false, false, true, false, true, true, false, true, true, false, true}},
  57. }
  58. var extendedTable map[rune]string = map[rune]string{
  59. 0: `%U`, 1: `$A`, 2: `$B`, 3: `$C`, 4: `$D`, 5: `$E`, 6: `$F`, 7: `$G`, 8: `$H`, 9: `$I`, 10: `$J`,
  60. 11: `$K`, 12: `$L`, 13: `$M`, 14: `$N`, 15: `$O`, 16: `$P`, 17: `$Q`, 18: `$R`, 19: `$S`, 20: `$T`,
  61. 21: `$U`, 22: `$V`, 23: `$W`, 24: `$X`, 25: `$Y`, 26: `$Z`, 27: `%A`, 28: `%B`, 29: `%C`, 30: `%D`,
  62. 31: `%E`, 33: `/A`, 34: `/B`, 35: `/C`, 36: `/D`, 37: `/E`, 38: `/F`, 39: `/G`, 40: `/H`, 41: `/I`,
  63. 42: `/J`, 43: `/K`, 44: `/L`, 47: `/O`, 58: `/Z`, 59: `%F`, 60: `%G`, 61: `%H`, 62: `%I`, 63: `%J`,
  64. 64: `%V`, 91: `%K`, 92: `%L`, 93: `%M`, 94: `%N`, 95: `%O`, 96: `%W`, 97: `+A`, 98: `+B`, 99: `+C`,
  65. 100: `+D`, 101: `+E`, 102: `+F`, 103: `+G`, 104: `+H`, 105: `+I`, 106: `+J`, 107: `+K`, 108: `+L`,
  66. 109: `+M`, 110: `+N`, 111: `+O`, 112: `+P`, 113: `+Q`, 114: `+R`, 115: `+S`, 116: `+T`, 117: `+U`,
  67. 118: `+V`, 119: `+W`, 120: `+X`, 121: `+Y`, 122: `+Z`, 123: `%P`, 124: `%Q`, 125: `%R`, 126: `%S`,
  68. 127: `%T`,
  69. }
  70. func getChecksum(content string) string {
  71. sum := 0
  72. for _, r := range content {
  73. info, ok := encodeTable[r]
  74. if !ok || info.value < 0 {
  75. return "#"
  76. }
  77. sum += info.value
  78. }
  79. sum = sum % 43
  80. for r, v := range encodeTable {
  81. if v.value == sum {
  82. return string(r)
  83. }
  84. }
  85. return "#"
  86. }
  87. func prepare(content string) (string, error) {
  88. result := ""
  89. for _, r := range content {
  90. if r > 127 {
  91. return "", errors.New("Only ASCII strings can be encoded")
  92. }
  93. val, ok := extendedTable[r]
  94. if ok {
  95. result += val
  96. } else {
  97. result += string([]rune{r})
  98. }
  99. }
  100. return result, nil
  101. }
  102. // encodes the given string as a code39 barcode
  103. // if includeChecksum is set to true, a checksum character is calculated and added to the content
  104. func Encode(content string, includeChecksum bool, fullASCIIMode bool) (barcode.Barcode, error) {
  105. if fullASCIIMode {
  106. var err error
  107. content, err = prepare(content)
  108. if err != nil {
  109. return nil, err
  110. }
  111. } else if strings.ContainsRune(content, '*') {
  112. return nil, errors.New("invalid data! try full ascii mode")
  113. }
  114. data := "*" + content
  115. if includeChecksum {
  116. data += getChecksum(content)
  117. }
  118. data += "*"
  119. result := new(utils.BitList)
  120. for i, r := range data {
  121. if i != 0 {
  122. result.AddBit(false)
  123. }
  124. info, ok := encodeTable[r]
  125. if !ok {
  126. return nil, errors.New("invalid data! try full ascii mode")
  127. }
  128. result.AddBit(info.data...)
  129. }
  130. return utils.New1DCode("Code 39", content, result), nil
  131. }