barcode/ean/encoder.go

193 lines
5.1 KiB
Go
Raw Normal View History

2014-08-11 09:11:24 +00:00
// Package ean can create EAN 8 and EAN 13 barcodes.
2013-12-11 13:31:11 +00:00
package ean
import (
"errors"
2014-08-11 09:11:24 +00:00
2013-12-11 13:31:11 +00:00
"github.com/boombuler/barcode"
2013-12-16 13:10:24 +00:00
"github.com/boombuler/barcode/utils"
2013-12-11 13:31:11 +00:00
)
type encodedNumber struct {
LeftOdd []bool
LeftEven []bool
Right []bool
CheckSum []bool
}
2014-08-11 09:11:24 +00:00
var encoderTable = map[rune]encodedNumber{
2013-12-11 13:31:11 +00:00
'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)
2013-12-11 13:31:11 +00:00
if curNum < 0 || curNum > 9 {
return 'B'
}
if x3 {
curNum = curNum * 3
}
x3 = !x3
sum += curNum
}
return utils.IntToRune((10 - (sum % 10)) % 10)
2013-12-11 13:31:11 +00:00
}
2013-12-16 13:10:24 +00:00
func encodeEAN8(code string) *utils.BitList {
result := new(utils.BitList)
result.AddBit(true, false, true)
2013-12-11 13:31:11 +00:00
for cpos, r := range code {
num, ok := encoderTable[r]
if !ok {
2013-12-16 13:10:24 +00:00
return nil
2013-12-11 13:31:11 +00:00
}
var data []bool
if cpos < 4 {
data = num.LeftOdd
} else {
data = num.Right
}
if cpos == 4 {
2013-12-16 13:10:24 +00:00
result.AddBit(false, true, false, true, false)
2013-12-11 13:31:11 +00:00
}
2013-12-16 13:10:24 +00:00
result.AddBit(data...)
2013-12-11 13:31:11 +00:00
}
2013-12-16 13:10:24 +00:00
result.AddBit(true, false, true)
2013-12-11 13:31:11 +00:00
2013-12-16 13:10:24 +00:00
return result
2013-12-11 13:31:11 +00:00
}
2013-12-16 13:10:24 +00:00
func encodeEAN13(code string) *utils.BitList {
result := new(utils.BitList)
result.AddBit(true, false, true)
2013-12-11 13:31:11 +00:00
var firstNum []bool
for cpos, r := range code {
num, ok := encoderTable[r]
if !ok {
2013-12-16 13:10:24 +00:00
return nil
2013-12-11 13:31:11 +00:00
}
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 {
2013-12-16 13:10:24 +00:00
result.AddBit(false, true, false, true, false)
2013-12-11 13:31:11 +00:00
}
2013-12-16 13:10:24 +00:00
result.AddBit(data...)
2013-12-11 13:31:11 +00:00
}
2013-12-16 20:12:46 +00:00
result.AddBit(true, false, true)
2013-12-16 13:10:24 +00:00
return result
2013-12-11 13:31:11 +00:00
}
2014-08-11 09:11:24 +00:00
// Encode returns a EAN 8 or EAN 13 barcode for the given code
func EncodeWithColor(code string, color barcode.ColorScheme) (barcode.BarcodeIntCS, error) {
var checkSum int
2013-12-11 13:31:11 +00:00
if len(code) == 7 || len(code) == 12 {
code += string(calcCheckNum(code))
checkSum = utils.RuneToInt(calcCheckNum(code))
2013-12-11 13:31:11 +00:00
} else if len(code) == 8 || len(code) == 13 {
check := code[0 : len(code)-1]
check += string(calcCheckNum(check))
if check != code {
2014-08-11 09:11:24 +00:00
return nil, errors.New("checksum missmatch")
2013-12-11 13:31:11 +00:00
}
checkSum = utils.RuneToInt(rune(code[len(code)-1]))
2013-12-11 13:31:11 +00:00
}
2013-12-16 20:12:46 +00:00
2013-12-11 13:31:11 +00:00
if len(code) == 8 {
2013-12-16 13:10:24 +00:00
result := encodeEAN8(code)
if result != nil {
return utils.New1DCodeIntCheckSumWithColor(barcode.TypeEAN8, code, result, checkSum, color), nil
2013-12-16 13:10:24 +00:00
}
} else if len(code) == 13 {
result := encodeEAN13(code)
if result != nil {
return utils.New1DCodeIntCheckSumWithColor(barcode.TypeEAN13, code, result, checkSum, color), nil
2013-12-16 13:10:24 +00:00
}
2013-12-11 13:31:11 +00:00
}
2013-12-16 13:10:24 +00:00
return nil, errors.New("invalid ean code data")
2013-12-11 13:31:11 +00:00
}
// Encode returns a EAN 8 or EAN 13 barcode for the given code
func Encode(code string) (barcode.BarcodeIntCS, error) {
return EncodeWithColor(code, barcode.ColorScheme16)
}