added 2 of 5 barcodes
This commit is contained in:
parent
ecbfc39708
commit
bc131f9157
|
@ -0,0 +1,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: 2,
|
||||
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...)
|
||||
|
||||
kindTxt := ""
|
||||
if interleaved {
|
||||
kindTxt = " (interleaved)"
|
||||
}
|
||||
return utils.New1DCode("2 of 5"+kindTxt, content, resBits), nil
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package twooffive
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_AddCheckSum(t *testing.T) {
|
||||
if sum, err := AddCheckSum("1234567"); err != nil || sum != "12345670" {
|
||||
t.Fail()
|
||||
}
|
||||
if _, err := AddCheckSum("1ABC"); err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
if _, err := AddCheckSum(""); err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Encode(t *testing.T) {
|
||||
_, err := Encode("FOOBAR", false)
|
||||
if err == nil {
|
||||
t.Error("\"FOOBAR\" should not be encodable")
|
||||
}
|
||||
|
||||
testEncode := func(interleaved bool, txt, testResult string) {
|
||||
code, err := Encode(txt, interleaved)
|
||||
if err != nil || code == nil {
|
||||
t.Fail()
|
||||
} else {
|
||||
if code.Bounds().Max.X != len(testResult) {
|
||||
t.Errorf("%v: length missmatch! %v != %v", txt, code.Bounds().Max.X, len(testResult))
|
||||
} else {
|
||||
for i, r := range testResult {
|
||||
if (code.At(i, 0) == color.Black) != (r == '1') {
|
||||
t.Errorf("%v: code missmatch on position %d", txt, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testEncode(false, "12345670", "1101101011101010101110101110101011101110111010101010101110101110111010111010101011101110101010101011101110101011101110101101011")
|
||||
testEncode(true, "12345670", "1010110100101011001101101001010011010011001010101010011001101101")
|
||||
}
|
Loading…
Reference in New Issue