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