added test + code cleanup
This commit is contained in:
parent
dcebd7d65f
commit
bccb3d2ede
|
@ -3,8 +3,9 @@ package qr
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/boombuler/barcode/utils"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/boombuler/barcode/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const charSet string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
|
const charSet string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
|
||||||
|
|
|
@ -5,11 +5,11 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeString(length int) string {
|
func makeString(length int, content string) string {
|
||||||
res := ""
|
res := ""
|
||||||
|
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
res += "A"
|
res += content
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
@ -24,11 +24,11 @@ func Test_AlphaNumericEncoding(t *testing.T) {
|
||||||
t.Errorf("\"HELLO WORLD\" failed to encode: %s", err)
|
t.Errorf("\"HELLO WORLD\" failed to encode: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
x, vi, err = encode(makeString(4296), L)
|
x, vi, err = encode(makeString(4296, "A"), L)
|
||||||
if x == nil || vi == nil || err != nil {
|
if x == nil || vi == nil || err != nil {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
x, vi, err = encode(makeString(4297), L)
|
x, vi, err = encode(makeString(4297, "A"), L)
|
||||||
if x != nil || vi != nil || err == nil {
|
if x != nil || vi != nil || err == nil {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package qr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/boombuler/barcode/utils"
|
"github.com/boombuler/barcode/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ func Test_AutomaticEncoding(t *testing.T) {
|
||||||
"0123456789": Numeric.getEncoder(),
|
"0123456789": Numeric.getEncoder(),
|
||||||
"ALPHA NUMERIC": AlphaNumeric.getEncoder(),
|
"ALPHA NUMERIC": AlphaNumeric.getEncoder(),
|
||||||
"unicode encoing": Unicode.getEncoder(),
|
"unicode encoing": Unicode.getEncoder(),
|
||||||
"very long unicode encoding" + makeString(3000): nil,
|
"very long unicode encoding" + makeString(3000, "A"): nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
for str, enc := range tests {
|
for str, enc := range tests {
|
||||||
|
|
269
qr/encoder.go
269
qr/encoder.go
|
@ -1,26 +1,29 @@
|
||||||
// package for QR barcode generation.
|
// Package qr can be used to create QR barcodes.
|
||||||
package qr
|
package qr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"image"
|
||||||
|
|
||||||
"github.com/boombuler/barcode"
|
"github.com/boombuler/barcode"
|
||||||
"github.com/boombuler/barcode/utils"
|
"github.com/boombuler/barcode/utils"
|
||||||
"image"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type encodeFn func(content string, eccLevel ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error)
|
type encodeFn func(content string, eccLevel ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error)
|
||||||
|
|
||||||
|
// Encoding mode for QR Codes.
|
||||||
type Encoding byte
|
type Encoding byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Choose best matching encoding
|
// Auto will choose ths best matching encoding
|
||||||
Auto Encoding = iota
|
Auto Encoding = iota
|
||||||
// Encode only numbers [0-9]
|
// Numeric encoding only encodes numbers [0-9]
|
||||||
Numeric
|
Numeric
|
||||||
// Encode only uppercase letters, numbers and [Space], $, %, *, +, -, ., /, :
|
// AlphaNumeric encoding only encodes uppercase letters, numbers and [Space], $, %, *, +, -, ., /, :
|
||||||
AlphaNumeric
|
AlphaNumeric
|
||||||
// Encodes string as utf-8
|
// Unicode encoding encodes the string as utf-8
|
||||||
Unicode
|
Unicode
|
||||||
|
// only for testing purpose
|
||||||
|
unknownEncoding
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e Encoding) getEncoder() encodeFn {
|
func (e Encoding) getEncoder() encodeFn {
|
||||||
|
@ -51,15 +54,12 @@ func (e Encoding) String() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encodes the given content to a QR barcode
|
// Encode returns a QR barcode with the given content, error correction level and uses the given encoding
|
||||||
func Encode(content string, level ErrorCorrectionLevel, mode Encoding) (barcode.Barcode, error) {
|
func Encode(content string, level ErrorCorrectionLevel, mode Encoding) (barcode.Barcode, error) {
|
||||||
bits, vi, err := mode.getEncoder()(content, level)
|
bits, vi, err := mode.getEncoder()(content, level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if bits == nil || vi == nil {
|
|
||||||
return nil, fmt.Errorf("Unable to encode \"%s\" with error correction level %s and encoding mode %s", content, level, mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks := splitToBlocks(bits.IterateBytes(), vi)
|
blocks := splitToBlocks(bits.IterateBytes(), vi)
|
||||||
data := blocks.interleave(vi)
|
data := blocks.interleave(vi)
|
||||||
|
@ -107,7 +107,7 @@ func render(data []byte, vi *versionInfo) *qrcode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the data
|
// Write the data
|
||||||
var curBitNo int = 0
|
var curBitNo int
|
||||||
|
|
||||||
for pos := range iterateModules(occupied) {
|
for pos := range iterateModules(occupied) {
|
||||||
var curBit bool
|
var curBit bool
|
||||||
|
@ -120,7 +120,7 @@ func render(data []byte, vi *versionInfo) *qrcode {
|
||||||
for i := 0; i < 8; i++ {
|
for i := 0; i < 8; i++ {
|
||||||
setMasked(pos.X, pos.Y, curBit, i, results[i].Set)
|
setMasked(pos.X, pos.Y, curBit, i, results[i].Set)
|
||||||
}
|
}
|
||||||
curBitNo += 1
|
curBitNo++
|
||||||
}
|
}
|
||||||
|
|
||||||
lowestPenalty := ^uint(0)
|
lowestPenalty := ^uint(0)
|
||||||
|
@ -176,12 +176,12 @@ func iterateModules(occupied *qrcode) <-chan image.Point {
|
||||||
if isUpward {
|
if isUpward {
|
||||||
allPoints <- image.Pt(curX, curY)
|
allPoints <- image.Pt(curX, curY)
|
||||||
allPoints <- image.Pt(curX-1, curY)
|
allPoints <- image.Pt(curX-1, curY)
|
||||||
curY -= 1
|
curY--
|
||||||
if curY < 0 {
|
if curY < 0 {
|
||||||
curY = 0
|
curY = 0
|
||||||
curX -= 2
|
curX -= 2
|
||||||
if curX == 6 {
|
if curX == 6 {
|
||||||
curX -= 1
|
curX--
|
||||||
}
|
}
|
||||||
if curX < 0 {
|
if curX < 0 {
|
||||||
break
|
break
|
||||||
|
@ -191,12 +191,12 @@ func iterateModules(occupied *qrcode) <-chan image.Point {
|
||||||
} else {
|
} else {
|
||||||
allPoints <- image.Pt(curX, curY)
|
allPoints <- image.Pt(curX, curY)
|
||||||
allPoints <- image.Pt(curX-1, curY)
|
allPoints <- image.Pt(curX-1, curY)
|
||||||
curY += 1
|
curY++
|
||||||
if curY >= occupied.dimension {
|
if curY >= occupied.dimension {
|
||||||
curY = occupied.dimension - 1
|
curY = occupied.dimension - 1
|
||||||
curX -= 2
|
curX -= 2
|
||||||
if curX == 6 {
|
if curX == 6 {
|
||||||
curX -= 1
|
curX--
|
||||||
}
|
}
|
||||||
isUpward = true
|
isUpward = true
|
||||||
if curX < 0 {
|
if curX < 0 {
|
||||||
|
@ -258,89 +258,56 @@ func drawAlignmentPatterns(occupied *qrcode, vi *versionInfo, set func(int, int,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var formatInfos = map[ErrorCorrectionLevel]map[int][]bool{
|
||||||
|
L: {
|
||||||
|
0: []bool{true, true, true, false, true, true, true, true, true, false, false, false, true, false, false},
|
||||||
|
1: []bool{true, true, true, false, false, true, false, true, true, true, true, false, false, true, true},
|
||||||
|
2: []bool{true, true, true, true, true, false, true, true, false, true, false, true, false, true, false},
|
||||||
|
3: []bool{true, true, true, true, false, false, false, true, false, false, true, true, true, false, true},
|
||||||
|
4: []bool{true, true, false, false, true, true, false, false, false, true, false, true, true, true, true},
|
||||||
|
5: []bool{true, true, false, false, false, true, true, false, false, false, true, true, false, false, false},
|
||||||
|
6: []bool{true, true, false, true, true, false, false, false, true, false, false, false, false, false, true},
|
||||||
|
7: []bool{true, true, false, true, false, false, true, false, true, true, true, false, true, true, false},
|
||||||
|
},
|
||||||
|
M: {
|
||||||
|
0: []bool{true, false, true, false, true, false, false, false, false, false, true, false, false, true, false},
|
||||||
|
1: []bool{true, false, true, false, false, false, true, false, false, true, false, false, true, false, true},
|
||||||
|
2: []bool{true, false, true, true, true, true, false, false, true, true, true, true, true, false, false},
|
||||||
|
3: []bool{true, false, true, true, false, true, true, false, true, false, false, true, false, true, true},
|
||||||
|
4: []bool{true, false, false, false, true, false, true, true, true, true, true, true, false, false, true},
|
||||||
|
5: []bool{true, false, false, false, false, false, false, true, true, false, false, true, true, true, false},
|
||||||
|
6: []bool{true, false, false, true, true, true, true, true, false, false, true, false, true, true, true},
|
||||||
|
7: []bool{true, false, false, true, false, true, false, true, false, true, false, false, false, false, false},
|
||||||
|
},
|
||||||
|
Q: {
|
||||||
|
0: []bool{false, true, true, false, true, false, true, false, true, false, true, true, true, true, true},
|
||||||
|
1: []bool{false, true, true, false, false, false, false, false, true, true, false, true, false, false, false},
|
||||||
|
2: []bool{false, true, true, true, true, true, true, false, false, true, true, false, false, false, true},
|
||||||
|
3: []bool{false, true, true, true, false, true, false, false, false, false, false, false, true, true, false},
|
||||||
|
4: []bool{false, true, false, false, true, false, false, true, false, true, true, false, true, false, false},
|
||||||
|
5: []bool{false, true, false, false, false, false, true, true, false, false, false, false, false, true, true},
|
||||||
|
6: []bool{false, true, false, true, true, true, false, true, true, false, true, true, false, true, false},
|
||||||
|
7: []bool{false, true, false, true, false, true, true, true, true, true, false, true, true, false, true},
|
||||||
|
},
|
||||||
|
H: {
|
||||||
|
0: []bool{false, false, true, false, true, true, false, true, false, false, false, true, false, false, true},
|
||||||
|
1: []bool{false, false, true, false, false, true, true, true, false, true, true, true, true, true, false},
|
||||||
|
2: []bool{false, false, true, true, true, false, false, true, true, true, false, false, true, true, true},
|
||||||
|
3: []bool{false, false, true, true, false, false, true, true, true, false, true, false, false, false, false},
|
||||||
|
4: []bool{false, false, false, false, true, true, true, false, true, true, false, false, false, true, false},
|
||||||
|
5: []bool{false, false, false, false, false, true, false, false, true, false, true, false, true, false, true},
|
||||||
|
6: []bool{false, false, false, true, true, false, true, false, false, false, false, true, true, false, false},
|
||||||
|
7: []bool{false, false, false, true, false, false, false, false, false, true, true, true, false, true, true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func drawFormatInfo(vi *versionInfo, usedMask int, set func(int, int, bool)) {
|
func drawFormatInfo(vi *versionInfo, usedMask int, set func(int, int, bool)) {
|
||||||
var formatInfo []bool
|
var formatInfo []bool
|
||||||
switch vi.Level {
|
|
||||||
case L:
|
|
||||||
switch usedMask {
|
|
||||||
case 0:
|
|
||||||
formatInfo = []bool{true, true, true, false, true, true, true, true, true, false, false, false, true, false, false}
|
|
||||||
case 1:
|
|
||||||
formatInfo = []bool{true, true, true, false, false, true, false, true, true, true, true, false, false, true, true}
|
|
||||||
case 2:
|
|
||||||
formatInfo = []bool{true, true, true, true, true, false, true, true, false, true, false, true, false, true, false}
|
|
||||||
case 3:
|
|
||||||
formatInfo = []bool{true, true, true, true, false, false, false, true, false, false, true, true, true, false, true}
|
|
||||||
case 4:
|
|
||||||
formatInfo = []bool{true, true, false, false, true, true, false, false, false, true, false, true, true, true, true}
|
|
||||||
case 5:
|
|
||||||
formatInfo = []bool{true, true, false, false, false, true, true, false, false, false, true, true, false, false, false}
|
|
||||||
case 6:
|
|
||||||
formatInfo = []bool{true, true, false, true, true, false, false, false, true, false, false, false, false, false, true}
|
|
||||||
case 7:
|
|
||||||
formatInfo = []bool{true, true, false, true, false, false, true, false, true, true, true, false, true, true, false}
|
|
||||||
}
|
|
||||||
case M:
|
|
||||||
switch usedMask {
|
|
||||||
case 0:
|
|
||||||
formatInfo = []bool{true, false, true, false, true, false, false, false, false, false, true, false, false, true, false}
|
|
||||||
case 1:
|
|
||||||
formatInfo = []bool{true, false, true, false, false, false, true, false, false, true, false, false, true, false, true}
|
|
||||||
case 2:
|
|
||||||
formatInfo = []bool{true, false, true, true, true, true, false, false, true, true, true, true, true, false, false}
|
|
||||||
case 3:
|
|
||||||
formatInfo = []bool{true, false, true, true, false, true, true, false, true, false, false, true, false, true, true}
|
|
||||||
case 4:
|
|
||||||
formatInfo = []bool{true, false, false, false, true, false, true, true, true, true, true, true, false, false, true}
|
|
||||||
case 5:
|
|
||||||
formatInfo = []bool{true, false, false, false, false, false, false, true, true, false, false, true, true, true, false}
|
|
||||||
case 6:
|
|
||||||
formatInfo = []bool{true, false, false, true, true, true, true, true, false, false, true, false, true, true, true}
|
|
||||||
case 7:
|
|
||||||
formatInfo = []bool{true, false, false, true, false, true, false, true, false, true, false, false, false, false, false}
|
|
||||||
}
|
|
||||||
case Q:
|
|
||||||
switch usedMask {
|
|
||||||
case 0:
|
|
||||||
formatInfo = []bool{false, true, true, false, true, false, true, false, true, false, true, true, true, true, true}
|
|
||||||
case 1:
|
|
||||||
formatInfo = []bool{false, true, true, false, false, false, false, false, true, true, false, true, false, false, false}
|
|
||||||
case 2:
|
|
||||||
formatInfo = []bool{false, true, true, true, true, true, true, false, false, true, true, false, false, false, true}
|
|
||||||
case 3:
|
|
||||||
formatInfo = []bool{false, true, true, true, false, true, false, false, false, false, false, false, true, true, false}
|
|
||||||
case 4:
|
|
||||||
formatInfo = []bool{false, true, false, false, true, false, false, true, false, true, true, false, true, false, false}
|
|
||||||
case 5:
|
|
||||||
formatInfo = []bool{false, true, false, false, false, false, true, true, false, false, false, false, false, true, true}
|
|
||||||
case 6:
|
|
||||||
formatInfo = []bool{false, true, false, true, true, true, false, true, true, false, true, true, false, true, false}
|
|
||||||
case 7:
|
|
||||||
formatInfo = []bool{false, true, false, true, false, true, true, true, true, true, false, true, true, false, true}
|
|
||||||
}
|
|
||||||
case H:
|
|
||||||
switch usedMask {
|
|
||||||
case 0:
|
|
||||||
formatInfo = []bool{false, false, true, false, true, true, false, true, false, false, false, true, false, false, true}
|
|
||||||
case 1:
|
|
||||||
formatInfo = []bool{false, false, true, false, false, true, true, true, false, true, true, true, true, true, false}
|
|
||||||
case 2:
|
|
||||||
formatInfo = []bool{false, false, true, true, true, false, false, true, true, true, false, false, true, true, true}
|
|
||||||
case 3:
|
|
||||||
formatInfo = []bool{false, false, true, true, false, false, true, true, true, false, true, false, false, false, false}
|
|
||||||
case 4:
|
|
||||||
formatInfo = []bool{false, false, false, false, true, true, true, false, true, true, false, false, false, true, false}
|
|
||||||
case 5:
|
|
||||||
formatInfo = []bool{false, false, false, false, false, true, false, false, true, false, true, false, true, false, true}
|
|
||||||
case 6:
|
|
||||||
formatInfo = []bool{false, false, false, true, true, false, true, false, false, false, false, true, true, false, false}
|
|
||||||
case 7:
|
|
||||||
formatInfo = []bool{false, false, false, true, false, false, false, false, false, true, true, true, false, true, true}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if usedMask == -1 {
|
if usedMask == -1 {
|
||||||
formatInfo = []bool{true, true, true, true, true, true, true, true, true, true, true, true, true, true, true} // Set all to true cause -1 --> occupied mask.
|
formatInfo = []bool{true, true, true, true, true, true, true, true, true, true, true, true, true, true, true} // Set all to true cause -1 --> occupied mask.
|
||||||
|
} else {
|
||||||
|
formatInfo = formatInfos[vi.Level][usedMask]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(formatInfo) == 15 {
|
if len(formatInfo) == 15 {
|
||||||
|
@ -379,81 +346,47 @@ func drawFormatInfo(vi *versionInfo, usedMask int, set func(int, int, bool)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawVersionInfo(vi *versionInfo, set func(int, int, bool)) {
|
var versionInfoBitsByVersion = map[byte][]bool{
|
||||||
var versionInfoBits []bool
|
7: []bool{false, false, false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false},
|
||||||
|
8: []bool{false, false, true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false},
|
||||||
switch vi.Version {
|
9: []bool{false, false, true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true},
|
||||||
case 7:
|
10: []bool{false, false, true, false, true, false, false, true, false, false, true, true, false, true, false, false, true, true},
|
||||||
versionInfoBits = []bool{false, false, false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false}
|
11: []bool{false, false, true, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false},
|
||||||
case 8:
|
12: []bool{false, false, true, true, false, false, false, true, true, true, false, true, true, false, false, false, true, false},
|
||||||
versionInfoBits = []bool{false, false, true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false}
|
13: []bool{false, false, true, true, false, true, true, false, false, false, false, true, false, false, false, true, true, true},
|
||||||
case 9:
|
14: []bool{false, false, true, true, true, false, false, true, true, false, false, false, false, false, true, true, false, true},
|
||||||
versionInfoBits = []bool{false, false, true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true}
|
15: []bool{false, false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false, false},
|
||||||
case 10:
|
16: []bool{false, true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false, false},
|
||||||
versionInfoBits = []bool{false, false, true, false, true, false, false, true, false, false, true, true, false, true, false, false, true, true}
|
17: []bool{false, true, false, false, false, true, false, true, false, false, false, true, false, true, true, true, false, true},
|
||||||
case 11:
|
18: []bool{false, true, false, false, true, false, true, false, true, false, false, false, false, true, false, true, true, true},
|
||||||
versionInfoBits = []bool{false, false, true, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false}
|
19: []bool{false, true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true, false},
|
||||||
case 12:
|
20: []bool{false, true, false, true, false, false, true, false, false, true, true, false, true, false, false, true, true, false},
|
||||||
versionInfoBits = []bool{false, false, true, true, false, false, false, true, true, true, false, true, true, false, false, false, true, false}
|
21: []bool{false, true, false, true, false, true, false, true, true, false, true, false, false, false, false, false, true, true},
|
||||||
case 13:
|
22: []bool{false, true, false, true, true, false, true, false, false, false, true, true, false, false, true, false, false, true},
|
||||||
versionInfoBits = []bool{false, false, true, true, false, true, true, false, false, false, false, true, false, false, false, true, true, true}
|
23: []bool{false, true, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false},
|
||||||
case 14:
|
24: []bool{false, true, true, false, false, false, true, true, true, false, true, true, false, false, false, true, false, false},
|
||||||
versionInfoBits = []bool{false, false, true, true, true, false, false, true, true, false, false, false, false, false, true, true, false, true}
|
25: []bool{false, true, true, false, false, true, false, false, false, true, true, true, true, false, false, false, false, true},
|
||||||
case 15:
|
26: []bool{false, true, true, false, true, false, true, true, true, true, true, false, true, false, true, false, true, true},
|
||||||
versionInfoBits = []bool{false, false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false, false}
|
27: []bool{false, true, true, false, true, true, false, false, false, false, true, false, false, false, true, true, true, false},
|
||||||
case 16:
|
28: []bool{false, true, true, true, false, false, true, true, false, false, false, false, false, true, true, false, true, false},
|
||||||
versionInfoBits = []bool{false, true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false, false}
|
29: []bool{false, true, true, true, false, true, false, false, true, true, false, false, true, true, true, true, true, true},
|
||||||
case 17:
|
30: []bool{false, true, true, true, true, false, true, true, false, true, false, true, true, true, false, true, false, true},
|
||||||
versionInfoBits = []bool{false, true, false, false, false, true, false, true, false, false, false, true, false, true, true, true, false, true}
|
31: []bool{false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false, false, false},
|
||||||
case 18:
|
32: []bool{true, false, false, false, false, false, true, false, false, true, true, true, false, true, false, true, false, true},
|
||||||
versionInfoBits = []bool{false, true, false, false, true, false, true, false, true, false, false, false, false, true, false, true, true, true}
|
33: []bool{true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false, false, false},
|
||||||
case 19:
|
34: []bool{true, false, false, false, true, false, true, false, false, false, true, false, true, true, true, false, true, false},
|
||||||
versionInfoBits = []bool{false, true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true, false}
|
35: []bool{true, false, false, false, true, true, false, true, true, true, true, false, false, true, true, true, true, true},
|
||||||
case 20:
|
36: []bool{true, false, false, true, false, false, true, false, true, true, false, false, false, false, true, false, true, true},
|
||||||
versionInfoBits = []bool{false, true, false, true, false, false, true, false, false, true, true, false, true, false, false, true, true, false}
|
37: []bool{true, false, false, true, false, true, false, true, false, false, false, false, true, false, true, true, true, false},
|
||||||
case 21:
|
38: []bool{true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true, false, false},
|
||||||
versionInfoBits = []bool{false, true, false, true, false, true, false, true, true, false, true, false, false, false, false, false, true, true}
|
39: []bool{true, false, false, true, true, true, false, true, false, true, false, true, false, false, false, false, false, true},
|
||||||
case 22:
|
40: []bool{true, false, true, false, false, false, true, true, false, false, false, true, true, false, true, false, false, true},
|
||||||
versionInfoBits = []bool{false, true, false, true, true, false, true, false, false, false, true, true, false, false, true, false, false, true}
|
|
||||||
case 23:
|
|
||||||
versionInfoBits = []bool{false, true, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false}
|
|
||||||
case 24:
|
|
||||||
versionInfoBits = []bool{false, true, true, false, false, false, true, true, true, false, true, true, false, false, false, true, false, false}
|
|
||||||
case 25:
|
|
||||||
versionInfoBits = []bool{false, true, true, false, false, true, false, false, false, true, true, true, true, false, false, false, false, true}
|
|
||||||
case 26:
|
|
||||||
versionInfoBits = []bool{false, true, true, false, true, false, true, true, true, true, true, false, true, false, true, false, true, true}
|
|
||||||
case 27:
|
|
||||||
versionInfoBits = []bool{false, true, true, false, true, true, false, false, false, false, true, false, false, false, true, true, true, false}
|
|
||||||
case 28:
|
|
||||||
versionInfoBits = []bool{false, true, true, true, false, false, true, true, false, false, false, false, false, true, true, false, true, false}
|
|
||||||
case 29:
|
|
||||||
versionInfoBits = []bool{false, true, true, true, false, true, false, false, true, true, false, false, true, true, true, true, true, true}
|
|
||||||
case 30:
|
|
||||||
versionInfoBits = []bool{false, true, true, true, true, false, true, true, false, true, false, true, true, true, false, true, false, true}
|
|
||||||
case 31:
|
|
||||||
versionInfoBits = []bool{false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false, false, false}
|
|
||||||
case 32:
|
|
||||||
versionInfoBits = []bool{true, false, false, false, false, false, true, false, false, true, true, true, false, true, false, true, false, true}
|
|
||||||
case 33:
|
|
||||||
versionInfoBits = []bool{true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false, false, false}
|
|
||||||
case 34:
|
|
||||||
versionInfoBits = []bool{true, false, false, false, true, false, true, false, false, false, true, false, true, true, true, false, true, false}
|
|
||||||
case 35:
|
|
||||||
versionInfoBits = []bool{true, false, false, false, true, true, false, true, true, true, true, false, false, true, true, true, true, true}
|
|
||||||
case 36:
|
|
||||||
versionInfoBits = []bool{true, false, false, true, false, false, true, false, true, true, false, false, false, false, true, false, true, true}
|
|
||||||
case 37:
|
|
||||||
versionInfoBits = []bool{true, false, false, true, false, true, false, true, false, false, false, false, true, false, true, true, true, false}
|
|
||||||
case 38:
|
|
||||||
versionInfoBits = []bool{true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true, false, false}
|
|
||||||
case 39:
|
|
||||||
versionInfoBits = []bool{true, false, false, true, true, true, false, true, false, true, false, true, false, false, false, false, false, true}
|
|
||||||
case 40:
|
|
||||||
versionInfoBits = []bool{true, false, true, false, false, false, true, true, false, false, false, true, true, false, true, false, false, true}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(versionInfoBits) > 0 {
|
func drawVersionInfo(vi *versionInfo, set func(int, int, bool)) {
|
||||||
|
versionInfoBits, ok := versionInfoBitsByVersion[vi.Version]
|
||||||
|
|
||||||
|
if ok && len(versionInfoBits) > 0 {
|
||||||
for i := 0; i < len(versionInfoBits); i++ {
|
for i := 0; i < len(versionInfoBits); i++ {
|
||||||
x := (vi.modulWidth() - 11) + i%3
|
x := (vi.modulWidth() - 11) + i%3
|
||||||
y := i / 3
|
y := i / 3
|
||||||
|
|
|
@ -2,13 +2,14 @@ package qr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/boombuler/barcode"
|
|
||||||
"image/png"
|
"image/png"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/boombuler/barcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
var qrHelloWorldHUni []bool = []bool{true, true, true, true, true, true, true, false, true, false, true, false, true, false, false, false, true, false, true, true, true, true, true, true, true,
|
var qrHelloWorldHUni = []bool{true, true, true, true, true, true, true, false, true, false, true, false, true, false, false, false, true, false, true, true, true, true, true, true, true,
|
||||||
true, false, false, false, false, false, true, false, true, true, false, false, false, true, true, true, false, false, true, false, false, false, false, false, true,
|
true, false, false, false, false, false, true, false, true, true, false, false, false, true, true, true, false, false, true, false, false, false, false, false, true,
|
||||||
true, false, true, true, true, false, true, false, true, false, true, false, true, true, false, true, true, false, true, false, true, true, true, false, true,
|
true, false, true, true, true, false, true, false, true, false, true, false, true, true, false, true, true, false, true, false, true, true, true, false, true,
|
||||||
true, false, true, true, true, false, true, false, false, false, false, true, true, false, true, true, false, false, true, false, true, true, true, false, true,
|
true, false, true, true, true, false, true, false, false, false, false, true, true, false, true, true, false, false, true, false, true, true, true, false, true,
|
||||||
|
@ -35,6 +36,35 @@ var qrHelloWorldHUni []bool = []bool{true, true, true, true, true, true, true, f
|
||||||
true, true, true, true, true, true, true, false, false, false, false, true, false, false, true, false, true, false, false, true, false, false, true, true, true,
|
true, true, true, true, true, true, true, false, false, false, false, true, false, false, true, false, true, false, false, true, false, false, true, true, true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_GetUnknownEncoder(t *testing.T) {
|
||||||
|
if unknownEncoding.getEncoder() != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_EncodingStringer(t *testing.T) {
|
||||||
|
tests := map[Encoding]string{
|
||||||
|
Auto: "Auto",
|
||||||
|
Numeric: "Numeric",
|
||||||
|
AlphaNumeric: "AlphaNumeric",
|
||||||
|
Unicode: "Unicode",
|
||||||
|
unknownEncoding: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
for enc, str := range tests {
|
||||||
|
if enc.String() != str {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_InvalidEncoding(t *testing.T) {
|
||||||
|
_, err := Encode("hello world", H, Numeric)
|
||||||
|
if err == nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Encode(t *testing.T) {
|
func Test_Encode(t *testing.T) {
|
||||||
res, err := Encode("hello world", H, Unicode)
|
res, err := Encode("hello world", H, Unicode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -9,7 +9,7 @@ type errorCorrection struct {
|
||||||
polynomes map[byte][]byte
|
polynomes map[byte][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var ec *errorCorrection = newGF()
|
var ec = newGF()
|
||||||
|
|
||||||
func newGF() *errorCorrection {
|
func newGF() *errorCorrection {
|
||||||
return &errorCorrection{utils.NewGaloisField(285), make(map[byte][]byte)}
|
return &errorCorrection{utils.NewGaloisField(285), make(map[byte][]byte)}
|
||||||
|
|
|
@ -3,8 +3,9 @@ package qr
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/boombuler/barcode/utils"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/boombuler/barcode/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func encodeNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) {
|
func encodeNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) {
|
||||||
|
|
|
@ -19,4 +19,8 @@ func Test_NumericEncoding(t *testing.T) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Numeric encoding should not be able to encode \"foo\"")
|
t.Error("Numeric encoding should not be able to encode \"foo\"")
|
||||||
}
|
}
|
||||||
|
x, vi, err = encode(makeString(14297, "1"), H)
|
||||||
|
if x != nil || vi != nil || err == nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
25
qr/qrcode.go
25
qr/qrcode.go
|
@ -1,11 +1,12 @@
|
||||||
package qr
|
package qr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/boombuler/barcode"
|
|
||||||
"github.com/boombuler/barcode/utils"
|
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/boombuler/barcode"
|
||||||
|
"github.com/boombuler/barcode/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type qrcode struct {
|
type qrcode struct {
|
||||||
|
@ -50,16 +51,16 @@ func (qr *qrcode) calcPenalty() uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qr *qrcode) calcPenaltyRule1() uint {
|
func (qr *qrcode) calcPenaltyRule1() uint {
|
||||||
var result uint = 0
|
var result uint
|
||||||
for x := 0; x < qr.dimension; x++ {
|
for x := 0; x < qr.dimension; x++ {
|
||||||
checkForX := false
|
checkForX := false
|
||||||
var cntX uint = 0
|
var cntX uint
|
||||||
checkForY := false
|
checkForY := false
|
||||||
var cntY uint = 0
|
var cntY uint
|
||||||
|
|
||||||
for y := 0; y < qr.dimension; y++ {
|
for y := 0; y < qr.dimension; y++ {
|
||||||
if qr.Get(x, y) == checkForX {
|
if qr.Get(x, y) == checkForX {
|
||||||
cntX += 1
|
cntX++
|
||||||
} else {
|
} else {
|
||||||
checkForX = !checkForX
|
checkForX = !checkForX
|
||||||
if cntX >= 5 {
|
if cntX >= 5 {
|
||||||
|
@ -69,7 +70,7 @@ func (qr *qrcode) calcPenaltyRule1() uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
if qr.Get(y, x) == checkForY {
|
if qr.Get(y, x) == checkForY {
|
||||||
cntY += 1
|
cntY++
|
||||||
} else {
|
} else {
|
||||||
checkForY = !checkForY
|
checkForY = !checkForY
|
||||||
if cntY >= 5 {
|
if cntY >= 5 {
|
||||||
|
@ -91,7 +92,7 @@ func (qr *qrcode) calcPenaltyRule1() uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qr *qrcode) calcPenaltyRule2() uint {
|
func (qr *qrcode) calcPenaltyRule2() uint {
|
||||||
var result uint = 0
|
var result uint
|
||||||
for x := 0; x < qr.dimension-1; x++ {
|
for x := 0; x < qr.dimension-1; x++ {
|
||||||
for y := 0; y < qr.dimension-1; y++ {
|
for y := 0; y < qr.dimension-1; y++ {
|
||||||
check := qr.Get(x, y)
|
check := qr.Get(x, y)
|
||||||
|
@ -104,10 +105,10 @@ func (qr *qrcode) calcPenaltyRule2() uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qr *qrcode) calcPenaltyRule3() uint {
|
func (qr *qrcode) calcPenaltyRule3() uint {
|
||||||
var pattern1 []bool = []bool{true, false, true, true, true, false, true, false, false, false, false}
|
pattern1 := []bool{true, false, true, true, true, false, true, false, false, false, false}
|
||||||
var pattern2 []bool = []bool{false, false, false, false, true, false, true, true, true, false, true}
|
pattern2 := []bool{false, false, false, false, true, false, true, true, true, false, true}
|
||||||
|
|
||||||
var result uint = 0
|
var result uint
|
||||||
for x := 0; x <= qr.dimension-len(pattern1); x++ {
|
for x := 0; x <= qr.dimension-len(pattern1); x++ {
|
||||||
for y := 0; y < qr.dimension; y++ {
|
for y := 0; y < qr.dimension; y++ {
|
||||||
pattern1XFound := true
|
pattern1XFound := true
|
||||||
|
@ -148,7 +149,7 @@ func (qr *qrcode) calcPenaltyRule4() uint {
|
||||||
trueCnt := 0
|
trueCnt := 0
|
||||||
for i := 0; i < totalNum; i++ {
|
for i := 0; i < totalNum; i++ {
|
||||||
if qr.data.GetBit(i) {
|
if qr.data.GetBit(i) {
|
||||||
trueCnt += 1
|
trueCnt++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
percDark := float64(trueCnt) * 100 / float64(totalNum)
|
percDark := float64(trueCnt) * 100 / float64(totalNum)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package qr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/boombuler/barcode/utils"
|
"github.com/boombuler/barcode/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ func Test_UnicodeEncoding(t *testing.T) {
|
||||||
if x == nil || vi == nil || vi.Version != 1 || bytes.Compare(x.GetBytes(), []byte{64, 20, 16, 236, 17, 236, 17, 236, 17}) != 0 {
|
if x == nil || vi == nil || vi.Version != 1 || bytes.Compare(x.GetBytes(), []byte{64, 20, 16, 236, 17, 236, 17, 236, 17}) != 0 {
|
||||||
t.Errorf("\"A\" failed to encode: %s", err)
|
t.Errorf("\"A\" failed to encode: %s", err)
|
||||||
}
|
}
|
||||||
_, _, err = encode(makeString(3000), H)
|
_, _, err = encode(makeString(3000, "A"), H)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Unicode encoding should not be able to encode a 3kb string")
|
t.Error("Unicode encoding should not be able to encode a 3kb string")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,17 @@ package qr
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
|
||||||
|
// ErrorCorrectionLevel indicates the amount of "backup data" stored in the QR code
|
||||||
type ErrorCorrectionLevel byte
|
type ErrorCorrectionLevel byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Recovers 7% of data
|
// L recovers 7% of data
|
||||||
L ErrorCorrectionLevel = iota
|
L ErrorCorrectionLevel = iota
|
||||||
// Recovers 15% of data
|
// M recovers 15% of data
|
||||||
M
|
M
|
||||||
// Recovers 25% of data
|
// Q recovers 25% of data
|
||||||
Q
|
Q
|
||||||
// Recovers 30% of data
|
// H recovers 30% of data
|
||||||
H
|
H
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ type versionInfo struct {
|
||||||
DataCodeWordsPerBlockInGroup2 byte
|
DataCodeWordsPerBlockInGroup2 byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var versionInfos []*versionInfo = []*versionInfo{
|
var versionInfos = []*versionInfo{
|
||||||
&versionInfo{1, L, 7, 1, 19, 0, 0},
|
&versionInfo{1, L, 7, 1, 19, 0, 0},
|
||||||
&versionInfo{1, M, 10, 1, 16, 0, 0},
|
&versionInfo{1, M, 10, 1, 16, 0, 0},
|
||||||
&versionInfo{1, Q, 13, 1, 13, 0, 0},
|
&versionInfo{1, Q, 13, 1, 13, 0, 0},
|
||||||
|
@ -218,39 +219,40 @@ func (vi *versionInfo) totalDataBytes() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vi *versionInfo) charCountBits(m encodingMode) byte {
|
func (vi *versionInfo) charCountBits(m encodingMode) byte {
|
||||||
if m == numericMode {
|
switch m {
|
||||||
|
case numericMode:
|
||||||
if vi.Version < 10 {
|
if vi.Version < 10 {
|
||||||
return 10
|
return 10
|
||||||
} else if vi.Version < 27 {
|
} else if vi.Version < 27 {
|
||||||
return 12
|
return 12
|
||||||
} else {
|
|
||||||
return 14
|
|
||||||
}
|
}
|
||||||
} else if m == alphaNumericMode {
|
return 14
|
||||||
|
|
||||||
|
case alphaNumericMode:
|
||||||
if vi.Version < 10 {
|
if vi.Version < 10 {
|
||||||
return 9
|
return 9
|
||||||
} else if vi.Version < 27 {
|
} else if vi.Version < 27 {
|
||||||
return 11
|
return 11
|
||||||
} else {
|
|
||||||
return 13
|
|
||||||
}
|
}
|
||||||
} else if m == byteMode {
|
return 13
|
||||||
|
|
||||||
|
case byteMode:
|
||||||
if vi.Version < 10 {
|
if vi.Version < 10 {
|
||||||
return 8
|
return 8
|
||||||
} else {
|
|
||||||
return 16
|
|
||||||
}
|
}
|
||||||
} else if m == kanjiMode {
|
return 16
|
||||||
|
|
||||||
|
case kanjiMode:
|
||||||
if vi.Version < 10 {
|
if vi.Version < 10 {
|
||||||
return 8
|
return 8
|
||||||
} else if vi.Version < 27 {
|
} else if vi.Version < 27 {
|
||||||
return 10
|
return 10
|
||||||
} else {
|
}
|
||||||
return 12
|
return 12
|
||||||
}
|
default:
|
||||||
}
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (vi *versionInfo) modulWidth() int {
|
func (vi *versionInfo) modulWidth() int {
|
||||||
return ((int(vi.Version) - 1) * 4) + 21
|
return ((int(vi.Version) - 1) * 4) + 21
|
||||||
|
@ -261,9 +263,9 @@ func (vi *versionInfo) alignmentPatternPlacements() []int {
|
||||||
return make([]int, 0)
|
return make([]int, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var first int = 6
|
first := 6
|
||||||
var last int = vi.modulWidth() - 7
|
last := vi.modulWidth() - 7
|
||||||
var space float64 = float64(last - first)
|
space := float64(last - first)
|
||||||
count := int(math.Ceil(space/28)) + 1
|
count := int(math.Ceil(space/28)) + 1
|
||||||
|
|
||||||
result := make([]int, count)
|
result := make([]int, count)
|
||||||
|
@ -281,9 +283,9 @@ func (vi *versionInfo) alignmentPatternPlacements() []int {
|
||||||
}
|
}
|
||||||
|
|
||||||
if int(frac)%2 == 0 {
|
if int(frac)%2 == 0 {
|
||||||
step -= 1
|
step--
|
||||||
} else {
|
} else {
|
||||||
step += 1
|
step++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ package qr
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
var testvi *versionInfo = &versionInfo{7, M, 0, 1, 10, 2, 5} // Fake versionInfo to run some of the tests
|
var testvi = &versionInfo{7, M, 0, 1, 10, 2, 5} // Fake versionInfo to run some of the tests
|
||||||
|
|
||||||
func Test_ErrorCorrectionStringer(t *testing.T) {
|
func Test_ErrorCorrectionStringer(t *testing.T) {
|
||||||
tests := map[ErrorCorrectionLevel]string{
|
tests := map[ErrorCorrectionLevel]string{
|
||||||
|
@ -56,6 +56,9 @@ func Test_CharCountBits(t *testing.T) {
|
||||||
if v3.charCountBits(kanjiMode) != 12 {
|
if v3.charCountBits(kanjiMode) != 12 {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
if v1.charCountBits(encodingMode(3)) != 0 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_TotalDataBytes(t *testing.T) {
|
func Test_TotalDataBytes(t *testing.T) {
|
||||||
|
@ -92,7 +95,7 @@ type aligmnentTest struct {
|
||||||
patterns []int
|
patterns []int
|
||||||
}
|
}
|
||||||
|
|
||||||
var allAligmnentTests []*aligmnentTest = []*aligmnentTest{
|
var allAligmnentTests = []*aligmnentTest{
|
||||||
&aligmnentTest{1, []int{}},
|
&aligmnentTest{1, []int{}},
|
||||||
&aligmnentTest{2, []int{6, 18}},
|
&aligmnentTest{2, []int{6, 18}},
|
||||||
&aligmnentTest{3, []int{6, 22}},
|
&aligmnentTest{3, []int{6, 22}},
|
||||||
|
|
Loading…
Reference in New Issue