188 lines
4.8 KiB
Go
188 lines
4.8 KiB
Go
// Package ean can create EAN 8 and EAN 13 barcodes.
|
|
package ean
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/boombuler/barcode"
|
|
"github.com/boombuler/barcode/utils"
|
|
)
|
|
|
|
type encodedNumber struct {
|
|
LeftOdd []bool
|
|
LeftEven []bool
|
|
Right []bool
|
|
CheckSum []bool
|
|
}
|
|
|
|
var encoderTable = map[rune]encodedNumber{
|
|
'0': encodedNumber{
|
|
[]bool{false, false, false, true, true, false, true},
|
|
[]bool{false, true, false, false, true, true, true},
|
|
[]bool{true, true, true, false, false, true, false},
|
|
[]bool{false, false, false, false, false, false},
|
|
},
|
|
'1': encodedNumber{
|
|
[]bool{false, false, true, true, false, false, true},
|
|
[]bool{false, true, true, false, false, true, true},
|
|
[]bool{true, true, false, false, true, true, false},
|
|
[]bool{false, false, true, false, true, true},
|
|
},
|
|
'2': encodedNumber{
|
|
[]bool{false, false, true, false, false, true, true},
|
|
[]bool{false, false, true, true, false, true, true},
|
|
[]bool{true, true, false, true, true, false, false},
|
|
[]bool{false, false, true, true, false, true},
|
|
},
|
|
'3': encodedNumber{
|
|
[]bool{false, true, true, true, true, false, true},
|
|
[]bool{false, true, false, false, false, false, true},
|
|
[]bool{true, false, false, false, false, true, false},
|
|
[]bool{false, false, true, true, true, false},
|
|
},
|
|
'4': encodedNumber{
|
|
[]bool{false, true, false, false, false, true, true},
|
|
[]bool{false, false, true, true, true, false, true},
|
|
[]bool{true, false, true, true, true, false, false},
|
|
[]bool{false, true, false, false, true, true},
|
|
},
|
|
'5': encodedNumber{
|
|
[]bool{false, true, true, false, false, false, true},
|
|
[]bool{false, true, true, true, false, false, true},
|
|
[]bool{true, false, false, true, true, true, false},
|
|
[]bool{false, true, true, false, false, true},
|
|
},
|
|
'6': encodedNumber{
|
|
[]bool{false, true, false, true, true, true, true},
|
|
[]bool{false, false, false, false, true, false, true},
|
|
[]bool{true, false, true, false, false, false, false},
|
|
[]bool{false, true, true, true, false, false},
|
|
},
|
|
'7': encodedNumber{
|
|
[]bool{false, true, true, true, false, true, true},
|
|
[]bool{false, false, true, false, false, false, true},
|
|
[]bool{true, false, false, false, true, false, false},
|
|
[]bool{false, true, false, true, false, true},
|
|
},
|
|
'8': encodedNumber{
|
|
[]bool{false, true, true, false, true, true, true},
|
|
[]bool{false, false, false, true, false, false, true},
|
|
[]bool{true, false, false, true, false, false, false},
|
|
[]bool{false, true, false, true, true, false},
|
|
},
|
|
'9': encodedNumber{
|
|
[]bool{false, false, false, true, false, true, true},
|
|
[]bool{false, false, true, false, true, true, true},
|
|
[]bool{true, true, true, false, true, false, false},
|
|
[]bool{false, true, true, false, true, false},
|
|
},
|
|
}
|
|
|
|
func calcCheckNum(code string) rune {
|
|
x3 := len(code) == 7
|
|
sum := 0
|
|
for _, r := range code {
|
|
curNum := utils.RuneToInt(r)
|
|
if curNum < 0 || curNum > 9 {
|
|
return 'B'
|
|
}
|
|
if x3 {
|
|
curNum = curNum * 3
|
|
}
|
|
x3 = !x3
|
|
sum += curNum
|
|
}
|
|
|
|
return utils.IntToRune((10 - (sum % 10)) % 10)
|
|
}
|
|
|
|
func encodeEAN8(code string) *utils.BitList {
|
|
result := new(utils.BitList)
|
|
result.AddBit(true, false, true)
|
|
|
|
for cpos, r := range code {
|
|
num, ok := encoderTable[r]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
var data []bool
|
|
if cpos < 4 {
|
|
data = num.LeftOdd
|
|
} else {
|
|
data = num.Right
|
|
}
|
|
|
|
if cpos == 4 {
|
|
result.AddBit(false, true, false, true, false)
|
|
}
|
|
result.AddBit(data...)
|
|
}
|
|
result.AddBit(true, false, true)
|
|
|
|
return result
|
|
}
|
|
|
|
func encodeEAN13(code string) *utils.BitList {
|
|
result := new(utils.BitList)
|
|
result.AddBit(true, false, true)
|
|
|
|
var firstNum []bool
|
|
for cpos, r := range code {
|
|
num, ok := encoderTable[r]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
if cpos == 0 {
|
|
firstNum = num.CheckSum
|
|
continue
|
|
}
|
|
|
|
var data []bool
|
|
if cpos < 7 { // Left
|
|
if firstNum[cpos-1] {
|
|
data = num.LeftEven
|
|
} else {
|
|
data = num.LeftOdd
|
|
}
|
|
} else {
|
|
data = num.Right
|
|
}
|
|
|
|
if cpos == 7 {
|
|
result.AddBit(false, true, false, true, false)
|
|
}
|
|
result.AddBit(data...)
|
|
}
|
|
result.AddBit(true, false, true)
|
|
return result
|
|
}
|
|
|
|
// Encode returns a EAN 8 or EAN 13 barcode for the given code
|
|
func Encode(code string) (barcode.BarcodeIntCS, error) {
|
|
var checkSum int
|
|
if len(code) == 7 || len(code) == 12 {
|
|
code += string(calcCheckNum(code))
|
|
checkSum = utils.RuneToInt(calcCheckNum(code))
|
|
} else if len(code) == 8 || len(code) == 13 {
|
|
check := code[0 : len(code)-1]
|
|
check += string(calcCheckNum(check))
|
|
if check != code {
|
|
return nil, errors.New("checksum missmatch")
|
|
}
|
|
checkSum = utils.RuneToInt(rune(code[len(code)-1]))
|
|
}
|
|
|
|
if len(code) == 8 {
|
|
result := encodeEAN8(code)
|
|
if result != nil {
|
|
return utils.New1DCodeIntCheckSum(barcode.TypeEAN8, code, result, checkSum), nil
|
|
}
|
|
} else if len(code) == 13 {
|
|
result := encodeEAN13(code)
|
|
if result != nil {
|
|
return utils.New1DCodeIntCheckSum(barcode.TypeEAN13, code, result, checkSum), nil
|
|
}
|
|
}
|
|
return nil, errors.New("invalid ean code data")
|
|
}
|