forked from boombuler/barcode
/
encoder.go
138 lines (122 loc) · 3.24 KB
/
encoder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Package twooffive can create interleaved and standard "2 of 5" barcodes.
package twooffive
import (
"errors"
"fmt"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/utils"
)
const patternWidth = 5
type pattern [patternWidth]bool
type encodeInfo struct {
start []bool
end []bool
widths map[bool]int
}
var (
encodingTable = map[rune]pattern{
'0': pattern{false, false, true, true, false},
'1': pattern{true, false, false, false, true},
'2': pattern{false, true, false, false, true},
'3': pattern{true, true, false, false, false},
'4': pattern{false, false, true, false, true},
'5': pattern{true, false, true, false, false},
'6': pattern{false, true, true, false, false},
'7': pattern{false, false, false, true, true},
'8': pattern{true, false, false, true, false},
'9': pattern{false, true, false, true, false},
}
modes = map[bool]encodeInfo{
false: encodeInfo{ // non-interleaved
start: []bool{true, true, false, true, true, false, true, false},
end: []bool{true, true, false, true, false, true, true},
widths: map[bool]int{
true: 3,
false: 1,
},
},
true: encodeInfo{ // interleaved
start: []bool{true, false, true, false},
end: []bool{true, true, false, true},
widths: map[bool]int{
true: 3,
false: 1,
},
},
}
nonInterleavedSpace = pattern{false, false, false, false, false}
)
// AddCheckSum calculates the correct check-digit and appends it to the given content.
func AddCheckSum(content string) (string, error) {
if content == "" {
return "", errors.New("content is empty")
}
even := len(content)%2 == 1
sum := 0
for _, r := range content {
if _, ok := encodingTable[r]; ok {
value := utils.RuneToInt(r)
if even {
sum += value * 3
} else {
sum += value
}
even = !even
} else {
return "", fmt.Errorf("can not encode \"%s\"", content)
}
}
return content + string(utils.IntToRune(sum%10)), nil
}
// Encode creates a codabar barcode for the given content
func Encode(content string, interleaved bool) (barcode.Barcode, error) {
if content == "" {
return nil, errors.New("content is empty")
}
if interleaved && len(content)%2 == 1 {
return nil, errors.New("can only encode even number of digits in interleaved mode")
}
mode := modes[interleaved]
resBits := new(utils.BitList)
resBits.AddBit(mode.start...)
var lastRune *rune
for _, r := range content {
var a, b pattern
if interleaved {
if lastRune == nil {
lastRune = new(rune)
*lastRune = r
continue
} else {
var o1, o2 bool
a, o1 = encodingTable[*lastRune]
b, o2 = encodingTable[r]
if !o1 || !o2 {
return nil, fmt.Errorf("can not encode \"%s\"", content)
}
lastRune = nil
}
} else {
var ok bool
a, ok = encodingTable[r]
if !ok {
return nil, fmt.Errorf("can not encode \"%s\"", content)
}
b = nonInterleavedSpace
}
for i := 0; i < patternWidth; i++ {
for x := 0; x < mode.widths[a[i]]; x++ {
resBits.AddBit(true)
}
for x := 0; x < mode.widths[b[i]]; x++ {
resBits.AddBit(false)
}
}
}
resBits.AddBit(mode.end...)
if interleaved {
return utils.New1DCode(barcode.Type2of5Interleaved, content, resBits), nil
} else {
return utils.New1DCode(barcode.Type2of5, content, resBits), nil
}
}