bugfix for datamatrix error correction

more tests and code cleanup
This commit is contained in:
Florian Sundermann 2013-12-13 13:53:27 +01:00
parent e754f1b44c
commit e5d11acdbf
19 changed files with 291 additions and 157 deletions

View File

@ -2,17 +2,18 @@ package code39
import ( import (
"github.com/boombuler/barcode" "github.com/boombuler/barcode"
"github.com/boombuler/barcode/utils"
"image" "image"
"image/color" "image/color"
) )
type code struct { type code struct {
*barcode.BitList *utils.BitList
content string content string
} }
func newCode() *code { func newCode() *code {
return &code{&barcode.BitList{}, ""} return &code{new(utils.BitList), ""}
} }
func (c *code) Content() string { func (c *code) Content() string {

View File

@ -1,21 +1,21 @@
package datamatrix package datamatrix
import ( import (
"github.com/boombuler/barcode" "github.com/boombuler/barcode/utils"
) )
type setValFunc func(byte) type setValFunc func(byte)
type codeLayout struct { type codeLayout struct {
matrix *barcode.BitList matrix *utils.BitList
occupy *barcode.BitList occupy *utils.BitList
size *dmCodeSize size *dmCodeSize
} }
func newCodeLayout(size *dmCodeSize) *codeLayout { func newCodeLayout(size *dmCodeSize) *codeLayout {
result := new(codeLayout) result := new(codeLayout)
result.matrix = barcode.NewBitList(size.MatrixColumns() * size.MatrixRows()) result.matrix = utils.NewBitList(size.MatrixColumns() * size.MatrixRows())
result.occupy = barcode.NewBitList(size.MatrixColumns() * size.MatrixRows()) result.occupy = utils.NewBitList(size.MatrixColumns() * size.MatrixRows())
result.size = size result.size = size
return result return result
} }

View File

@ -2,18 +2,19 @@ package datamatrix
import ( import (
"github.com/boombuler/barcode" "github.com/boombuler/barcode"
"github.com/boombuler/barcode/utils"
"image" "image"
"image/color" "image/color"
) )
type datamatrixCode struct { type datamatrixCode struct {
*barcode.BitList *utils.BitList
*dmCodeSize *dmCodeSize
content string content string
} }
func newDataMatrixCode(size *dmCodeSize) *datamatrixCode { func newDataMatrixCode(size *dmCodeSize) *datamatrixCode {
return &datamatrixCode{barcode.NewBitList(size.Rows * size.Columns), size, ""} return &datamatrixCode{utils.NewBitList(size.Rows * size.Columns), size, ""}
} }
func (c *datamatrixCode) Content() string { func (c *datamatrixCode) Content() string {

View File

@ -20,7 +20,7 @@ func Encode(content string) (barcode.Barcode, error) {
return nil, errors.New("to much data to encode") return nil, errors.New("to much data to encode")
} }
data = addPadding(data, size.DataCodewords()) data = addPadding(data, size.DataCodewords())
data = generateECC(data, size) data = ec.calcECC(data, size)
code := render(data, size) code := render(data, size)
if code != nil { if code != nil {
code.content = content code.content = content

View File

@ -1,103 +1,80 @@
package datamatrix package datamatrix
// a more generic way would be great! import (
// like qr.galoisField with 301 "github.com/boombuler/barcode/utils"
)
var gf_log []int = []int{ type errorCorrection struct {
0, 255, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43, 54, 210, fld *utils.GaloisField
4, 195, 39, 114, 227, 106, 134, 28, 243, 140, 44, 23, 55, 118, 211, 234, polynomes map[int][]int
5, 219, 196, 96, 40, 222, 115, 103, 228, 78, 107, 125, 135, 8, 29, 162,
244, 186, 141, 180, 45, 99, 24, 49, 56, 13, 119, 153, 212, 199, 235, 91,
6, 76, 220, 217, 197, 11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193,
229, 86, 79, 171, 108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84,
245, 173, 187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207,
57, 147, 14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176,
7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179,
42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 113,
230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127, 247, 146, 66,
137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 164, 144, 85, 170,
246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251,
47, 178, 89, 151, 101, 94, 160, 123, 26, 112, 232, 21, 51, 238, 208, 131,
58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59, 249, 70,
214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20, 93, 122, 177, 150,
} }
var gf_alog []int = []int{ var ec *errorCorrection = newErrorCorrection()
1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57, 114, 228,
229, 231, 227, 235, 251, 219, 155, 27, 54, 108, 216, 157, 23, 46, 92, 184, func newErrorCorrection() *errorCorrection {
93, 186, 89, 178, 73, 146, 9, 18, 36, 72, 144, 13, 26, 52, 104, 208, result := new(errorCorrection)
141, 55, 110, 220, 149, 7, 14, 28, 56, 112, 224, 237, 247, 195, 171, 123, result.fld = utils.NewGaloisField(301)
246, 193, 175, 115, 230, 225, 239, 243, 203, 187, 91, 182, 65, 130, 41, 82, result.polynomes = make(map[int][]int)
164, 101, 202, 185, 95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 135, return result
35, 70, 140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250,
217, 159, 19, 38, 76, 152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172,
117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200,
189, 87, 174, 113, 226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107,
214, 129, 47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169,
127, 254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206,
177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111,
222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74,
148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248, 221, 151,
3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 150, 1,
} }
var gf_polys map[int][]int = map[int][]int{ func (ec *errorCorrection) getPolynomial(count int) []int {
5: []int{228, 48, 15, 111, 62}, poly, ok := ec.polynomes[count]
7: []int{23, 68, 144, 134, 240, 92, 254}, if !ok {
10: []int{28, 24, 185, 166, 223, 248, 116, 255, 110, 61}, idx := 1
11: []int{175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120}, poly = make([]int, count+1)
12: []int{41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242}, poly[0] = 1
14: []int{156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185}, for i := 1; i <= count; i++ {
18: []int{83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48, 90, 188}, poly[i] = 1
20: []int{15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82, 27, 174, 186, 172}, for j := i - 1; j > 0; j-- {
24: []int{52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172, 254, 124, 12, 181, 184, 96, 50, 193}, if poly[j] != 0 {
28: []int{211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121, 17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255}, poly[j] = ec.fld.ALogTbl[(int(ec.fld.LogTbl[poly[j]])+idx)%255]
36: []int{245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 182, 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25, 225, 98, 81, 112}, }
42: []int{77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8, 175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101, 248, 202, 69, 50, 150, 177, 226, 5, 9, 5}, poly[j] = ec.fld.AddOrSub(poly[j], poly[j-1])
48: []int{245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87, 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138, 186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19}, }
56: []int{175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235, 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232, 144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28, 155, 43, 203, 107, 233, 53, 143, 46}, poly[0] = ec.fld.ALogTbl[(int(ec.fld.LogTbl[poly[0]])+idx)%255]
62: []int{242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37, 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71, 161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31, 176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204}, idx++
68: []int{220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127, 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236, 66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239, 181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63, 96, 103, 82, 186}, }
} poly = poly[0:count]
ec.polynomes[count] = poly
func rsBlock(data []byte, ncout []byte, poly []int) {
for i := 0; i < len(ncout); i++ {
ncout[i] = 0
} }
return poly
}
func (ec *errorCorrection) calcECCBlock(data []byte, poly []int) []byte {
ecc := make([]byte, len(poly)+1)
for i := 0; i < len(data); i++ { for i := 0; i < len(data); i++ {
k := (ncout[0] ^ data[i]) & 0xff k := ec.fld.AddOrSub(int(ecc[0]), int(data[i]))
for j := 0; j < len(ncout)-1; j++ { for j := 0; j < len(ecc)-1; j++ {
k1 := 0 ecc[j] = byte(ec.fld.AddOrSub(int(ecc[j+1]), ec.fld.Multiply(k, poly[len(ecc)-j-2])))
if k != 0 {
k1 = gf_alog[(gf_log[k]+gf_log[poly[len(ncout)-j-2]])%255]
}
ncout[j] = ncout[j+1] ^ byte(k1)
} }
} }
return ecc
} }
func generateECC(data []byte, size *dmCodeSize) []byte { func (ec *errorCorrection) calcECC(data []byte, size *dmCodeSize) []byte {
buff := make([]byte, size.DataCodewordsPerBlock()) buff := make([]byte, size.DataCodewordsPerBlock())
ecc := make([]byte, size.ErrorCorrectionCodewordsPerBlock()+1) poly := ec.getPolynomial(size.ErrorCorrectionCodewordsPerBlock())
poly := gf_polys[size.ErrorCorrectionCodewordsPerBlock()]
dataSize := len(data) dataSize := len(data)
// make some space... // make some space for error correction codes
space := make([]byte, size.ECCCount) data = append(data, make([]byte, size.ECCCount)...)
data = append(data, space...)
for b := 0; b < size.BlockCount; b++ { for block := 0; block < size.BlockCount; block++ {
p := 0 // copy the data for the current block to buff
for n := b; n < dataSize; n += size.BlockCount { j := 0
buff[p] = data[n] for i := block; i < dataSize; i += size.BlockCount {
p++ buff[j] = data[i]
j++
} }
rsBlock(buff, ecc, poly) // calc the error correction codes
p = 0 ecc := ec.calcECCBlock(buff, poly)
for n := b; n < size.ErrorCorrectionCodewordsPerBlock()*size.BlockCount; n += size.BlockCount { // and append them to the result
data[dataSize+n] = ecc[p] j = 0
p++ for i := block; i < size.ErrorCorrectionCodewordsPerBlock()*size.BlockCount; i += size.BlockCount {
data[dataSize+i] = ecc[j]
j++
} }
} }

View File

@ -0,0 +1,61 @@
package datamatrix
import (
"bytes"
"testing"
)
func Test_GetPolynomial(t *testing.T) {
var gf_polys map[int][]int = map[int][]int{
5: []int{228, 48, 15, 111, 62},
7: []int{23, 68, 144, 134, 240, 92, 254},
10: []int{28, 24, 185, 166, 223, 248, 116, 255, 110, 61},
11: []int{175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120},
12: []int{41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242},
14: []int{156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185},
18: []int{83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48, 90, 188},
20: []int{15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82, 27, 174, 186, 172},
24: []int{52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172, 254, 124, 12, 181, 184, 96, 50, 193},
28: []int{211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121, 17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255},
36: []int{245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 182, 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25, 225, 98, 81, 112},
42: []int{77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8, 175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101, 248, 202, 69, 50, 150, 177, 226, 5, 9, 5},
48: []int{245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87, 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138, 186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19},
56: []int{175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235, 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232, 144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28, 155, 43, 203, 107, 233, 53, 143, 46},
62: []int{242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37, 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71, 161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31, 176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204},
68: []int{220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127, 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236, 66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239, 181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63, 96, 103, 82, 186},
}
for i, tst := range gf_polys {
res := ec.getPolynomial(i)
if len(res) != len(tst) {
t.Fail()
}
for i := 0; i < len(res); i++ {
if res[i] != tst[i] {
t.Fail()
}
}
}
}
func Test_CalcECC(t *testing.T) {
data := []byte{142, 164, 186}
var size *dmCodeSize = nil
for _, s := range codeSizes {
if s.DataCodewords() >= len(data) {
size = s
break
}
}
if size == nil {
t.Error("size not found")
}
if bytes.Compare(ec.calcECC(data, size), []byte{142, 164, 186, 114, 25, 5, 88, 102}) != 0 {
t.Error("ECC Test 1 failed")
}
data = []byte{66, 129, 70}
if bytes.Compare(ec.calcECC(data, size), []byte{66, 129, 70, 138, 234, 82, 82, 95}) != 0 {
t.Error("ECC Test 2 failed")
}
}

View File

@ -2,12 +2,13 @@ package ean
import ( import (
"github.com/boombuler/barcode" "github.com/boombuler/barcode"
"github.com/boombuler/barcode/utils"
"image" "image"
"image/color" "image/color"
) )
type eancode struct { type eancode struct {
*barcode.BitList *utils.BitList
content string content string
} }
@ -16,7 +17,7 @@ func newEANCode(isEAN8 bool) *eancode {
if isEAN8 { if isEAN8 {
capacity = 67 capacity = 67
} }
return &eancode{barcode.NewBitList(capacity), ""} return &eancode{utils.NewBitList(capacity), ""}
} }
func (c *eancode) Content() string { func (c *eancode) Content() string {

View File

@ -3,7 +3,7 @@ package qr
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/boombuler/barcode" "github.com/boombuler/barcode/utils"
"strings" "strings"
) )
@ -25,7 +25,7 @@ func stringToAlphaIdx(content string) <-chan int {
return result return result
} }
func encodeAlphaNumeric(content string, ecl ErrorCorrectionLevel) (*barcode.BitList, *versionInfo, error) { func encodeAlphaNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) {
contentLenIsOdd := len(content)%2 == 1 contentLenIsOdd := len(content)%2 == 1
contentBitCount := (len(content) / 2) * 11 contentBitCount := (len(content) / 2) * 11
@ -37,7 +37,7 @@ func encodeAlphaNumeric(content string, ecl ErrorCorrectionLevel) (*barcode.BitL
return nil, nil, errors.New("To much data to encode") return nil, nil, errors.New("To much data to encode")
} }
res := new(barcode.BitList) res := new(utils.BitList)
res.AddBits(int(alphaNumericMode), 4) res.AddBits(int(alphaNumericMode), 4)
res.AddBits(len(content), vi.charCountBits(alphaNumericMode)) res.AddBits(len(content), vi.charCountBits(alphaNumericMode))

View File

@ -2,10 +2,10 @@ package qr
import ( import (
"fmt" "fmt"
"github.com/boombuler/barcode" "github.com/boombuler/barcode/utils"
) )
func encodeAuto(content string, ecl ErrorCorrectionLevel) (*barcode.BitList, *versionInfo, error) { func encodeAuto(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) {
bits, vi, _ := Numeric.getEncoder()(content, ecl) bits, vi, _ := Numeric.getEncoder()(content, ecl)
if bits != nil && vi != nil { if bits != nil && vi != nil {
return bits, vi, nil return bits, vi, nil

View File

@ -15,7 +15,7 @@ func splitToBlocks(data <-chan byte, vi *versionInfo) blockList {
for cw := 0; cw < int(vi.DataCodeWordsPerBlockInGroup1); cw++ { for cw := 0; cw < int(vi.DataCodeWordsPerBlockInGroup1); cw++ {
blk.data[cw] = <-data blk.data[cw] = <-data
} }
blk.ecc = gf.calcECC(blk.data, vi.ErrorCorrectionCodewordsPerBlock) blk.ecc = ec.calcECC(blk.data, vi.ErrorCorrectionCodewordsPerBlock)
result[b] = blk result[b] = blk
} }
@ -25,7 +25,7 @@ func splitToBlocks(data <-chan byte, vi *versionInfo) blockList {
for cw := 0; cw < int(vi.DataCodeWordsPerBlockInGroup2); cw++ { for cw := 0; cw < int(vi.DataCodeWordsPerBlockInGroup2); cw++ {
blk.data[cw] = <-data blk.data[cw] = <-data
} }
blk.ecc = gf.calcECC(blk.data, vi.ErrorCorrectionCodewordsPerBlock) blk.ecc = ec.calcECC(blk.data, vi.ErrorCorrectionCodewordsPerBlock)
result[int(vi.NumberOfBlocksInGroup1)+b] = blk result[int(vi.NumberOfBlocksInGroup1)+b] = blk
} }

View File

@ -4,10 +4,11 @@ package qr
import ( import (
"fmt" "fmt"
"github.com/boombuler/barcode" "github.com/boombuler/barcode"
"github.com/boombuler/barcode/utils"
"image" "image"
) )
type encodeFn func(content string, eccLevel ErrorCorrectionLevel) (*barcode.BitList, *versionInfo, error) type encodeFn func(content string, eccLevel ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error)
type Encoding byte type Encoding byte
@ -463,7 +464,7 @@ func drawVersionInfo(vi *versionInfo, set func(int, int, bool)) {
} }
func addPaddingAndTerminator(bl *barcode.BitList, vi *versionInfo) { func addPaddingAndTerminator(bl *utils.BitList, vi *versionInfo) {
for i := 0; i < 4 && bl.Len() < vi.totalDataBytes()*8; i++ { for i := 0; i < 4 && bl.Len() < vi.totalDataBytes()*8; i++ {
bl.AddBit(false) bl.AddBit(false)
} }

View File

@ -1,73 +1,56 @@
package qr package qr
type galoisField struct { import (
aLogTbl []byte "github.com/boombuler/barcode/utils"
logTbl []byte )
type errorCorrection struct {
fld *utils.GaloisField
polynomes map[byte][]byte polynomes map[byte][]byte
} }
var gf *galoisField = newGF() var ec *errorCorrection = newGF()
func newGF() *galoisField { func newGF() *errorCorrection {
result := new(galoisField) return &errorCorrection{utils.NewGaloisField(285), make(map[byte][]byte)}
result.polynomes = make(map[byte][]byte)
result.aLogTbl = make([]byte, 255)
result.logTbl = make([]byte, 256)
result.aLogTbl[0] = 1
x := 1
for i := 1; i < 255; i++ {
x = x * 2
if x > 255 {
x = x ^ 285
}
result.aLogTbl[i] = byte(x)
}
for i := 1; i < 255; i++ {
result.logTbl[result.aLogTbl[i]] = byte(i)
}
return result
} }
func (gf *galoisField) getPolynom(eccc byte) []byte { func (ec *errorCorrection) getPolynomial(eccc byte) []byte {
_, ok := gf.polynomes[eccc] _, ok := ec.polynomes[eccc]
if !ok { if !ok {
if eccc == 1 { if eccc == 1 {
gf.polynomes[eccc] = []byte{0, 0} ec.polynomes[eccc] = []byte{0, 0}
} else { } else {
b1 := gf.getPolynom(eccc - 1) b1 := ec.getPolynomial(eccc - 1)
result := make([]byte, eccc+1) result := make([]byte, eccc+1)
for x := 0; x < len(b1); x++ { for x := 0; x < len(b1); x++ {
tmp1 := (int(b1[x]) + int(eccc-1)) % 255 tmp1 := (int(b1[x]) + int(eccc-1)) % 255
if x == 0 { if x == 0 {
result[x] = b1[x] result[x] = b1[x]
} else { } else {
tmp0 := int(gf.aLogTbl[result[x]]) ^ int(gf.aLogTbl[b1[x]]) tmp0 := int(ec.fld.ALogTbl[result[x]]) ^ int(ec.fld.ALogTbl[b1[x]])
result[x] = gf.logTbl[tmp0] result[x] = byte(ec.fld.LogTbl[tmp0])
} }
result[x+1] = byte(tmp1) result[x+1] = byte(tmp1)
} }
gf.polynomes[eccc] = result ec.polynomes[eccc] = result
} }
} }
return gf.polynomes[eccc] return ec.polynomes[eccc]
} }
func (gf *galoisField) calcECC(data []byte, eccCount byte) []byte { func (ec *errorCorrection) calcECC(data []byte, eccCount byte) []byte {
tmp := make([]byte, len(data)+int(eccCount)) tmp := make([]byte, len(data)+int(eccCount))
copy(tmp, data) copy(tmp, data)
generator := gf.getPolynom(eccCount) generator := ec.getPolynomial(eccCount)
for i := 0; i < len(data); i++ { for i := 0; i < len(data); i++ {
alpha := gf.logTbl[tmp[i]] alpha := ec.fld.LogTbl[tmp[i]]
for j := 0; j < len(generator); j++ { for j := 0; j < len(generator); j++ {
idx := (int(alpha) + int(generator[j])) % 255 idx := (int(alpha) + int(generator[j])) % 255
polyJ := gf.aLogTbl[idx] polyJ := ec.fld.ALogTbl[idx]
tmp[i+j] = (tmp[i+j] ^ polyJ) tmp[i+j] = byte(ec.fld.AddOrSub(int(tmp[i+j]), polyJ))
} }
} }

View File

@ -7,22 +7,22 @@ import (
func Test_LogTables(t *testing.T) { func Test_LogTables(t *testing.T) {
for i := 1; i <= 255; i++ { for i := 1; i <= 255; i++ {
tmp := gf.logTbl[i] tmp := ec.fld.LogTbl[i]
if byte(i) != gf.aLogTbl[tmp] { if i != ec.fld.ALogTbl[tmp] {
t.Errorf("Invalid LogTables: %d", i) t.Errorf("Invalid LogTables: %d", i)
} }
} }
if gf.aLogTbl[11] != 232 || gf.aLogTbl[87] != 127 || gf.aLogTbl[225] != 36 { if ec.fld.ALogTbl[11] != 232 || ec.fld.ALogTbl[87] != 127 || ec.fld.ALogTbl[225] != 36 {
t.Fail() t.Fail()
} }
} }
func Test_Polynoms(t *testing.T) { func Test_GetPolynomial(t *testing.T) {
doTest := func(b []byte) { doTest := func(b []byte) {
cnt := byte(len(b) - 1) cnt := byte(len(b) - 1)
if bytes.Compare(gf.getPolynom(cnt), b) != 0 { if bytes.Compare(ec.getPolynomial(cnt), b) != 0 {
t.Errorf("Failed getPolynom(%d)", cnt) t.Errorf("Failed getPolynomial(%d)", cnt)
} }
} }
doTest([]byte{0, 0}) doTest([]byte{0, 0})
@ -34,7 +34,7 @@ func Test_Polynoms(t *testing.T) {
func Test_ErrorCorrection(t *testing.T) { func Test_ErrorCorrection(t *testing.T) {
doTest := func(b []byte, ecc []byte) { doTest := func(b []byte, ecc []byte) {
cnt := byte(len(ecc)) cnt := byte(len(ecc))
if bytes.Compare(gf.calcECC(b, cnt), ecc) != 0 { if bytes.Compare(ec.calcECC(b, cnt), ecc) != 0 {
t.Fail() t.Fail()
} }
} }

View File

@ -3,11 +3,11 @@ package qr
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/boombuler/barcode" "github.com/boombuler/barcode/utils"
"strconv" "strconv"
) )
func encodeNumeric(content string, ecl ErrorCorrectionLevel) (*barcode.BitList, *versionInfo, error) { func encodeNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) {
contentBitCount := (len(content) / 3) * 10 contentBitCount := (len(content) / 3) * 10
switch len(content) % 3 { switch len(content) % 3 {
case 1: case 1:
@ -19,7 +19,7 @@ func encodeNumeric(content string, ecl ErrorCorrectionLevel) (*barcode.BitList,
if vi == nil { if vi == nil {
return nil, nil, errors.New("To much data to encode") return nil, nil, errors.New("To much data to encode")
} }
res := new(barcode.BitList) res := new(utils.BitList)
res.AddBits(int(numericMode), 4) res.AddBits(int(numericMode), 4)
res.AddBits(len(content), vi.charCountBits(numericMode)) res.AddBits(len(content), vi.charCountBits(numericMode))

View File

@ -2,6 +2,7 @@ package qr
import ( import (
"github.com/boombuler/barcode" "github.com/boombuler/barcode"
"github.com/boombuler/barcode/utils"
"image" "image"
"image/color" "image/color"
"math" "math"
@ -9,7 +10,7 @@ import (
type qrcode struct { type qrcode struct {
dimension int dimension int
data *barcode.BitList data *utils.BitList
content string content string
} }
@ -159,6 +160,6 @@ func (qr *qrcode) calcPenaltyRule4() uint {
func newBarcode(dim int) *qrcode { func newBarcode(dim int) *qrcode {
res := new(qrcode) res := new(qrcode)
res.dimension = dim res.dimension = dim
res.data = barcode.NewBitList(dim * dim) res.data = utils.NewBitList(dim * dim)
return res return res
} }

View File

@ -2,10 +2,10 @@ package qr
import ( import (
"errors" "errors"
"github.com/boombuler/barcode" "github.com/boombuler/barcode/utils"
) )
func encodeUnicode(content string, ecl ErrorCorrectionLevel) (*barcode.BitList, *versionInfo, error) { func encodeUnicode(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) {
data := []byte(content) data := []byte(content)
vi := findSmallestVersionInfo(ecl, byteMode, len(data)*8) vi := findSmallestVersionInfo(ecl, byteMode, len(data)*8)
@ -15,7 +15,7 @@ func encodeUnicode(content string, ecl ErrorCorrectionLevel) (*barcode.BitList,
// It's not correct to add the unicode bytes to the result directly but most readers can't handle the // It's not correct to add the unicode bytes to the result directly but most readers can't handle the
// required ECI header... // required ECI header...
res := new(barcode.BitList) res := new(utils.BitList)
res.AddBits(int(byteMode), 4) res.AddBits(int(byteMode), 4)
res.AddBits(len(content), vi.charCountBits(byteMode)) res.AddBits(len(content), vi.charCountBits(byteMode))
for _, b := range data { for _, b := range data {

View File

@ -1,4 +1,4 @@
package barcode package utils
// utility class that contains bits // utility class that contains bits
type BitList struct { type BitList struct {

49
utils/galoisfield.go Normal file
View File

@ -0,0 +1,49 @@
package utils
type GaloisField struct {
ALogTbl []int
LogTbl []int
}
func NewGaloisField(pp int) *GaloisField {
result := new(GaloisField)
fldSize := 256
result.ALogTbl = make([]int, fldSize)
result.LogTbl = make([]int, fldSize)
x := 1
for i := 0; i < fldSize; i++ {
result.ALogTbl[i] = x
x = x * 2
if x >= fldSize {
x = (x ^ pp) & (fldSize - 1)
}
}
for i := 0; i < fldSize; i++ {
result.LogTbl[result.ALogTbl[i]] = int(i)
}
return result
}
func (gf *GaloisField) AddOrSub(a, b int) int {
return a ^ b
}
func (gf *GaloisField) Multiply(a, b int) int {
if a == 0 || b == 0 {
return 0
}
return gf.ALogTbl[(gf.LogTbl[a]+gf.LogTbl[b])%255]
}
func (gf *GaloisField) Divide(a, b int) int {
if b == 0 {
panic("divide by zero")
} else if a == 0 {
return 0
}
return gf.ALogTbl[(gf.LogTbl[a]-gf.LogTbl[b])%255]
}

59
utils/galoisfield_test.go Normal file
View File

@ -0,0 +1,59 @@
package utils
import (
"testing"
)
func Test_GF(t *testing.T) {
log := []int{
0, 255, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43, 54, 210,
4, 195, 39, 114, 227, 106, 134, 28, 243, 140, 44, 23, 55, 118, 211, 234,
5, 219, 196, 96, 40, 222, 115, 103, 228, 78, 107, 125, 135, 8, 29, 162,
244, 186, 141, 180, 45, 99, 24, 49, 56, 13, 119, 153, 212, 199, 235, 91,
6, 76, 220, 217, 197, 11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193,
229, 86, 79, 171, 108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84,
245, 173, 187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207,
57, 147, 14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176,
7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179,
42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 113,
230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127, 247, 146, 66,
137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 164, 144, 85, 170,
246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251,
47, 178, 89, 151, 101, 94, 160, 123, 26, 112, 232, 21, 51, 238, 208, 131,
58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59, 249, 70,
214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20, 93, 122, 177, 150,
}
alog := []int{
1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57, 114, 228,
229, 231, 227, 235, 251, 219, 155, 27, 54, 108, 216, 157, 23, 46, 92, 184,
93, 186, 89, 178, 73, 146, 9, 18, 36, 72, 144, 13, 26, 52, 104, 208,
141, 55, 110, 220, 149, 7, 14, 28, 56, 112, 224, 237, 247, 195, 171, 123,
246, 193, 175, 115, 230, 225, 239, 243, 203, 187, 91, 182, 65, 130, 41, 82,
164, 101, 202, 185, 95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 135,
35, 70, 140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250,
217, 159, 19, 38, 76, 152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172,
117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200,
189, 87, 174, 113, 226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107,
214, 129, 47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169,
127, 254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206,
177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111,
222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74,
148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248, 221, 151,
3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 150, 1,
}
gf := NewGaloisField(301)
if len(gf.LogTbl) != len(gf.ALogTbl) || len(gf.LogTbl) != len(log) {
t.Fail()
}
for i := 0; i < len(log); i++ {
if gf.LogTbl[i] != log[i] {
t.Error("Invalid Log Table")
}
if gf.ALogTbl[i] != alog[i] {
t.Error("Invalid ALog Table")
}
}
}